Asterisk - The Open Source Telephony Project  18.5.0
Macros | Functions | Variables
res_ari.c File Reference

HTTP binding for the Stasis API. More...

#include "asterisk.h"
#include "ari/internal.h"
#include "asterisk/ari.h"
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/paths.h"
#include "asterisk/stasis_app.h"
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
Include dependency graph for res_ari.c:

Go to the source code of this file.

Macros

#define ACA_HEADERS   "Access-Control-Allow-Headers"
 
#define ACA_METHODS   "Access-Control-Allow-Methods"
 
#define ACR_HEADERS   "Access-Control-Request-Headers"
 
#define ACR_METHOD   "Access-Control-Request-Method"
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void add_allow_header (struct stasis_rest_handlers *handler, struct ast_ari_response *response)
 
int ast_ari_add_handler (struct stasis_rest_handlers *handler)
 
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)
 
void ast_ari_get_docs (const char *uri, const char *prefix, struct ast_variable *headers, struct ast_ari_response *response)
 
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)
 
enum ast_json_encoding_format ast_ari_json_format (void)
 Configured encoding format for JSON output. More...
 
struct ast_jsonast_ari_oom_json (void)
 The stock message to return when out of memory. More...
 
int ast_ari_remove_handler (struct stasis_rest_handlers *handler)
 
void ast_ari_response_accepted (struct ast_ari_response *response)
 Fill in a Accepted (202) ast_ari_response. More...
 
void ast_ari_response_alloc_failed (struct ast_ari_response *response)
 Fill in response with a 500 message for allocation failures. More...
 
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. More...
 
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. More...
 
void ast_ari_response_no_content (struct ast_ari_response *response)
 Fill in a No Content (204) ast_ari_response. More...
 
void ast_ari_response_ok (struct ast_ari_response *response, struct ast_json *message)
 Fill in an OK (200) ast_ari_response. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static struct ast_ari_conf_userauthenticate_api_key (const char *api_key)
 Authenticate a ?api_key=userid:password More...
 
static struct ast_ari_conf_userauthenticate_user (struct ast_variable *get_params, struct ast_variable *headers)
 Authenticate an HTTP request. More...
 
static struct stasis_rest_handlersget_root_handler (void)
 
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. More...
 
static int is_enabled (void)
 Helper function to check if module is enabled. More...
 
static int load_module (void)
 
static int origin_allowed (const char *origin)
 
static void process_cors_request (struct ast_variable *headers, struct ast_ari_response *response)
 Handle CORS headers for simple requests. More...
 
static int reload_module (void)
 
static void remove_trailing_slash (const char *uri, struct ast_ari_response *response)
 
static struct stasis_rest_handlersroot_handler_create (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk RESTful Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .optional_modules = "res_http_websocket", .requires = "http,res_stasis", .load_pri = AST_MODPRI_APP_DEPEND, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_http_uri http_uri
 
static struct ast_jsonoom_json
 
static struct stasis_rest_handlersroot_handler
 
static ast_mutex_t root_handler_lock
 

Detailed Description

HTTP binding for the Stasis API.

Author
David M. Lee, II dlee@.nosp@m.digi.nosp@m.um.co.nosp@m.m

The API itself is documented using Swagger, a lightweight mechanism for documenting RESTful API's using JSON. This allows us to use swagger-ui to provide executable documentation for the API, generate client bindings in different languages, and generate a lot of the boilerplate code for implementing the RESTful bindings. The API docs live in the rest-api/ directory.

The RESTful bindings are generated from the Swagger API docs using a set of Mustache templates. The code generator is written in Python, and uses the Python implementation pystache. Pystache has no dependencies, and be installed easily using pip. Code generation code lives in rest-api-templates/.

The generated code reduces a lot of boilerplate when it comes to handling HTTP requests. It also helps us have greater consistency in the REST API.

The structure of the generated code is:

The basic flow of an HTTP request is:

Definition in file res_ari.c.

Macro Definition Documentation

◆ ACA_HEADERS

#define ACA_HEADERS   "Access-Control-Allow-Headers"

Definition at line 353 of file res_ari.c.

Referenced by handle_options().

◆ ACA_METHODS

#define ACA_METHODS   "Access-Control-Allow-Methods"

Definition at line 352 of file res_ari.c.

Referenced by handle_options().

◆ ACR_HEADERS

#define ACR_HEADERS   "Access-Control-Request-Headers"

Definition at line 351 of file res_ari.c.

Referenced by handle_options().

◆ ACR_METHOD

#define ACR_METHOD   "Access-Control-Request-Method"

Definition at line 350 of file res_ari.c.

Referenced by handle_options().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1214 of file res_ari.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1214 of file res_ari.c.

◆ add_allow_header()

static void add_allow_header ( struct stasis_rest_handlers handler,
struct ast_ari_response response 
)
static

Definition at line 315 of file res_ari.c.

References ast_get_http_method(), AST_HTTP_MAX_METHOD, ast_str_append(), stasis_rest_handlers::callbacks, ast_ari_response::headers, and NULL.

Referenced by ast_ari_invoke(), and handle_options().

317 {
318  enum ast_http_method m;
319  ast_str_append(&response->headers, 0,
320  "Allow: OPTIONS");
321  for (m = 0; m < AST_HTTP_MAX_METHOD; ++m) {
322  if (handler->callbacks[m] != NULL) {
323  ast_str_append(&response->headers, 0,
324  ",%s", ast_get_http_method(m));
325  }
326  }
327  ast_str_append(&response->headers, 0, "\r\n");
328 }
struct ast_str * headers
Definition: ari.h:95
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define NULL
Definition: resample.c:96
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:190
stasis_rest_callback callbacks[AST_HTTP_MAX_METHOD]
Definition: ari.h:79
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:56

◆ ast_ari_add_handler()

int ast_ari_add_handler ( struct stasis_rest_handlers handler)

Add a resource for REST handling.

Parameters
handlerHandler to add.
Returns
0 on success.
non-zero on failure.

Definition at line 179 of file res_ari.c.

References ao2_alloc, ao2_cleanup, ao2_ref, handler(), lock, NULL, stasis_rest_handlers::num_children, RAII_VAR, and SCOPED_MUTEX.

Referenced by load_module(), and setup_invocation_test().

180 {
181  RAII_VAR(struct stasis_rest_handlers *, new_handler, NULL, ao2_cleanup);
182  size_t old_size, new_size;
183 
185 
186  old_size = sizeof(*new_handler) + root_handler->num_children * sizeof(handler);
187  new_size = old_size + sizeof(handler);
188 
189  new_handler = ao2_alloc(new_size, NULL);
190  if (!new_handler) {
191  return -1;
192  }
193  memcpy(new_handler, root_handler, old_size);
194  new_handler->children[new_handler->num_children++] = handler;
195 
197  ao2_ref(new_handler, +1);
198  root_handler = new_handler;
199  return 0;
200 }
#define NULL
Definition: resample.c:96
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:587
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
ast_mutex_t lock
Definition: app_meetme.c:1091
static struct stasis_rest_handlers * root_handler
Definition: res_ari.c:169
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
size_t num_children
Definition: ari.h:83
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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: test_ari.c:59
static ast_mutex_t root_handler_lock
Definition: res_ari.c:166
Handler for a single RESTful path segment.
Definition: ari.h:68

◆ ast_ari_callback()

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

Definition at line 885 of file res_ari.c.

References ao2_cleanup, app, app_name(), ast_ari_config_get(), ast_ari_get_docs(), ast_ari_invoke(), ast_ari_json_format(), ast_ari_response_error(), ast_assert, ast_begins_with(), ast_ends_with(), ast_free, ast_fully_booted, ast_http_error(), AST_HTTP_GET, ast_http_get_json(), ast_http_get_post_vars(), AST_HTTP_OPTIONS, ast_http_request_close_on_completion(), ast_http_send(), ast_json_dump_str_format(), ast_json_dump_string_format(), ast_json_free(), ast_json_is_null(), ast_json_null(), ast_json_object_get(), ast_json_string_get(), ast_json_unref(), ast_sockaddr_stringify(), ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_variable_find_in_list(), ast_variables_destroy(), ast_variables_dup(), ast_verbose(), authenticate_user(), buf, errno, ast_ari_response::fd, ast_ari_response::headers, ast_ari_response::message, ast_variable::name, ast_variable::next, ast_ari_response::no_response, NULL, ast_http_uri::prefix, process_cors_request(), RAII_VAR, ast_tcptls_session_instance::remote_address, remove_trailing_slash(), ast_ari_response::response_code, ast_ari_response::response_text, S_OR, stasis_app_get_debug_by_name(), str, ast_variable::value, and var.

891 {
893  RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
895  struct ast_ari_response response = { .fd = -1, 0 };
896  RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
897  struct ast_variable *var;
898  const char *app_name = NULL;
899  RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_unref);
900  int debug_app = 0;
901 
902  if (!response_body) {
904  ast_http_error(ser, 500, "Server Error", "Out of memory");
905  return 0;
906  }
907 
908  response.headers = ast_str_create(40);
909  if (!response.headers) {
911  ast_http_error(ser, 500, "Server Error", "Out of memory");
912  return 0;
913  }
914 
916  if (!conf || !conf->general) {
917  ast_free(response.headers);
919  ast_http_error(ser, 500, "Server Error", "URI handler config missing");
920  return 0;
921  }
922 
923  process_cors_request(headers, &response);
924 
925  /* Process form data from a POST. It could be mixed with query
926  * parameters, which seems a bit odd. But it's allowed, so that's okay
927  * with us.
928  */
929  post_vars = ast_http_get_post_vars(ser, headers);
930  if (!post_vars) {
931  switch (errno) {
932  case EFBIG:
933  ast_ari_response_error(&response, 413,
934  "Request Entity Too Large",
935  "Request body too large");
936  goto request_failed;
937  case ENOMEM:
939  ast_ari_response_error(&response, 500,
940  "Internal Server Error",
941  "Out of memory");
942  goto request_failed;
943  case EIO:
944  ast_ari_response_error(&response, 400,
945  "Bad Request", "Error parsing request body");
946  goto request_failed;
947  }
948 
949  /* Look for a JSON request entity only if there were no post_vars.
950  * If there were post_vars, then the request body would already have
951  * been consumed and can not be read again.
952  */
953  body = ast_http_get_json(ser, headers);
954  if (!body) {
955  switch (errno) {
956  case EFBIG:
957  ast_ari_response_error(&response, 413, "Request Entity Too Large", "Request body too large");
958  goto request_failed;
959  case ENOMEM:
960  ast_ari_response_error(&response, 500, "Internal Server Error", "Error processing request");
961  goto request_failed;
962  case EIO:
963  ast_ari_response_error(&response, 400, "Bad Request", "Error parsing request body");
964  goto request_failed;
965  }
966  }
967  }
968  if (get_params == NULL) {
969  get_params = post_vars;
970  } else if (get_params && post_vars) {
971  /* Has both post_vars and get_params */
972  struct ast_variable *last_var = post_vars;
973  while (last_var->next) {
974  last_var = last_var->next;
975  }
976  /* The duped get_params will get freed when post_vars gets
977  * ast_variables_destroyed.
978  */
979  last_var->next = ast_variables_dup(get_params);
980  get_params = post_vars;
981  }
982 
983  /* At this point, get_params will contain post_vars (if any) */
984  app_name = ast_variable_find_in_list(get_params, "app");
985  if (!app_name) {
986  struct ast_json *app = ast_json_object_get(body, "app");
987 
988  app_name = (app ? ast_json_string_get(app) : NULL);
989  }
990 
991  /* stasis_app_get_debug_by_name returns an "||" of the app's debug flag
992  * and the global debug flag.
993  */
994  debug_app = stasis_app_get_debug_by_name(app_name);
995  if (debug_app) {
996  struct ast_str *buf = ast_str_create(512);
998 
999  if (!buf || (body && !str)) {
1001  ast_ari_response_error(&response, 500, "Server Error", "Out of memory");
1002  ast_json_free(str);
1003  ast_free(buf);
1004  goto request_failed;
1005  }
1006 
1007  ast_str_append(&buf, 0, "<--- ARI request received from: %s --->\n",
1009  for (var = headers; var; var = var->next) {
1010  ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
1011  }
1012  for (var = get_params; var; var = var->next) {
1013  ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
1014  }
1015  ast_verbose("%sbody:\n%s\n\n", ast_str_buffer(buf), S_OR(str, ""));
1016  ast_json_free(str);
1017  ast_free(buf);
1018  }
1019 
1020  user = authenticate_user(get_params, headers);
1021  if (response.response_code > 0) {
1022  /* POST parameter processing error. Do nothing. */
1023  } else if (!user) {
1024  /* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
1025  * message is used by an origin server to challenge the
1026  * authorization of a user agent. This response MUST include a
1027  * WWW-Authenticate header field containing at least one
1028  * challenge applicable to the requested resource.
1029  */
1030  ast_ari_response_error(&response, 401, "Unauthorized", "Authentication required");
1031 
1032  /* Section 1.2:
1033  * realm = "realm" "=" realm-value
1034  * realm-value = quoted-string
1035  * Section 2:
1036  * challenge = "Basic" realm
1037  */
1038  ast_str_append(&response.headers, 0,
1039  "WWW-Authenticate: Basic realm=\"%s\"\r\n",
1040  conf->general->auth_realm);
1041  } else if (!ast_fully_booted) {
1043  ast_ari_response_error(&response, 503, "Service Unavailable", "Asterisk not booted");
1044  } else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) {
1045  ast_ari_response_error(&response, 403, "Forbidden", "Write access denied");
1046  } else if (ast_ends_with(uri, "/")) {
1047  remove_trailing_slash(uri, &response);
1048  } else if (ast_begins_with(uri, "api-docs/")) {
1049  /* Serving up API docs */
1050  if (method != AST_HTTP_GET) {
1051  ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method");
1052  } else {
1053  /* Skip the api-docs prefix */
1054  ast_ari_get_docs(strchr(uri, '/') + 1, urih->prefix, headers, &response);
1055  }
1056  } else {
1057  /* Other RESTful resources */
1058  ast_ari_invoke(ser, uri, method, get_params, headers, body,
1059  &response);
1060  }
1061 
1062  if (response.no_response) {
1063  /* The handler indicates no further response is necessary.
1064  * Probably because it already handled it */
1065  ast_free(response.headers);
1066  return 0;
1067  }
1068 
1069 request_failed:
1070 
1071  /* If you explicitly want to have no content, set message to
1072  * ast_json_null().
1073  */
1074  ast_assert(response.message != NULL);
1075  ast_assert(response.response_code > 0);
1076 
1077  /* response.message could be NULL, in which case the empty response_body
1078  * is correct
1079  */
1080  if (response.message && !ast_json_is_null(response.message)) {
1081  ast_str_append(&response.headers, 0,
1082  "Content-type: application/json\r\n");
1083  if (ast_json_dump_str_format(response.message, &response_body,
1084  conf->general->format) != 0) {
1085  /* Error encoding response */
1086  response.response_code = 500;
1087  response.response_text = "Internal Server Error";
1088  ast_str_set(&response_body, 0, "%s", "");
1089  ast_str_set(&response.headers, 0, "%s", "");
1090  }
1091  }
1092 
1093  if (debug_app) {
1094  ast_verbose("<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n",
1096  response.response_text, ast_str_buffer(response.headers),
1097  ast_str_buffer(response_body));
1098  }
1099 
1100  ast_http_send(ser, method, response.response_code,
1101  response.response_text, response.headers, response_body,
1102  response.fd != -1 ? response.fd : 0, 0);
1103  /* ast_http_send takes ownership, so we don't have to free them */
1104  response_body = NULL;
1105 
1106  ast_json_unref(response.message);
1107  if (response.fd >= 0) {
1108  close(response.fd);
1109  }
1110  return 0;
1111 }
struct ast_variable * next
struct ast_str * headers
Definition: ari.h:95
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.
Definition: http.c:648
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
Definition: strings.h:112
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
void ast_json_free(void *p)
Asterisk&#39;s custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
All configuration options for ARI.
Definition: internal.h:54
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
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.
Definition: http.c:1314
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_assert(a)
Definition: utils.h:695
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
Definition: json.c:263
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.
Definition: http.c:456
int response_code
Definition: ari.h:98
int stasis_app_get_debug_by_name(const char *app_name)
Get debug status of an application.
All configuration options for statsd client.
Definition: res_statsd.c:95
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
static void process_cors_request(struct ast_variable *headers, struct ast_ari_response *response)
Handle CORS headers for simple requests.
Definition: res_ari.c:753
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_fully_booted
Definition: options.h:115
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.
Definition: main/config.c:830
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
const char * method
Definition: res_pjsip.c:4335
char * ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
Encode a JSON value to a string.
Definition: json.c:463
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.
Definition: json.c:499
Per-user configuration options.
Definition: internal.h:96
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
void ast_ari_get_docs(const char *uri, const char *prefix, struct ast_variable *headers, struct ast_ari_response *response)
Definition: res_ari.c:598
const char * response_text
Definition: ari.h:102
#define ast_free(a)
Definition: astmm.h:182
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.
Definition: res_ari.c:259
const char * prefix
Definition: http.h:104
structure to hold users read from users.conf
struct ast_json * message
Definition: ari.h:93
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)
Definition: res_ari.c:491
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static void remove_trailing_slash(const char *uri, struct ast_ari_response *response)
Definition: res_ari.c:722
static struct ast_ari_conf_user * authenticate_user(struct ast_variable *get_params, struct ast_variable *headers)
Authenticate an HTTP request.
Definition: res_ari.c:848
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...
Definition: http.c:1353
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Definition: strings.h:94
Abstract JSON element (object, array, string, int, ...).
unsigned int no_response
Definition: ari.h:104
static const char app[]
Definition: app_mysql.c:62
enum ast_json_encoding_format ast_ari_json_format(void)
Configured encoding format for JSON output.
Definition: res_ari.c:806
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
Definition: http.c:836
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:545
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
struct ast_sockaddr remote_address
Definition: tcptls.h:151

◆ ast_ari_get_docs()

void ast_ari_get_docs ( const char *  uri,
const char *  prefix,
struct ast_variable headers,
struct ast_ari_response response 
)

Definition at line 598 of file res_ari.c.

References ast_ari_response_alloc_failed(), ast_ari_response_error(), ast_ari_response_ok(), ast_begins_with(), ast_config_AST_DATA_DIR, ast_debug, ast_free, ast_json_load_new_file(), ast_json_object_del(), ast_json_object_get(), ast_json_object_set(), ast_json_stringf(), ast_log, ast_std_free(), ast_str_append(), ast_str_buffer(), ast_str_create, ast_json_error::column, errno, host, ast_json_error::line, LOG_ERROR, ast_variable::name, ast_variable::next, NULL, RAII_VAR, ast_json_error::source, ast_json_error::text, and ast_variable::value.

Referenced by ast_ari_callback(), and AST_TEST_DEFINE().

600 {
601  RAII_VAR(struct ast_str *, absolute_path_builder, NULL, ast_free);
602  RAII_VAR(char *, absolute_api_dirname, NULL, ast_std_free);
603  RAII_VAR(char *, absolute_filename, NULL, ast_std_free);
604  struct ast_json *obj = NULL;
605  struct ast_variable *host = NULL;
606  struct ast_json_error error = {};
607  struct stat file_stat;
608 
609  ast_debug(3, "%s(%s)\n", __func__, uri);
610 
611  absolute_path_builder = ast_str_create(80);
612  if (absolute_path_builder == NULL) {
614  return;
615  }
616 
617  /* absolute path to the rest-api directory */
618  ast_str_append(&absolute_path_builder, 0, "%s", ast_config_AST_DATA_DIR);
619  ast_str_append(&absolute_path_builder, 0, "/rest-api/");
620  absolute_api_dirname = realpath(ast_str_buffer(absolute_path_builder), NULL);
621  if (absolute_api_dirname == NULL) {
622  ast_log(LOG_ERROR, "Error determining real directory for rest-api\n");
624  response, 500, "Internal Server Error",
625  "Cannot find rest-api directory");
626  return;
627  }
628 
629  /* absolute path to the requested file */
630  ast_str_append(&absolute_path_builder, 0, "%s", uri);
631  absolute_filename = realpath(ast_str_buffer(absolute_path_builder), NULL);
632  if (absolute_filename == NULL) {
633  switch (errno) {
634  case ENAMETOOLONG:
635  case ENOENT:
636  case ENOTDIR:
638  response, 404, "Not Found",
639  "Resource not found");
640  break;
641  case EACCES:
643  response, 403, "Forbidden",
644  "Permission denied");
645  break;
646  default:
648  "Error determining real path for uri '%s': %s\n",
649  uri, strerror(errno));
651  response, 500, "Internal Server Error",
652  "Cannot find file");
653  break;
654  }
655  return;
656  }
657 
658  if (!ast_begins_with(absolute_filename, absolute_api_dirname)) {
659  /* HACKERZ! */
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");
666  return;
667  }
668 
669  if (stat(absolute_filename, &file_stat) == 0) {
670  if (!(file_stat.st_mode & S_IFREG)) {
671  /* Not a file */
673  response, 403, "Forbidden",
674  "Invalid access");
675  return;
676  }
677  } else {
678  /* Does not exist */
680  response, 404, "Not Found",
681  "Resource not found");
682  return;
683  }
684 
685  /* Load resource object from file */
686  obj = ast_json_load_new_file(absolute_filename, &error);
687  if (obj == NULL) {
688  ast_log(LOG_ERROR, "Error parsing resource file: %s:%d(%d) %s\n",
689  error.source, error.line, error.column, error.text);
691  response, 500, "Internal Server Error",
692  "Yikes! Cannot parse resource");
693  return;
694  }
695 
696  /* Update the basePath properly */
697  if (ast_json_object_get(obj, "basePath") != NULL) {
698  for (host = headers; host; host = host->next) {
699  if (strcasecmp(host->name, "Host") == 0) {
700  break;
701  }
702  }
703  if (host != NULL) {
704  if (prefix != NULL && strlen(prefix) > 0) {
706  obj, "basePath",
707  ast_json_stringf("http://%s%s/ari", host->value,prefix));
708  } else {
710  obj, "basePath",
711  ast_json_stringf("http://%s/ari", host->value));
712  }
713  } else {
714  /* Without the host, we don't have the basePath */
715  ast_json_object_del(obj, "basePath");
716  }
717  }
718 
719  ast_ari_response_ok(response, obj);
720 }
struct ast_variable * next
void ast_std_free(void *ptr)
Definition: astmm.c:1766
void ast_ari_response_ok(struct ast_ari_response *response, struct ast_json *message)
Fill in an OK (200) ast_ari_response.
Definition: res_ari.c:276
char text[AST_JSON_ERROR_TEXT_LENGTH]
Definition: json.h:837
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_json_object_del(struct ast_json *object, const char *key)
Delete a field from a JSON object.
Definition: json.c:408
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
Definition: res_ari.c:298
Structure for variables, used for configurations and for channel variables.
struct ast_json * ast_json_stringf(const char *format,...)
Create a JSON string, printf style.
Definition: json.c:283
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define NULL
Definition: resample.c:96
JSON parsing error information.
Definition: json.h:829
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:404
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static char host[256]
Definition: muted.c:77
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
#define LOG_ERROR
Definition: logger.h:285
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.
Definition: json.c:583
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
int column
Definition: json.h:833
int errno
#define ast_free(a)
Definition: astmm.h:182
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.
Definition: res_ari.c:259
char source[AST_JSON_ERROR_TEXT_LENGTH]
Definition: json.h:839
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Definition: strings.h:94
Abstract JSON element (object, array, string, int, ...).
int error(const char *format,...)
Definition: utils/frame.c:999
int line
Definition: json.h:831
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ ast_ari_invoke()

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 
)

Definition at line 491 of file res_ari.c.

References add_allow_header(), ao2_cleanup, ari_handle_websocket(), ast_ari_response_error(), ast_assert, ast_debug, ast_get_http_method(), AST_HTTP_GET, AST_HTTP_MAX_METHOD, AST_HTTP_OPTIONS, ast_log, ast_strdupa, ast_uri_decode(), ast_uri_http_legacy, ast_variable_new, ast_variables_destroy(), stasis_rest_handlers::callbacks, stasis_rest_handlers::children, get_root_handler(), handle_options(), handler(), stasis_rest_handlers::is_wildcard, LOG_ERROR, ast_ari_response::message, method, ast_variable::next, ast_ari_response::no_response, NULL, stasis_rest_handlers::num_children, stasis_rest_handlers::path_segment, RAII_VAR, ast_ari_response::response_code, strsep(), and stasis_rest_handlers::ws_server.

Referenced by ast_ari_callback(), and AST_TEST_DEFINE().

495 {
496  RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
498  struct stasis_rest_handlers *wildcard_handler = NULL;
499  RAII_VAR(struct ast_variable *, path_vars, NULL, ast_variables_destroy);
500  char *path = ast_strdupa(uri);
501  char *path_segment;
502  stasis_rest_callback callback;
503 
504  root = handler = get_root_handler();
505  ast_assert(root != NULL);
506 
507  ast_debug(3, "Finding handler for %s\n", path);
508 
509  while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
510  struct stasis_rest_handlers *found_handler = NULL;
511  int i;
512 
513  ast_uri_decode(path_segment, ast_uri_http_legacy);
514  ast_debug(3, " Finding handler for %s\n", path_segment);
515 
516  for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
517  struct stasis_rest_handlers *child = handler->children[i];
518 
519  if (child->is_wildcard) {
520  /* Record the path variable */
521  struct ast_variable *path_var = ast_variable_new(child->path_segment, path_segment, __FILE__);
522  path_var->next = path_vars;
523  path_vars = path_var;
524  wildcard_handler = child;
525  ast_debug(3, " Checking %s %s: Matched wildcard.\n", handler->path_segment, child->path_segment);
526 
527  } else if (strcmp(child->path_segment, path_segment) == 0) {
528  found_handler = child;
529  ast_debug(3, " Checking %s %s: Explicit match with %s\n", handler->path_segment, child->path_segment, path_segment);
530  } else {
531  ast_debug(3, " Checking %s %s: Didn't match %s\n", handler->path_segment, child->path_segment, path_segment);
532  }
533  }
534 
535  if (!found_handler && wildcard_handler) {
536  ast_debug(3, " No explicit handler found for %s. Using wildcard %s.\n",
537  path_segment, wildcard_handler->path_segment);
538  found_handler = wildcard_handler;
539  wildcard_handler = NULL;
540  }
541 
542  if (found_handler == NULL) {
543  /* resource not found */
544  ast_debug(3, " Handler not found for %s\n", path_segment);
546  response, 404, "Not Found",
547  "Resource not found");
548  return;
549  } else {
550  handler = found_handler;
551  }
552  }
553 
554  ast_assert(handler != NULL);
555  if (method == AST_HTTP_OPTIONS) {
556  handle_options(handler, headers, response);
557  return;
558  }
559 
560  if (method < 0 || method >= AST_HTTP_MAX_METHOD) {
561  add_allow_header(handler, response);
563  response, 405, "Method Not Allowed",
564  "Invalid method");
565  return;
566  }
567 
568  if (handler->ws_server && method == AST_HTTP_GET) {
569  /* WebSocket! */
570  ari_handle_websocket(handler->ws_server, ser, uri, method,
571  get_params, headers);
572  /* Since the WebSocket code handles the connection, we shouldn't
573  * do anything else; setting no_response */
574  response->no_response = 1;
575  return;
576  }
577 
578  callback = handler->callbacks[method];
579  if (callback == NULL) {
580  add_allow_header(handler, response);
582  response, 405, "Method Not Allowed",
583  "Invalid method");
584  return;
585  }
586 
587  callback(ser, get_params, path_vars, headers, body, response);
588  if (response->message == NULL && response->response_code == 0) {
589  /* Really should not happen */
590  ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
593  response, 501, "Not Implemented",
594  "Method not implemented");
595  }
596 }
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: main/utils.c:616
struct ast_variable * next
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
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.
Structure for variables, used for configurations and for channel variables.
#define ast_assert(a)
Definition: utils.h:695
static struct stasis_rest_handlers * get_root_handler(void)
Definition: res_ari.c:238
#define NULL
Definition: resample.c:96
int response_code
Definition: ari.h:98
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.
Definition: res_ari.c:361
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * method
Definition: res_pjsip.c:4335
#define ast_variable_new(name, value, filename)
struct ast_websocket_server * ws_server
Definition: ari.h:81
#define LOG_ERROR
Definition: logger.h:285
const struct ast_flags ast_uri_http_legacy
Definition: main/utils.c:574
size_t num_children
Definition: ari.h:83
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.
Definition: res_ari.c:259
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:190
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.
Definition: ari.h:59
struct ast_json * message
Definition: ari.h:93
const char * path_segment
Definition: ari.h:70
char * strsep(char **str, const char *delims)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct stasis_rest_handlers * children[]
Definition: ari.h:85
static void add_allow_header(struct stasis_rest_handlers *handler, struct ast_ari_response *response)
Definition: res_ari.c:315
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: test_ari.c:59
stasis_rest_callback callbacks[AST_HTTP_MAX_METHOD]
Definition: ari.h:79
unsigned int no_response
Definition: ari.h:104
Handler for a single RESTful path segment.
Definition: ari.h:68

◆ ast_ari_json_format()

enum ast_json_encoding_format ast_ari_json_format ( void  )

Configured encoding format for JSON output.

Returns
JSON output encoding (compact, pretty, etc.)

Definition at line 806 of file res_ari.c.

References ao2_cleanup, ast_ari_config_get(), NULL, and RAII_VAR.

Referenced by ast_ari_callback(), ast_ari_websocket_session_write(), and stasis_app_message_handler().

807 {
808  RAII_VAR(struct ast_ari_conf *, cfg, NULL, ao2_cleanup);
809  cfg = ast_ari_config_get();
810  return cfg->general->format;
811 }
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
All configuration options for ARI.
Definition: internal.h:54
#define NULL
Definition: resample.c:96
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ ast_ari_oom_json()

struct ast_json* ast_ari_oom_json ( void  )

The stock message to return when out of memory.

The refcount is NOT bumped on this object, so ast_json_ref() if you want to keep the reference.

Returns
JSON message specifying an out-of-memory error.

Definition at line 174 of file res_ari.c.

References oom_json.

175 {
176  return oom_json;
177 }
static struct ast_json * oom_json
Definition: res_ari.c:172

◆ ast_ari_remove_handler()

int ast_ari_remove_handler ( struct stasis_rest_handlers handler)

Remove a resource for REST handling.

Parameters
handlerHandler to add.
Returns
0 on success.
non-zero on failure.

Definition at line 202 of file res_ari.c.

References ao2_alloc, ao2_cleanup, ast_assert, ast_mutex_lock, ast_mutex_unlock, stasis_rest_handlers::children, handler(), NULL, and stasis_rest_handlers::num_children.

Referenced by tear_down_invocation_test(), and unload_module().

203 {
204  struct stasis_rest_handlers *new_handler;
205  size_t size;
206  size_t i;
207  size_t j;
208 
210 
212  size = sizeof(*new_handler) + root_handler->num_children * sizeof(handler);
213 
214  new_handler = ao2_alloc(size, NULL);
215  if (!new_handler) {
217  return -1;
218  }
219 
220  /* Create replacement root_handler less the handler to remove. */
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) {
224  continue;
225  }
226  new_handler->children[j++] = root_handler->children[i];
227  }
228  new_handler->num_children = j;
229 
230  /* Replace the old root_handler with the new. */
232  root_handler = new_handler;
233 
235  return 0;
236 }
#define ast_assert(a)
Definition: utils.h:695
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
static struct stasis_rest_handlers * root_handler
Definition: res_ari.c:169
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
size_t num_children
Definition: ari.h:83
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct stasis_rest_handlers * children[]
Definition: ari.h:85
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: test_ari.c:59
static ast_mutex_t root_handler_lock
Definition: res_ari.c:166
Handler for a single RESTful path segment.
Definition: ari.h:68
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ ast_ari_response_accepted()

void ast_ari_response_accepted ( struct ast_ari_response response)

Fill in a Accepted (202) ast_ari_response.

Definition at line 291 of file res_ari.c.

References ast_json_null(), ast_ari_response::message, ast_ari_response::response_code, and ast_ari_response::response_text.

Referenced by ast_ari_asterisk_reload_module().

292 {
293  response->message = ast_json_null();
294  response->response_code = 202;
295  response->response_text = "Accepted";
296 }
int response_code
Definition: ari.h:98
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
const char * response_text
Definition: ari.h:102
struct ast_json * message
Definition: ari.h:93

◆ ast_ari_response_alloc_failed()

void ast_ari_response_alloc_failed ( struct ast_ari_response response)

Fill in response with a 500 message for allocation failures.

Parameters
responseResponse to fill in.

Definition at line 298 of file res_ari.c.

References ast_json_ref(), ast_ari_response::message, ast_ari_response::response_code, and ast_ari_response::response_text.

Referenced by ari_bridges_play_helper(), ari_bridges_play_new(), ari_channels_handle_originate_with_id(), ast_ari_applications_subscribe_cb(), ast_ari_applications_unsubscribe_cb(), ast_ari_asterisk_add_log_cb(), ast_ari_asterisk_get_global_var(), ast_ari_asterisk_get_global_var_cb(), ast_ari_asterisk_get_info(), ast_ari_asterisk_get_info_cb(), ast_ari_asterisk_get_module(), ast_ari_asterisk_list_modules(), ast_ari_asterisk_set_global_var_cb(), ast_ari_asterisk_update_object(), ast_ari_bridges_add_channel(), ast_ari_bridges_add_channel_cb(), ast_ari_bridges_create_cb(), ast_ari_bridges_create_with_id_cb(), ast_ari_bridges_list(), ast_ari_bridges_play_cb(), ast_ari_bridges_play_with_id_cb(), ast_ari_bridges_record(), ast_ari_bridges_record_cb(), ast_ari_bridges_remove_channel_cb(), ast_ari_bridges_start_moh(), ast_ari_bridges_start_moh_cb(), ast_ari_channels_continue_in_dialplan(), ast_ari_channels_continue_in_dialplan_cb(), ast_ari_channels_create(), ast_ari_channels_dial(), ast_ari_channels_dial_cb(), ast_ari_channels_get_channel_var(), ast_ari_channels_get_channel_var_cb(), ast_ari_channels_hangup_cb(), ast_ari_channels_list(), ast_ari_channels_move_cb(), ast_ari_channels_mute_cb(), ast_ari_channels_play_cb(), ast_ari_channels_play_with_id_cb(), ast_ari_channels_record_cb(), ast_ari_channels_redirect_cb(), ast_ari_channels_send_dtmf_cb(), ast_ari_channels_set_channel_var_cb(), ast_ari_channels_snoop_channel_cb(), ast_ari_channels_snoop_channel_with_id_cb(), ast_ari_channels_start_moh_cb(), ast_ari_channels_unmute_cb(), ast_ari_device_states_update_cb(), ast_ari_endpoints_get(), ast_ari_endpoints_list(), ast_ari_endpoints_list_by_tech(), ast_ari_events_event_websocket_ws_attempted_cb(), ast_ari_events_event_websocket_ws_established_cb(), ast_ari_events_user_event_cb(), ast_ari_get_docs(), ast_ari_mailboxes_update_cb(), ast_ari_playbacks_control_cb(), ast_ari_recordings_copy_stored_cb(), ast_ari_recordings_list_stored(), ast_ari_sounds_list_cb(), control_list_create(), handle_options(), json_to_ast_variables(), return_sorcery_object(), and send_message().

299 {
300  response->message = ast_json_ref(oom_json);
301  response->response_code = 500;
302  response->response_text = "Internal Server Error";
303 }
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
int response_code
Definition: ari.h:98
static struct ast_json * oom_json
Definition: res_ari.c:172
const char * response_text
Definition: ari.h:102
struct ast_json * message
Definition: ari.h:93

◆ ast_ari_response_created()

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.

Parameters
responseResponse to fill in.
urlURL to the created resource.
messageJSON response. This reference is stolen, so just ast_json_ref if you need to keep a reference to it.

Definition at line 305 of file res_ari.c.

References ao2_cleanup, ast_str_append(), get_root_handler(), ast_ari_response::headers, ast_ari_response::message, RAII_VAR, ast_ari_response::response_code, and ast_ari_response::response_text.

Referenced by ari_bridges_play_found(), ari_bridges_play_new(), ari_channels_handle_play(), ast_ari_bridges_record(), and ast_ari_channels_record().

307 {
309  response->message = message;
310  response->response_code = 201;
311  response->response_text = "Created";
312  ast_str_append(&response->headers, 0, "Location: /%s%s\r\n", root->path_segment, url);
313 }
struct ast_str * headers
Definition: ari.h:95
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
static struct stasis_rest_handlers * get_root_handler(void)
Definition: res_ari.c:238
int response_code
Definition: ari.h:98
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
const char * response_text
Definition: ari.h:102
struct ast_json * message
Definition: ari.h:93
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static char url[512]
Handler for a single RESTful path segment.
Definition: ari.h:68

◆ ast_ari_response_error()

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.

Parameters
responseResponse to fill in.
response_codeHTTP response code.
response_textText corresponding to the HTTP response code.
message_fmtError message format string.

Definition at line 259 of file res_ari.c.

References ast_json_pack(), ast_json_ref(), ast_json_unref(), ast_json_vstringf(), ast_ari_response::message, NULL, RAII_VAR, ast_ari_response::response_code, and ast_ari_response::response_text.

Referenced by ari_bridges_play_helper(), ari_bridges_play_new(), ari_channels_handle_originate_with_id(), ari_channels_handle_play(), ari_channels_handle_snoop_channel(), ast_ari_applications_filter(), ast_ari_applications_filter_cb(), ast_ari_applications_get(), ast_ari_applications_get_cb(), ast_ari_applications_list(), ast_ari_applications_list_cb(), ast_ari_applications_subscribe(), ast_ari_applications_subscribe_cb(), ast_ari_applications_unsubscribe(), ast_ari_applications_unsubscribe_cb(), ast_ari_asterisk_add_log(), ast_ari_asterisk_add_log_cb(), ast_ari_asterisk_delete_log(), ast_ari_asterisk_delete_log_cb(), ast_ari_asterisk_delete_object(), ast_ari_asterisk_delete_object_cb(), ast_ari_asterisk_get_global_var(), ast_ari_asterisk_get_global_var_cb(), ast_ari_asterisk_get_info_cb(), ast_ari_asterisk_get_module(), ast_ari_asterisk_get_module_cb(), ast_ari_asterisk_get_object(), ast_ari_asterisk_get_object_cb(), ast_ari_asterisk_list_log_channels(), ast_ari_asterisk_list_log_channels_cb(), ast_ari_asterisk_list_modules_cb(), ast_ari_asterisk_load_module(), ast_ari_asterisk_load_module_cb(), ast_ari_asterisk_ping_cb(), ast_ari_asterisk_reload_module(), ast_ari_asterisk_reload_module_cb(), ast_ari_asterisk_rotate_log(), ast_ari_asterisk_rotate_log_cb(), ast_ari_asterisk_set_global_var(), ast_ari_asterisk_set_global_var_cb(), ast_ari_asterisk_unload_module(), ast_ari_asterisk_unload_module_cb(), ast_ari_asterisk_update_object(), ast_ari_asterisk_update_object_cb(), ast_ari_bridges_add_channel_cb(), ast_ari_bridges_clear_video_source_cb(), ast_ari_bridges_create(), ast_ari_bridges_create_cb(), ast_ari_bridges_create_with_id(), ast_ari_bridges_create_with_id_cb(), ast_ari_bridges_destroy_cb(), ast_ari_bridges_get(), ast_ari_bridges_get_cb(), ast_ari_bridges_list_cb(), ast_ari_bridges_play_cb(), ast_ari_bridges_play_with_id_cb(), ast_ari_bridges_record(), ast_ari_bridges_record_cb(), ast_ari_bridges_remove_channel(), ast_ari_bridges_remove_channel_cb(), ast_ari_bridges_set_video_source(), ast_ari_bridges_set_video_source_cb(), ast_ari_bridges_start_moh_cb(), ast_ari_bridges_stop_moh(), ast_ari_bridges_stop_moh_cb(), ast_ari_callback(), ast_ari_channels_answer(), ast_ari_channels_answer_cb(), ast_ari_channels_continue_in_dialplan(), ast_ari_channels_continue_in_dialplan_cb(), ast_ari_channels_create(), ast_ari_channels_create_cb(), ast_ari_channels_dial(), ast_ari_channels_dial_cb(), ast_ari_channels_external_media(), ast_ari_channels_external_media_cb(), ast_ari_channels_get(), ast_ari_channels_get_cb(), ast_ari_channels_get_channel_var(), ast_ari_channels_get_channel_var_cb(), ast_ari_channels_hangup(), ast_ari_channels_hangup_cb(), ast_ari_channels_hold_cb(), ast_ari_channels_list_cb(), ast_ari_channels_move(), ast_ari_channels_move_cb(), ast_ari_channels_mute(), ast_ari_channels_mute_cb(), ast_ari_channels_originate_cb(), ast_ari_channels_originate_with_id_cb(), ast_ari_channels_play_cb(), ast_ari_channels_play_with_id_cb(), ast_ari_channels_record(), ast_ari_channels_record_cb(), ast_ari_channels_redirect(), ast_ari_channels_redirect_cb(), ast_ari_channels_ring_cb(), ast_ari_channels_ring_stop_cb(), ast_ari_channels_rtpstatistics(), ast_ari_channels_rtpstatistics_cb(), ast_ari_channels_send_dtmf(), ast_ari_channels_send_dtmf_cb(), ast_ari_channels_set_channel_var(), ast_ari_channels_set_channel_var_cb(), ast_ari_channels_snoop_channel_cb(), ast_ari_channels_snoop_channel_with_id_cb(), ast_ari_channels_start_moh_cb(), ast_ari_channels_start_silence_cb(), ast_ari_channels_stop_moh_cb(), ast_ari_channels_stop_silence_cb(), ast_ari_channels_unhold_cb(), ast_ari_channels_unmute(), ast_ari_channels_unmute_cb(), ast_ari_device_states_delete(), ast_ari_device_states_delete_cb(), ast_ari_device_states_get(), ast_ari_device_states_get_cb(), ast_ari_device_states_list(), ast_ari_device_states_list_cb(), ast_ari_device_states_update(), ast_ari_device_states_update_cb(), ast_ari_endpoints_get(), ast_ari_endpoints_get_cb(), ast_ari_endpoints_list(), ast_ari_endpoints_list_by_tech(), ast_ari_endpoints_list_by_tech_cb(), ast_ari_endpoints_list_cb(), ast_ari_endpoints_send_message_cb(), ast_ari_endpoints_send_message_to_endpoint(), ast_ari_endpoints_send_message_to_endpoint_cb(), ast_ari_events_event_websocket_ws_attempted_cb(), ast_ari_events_event_websocket_ws_established_cb(), ast_ari_events_user_event(), ast_ari_events_user_event_cb(), ast_ari_get_docs(), ast_ari_invoke(), ast_ari_mailboxes_delete(), ast_ari_mailboxes_delete_cb(), ast_ari_mailboxes_get(), ast_ari_mailboxes_get_cb(), ast_ari_mailboxes_list(), ast_ari_mailboxes_list_cb(), ast_ari_mailboxes_update(), ast_ari_mailboxes_update_cb(), ast_ari_playbacks_control(), ast_ari_playbacks_control_cb(), ast_ari_playbacks_get(), ast_ari_playbacks_get_cb(), ast_ari_playbacks_stop(), ast_ari_playbacks_stop_cb(), ast_ari_recordings_cancel_cb(), ast_ari_recordings_copy_stored(), ast_ari_recordings_copy_stored_cb(), ast_ari_recordings_delete_stored(), ast_ari_recordings_delete_stored_cb(), ast_ari_recordings_get_live(), ast_ari_recordings_get_live_cb(), ast_ari_recordings_get_stored(), ast_ari_recordings_get_stored_cb(), ast_ari_recordings_get_stored_file(), ast_ari_recordings_get_stored_file_cb(), ast_ari_recordings_list_stored_cb(), ast_ari_recordings_mute_cb(), ast_ari_recordings_pause_cb(), ast_ari_recordings_stop_cb(), ast_ari_recordings_unmute_cb(), ast_ari_recordings_unpause_cb(), ast_ari_sounds_get(), ast_ari_sounds_get_cb(), ast_ari_sounds_list(), ast_ari_sounds_list_cb(), channel_state_invalid(), check_add_remove_channel(), control_list_create(), control_recording(), find_bridge(), find_channel_control(), find_control(), json_to_ast_variables(), remove_trailing_slash(), and send_message().

263 {
265  va_list ap;
266 
267  va_start(ap, message_fmt);
268  message = ast_json_vstringf(message_fmt, ap);
269  va_end(ap);
270  response->message = ast_json_pack("{s: o}",
271  "message", ast_json_ref(message));
272  response->response_code = response_code;
273  response->response_text = response_text;
274 }
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define NULL
Definition: resample.c:96
int response_code
Definition: ari.h:98
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
struct ast_json * ast_json_vstringf(const char *format, va_list args)
Create a JSON string, vprintf style.
Definition: json.c:293
const char * response_text
Definition: ari.h:102
struct ast_json * message
Definition: ari.h:93
Abstract JSON element (object, array, string, int, ...).

◆ ast_ari_response_no_content()

void ast_ari_response_no_content ( struct ast_ari_response response)

Fill in a No Content (204) ast_ari_response.

Definition at line 284 of file res_ari.c.

References ast_json_null(), ast_ari_response::message, ast_ari_response::response_code, and ast_ari_response::response_text.

Referenced by ast_ari_asterisk_add_log(), ast_ari_asterisk_delete_log(), ast_ari_asterisk_delete_object(), ast_ari_asterisk_load_module(), ast_ari_asterisk_reload_module(), ast_ari_asterisk_rotate_log(), ast_ari_asterisk_set_global_var(), ast_ari_asterisk_unload_module(), ast_ari_bridges_add_channel(), ast_ari_bridges_clear_video_source(), ast_ari_bridges_destroy(), ast_ari_bridges_remove_channel(), ast_ari_bridges_set_video_source(), ast_ari_bridges_start_moh(), ast_ari_bridges_stop_moh(), ast_ari_channels_answer(), ast_ari_channels_continue_in_dialplan(), ast_ari_channels_dial(), ast_ari_channels_hangup(), ast_ari_channels_hold(), ast_ari_channels_move(), ast_ari_channels_mute(), ast_ari_channels_redirect(), ast_ari_channels_ring(), ast_ari_channels_ring_stop(), ast_ari_channels_send_dtmf(), ast_ari_channels_set_channel_var(), ast_ari_channels_start_moh(), ast_ari_channels_start_silence(), ast_ari_channels_stop_moh(), ast_ari_channels_stop_silence(), ast_ari_channels_unhold(), ast_ari_channels_unmute(), ast_ari_device_states_delete(), ast_ari_device_states_update(), ast_ari_events_user_event(), ast_ari_mailboxes_delete(), ast_ari_mailboxes_update(), ast_ari_playbacks_control(), ast_ari_playbacks_stop(), ast_ari_recordings_delete_stored(), control_recording(), and handle_options().

285 {
286  response->message = ast_json_null();
287  response->response_code = 204;
288  response->response_text = "No Content";
289 }
int response_code
Definition: ari.h:98
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
const char * response_text
Definition: ari.h:102
struct ast_json * message
Definition: ari.h:93

◆ ast_ari_response_ok()

void ast_ari_response_ok ( struct ast_ari_response response,
struct ast_json message 
)

Fill in an OK (200) ast_ari_response.

Parameters
responseResponse to fill in.
messageJSON response. This reference is stolen, so just ast_json_ref if you need to keep a reference to it.

Definition at line 276 of file res_ari.c.

References ast_ari_response::message, ast_ari_response::response_code, and ast_ari_response::response_text.

Referenced by ari_channels_handle_originate_with_id(), ari_channels_handle_snoop_channel(), ast_ari_applications_filter(), ast_ari_applications_get(), ast_ari_applications_list(), ast_ari_applications_subscribe(), ast_ari_applications_unsubscribe(), ast_ari_asterisk_get_global_var(), ast_ari_asterisk_get_info(), ast_ari_asterisk_get_module(), ast_ari_asterisk_list_log_channels(), ast_ari_asterisk_list_modules(), ast_ari_asterisk_ping(), ast_ari_bridges_create(), ast_ari_bridges_create_with_id(), ast_ari_bridges_get(), ast_ari_bridges_list(), ast_ari_channels_create(), ast_ari_channels_get(), ast_ari_channels_get_channel_var(), ast_ari_channels_list(), ast_ari_channels_rtpstatistics(), ast_ari_device_states_get(), ast_ari_device_states_list(), ast_ari_endpoints_get(), ast_ari_endpoints_list(), ast_ari_endpoints_list_by_tech(), ast_ari_get_docs(), ast_ari_mailboxes_get(), ast_ari_mailboxes_list(), ast_ari_playbacks_get(), ast_ari_recordings_copy_stored(), ast_ari_recordings_get_live(), ast_ari_recordings_get_stored(), ast_ari_recordings_get_stored_file(), ast_ari_recordings_list_stored(), ast_ari_sounds_get(), ast_ari_sounds_list(), and return_sorcery_object().

278 {
279  response->message = message;
280  response->response_code = 200;
281  response->response_text = "OK";
282 }
int response_code
Definition: ari.h:98
const char * response_text
Definition: ari.h:102
struct ast_json * message
Definition: ari.h:93

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1214 of file res_ari.c.

◆ authenticate_api_key()

static struct ast_ari_conf_user* authenticate_api_key ( const char *  api_key)
static

Authenticate a ?api_key=userid:password

Parameters
api_keyAPI key query parameter
Returns
User object for the authenticated user.
NULL if authentication failed.

Definition at line 820 of file res_ari.c.

References ast_ari_config_validate_user(), ast_free, ast_log, ast_strdup, copy(), LOG_WARNING, NULL, password, RAII_VAR, strsep(), and ast_ari_conf_user::username.

Referenced by authenticate_user().

821 {
822  RAII_VAR(char *, copy, NULL, ast_free);
823  char *username;
824  char *password;
825 
826  password = copy = ast_strdup(api_key);
827  if (!copy) {
828  return NULL;
829  }
830 
831  username = strsep(&password, ":");
832  if (!password) {
833  ast_log(LOG_WARNING, "Invalid api_key\n");
834  return NULL;
835  }
836 
837  return ast_ari_config_validate_user(username, password);
838 }
#define LOG_WARNING
Definition: logger.h:274
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
static struct ast_str * password
Definition: cdr_mysql.c:77
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_free(a)
Definition: astmm.h:182
char * strsep(char **str, const char *delims)
struct ast_ari_conf_user * ast_ari_config_validate_user(const char *username, const char *password)
Validated a user&#39;s credentials.

◆ authenticate_user()

static struct ast_ari_conf_user* authenticate_user ( struct ast_variable get_params,
struct ast_variable headers 
)
static

Authenticate an HTTP request.

Parameters
get_paramsGET parameters of the request.
headerHTTP headers.
Returns
User object for the authenticated user.
NULL if authentication failed.

Definition at line 848 of file res_ari.c.

References ao2_cleanup, ast_ari_config_validate_user(), ast_http_get_auth(), authenticate_api_key(), ast_variable::name, ast_variable::next, NULL, RAII_VAR, and ast_variable::value.

Referenced by ast_ari_callback().

850 {
851  RAII_VAR(struct ast_http_auth *, http_auth, NULL, ao2_cleanup);
852  struct ast_variable *v;
853 
854  /* HTTP Basic authentication */
855  http_auth = ast_http_get_auth(headers);
856  if (http_auth) {
857  return ast_ari_config_validate_user(http_auth->userid,
858  http_auth->password);
859  }
860 
861  /* ?api_key authentication */
862  for (v = get_params; v; v = v->next) {
863  if (strcasecmp("api_key", v->name) == 0) {
864  return authenticate_api_key(v->value);
865  }
866  }
867 
868  return NULL;
869 }
struct ast_variable * next
Structure for variables, used for configurations and for channel variables.
#define NULL
Definition: resample.c:96
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static struct ast_ari_conf_user * authenticate_api_key(const char *api_key)
Authenticate a ?api_key=userid:password
Definition: res_ari.c:820
HTTP authentication information.
Definition: http.h:123
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_http_auth * ast_http_get_auth(struct ast_variable *headers)
Get HTTP authentication information from headers.
Definition: http.c:1579
struct ast_ari_conf_user * ast_ari_config_validate_user(const char *username, const char *password)
Validated a user&#39;s credentials.

◆ get_root_handler()

static struct stasis_rest_handlers* get_root_handler ( void  )
static

Definition at line 238 of file res_ari.c.

References ao2_ref, lock, root_handler, and SCOPED_MUTEX.

Referenced by ast_ari_invoke(), and ast_ari_response_created().

239 {
241  ao2_ref(root_handler, +1);
242  return root_handler;
243 }
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:587
ast_mutex_t lock
Definition: app_meetme.c:1091
static struct stasis_rest_handlers * root_handler
Definition: res_ari.c:169
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static ast_mutex_t root_handler_lock
Definition: res_ari.c:166

◆ handle_options()

static void handle_options ( struct stasis_rest_handlers handler,
struct ast_variable headers,
struct ast_ari_response response 
)
static

Handle OPTIONS request, mainly for CORS preflight requests.

Some browsers will send this prior to non-simple methods (i.e. DELETE). See http://www.w3.org/TR/cors/ for the spec. Especially section 6.2.

Definition at line 361 of file res_ari.c.

References ACA_HEADERS, ACA_METHODS, ACR_HEADERS, ACR_METHOD, add_allow_header(), ast_ari_response_alloc_failed(), ast_ari_response_no_content(), ast_free, ast_get_http_method(), AST_HTTP_MAX_METHOD, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create, ast_strlen_zero, stasis_rest_handlers::callbacks, ast_ari_response::headers, LOG_NOTICE, ast_variable::name, ast_variable::next, NULL, origin_allowed(), RAII_VAR, and ast_variable::value.

Referenced by ast_ari_invoke().

364 {
365  struct ast_variable *header;
366  char const *acr_method = NULL;
367  char const *acr_headers = NULL;
368  char const *origin = NULL;
369 
370  RAII_VAR(struct ast_str *, allow, NULL, ast_free);
371  enum ast_http_method m;
372  int allowed = 0;
373 
374  /* Regular OPTIONS response */
375  add_allow_header(handler, response);
376  ast_ari_response_no_content(response);
377 
378  /* Parse CORS headers */
379  for (header = headers; header != NULL; header = header->next) {
380  if (strcmp(ACR_METHOD, header->name) == 0) {
381  acr_method = header->value;
382  } else if (strcmp(ACR_HEADERS, header->name) == 0) {
383  acr_headers = header->value;
384  } else if (strcmp("Origin", header->name) == 0) {
385  origin = header->value;
386  }
387  }
388 
389  /* CORS 6.2, #1 - "If the Origin header is not present terminate this
390  * set of steps."
391  */
392  if (origin == NULL) {
393  return;
394  }
395 
396  /* CORS 6.2, #2 - "If the value of the Origin header is not a
397  * case-sensitive match for any of the values in list of origins do not
398  * set any additional headers and terminate this set of steps.
399  *
400  * Always matching is acceptable since the list of origins can be
401  * unbounded.
402  *
403  * The Origin header can only contain a single origin as the user agent
404  * will not follow redirects."
405  */
406  if (!origin_allowed(origin)) {
407  ast_log(LOG_NOTICE, "Origin header '%s' does not match an allowed origin.\n", origin);
408  return;
409  }
410 
411  /* CORS 6.2, #3 - "If there is no Access-Control-Request-Method header
412  * or if parsing failed, do not set any additional headers and terminate
413  * this set of steps."
414  */
415  if (acr_method == NULL) {
416  return;
417  }
418 
419  /* CORS 6.2, #4 - "If there are no Access-Control-Request-Headers
420  * headers let header field-names be the empty list."
421  */
422  if (acr_headers == NULL) {
423  acr_headers = "";
424  }
425 
426  /* CORS 6.2, #5 - "If method is not a case-sensitive match for any of
427  * the values in list of methods do not set any additional headers and
428  * terminate this set of steps."
429  */
430  allow = ast_str_create(20);
431 
432  if (!allow) {
434  return;
435  }
436 
437  /* Go ahead and build the ACA_METHODS header at the same time */
438  for (m = 0; m < AST_HTTP_MAX_METHOD; ++m) {
439  if (handler->callbacks[m] != NULL) {
440  char const *m_str = ast_get_http_method(m);
441  if (strcmp(m_str, acr_method) == 0) {
442  allowed = 1;
443  }
444  ast_str_append(&allow, 0, ",%s", m_str);
445  }
446  }
447 
448  if (!allowed) {
449  return;
450  }
451 
452  /* CORS 6.2 #6 - "If any of the header field-names is not a ASCII
453  * case-insensitive match for any of the values in list of headers do
454  * not set any additional headers and terminate this set of steps.
455  *
456  * Note: Always matching is acceptable since the list of headers can be
457  * unbounded."
458  */
459 
460  /* CORS 6.2 #7 - "If the resource supports credentials add a single
461  * Access-Control-Allow-Origin header, with the value of the Origin
462  * header as value, and add a single Access-Control-Allow-Credentials
463  * header with the case-sensitive string "true" as value."
464  *
465  * Added by process_cors_request() earlier in the request.
466  */
467 
468  /* CORS 6.2 #8 - "Optionally add a single Access-Control-Max-Age
469  * header..."
470  */
471 
472  /* CORS 6.2 #9 - "Add one or more Access-Control-Allow-Methods headers
473  * consisting of (a subset of) the list of methods."
474  */
475  ast_str_append(&response->headers, 0, "%s: OPTIONS%s\r\n",
476  ACA_METHODS, ast_str_buffer(allow));
477 
478 
479  /* CORS 6.2, #10 - "Add one or more Access-Control-Allow-Headers headers
480  * consisting of (a subset of) the list of headers.
481  *
482  * Since the list of headers can be unbounded simply returning headers
483  * can be enough."
484  */
485  if (!ast_strlen_zero(acr_headers)) {
486  ast_str_append(&response->headers, 0, "%s: %s\r\n",
487  ACA_HEADERS, acr_headers);
488  }
489 }
struct ast_variable * next
struct ast_str * headers
Definition: ari.h:95
#define ACR_HEADERS
Definition: res_ari.c:351
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
Definition: res_ari.c:298
Structure for variables, used for configurations and for channel variables.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
void ast_ari_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
Definition: res_ari.c:284
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ACR_METHOD
Definition: res_ari.c:350
#define LOG_NOTICE
Definition: logger.h:263
#define ast_free(a)
Definition: astmm.h:182
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:190
static void add_allow_header(struct stasis_rest_handlers *handler, struct ast_ari_response *response)
Definition: res_ari.c:315
stasis_rest_callback callbacks[AST_HTTP_MAX_METHOD]
Definition: ari.h:79
static int origin_allowed(const char *origin)
Definition: res_ari.c:330
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:56
#define ACA_METHODS
Definition: res_ari.c:352
#define ACA_HEADERS
Definition: res_ari.c:353
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ is_enabled()

static int is_enabled ( void  )
static

Helper function to check if module is enabled.

Definition at line 159 of file res_ari.c.

References ao2_cleanup, ast_ari_config_get(), and RAII_VAR.

Referenced by ast_cel_set_config(), load_module(), reload_module(), and unload_module().

160 {
162  return cfg && cfg->general && cfg->general->enabled;
163 }
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
All configuration options for ARI.
Definition: internal.h:54
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ load_module()

static int load_module ( void  )
static

Definition at line 1144 of file res_ari.c.

References ast_ari_cli_register(), ast_ari_config_init(), ast_debug, ast_http_uri_link(), ast_json_pack(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init, is_enabled(), root_handler_create(), and unload_module().

Referenced by reload_module().

1145 {
1147 
1148  /* root_handler may have been built during a declined load */
1149  if (!root_handler) {
1151  }
1152  if (!root_handler) {
1153  return AST_MODULE_LOAD_DECLINE;
1154  }
1155 
1156  /* oom_json may have been built during a declined load */
1157  if (!oom_json) {
1159  "{s: s}", "error", "Allocation failed");
1160  }
1161  if (!oom_json) {
1162  /* Ironic */
1163  unload_module();
1164  return AST_MODULE_LOAD_DECLINE;
1165  }
1166 
1167  if (ast_ari_config_init() != 0) {
1168  unload_module();
1169  return AST_MODULE_LOAD_DECLINE;
1170  }
1171 
1172  if (is_enabled()) {
1173  ast_debug(3, "ARI enabled\n");
1175  } else {
1176  ast_debug(3, "ARI disabled\n");
1177  }
1178 
1179  if (ast_ari_cli_register() != 0) {
1180  unload_module();
1181  return AST_MODULE_LOAD_DECLINE;
1182  }
1183 
1184  return AST_MODULE_LOAD_SUCCESS;
1185 }
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:673
static int unload_module(void)
Definition: res_ari.c:1123
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct stasis_rest_handlers * root_handler
Definition: res_ari.c:169
int ast_ari_cli_register(void)
Register CLI commands for ARI.
Definition: res/ari/cli.c:434
static struct ast_json * oom_json
Definition: res_ari.c:172
int ast_ari_config_init(void)
Initialize the ARI configuration.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int is_enabled(void)
Helper function to check if module is enabled.
Definition: res_ari.c:159
static struct ast_http_uri http_uri
Definition: res_ari.c:1113
static ast_mutex_t root_handler_lock
Definition: res_ari.c:166
#define ast_mutex_init(pmutex)
Definition: lock.h:184
static struct stasis_rest_handlers * root_handler_create(void)
Definition: res_ari.c:245

◆ origin_allowed()

static int origin_allowed ( const char *  origin)
static

Definition at line 330 of file res_ari.c.

References ao2_cleanup, ast_ari_config_get(), ast_strdupa, RAII_VAR, and strsep().

Referenced by handle_options(), and process_cors_request().

331 {
333 
334  char *allowed = ast_strdupa(cfg->general->allowed_origins);
335  char *current;
336 
337  while ((current = strsep(&allowed, ","))) {
338  if (!strcmp(current, "*")) {
339  return 1;
340  }
341 
342  if (!strcmp(current, origin)) {
343  return 1;
344  }
345  }
346 
347  return 0;
348 }
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
All configuration options for ARI.
Definition: internal.h:54
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char * strsep(char **str, const char *delims)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ process_cors_request()

static void process_cors_request ( struct ast_variable headers,
struct ast_ari_response response 
)
static

Handle CORS headers for simple requests.

See http://www.w3.org/TR/cors/ for the spec. Especially section 6.1.

Definition at line 753 of file res_ari.c.

References ast_log, ast_str_append(), ast_ari_response::headers, LOG_NOTICE, ast_variable::name, ast_variable::next, NULL, origin_allowed(), and ast_variable::value.

Referenced by ast_ari_callback().

755 {
756  char const *origin = NULL;
757  struct ast_variable *header;
758 
759  /* Parse CORS headers */
760  for (header = headers; header != NULL; header = header->next) {
761  if (strcmp("Origin", header->name) == 0) {
762  origin = header->value;
763  }
764  }
765 
766  /* CORS 6.1, #1 - "If the Origin header is not present terminate this
767  * set of steps."
768  */
769  if (origin == NULL) {
770  return;
771  }
772 
773  /* CORS 6.1, #2 - "If the value of the Origin header is not a
774  * case-sensitive match for any of the values in list of origins, do not
775  * set any additional headers and terminate this set of steps.
776  *
777  * Note: Always matching is acceptable since the list of origins can be
778  * unbounded."
779  */
780  if (!origin_allowed(origin)) {
781  ast_log(LOG_NOTICE, "Origin header '%s' does not match an allowed origin.\n", origin);
782  return;
783  }
784 
785  /* CORS 6.1, #3 - "If the resource supports credentials add a single
786  * Access-Control-Allow-Origin header, with the value of the Origin
787  * header as value, and add a single Access-Control-Allow-Credentials
788  * header with the case-sensitive string "true" as value.
789  *
790  * Otherwise, add a single Access-Control-Allow-Origin header, with
791  * either the value of the Origin header or the string "*" as value."
792  */
793  ast_str_append(&response->headers, 0,
794  "Access-Control-Allow-Origin: %s\r\n", origin);
795  ast_str_append(&response->headers, 0,
796  "Access-Control-Allow-Credentials: true\r\n");
797 
798  /* CORS 6.1, #4 - "If the list of exposed headers is not empty add one
799  * or more Access-Control-Expose-Headers headers, with as values the
800  * header field names given in the list of exposed headers."
801  *
802  * No exposed headers; skipping
803  */
804 }
struct ast_variable * next
struct ast_str * headers
Definition: ari.h:95
Structure for variables, used for configurations and for channel variables.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define LOG_NOTICE
Definition: logger.h:263
static int origin_allowed(const char *origin)
Definition: res_ari.c:330

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 1187 of file res_ari.c.

References ast_ari_config_reload(), ast_debug, ast_http_uri_link(), ast_http_uri_unlink(), AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_APP_DEPEND, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_CORE, ASTERISK_GPL_KEY, is_enabled(), load_module(), reload(), and unload_module().

1188 {
1189  char was_enabled = is_enabled();
1190 
1191  if (ast_ari_config_reload() != 0) {
1192  return AST_MODULE_LOAD_DECLINE;
1193  }
1194 
1195  if (was_enabled && !is_enabled()) {
1196  ast_debug(3, "Disabling ARI\n");
1198  } else if (!was_enabled && is_enabled()) {
1199  ast_debug(3, "Enabling ARI\n");
1201  }
1202 
1203  return AST_MODULE_LOAD_SUCCESS;
1204 }
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:673
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:705
int ast_ari_config_reload(void)
Reload the ARI configuration.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int is_enabled(void)
Helper function to check if module is enabled.
Definition: res_ari.c:159
static struct ast_http_uri http_uri
Definition: res_ari.c:1113

◆ remove_trailing_slash()

static void remove_trailing_slash ( const char *  uri,
struct ast_ari_response response 
)
static

Definition at line 722 of file res_ari.c.

References ast_ari_response_error(), and ast_strdupa.

Referenced by ast_ari_callback().

724 {
725  char *slashless = ast_strdupa(uri);
726  slashless[strlen(slashless) - 1] = '\0';
727 
728  /* While it's tempting to redirect the client to the slashless URL,
729  * that is problematic. A 302 Found is the most appropriate response,
730  * but most clients issue a GET on the location you give them,
731  * regardless of the method of the original request.
732  *
733  * While there are some ways around this, it gets into a lot of client
734  * specific behavior and corner cases in the HTTP standard. There's also
735  * very little practical benefit of redirecting; only GET and HEAD can
736  * be redirected automagically; all other requests "MUST NOT
737  * automatically redirect the request unless it can be confirmed by the
738  * user, since this might change the conditions under which the request
739  * was issued."
740  *
741  * Given all of that, a 404 with a nice message telling them what to do
742  * is probably our best bet.
743  */
744  ast_ari_response_error(response, 404, "Not Found",
745  "ARI URLs do not end with a slash. Try /ari/%s", slashless);
746 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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.
Definition: res_ari.c:259

◆ root_handler_create()

static struct stasis_rest_handlers* root_handler_create ( void  )
static

Definition at line 245 of file res_ari.c.

References ao2_alloc, ao2_cleanup, ao2_ref, handler(), NULL, and RAII_VAR.

Referenced by load_module().

246 {
248 
249  handler = ao2_alloc(sizeof(*handler), NULL);
250  if (!handler) {
251  return NULL;
252  }
253  handler->path_segment = "ari";
254 
255  ao2_ref(handler, +1);
256  return handler;
257 }
#define NULL
Definition: resample.c:96
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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: test_ari.c:59
Handler for a single RESTful path segment.
Definition: ari.h:68

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1123 of file res_ari.c.

References ao2_cleanup, ast_ari_cli_unregister(), ast_ari_config_destroy(), ast_debug, ast_http_uri_unlink(), ast_json_unref(), ast_mutex_destroy, is_enabled(), and NULL.

Referenced by load_module(), and reload_module().

1124 {
1126 
1127  if (is_enabled()) {
1128  ast_debug(3, "Disabling ARI\n");
1130  }
1131 
1133 
1135  root_handler = NULL;
1137 
1139  oom_json = NULL;
1140 
1141  return 0;
1142 }
void ast_ari_config_destroy(void)
Destroy the ARI configuration.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:705
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct stasis_rest_handlers * root_handler
Definition: res_ari.c:169
static struct ast_json * oom_json
Definition: res_ari.c:172
static int is_enabled(void)
Helper function to check if module is enabled.
Definition: res_ari.c:159
static struct ast_http_uri http_uri
Definition: res_ari.c:1113
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_ari_cli_unregister(void)
Unregister CLI commands for ARI.
Definition: res/ari/cli.c:438
static ast_mutex_t root_handler_lock
Definition: res_ari.c:166
#define ast_mutex_destroy(a)
Definition: lock.h:186

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk RESTful Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .optional_modules = "res_http_websocket", .requires = "http,res_stasis", .load_pri = AST_MODPRI_APP_DEPEND, }
static

Definition at line 1214 of file res_ari.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1214 of file res_ari.c.

◆ http_uri

struct ast_http_uri http_uri
static

Definition at line 1113 of file res_ari.c.

◆ oom_json

struct ast_json* oom_json
static

Pre-defined message for allocation failures.

Definition at line 172 of file res_ari.c.

Referenced by ast_ari_oom_json().

◆ root_handler

struct stasis_rest_handlers* root_handler
static

Handler for root RESTful resource.

Definition at line 169 of file res_ari.c.

Referenced by get_root_handler().

◆ root_handler_lock

ast_mutex_t root_handler_lock
static

Lock for root_handler

Definition at line 166 of file res_ari.c.