99 return general && general->enabled;
119 .description =
"Asterisk RESTful API",
135 size_t old_size, new_size;
140 new_size = old_size +
sizeof(
handler);
147 new_handler->children[new_handler->num_children++] =
handler;
174 memcpy(new_handler,
root_handler,
sizeof(*new_handler));
214 const char *response_text,
215 const char *message_fmt, ...)
220 va_start(ap, message_fmt);
287 char *allowed =
ast_strdupa(general ? general->allowed_origins :
"");
295 if (!strcmp(
current, origin)) {
303#define ACR_METHOD "Access-Control-Request-Method"
304#define ACR_HEADERS "Access-Control-Request-Headers"
305#define ACA_METHODS "Access-Control-Allow-Methods"
306#define ACA_HEADERS "Access-Control-Allow-Headers"
319 char const *acr_method =
NULL;
320 char const *acr_headers =
NULL;
321 char const *origin =
NULL;
337 }
else if (strcmp(
"Origin",
header->
name) == 0) {
345 if (origin ==
NULL) {
360 ast_log(
LOG_NOTICE,
"Origin header '%s' does not match an allowed origin.\n", origin);
368 if (acr_method ==
NULL) {
375 if (acr_headers ==
NULL) {
394 if (strcmp(m_str, acr_method) == 0) {
459 userid_len = strlen(
userid) + 1;
460 password_len = strlen(
password) + 1;
469 auth->
userid = (
char *)(auth + 1);
490 for (v = get_params; v; v = v->
next) {
494 char *username =
strsep(&password,
":");
506static void test_ari_user_destructor(
void *obj)
539 ast_trace(-1,
"Validating user %s\n", http_auth->userid);
567 ari_user =
ao2_alloc(
sizeof(*ari_user), test_ari_user_destructor);
590 slashless[strlen(slashless) - 1] =
'\0';
609 "ARI URLs do not end with a slash. Try /ari/%s", slashless);
658 "WWW-Authenticate: Basic realm=\"%s\"\r\n",
659 general->auth_realm);
720 path_var->
next = path_vars;
721 path_vars = path_var;
722 wildcard_handler = child;
725 }
else if (strcmp(child->
path_segment, path_segment) == 0) {
726 found_handler = child;
734 if (!found_handler && wildcard_handler) {
735 ast_trace(-1,
" No explicit handler found for %s. Using wildcard %s.\n",
737 found_handler = wildcard_handler;
738 wildcard_handler =
NULL;
741 if (found_handler ==
NULL) {
744 response, 404,
"Not Found",
745 "Resource not found");
750 SCOPE_EXIT(
"Done checking %s\n", path_segment);
768 response, 405,
"Method Not Allowed",
777 response, 400,
"Bad request",
778 "Can't upgrade to websocket from a websocket");
783 ast_trace(-1,
"Handling websocket %s\n", uri);
785 get_params, headers);
796 response, 405,
"Method Not Allowed",
802 ast_trace(-1,
"Running callback: %s\n", uri);
803 callback(ser, get_params, path_vars, headers, body, response);
809 response, 501,
"Not Implemented",
810 "Method not implemented");
827 struct stat file_stat;
832 if (absolute_path_builder ==
NULL) {
841 if (absolute_api_dirname ==
NULL) {
844 response, 500,
"Internal Server Error",
845 "Cannot find rest-api directory");
852 if (absolute_filename ==
NULL) {
858 response, 404,
"Not Found",
859 "Resource not found");
863 response, 403,
"Forbidden",
864 "Permission denied");
868 "Error determining real path for uri '%s': %s\n",
869 uri, strerror(
errno));
871 response, 500,
"Internal Server Error",
881 "Invalid attempt to access '%s' (not in %s)\n",
882 absolute_filename, absolute_api_dirname);
884 response, 404,
"Not Found",
885 "Resource not found");
889 if (stat(absolute_filename, &file_stat) == 0) {
890 if (!(file_stat.st_mode & S_IFREG)) {
893 response, 403,
"Forbidden",
900 response, 404,
"Not Found",
901 "Resource not found");
911 response, 500,
"Internal Server Error",
912 "Yikes! Cannot parse resource");
918 for (host = headers; host; host = host->
next) {
919 if (strcasecmp(host->
name,
"Host") == 0) {
950 char const *origin =
NULL;
963 if (origin ==
NULL) {
975 ast_log(
LOG_NOTICE,
"Origin header '%s' does not match an allowed origin.\n", origin);
988 "Access-Control-Allow-Origin: %s\r\n", origin);
990 "Access-Control-Allow-Credentials: true\r\n");
1038 if (!response_body) {
1063 "Request Entity Too Large",
1064 "Request body too large");
1065 goto request_failed;
1069 "Internal Server Error",
1071 goto request_failed;
1074 "Bad Request",
"Error parsing request body");
1075 goto request_failed;
1082 ast_trace(-1,
"Checking body for vars\n");
1088 goto request_failed;
1091 goto request_failed;
1094 goto request_failed;
1098 if (get_params ==
NULL) {
1099 ast_trace(-1,
"No get_params, using post_vars if any\n");
1100 get_params = post_vars;
1101 }
else if (get_params && post_vars) {
1104 ast_trace(-1,
"Has get_params and post_vars. Merging\n");
1105 while (last_var->
next) {
1106 last_var = last_var->
next;
1112 get_params = post_vars;
1132 if (!
buf || (body && !
str)) {
1137 goto request_failed;
1156 urih, uri,
method, get_params, headers, body, &response);
1181 "Content-type: application/json\r\n");
1193 ast_verbose(
"<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n",
1201 response.
fd != -1 ? response.
fd : 0, 0);
1203 response_body =
NULL;
1206 if (response.
fd >= 0) {
1251 "{s: s}",
"error",
"Allocation failed");
1303 int is_now_enabled = 0;
1309 if (was_enabled && !is_now_enabled) {
1312 }
else if (!was_enabled && is_now_enabled) {
1325 .
requires =
"http,res_stasis,res_http_websocket,res_websocket_client",
1326 .optional_modules =
"res_ari_model",
enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
Apply a set of rules to a given IP address.
int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
Determines if an ACL is empty or if it contains entries.
Asterisk RESTful API hooks.
@ ARI_INVOKE_SOURCE_WEBSOCKET
@ ARI_INVOKE_RESULT_SUCCESS
@ ARI_INVOKE_RESULT_ERROR_CLOSE
@ ARI_INVOKE_RESULT_ERROR_CONTINUE
void(* stasis_rest_callback)(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Callback type for RESTful method handlers.
int ari_websocket_load_module(int is_enabled)
int ari_websocket_unload_module(void)
void ari_handle_websocket(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Wrapper for invoking the websocket code for an incoming connection.
Internal API's for websockets.
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
void ast_std_free(void *ptr)
#define ast_strdupa(s)
duplicate a string in memory from the stack
@ AO2_ALLOC_OPT_LOCK_NOLOCK
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ao2_alloc(data_size, destructor_fn)
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_CALL_WITH_RESULT(level, __var, __funcname,...)
#define SCOPE_ENTER(level,...)
#define SCOPE_EXIT_EXPR(__expr,...)
#define ast_trace(level,...)
static char prefix[MAX_PREFIX]
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
struct ast_variable * ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlenco...
struct ast_json * ast_http_get_json(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
Get JSON from client Request Entity-Body, if content type is application/json.
ast_http_method
HTTP Request methods known by Asterisk.
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
struct ast_http_auth * ast_http_get_auth(struct ast_variable *headers)
Get HTTP authentication information from headers.
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
const char * ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
Gets the value of a variable from a variable list by name.
#define ast_variable_new(name, value, filename)
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_debug(level,...)
Log a DEBUG message.
Internal API's for res_ari.
struct ast_json * ast_json_null(void)
Get the JSON null value.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
struct ast_json * ast_json_vstringf(const char *format, va_list args)
Create a JSON string, vprintf style.
struct ast_json * ast_json_stringf(const char *format,...)
Create a JSON string, printf style.
int ast_json_object_del(struct ast_json *object, const char *key)
Delete a field from a JSON object.
ast_json_encoding_format
Encoding format type.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
int ast_json_dump_str_format(struct ast_json *root, struct ast_str **dst, enum ast_json_encoding_format format)
Encode a JSON value to an ast_str.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
char * ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
Encode a JSON value to a string.
struct ast_json * ast_json_load_new_file(const char *path, struct ast_json_error *error)
Parse file at path into JSON object or array.
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
#define ast_mutex_destroy(a)
#define ast_mutex_lock(a)
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_DATA_DIR
const char * app_name(struct ast_app *app)
void ari_cli_unregister(void)
Unregister CLI commands for ARI.
int ari_cli_register(void)
Register CLI commands for ARI.
int ari_conf_load(enum ari_conf_load_flags flags)
(Re)load the ARI configuration
struct ari_conf_general * ari_conf_get_general(void)
struct ari_conf_user * ari_conf_validate_user(const char *username, const char *password)
Validated a user's credentials.
void ari_conf_destroy(void)
Destroy the ARI configuration.
static void remove_trailing_slash(const char *uri, struct ast_ari_response *response)
static struct ast_http_auth * parse_api_keys(struct ast_variable *get_params)
Parse an api_key parameter from the query parameters into an ast_http_auth structure.
static int ast_ari_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Callback for the root URI.
static struct stasis_rest_handlers * root_handler_create(void)
enum ast_json_encoding_format ast_ari_json_format(void)
Configured encoding format for JSON output.
static struct ast_http_auth * create_http_auth(const char *userid, const char *password)
static struct stasis_rest_handlers * root_handler
static ast_mutex_t root_handler_lock
static int is_enabled(void)
Helper function to check if module is enabled.
void ast_ari_response_created(struct ast_ari_response *response, const char *url, struct ast_json *message)
Fill in a Created (201) ast_ari_response.
int ast_ari_remove_handler(struct stasis_rest_handlers *handler)
static void add_allow_header(struct stasis_rest_handlers *handler, struct ast_ari_response *response)
static struct ast_http_uri http_uri
static int reload_module(void)
void ast_ari_response_error(struct ast_ari_response *response, int response_code, const char *response_text, const char *message_fmt,...)
Fill in an error ast_ari_response.
void ast_ari_response_ok(struct ast_ari_response *response, struct ast_json *message)
Fill in an OK (200) ast_ari_response.
static int origin_allowed(const char *origin)
static struct ari_conf_user * authenticate_user(struct ast_variable *get_params, struct ast_variable *headers, enum ast_ari_invoke_source source)
Authenticate an HTTP request.
static void handle_options(struct stasis_rest_handlers *handler, struct ast_variable *headers, struct ast_ari_response *response)
Handle OPTIONS request, mainly for CORS preflight requests.
void ast_ari_response_accepted(struct ast_ari_response *response)
Fill in a Accepted (202) ast_ari_response.
struct ast_json * ast_ari_oom_json(void)
The stock message to return when out of memory.
static void process_cors_request(struct ast_variable *headers, struct ast_ari_response *response)
Handle CORS headers for simple requests.
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
void ast_ari_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
static int load_module(void)
void ast_ari_get_docs(const char *uri, const char *prefix, struct ast_variable *headers, struct ast_ari_response *response)
static struct ast_json * oom_json
static int unload_module(void)
int ast_ari_add_handler(struct stasis_rest_handlers *handler)
enum ast_ari_invoke_result ast_ari_invoke(struct ast_tcptls_session_instance *ser, enum ast_ari_invoke_source source, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
static struct stasis_rest_handlers * get_root_handler(void)
Stasis Application API. See Stasis Application API for detailed documentation.
int stasis_app_get_debug_by_name(const char *app_name)
Get debug status of an application.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
Checks whether a string ends with another.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
#define AST_YESNO(x)
return Yes or No depending on the argument.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Global configuration options for ARI.
Per-user configuration options.
const ast_string_field password
struct ast_json * message
const char * response_text
HTTP authentication information.
Definition of a URI handler.
ast_http_callback callback
JSON parsing error information.
Abstract JSON element (object, array, string, int, ...).
Structure for mutex and tracking information.
Support for dynamic strings.
describes a server instance
struct ast_sockaddr remote_address
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Handler for a single RESTful path segment.
const char * path_segment
struct stasis_rest_handlers * children[]
structure to hold users read from phoneprov_users.conf
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
int error(const char *format,...)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
const struct ast_flags ast_uri_http_legacy