155 #include <sys/stat.h> 162 return cfg && cfg->general && cfg->general->enabled;
182 size_t old_size, new_size;
187 new_size = old_size +
sizeof(
handler);
193 memcpy(new_handler, root_handler, old_size);
194 new_handler->children[new_handler->num_children++] =
handler;
198 root_handler = new_handler;
221 memcpy(new_handler, root_handler,
sizeof(*new_handler));
222 for (i = 0, j = 0; i < root_handler->
num_children; ++i) {
223 if (root_handler->
children[i] == handler) {
232 root_handler = new_handler;
261 const char *response_text,
262 const char *message_fmt, ...)
267 va_start(ap, message_fmt);
334 char *allowed =
ast_strdupa(cfg->general->allowed_origins);
337 while ((current =
strsep(&allowed,
","))) {
338 if (!strcmp(current,
"*")) {
342 if (!strcmp(current, origin)) {
350 #define ACR_METHOD "Access-Control-Request-Method" 351 #define ACR_HEADERS "Access-Control-Request-Headers" 352 #define ACA_METHODS "Access-Control-Allow-Methods" 353 #define ACA_HEADERS "Access-Control-Allow-Headers" 366 char const *acr_method =
NULL;
367 char const *acr_headers =
NULL;
368 char const *origin =
NULL;
379 for (header = headers; header !=
NULL; header = header->
next) {
381 acr_method = header->
value;
383 acr_headers = header->
value;
384 }
else if (strcmp(
"Origin", header->
name) == 0) {
385 origin = header->
value;
392 if (origin ==
NULL) {
407 ast_log(
LOG_NOTICE,
"Origin header '%s' does not match an allowed origin.\n", origin);
415 if (acr_method ==
NULL) {
422 if (acr_headers ==
NULL) {
441 if (strcmp(m_str, acr_method) == 0) {
507 ast_debug(3,
"Finding handler for %s\n", path);
509 while ((path_segment =
strsep(&path,
"/")) && (strlen(path_segment) > 0)) {
514 ast_debug(3,
" Finding handler for %s\n", path_segment);
522 path_var->
next = path_vars;
523 path_vars = path_var;
524 wildcard_handler = child;
527 }
else if (strcmp(child->
path_segment, path_segment) == 0) {
528 found_handler = child;
535 if (!found_handler && wildcard_handler) {
536 ast_debug(3,
" No explicit handler found for %s. Using wildcard %s.\n",
538 found_handler = wildcard_handler;
539 wildcard_handler =
NULL;
542 if (found_handler ==
NULL) {
544 ast_debug(3,
" Handler not found for %s\n", path_segment);
546 response, 404,
"Not Found",
547 "Resource not found");
550 handler = found_handler;
563 response, 405,
"Method Not Allowed",
571 get_params, headers);
579 if (callback ==
NULL) {
582 response, 405,
"Method Not Allowed",
587 callback(ser, get_params, path_vars, headers, body, response);
593 response, 501,
"Not Implemented",
594 "Method not implemented");
607 struct stat file_stat;
612 if (absolute_path_builder ==
NULL) {
621 if (absolute_api_dirname ==
NULL) {
624 response, 500,
"Internal Server Error",
625 "Cannot find rest-api directory");
632 if (absolute_filename ==
NULL) {
638 response, 404,
"Not Found",
639 "Resource not found");
643 response, 403,
"Forbidden",
644 "Permission denied");
648 "Error determining real path for uri '%s': %s\n",
649 uri, strerror(
errno));
651 response, 500,
"Internal Server Error",
661 "Invalid attempt to access '%s' (not in %s)\n",
662 absolute_filename, absolute_api_dirname);
664 response, 404,
"Not Found",
665 "Resource not found");
669 if (stat(absolute_filename, &file_stat) == 0) {
670 if (!(file_stat.st_mode & S_IFREG)) {
673 response, 403,
"Forbidden",
680 response, 404,
"Not Found",
681 "Resource not found");
691 response, 500,
"Internal Server Error",
692 "Yikes! Cannot parse resource");
698 for (host = headers;
host; host = host->
next) {
699 if (strcasecmp(host->
name,
"Host") == 0) {
704 if (prefix !=
NULL && strlen(prefix) > 0) {
726 slashless[strlen(slashless) - 1] =
'\0';
745 "ARI URLs do not end with a slash. Try /ari/%s", slashless);
756 char const *origin =
NULL;
760 for (header = headers; header !=
NULL; header = header->
next) {
761 if (strcmp(
"Origin", header->
name) == 0) {
762 origin = header->
value;
769 if (origin ==
NULL) {
781 ast_log(
LOG_NOTICE,
"Origin header '%s' does not match an allowed origin.\n", origin);
794 "Access-Control-Allow-Origin: %s\r\n", origin);
796 "Access-Control-Allow-Credentials: true\r\n");
810 return cfg->general->format;
831 username =
strsep(&password,
":");
858 http_auth->password);
862 for (v = get_params; v; v = v->
next) {
863 if (strcasecmp(
"api_key", v->
name) == 0) {
902 if (!response_body) {
919 ast_http_error(ser, 500,
"Server Error",
"URI handler config missing");
934 "Request Entity Too Large",
935 "Request body too large");
940 "Internal Server Error",
945 "Bad Request",
"Error parsing request body");
968 if (get_params ==
NULL) {
969 get_params = post_vars;
970 }
else if (get_params && post_vars) {
973 while (last_var->
next) {
974 last_var = last_var->
next;
980 get_params = post_vars;
999 if (!buf || (body && !str)) {
1004 goto request_failed;
1007 ast_str_append(&buf, 0,
"<--- ARI request received from: %s --->\n",
1009 for (var = headers;
var; var = var->
next) {
1012 for (var = get_params;
var; var = var->
next) {
1039 "WWW-Authenticate: Basic realm=\"%s\"\r\n",
1040 conf->general->auth_realm);
1082 "Content-type: application/json\r\n");
1084 conf->general->format) != 0) {
1094 ast_verbose(
"<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n",
1102 response.
fd != -1 ? response.
fd : 0, 0);
1104 response_body =
NULL;
1107 if (response.
fd >= 0) {
1115 .description =
"Asterisk RESTful API",
1135 root_handler =
NULL;
1149 if (!root_handler) {
1152 if (!root_handler) {
1159 "{s: s}",
"error",
"Allocation failed");
1211 .optional_modules =
"res_http_websocket",
1212 .requires =
"http,res_stasis",
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
void ast_ari_config_destroy(void)
Destroy the ARI configuration.
struct ast_variable * next
void ast_std_free(void *ptr)
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Asterisk main include file. File version handling, generic pbx functions.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
void ast_ari_response_ok(struct ast_ari_response *response, struct ast_json *message)
Fill in an OK (200) ast_ari_response.
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.
ast_http_callback callback
int ast_ari_remove_handler(struct stasis_rest_handlers *handler)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
char text[AST_JSON_ERROR_TEXT_LENGTH]
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
void ari_handle_websocket(struct ast_websocket_server *ws_server, 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.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
int ast_ari_add_handler(struct stasis_rest_handlers *handler)
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
int ast_json_object_del(struct ast_json *object, const char *key)
Delete a field from a JSON object.
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
All configuration options for ARI.
Structure for variables, used for configurations and for channel variables.
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
struct ast_json * ast_json_stringf(const char *format,...)
Create a JSON string, printf style.
static int reload_module(void)
Asterisk RESTful API hooks.
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.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
int ast_ari_config_reload(void)
Reload the ARI configuration.
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)
static int copy(char *infile, char *outfile)
Utility function to copy a file.
static struct stasis_rest_handlers * get_root_handler(void)
#define ast_mutex_lock(a)
void ast_verbose(const char *fmt,...)
static int unload_module(void)
#define ast_strdup(str)
A wrapper for strdup()
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
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.
static struct ast_str * password
JSON parsing error information.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
#define ast_strlen_zero(foo)
int stasis_app_get_debug_by_name(const char *app_name)
Get debug status of an application.
All configuration options for statsd client.
struct ast_json * ast_json_null(void)
Get the JSON null value.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
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.
#define ast_debug(level,...)
Log a DEBUG message.
static void process_cors_request(struct ast_variable *headers, struct ast_ari_response *response)
Handle CORS headers for simple requests.
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Asterisk file paths, configured in asterisk.conf.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
static struct stasis_rest_handlers * root_handler
#define ao2_ref(o, delta)
#define ast_strdupa(s)
duplicate a string in memory from the stack
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.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
int ast_ari_cli_register(void)
Register CLI commands for ARI.
#define ast_variable_new(name, value, filename)
struct ast_json * ast_json_vstringf(const char *format, va_list args)
Create a JSON string, vprintf style.
static struct ast_json * oom_json
void ast_ari_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
char * ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
Encode a JSON value to a string.
describes a server instance
struct ast_websocket_server * ws_server
const char * ast_config_AST_DATA_DIR
const struct ast_flags ast_uri_http_legacy
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.
Per-user configuration options.
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.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Internal API's for res_ari.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
int ast_ari_config_init(void)
Initialize the ARI configuration.
const char * app_name(struct ast_app *app)
#define ao2_alloc(data_size, destructor_fn)
struct ast_json * ast_ari_oom_json(void)
The stock message to return when out of memory.
void ast_ari_get_docs(const char *uri, const char *prefix, struct ast_variable *headers, struct ast_ari_response *response)
const char * response_text
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.
Module has failed to load, may be in an inconsistent state.
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
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.
static struct ast_ari_conf_user * authenticate_api_key(const char *api_key)
Authenticate a ?api_key=userid:password
structure to hold users read from users.conf
struct ast_json * message
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
static int is_enabled(void)
Helper function to check if module is enabled.
char source[AST_JSON_ERROR_TEXT_LENGTH]
const char * path_segment
void ast_ari_invoke(struct ast_tcptls_session_instance *ser, 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)
char * strsep(char **str, const char *delims)
static struct ast_http_uri http_uri
HTTP authentication information.
struct stasis_rest_handlers * children[]
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static void remove_trailing_slash(const char *uri, struct ast_ari_response *response)
void ast_ari_cli_unregister(void)
Unregister CLI commands for ARI.
static void add_allow_header(struct stasis_rest_handlers *handler, struct ast_ari_response *response)
static struct ast_ari_conf_user * authenticate_user(struct ast_variable *get_params, struct ast_variable *headers)
Authenticate an HTTP request.
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)
Definition of a URI handler.
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_http_auth * ast_http_get_auth(struct ast_variable *headers)
Get HTTP authentication information from headers.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
stasis_rest_callback callbacks[AST_HTTP_MAX_METHOD]
static ast_mutex_t root_handler_lock
Abstract JSON element (object, array, string, int, ...).
static int origin_allowed(const char *origin)
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.
struct ast_ari_conf_user * ast_ari_config_validate_user(const char *username, const char *password)
Validated a user's credentials.
Stasis Application API. See Stasis Application API for detailed documentation.
#define ast_mutex_init(pmutex)
ast_http_method
HTTP Request methods known by Asterisk.
#define ast_mutex_destroy(a)
#define ASTERISK_GPL_KEY
The text the key() function should return.
static int load_module(void)
Asterisk module definitions.
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.
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Handler for a single RESTful path segment.
Structure for mutex and tracking information.
void ast_ari_response_accepted(struct ast_ari_response *response)
Fill in a Accepted (202) ast_ari_response.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define ast_mutex_unlock(a)
ast_json_encoding_format
Encoding format type.
static char prefix[MAX_PREFIX]
struct ast_sockaddr remote_address