diff options
-rw-r--r-- | include/asterisk/ari.h | 9 | ||||
-rw-r--r-- | include/asterisk/http.h | 12 | ||||
-rw-r--r-- | main/http.c | 103 | ||||
-rw-r--r-- | res/res_ari.c | 2 | ||||
-rw-r--r-- | res/res_ari_applications.c | 104 | ||||
-rw-r--r-- | res/res_ari_asterisk.c | 100 | ||||
-rw-r--r-- | res/res_ari_bridges.c | 240 | ||||
-rw-r--r-- | res/res_ari_channels.c | 400 | ||||
-rw-r--r-- | res/res_ari_device_states.c | 29 | ||||
-rw-r--r-- | res/res_ari_endpoints.c | 6 | ||||
-rw-r--r-- | res/res_ari_playbacks.c | 27 | ||||
-rw-r--r-- | res/res_ari_recordings.c | 20 | ||||
-rw-r--r-- | res/res_ari_sounds.c | 29 | ||||
-rw-r--r-- | rest-api-templates/asterisk_processor.py | 26 | ||||
-rw-r--r-- | rest-api-templates/param_parsing.mustache | 63 | ||||
-rw-r--r-- | rest-api-templates/res_ari_resource.c.mustache | 7 | ||||
-rw-r--r-- | rest-api-templates/swagger_model.py | 13 | ||||
-rw-r--r-- | tests/test_ari.c | 9 |
18 files changed, 1170 insertions, 29 deletions
diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index dfeef513c..f5b76f8dc 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -50,15 +50,16 @@ struct ast_ari_response; /*! * \brief Callback type for RESTful method handlers. + * \param ser TCP/TLS session object * \param get_params GET parameters from the HTTP request. * \param path_vars Path variables from any wildcard path segments. * \param headers HTTP headers from the HTTP requiest. * \param[out] response The RESTful response. */ -typedef void (*stasis_rest_callback)(struct ast_variable *get_params, - struct ast_variable *path_vars, - struct ast_variable *headers, - struct ast_ari_response *response); +typedef 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_ari_response *response); /*! * \brief Handler for a single RESTful path segment. diff --git a/include/asterisk/http.h b/include/asterisk/http.h index 59e185a6f..0642cfa9b 100644 --- a/include/asterisk/http.h +++ b/include/asterisk/http.h @@ -212,5 +212,17 @@ void ast_http_prefix(char *buf, int len); */ struct ast_variable *ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers); +struct ast_json; + +/*!\brief Get JSON from client Request Entity-Body, if content type is + * application/json. + * \param ser TCP/TLS session object + * \param headers List of HTTP headers + * \return Parsed JSON content body + * \return \c NULL on error, if no content, or if different content type. + * \since 12 + */ +struct ast_json *ast_http_get_json( + struct ast_tcptls_session_instance *ser, struct ast_variable *headers); #endif /* _ASTERISK_SRV_H */ diff --git a/main/http.c b/main/http.c index a9c8a3564..0c9b09a90 100644 --- a/main/http.c +++ b/main/http.c @@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "asterisk/netsock2.h" +#include "asterisk/json.h" #define MAX_PREFIX 80 #define DEFAULT_PORT 8088 @@ -607,6 +608,91 @@ void ast_http_uri_unlink_all_with_key(const char *key) #define MAX_POST_CONTENT 1025 +static const char *get_content_type(struct ast_variable *headers) +{ + struct ast_variable *v; + + for (v = headers; v; v = v->next) { + if (strcasecmp(v->name, "Content-Type") == 0) { + return v->value; + } + } + + /* Missing content type; assume empty string */ + return ""; +} + +static int get_content_length(struct ast_variable *headers) +{ + struct ast_variable *v; + + for (v = headers; v; v = v->next) { + if (!strcasecmp(v->name, "Content-Length")) { + return atoi(v->value); + } + } + + /* Missing content length; assume zero */ + return 0; +} + +struct ast_json *ast_http_get_json( + struct ast_tcptls_session_instance *ser, struct ast_variable *headers) +{ + int content_length = 0; + int res; + struct ast_json *body; + RAII_VAR(char *, buf, NULL, ast_free); + + /* Use errno to distinguish errors from no body */ + errno = 0; + + if (strcasecmp(get_content_type(headers), "application/json") != 0) { + /* Content type is not JSON */ + return NULL; + } + + content_length = get_content_length(headers); + + if (content_length <= 0) { + /* No content (or streaming content). */ + return NULL; + } + + if (content_length > MAX_POST_CONTENT - 1) { + ast_log(LOG_WARNING, + "Excessively long HTTP content. (%d > %d)\n", + content_length, MAX_POST_CONTENT); + errno = EFBIG; + return NULL; + } + + buf = ast_malloc(content_length); + if (!buf) { + /* Malloc sets ENOMEM */ + return NULL; + } + + res = fread(buf, 1, content_length, ser->f); + if (res < content_length) { + /* Error, distinguishable by ferror() or feof(), but neither + * is good. Treat either one as I/O error */ + ast_log(LOG_WARNING, "Short HTTP request body (%d < %d)\n", + res, content_length); + errno = EIO; + return NULL; + } + + body = ast_json_load_buf(buf, content_length, NULL); + if (body == NULL) { + /* Failed to parse JSON; treat as an I/O error */ + errno = EIO; + return NULL; + } + + return body; +} + /* * get post variables from client Request Entity-Body, if content type is * application/x-www-form-urlencoded @@ -623,21 +709,12 @@ struct ast_variable *ast_http_get_post_vars( /* Use errno to distinguish errors from no params */ errno = 0; - for (v = headers; v; v = v->next) { - if (!strcasecmp(v->name, "Content-Type")) { - if (strcasecmp(v->value, "application/x-www-form-urlencoded")) { - return NULL; - } - break; - } + if (strcasecmp(get_content_type(headers), "application/x-www-form-urlencoded") != 0) { + /* Content type is not form data */ + return NULL; } - for (v = headers; v; v = v->next) { - if (!strcasecmp(v->name, "Content-Length")) { - content_length = atoi(v->value); - break; - } - } + content_length = get_content_length(headers); if (content_length <= 0) { return NULL; diff --git a/res/res_ari.c b/res/res_ari.c index 4ceb3847e..108f6c7e1 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -539,7 +539,7 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser, return; } - callback(get_params, path_vars, headers, response); + callback(ser, get_params, path_vars, headers, response); if (response->message == NULL && response->response_code == 0) { /* Really should not happen */ ast_log(LOG_ERROR, "ARI %s %s not implemented\n", diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index 565e3a7ab..1f021c41d 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -59,10 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_applications_list_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_applications_list_args args = {}; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -108,11 +110,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_applications_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_applications_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -165,11 +169,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_applications_subscribe_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_applications_subscribe_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -227,6 +234,53 @@ static void ast_ari_applications_subscribe_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "eventSource"); + if (field) { + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args.event_source); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args.event_source_count = ast_json_array_size(field); + args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count); + + if (!args.event_source) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (i = 0; i < args.event_source_count; ++i) { + args.event_source[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args.event_source_count = 1; + args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count); + if (!args.event_source) { + ast_ari_response_alloc_failed(response); + goto fin; + } + args.event_source[0] = ast_json_string_get(field); + } + } ast_ari_applications_subscribe(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -272,11 +326,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_applications_unsubscribe_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_applications_unsubscribe_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -334,6 +391,53 @@ static void ast_ari_applications_unsubscribe_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "eventSource"); + if (field) { + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args.event_source); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args.event_source_count = ast_json_array_size(field); + args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count); + + if (!args.event_source) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (i = 0; i < args.event_source_count; ++i) { + args.event_source[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args.event_source_count = 1; + args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count); + if (!args.event_source) { + ast_ari_response_alloc_failed(response); + goto fin; + } + args.event_source[0] = ast_json_string_get(field); + } + } ast_ari_applications_unsubscribe(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index c83c2f6a3..6d561aca9 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -59,11 +59,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_asterisk_get_info_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_asterisk_get_info_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -115,6 +118,53 @@ static void ast_ari_asterisk_get_info_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "only"); + if (field) { + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args.only); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args.only_count = ast_json_array_size(field); + args.only = ast_malloc(sizeof(*args.only) * args.only_count); + + if (!args.only) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (i = 0; i < args.only_count; ++i) { + args.only[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args.only_count = 1; + args.only = ast_malloc(sizeof(*args.only) * args.only_count); + if (!args.only) { + ast_ari_response_alloc_failed(response); + goto fin; + } + args.only[0] = ast_json_string_get(field); + } + } ast_ari_asterisk_get_info(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -157,11 +207,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_asterisk_get_global_var_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_asterisk_get_global_var_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -173,6 +226,26 @@ static void ast_ari_asterisk_get_global_var_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "variable"); + if (field) { + args.variable = ast_json_string_get(field); + } ast_ari_asterisk_get_global_var(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -214,11 +287,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_asterisk_set_global_var_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_asterisk_set_global_var_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -233,6 +309,30 @@ static void ast_ari_asterisk_set_global_var_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "variable"); + if (field) { + args.variable = ast_json_string_get(field); + } + field = ast_json_object_get(body, "value"); + if (field) { + args.value = ast_json_string_get(field); + } ast_ari_asterisk_set_global_var(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 3020c4a62..f72a72805 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -59,10 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_list_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_list_args args = {}; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -108,11 +110,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_create_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_create_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -124,6 +129,26 @@ static void ast_ari_bridges_create_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "type"); + if (field) { + args.type = ast_json_string_get(field); + } ast_ari_bridges_create(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -164,11 +189,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -221,11 +248,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_destroy_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_destroy_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -278,11 +307,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_add_channel_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_add_channel_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -343,6 +375,57 @@ static void ast_ari_bridges_add_channel_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "channel"); + if (field) { + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args.channel); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args.channel_count = ast_json_array_size(field); + args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count); + + if (!args.channel) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (i = 0; i < args.channel_count; ++i) { + args.channel[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args.channel_count = 1; + args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count); + if (!args.channel) { + ast_ari_response_alloc_failed(response); + goto fin; + } + args.channel[0] = ast_json_string_get(field); + } + } + field = ast_json_object_get(body, "role"); + if (field) { + args.role = ast_json_string_get(field); + } ast_ari_bridges_add_channel(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -389,11 +472,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_remove_channel_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_remove_channel_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -451,6 +537,53 @@ static void ast_ari_bridges_remove_channel_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "channel"); + if (field) { + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args.channel); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args.channel_count = ast_json_array_size(field); + args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count); + + if (!args.channel) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (i = 0; i < args.channel_count; ++i) { + args.channel[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args.channel_count = 1; + args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count); + if (!args.channel) { + ast_ari_response_alloc_failed(response); + goto fin; + } + args.channel[0] = ast_json_string_get(field); + } + } ast_ari_bridges_remove_channel(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -497,11 +630,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_start_moh_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_start_moh_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -519,6 +655,26 @@ static void ast_ari_bridges_start_moh_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "mohClass"); + if (field) { + args.moh_class = ast_json_string_get(field); + } ast_ari_bridges_start_moh(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -561,11 +717,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_stop_moh_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_stop_moh_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -619,11 +777,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_play_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_play_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -650,6 +811,38 @@ static void ast_ari_bridges_play_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "media"); + if (field) { + args.media = ast_json_string_get(field); + } + field = ast_json_object_get(body, "lang"); + if (field) { + args.lang = ast_json_string_get(field); + } + field = ast_json_object_get(body, "offsetms"); + if (field) { + args.offsetms = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "skipms"); + if (field) { + args.skipms = ast_json_integer_get(field); + } ast_ari_bridges_play(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -692,11 +885,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_bridges_record_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_bridges_record_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -732,6 +928,50 @@ static void ast_ari_bridges_record_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "name"); + if (field) { + args.name = ast_json_string_get(field); + } + field = ast_json_object_get(body, "format"); + if (field) { + args.format = ast_json_string_get(field); + } + field = ast_json_object_get(body, "maxDurationSeconds"); + if (field) { + args.max_duration_seconds = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "maxSilenceSeconds"); + if (field) { + args.max_silence_seconds = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "ifExists"); + if (field) { + args.if_exists = ast_json_string_get(field); + } + field = ast_json_object_get(body, "beep"); + if (field) { + args.beep = ast_json_is_true(field); + } + field = ast_json_object_get(body, "terminateOn"); + if (field) { + args.terminate_on = ast_json_string_get(field); + } ast_ari_bridges_record(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 7e7da356f..40ad32b2b 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -59,10 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_list_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_list_args args = {}; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -108,11 +110,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_originate_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_originate_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -145,6 +150,54 @@ static void ast_ari_channels_originate_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "endpoint"); + if (field) { + args.endpoint = ast_json_string_get(field); + } + field = ast_json_object_get(body, "extension"); + if (field) { + args.extension = ast_json_string_get(field); + } + field = ast_json_object_get(body, "context"); + if (field) { + args.context = ast_json_string_get(field); + } + field = ast_json_object_get(body, "priority"); + if (field) { + args.priority = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "app"); + if (field) { + args.app = ast_json_string_get(field); + } + field = ast_json_object_get(body, "appArgs"); + if (field) { + args.app_args = ast_json_string_get(field); + } + field = ast_json_object_get(body, "callerId"); + if (field) { + args.caller_id = ast_json_string_get(field); + } + field = ast_json_object_get(body, "timeout"); + if (field) { + args.timeout = ast_json_integer_get(field); + } ast_ari_channels_originate(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -186,11 +239,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -243,11 +298,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_hangup_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_hangup_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -265,6 +323,26 @@ static void ast_ari_channels_hangup_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "reason"); + if (field) { + args.reason = ast_json_string_get(field); + } ast_ari_channels_hangup(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -307,11 +385,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_continue_in_dialplan_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_continue_in_dialplan_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -335,6 +416,34 @@ static void ast_ari_channels_continue_in_dialplan_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "context"); + if (field) { + args.context = ast_json_string_get(field); + } + field = ast_json_object_get(body, "extension"); + if (field) { + args.extension = ast_json_string_get(field); + } + field = ast_json_object_get(body, "priority"); + if (field) { + args.priority = ast_json_integer_get(field); + } ast_ari_channels_continue_in_dialplan(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -377,11 +486,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_answer_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_answer_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -435,11 +546,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_ring_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_ring_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -493,11 +606,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_ring_stop_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_ring_stop_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -551,11 +666,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_send_dtmf_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_send_dtmf_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -585,6 +703,42 @@ static void ast_ari_channels_send_dtmf_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "dtmf"); + if (field) { + args.dtmf = ast_json_string_get(field); + } + field = ast_json_object_get(body, "before"); + if (field) { + args.before = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "between"); + if (field) { + args.between = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "duration"); + if (field) { + args.duration = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "after"); + if (field) { + args.after = ast_json_integer_get(field); + } ast_ari_channels_send_dtmf(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -628,11 +782,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_mute_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_mute_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -650,6 +807,26 @@ static void ast_ari_channels_mute_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "direction"); + if (field) { + args.direction = ast_json_string_get(field); + } ast_ari_channels_mute(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -692,11 +869,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_unmute_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_unmute_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -714,6 +894,26 @@ static void ast_ari_channels_unmute_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "direction"); + if (field) { + args.direction = ast_json_string_get(field); + } ast_ari_channels_unmute(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -756,11 +956,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_hold_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_hold_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -814,11 +1016,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_unhold_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_unhold_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -872,11 +1076,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_start_moh_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_start_moh_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -894,6 +1101,26 @@ static void ast_ari_channels_start_moh_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "mohClass"); + if (field) { + args.moh_class = ast_json_string_get(field); + } ast_ari_channels_start_moh(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -936,11 +1163,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_stop_moh_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_stop_moh_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -994,11 +1223,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_start_silence_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_start_silence_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1052,11 +1283,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_stop_silence_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_stop_silence_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1110,11 +1343,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_play_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_play_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -1141,6 +1377,38 @@ static void ast_ari_channels_play_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "media"); + if (field) { + args.media = ast_json_string_get(field); + } + field = ast_json_object_get(body, "lang"); + if (field) { + args.lang = ast_json_string_get(field); + } + field = ast_json_object_get(body, "offsetms"); + if (field) { + args.offsetms = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "skipms"); + if (field) { + args.skipms = ast_json_integer_get(field); + } ast_ari_channels_play(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -1183,11 +1451,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_record_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_record_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -1223,6 +1494,50 @@ static void ast_ari_channels_record_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "name"); + if (field) { + args.name = ast_json_string_get(field); + } + field = ast_json_object_get(body, "format"); + if (field) { + args.format = ast_json_string_get(field); + } + field = ast_json_object_get(body, "maxDurationSeconds"); + if (field) { + args.max_duration_seconds = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "maxSilenceSeconds"); + if (field) { + args.max_silence_seconds = ast_json_integer_get(field); + } + field = ast_json_object_get(body, "ifExists"); + if (field) { + args.if_exists = ast_json_string_get(field); + } + field = ast_json_object_get(body, "beep"); + if (field) { + args.beep = ast_json_is_true(field); + } + field = ast_json_object_get(body, "terminateOn"); + if (field) { + args.terminate_on = ast_json_string_get(field); + } ast_ari_channels_record(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -1267,11 +1582,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_get_channel_var_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_get_channel_var_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -1289,6 +1607,26 @@ static void ast_ari_channels_get_channel_var_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "variable"); + if (field) { + args.variable = ast_json_string_get(field); + } ast_ari_channels_get_channel_var(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -1332,11 +1670,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_set_channel_var_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_set_channel_var_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -1357,6 +1698,30 @@ static void ast_ari_channels_set_channel_var_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "variable"); + if (field) { + args.variable = ast_json_string_get(field); + } + field = ast_json_object_get(body, "value"); + if (field) { + args.value = ast_json_string_get(field); + } ast_ari_channels_set_channel_var(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -1400,11 +1765,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_channels_snoop_channel_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_channels_snoop_channel_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -1431,6 +1799,38 @@ static void ast_ari_channels_snoop_channel_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "spy"); + if (field) { + args.spy = ast_json_string_get(field); + } + field = ast_json_object_get(body, "whisper"); + if (field) { + args.whisper = ast_json_string_get(field); + } + field = ast_json_object_get(body, "app"); + if (field) { + args.app = ast_json_string_get(field); + } + field = ast_json_object_get(body, "appArgs"); + if (field) { + args.app_args = ast_json_string_get(field); + } ast_ari_channels_snoop_channel(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index 07f51ba3e..a8079f139 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -59,10 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_device_states_list_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_device_states_list_args args = {}; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -108,11 +110,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_device_states_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_device_states_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -164,11 +168,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_device_states_update_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_device_states_update_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -186,6 +193,26 @@ static void ast_ari_device_states_update_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "deviceState"); + if (field) { + args.device_state = ast_json_string_get(field); + } ast_ari_device_states_update(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -228,11 +255,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_device_states_delete_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_device_states_delete_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index 10accb968..f7995ef4d 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -59,10 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_endpoints_list_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_endpoints_list_args args = {}; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -108,11 +110,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_endpoints_list_by_tech_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_endpoints_list_by_tech_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -165,11 +169,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_endpoints_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_endpoints_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index 5b6dc919b..429f00dc2 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -59,11 +59,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_playbacks_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_playbacks_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -116,11 +118,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_playbacks_stop_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_playbacks_stop_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -173,11 +177,14 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_playbacks_control_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_playbacks_control_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -195,6 +202,26 @@ static void ast_ari_playbacks_control_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "operation"); + if (field) { + args.operation = ast_json_string_get(field); + } ast_ari_playbacks_control(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index 3a4afdc71..56fb9ecca 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -59,10 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_list_stored_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_list_stored_args args = {}; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -108,11 +110,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_get_stored_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_get_stored_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -165,11 +169,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_delete_stored_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_delete_stored_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -222,11 +228,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_get_live_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_get_live_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -279,11 +287,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_cancel_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_cancel_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -336,11 +346,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_stop_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_stop_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -393,11 +405,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_pause_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_pause_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -451,11 +465,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_unpause_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_unpause_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -509,11 +525,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_mute_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_mute_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -567,11 +585,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_unmute_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_unmute_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index 62a34364e..a3657d13b 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -59,11 +59,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_sounds_list_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_sounds_list_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); + struct ast_json *field; #if defined(AST_DEVMODE) int is_valid; int code; @@ -78,6 +81,30 @@ static void ast_ari_sounds_list_cb( } else {} } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "lang"); + if (field) { + args.lang = ast_json_string_get(field); + } + field = ast_json_object_get(body, "format"); + if (field) { + args.format = ast_json_string_get(field); + } ast_ari_sounds_list(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -118,11 +145,13 @@ fin: __attribute__((unused)) * \param[out] response Response to the HTTP request. */ static void ast_ari_sounds_get_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_sounds_get_args args = {}; struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/rest-api-templates/asterisk_processor.py b/rest-api-templates/asterisk_processor.py index 18044f57e..7eb5bff6f 100644 --- a/rest-api-templates/asterisk_processor.py +++ b/rest-api-templates/asterisk_processor.py @@ -146,6 +146,15 @@ class AsteriskProcessor(SwaggerPostProcessor): 'boolean': 'ast_true', } + #: JSON conversion functions + json_convert_mapping = { + 'string': 'ast_json_string_get', + 'int': 'ast_json_integer_get', + 'long': 'ast_json_integer_get', + 'double': 'ast_json_real_get', + 'boolean': 'ast_json_is_true', + } + def __init__(self, wiki_prefix): self.wiki_prefix = wiki_prefix @@ -190,15 +199,22 @@ class AsteriskProcessor(SwaggerPostProcessor): raise SwaggerError("Summary should end with .", context) operation.wiki_summary = wikify(operation.summary or "") operation.wiki_notes = wikify(operation.notes or "") + operation.parse_body = (operation.body_parameter or operation.has_query_parameters) and True def process_parameter(self, parameter, context): - if not parameter.data_type in self.type_mapping: - raise SwaggerError( - "Invalid parameter type %s" % parameter.data_type, context) + if parameter.param_type == 'body': + parameter.c_data_type = 'struct ast_json *' + else: + if not parameter.data_type in self.type_mapping: + raise SwaggerError( + "Invalid parameter type %s" % parameter.data_type, context) + # Type conversions + parameter.c_data_type = self.type_mapping[parameter.data_type] + parameter.c_convert = self.convert_mapping[parameter.data_type] + parameter.json_convert = self.json_convert_mapping[parameter.data_type] + # Parameter names are camelcase, Asterisk convention is snake case parameter.c_name = snakify(parameter.name) - parameter.c_data_type = self.type_mapping[parameter.data_type] - parameter.c_convert = self.convert_mapping[parameter.data_type] # You shouldn't put a space between 'char *' and the variable if parameter.c_data_type.endswith('*'): parameter.c_space = '' diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache index aabd728fd..9d2073869 100644 --- a/rest-api-templates/param_parsing.mustache +++ b/rest-api-templates/param_parsing.mustache @@ -83,3 +83,66 @@ {} } {{/has_path_parameters}} +{{^is_websocket}} +{{#parse_body}} + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } +{{#body_parameter}} + args.{{c_name}} = ast_json_ref(body); +{{/body_parameter}} +{{^body_parameter}} + /* Parse query parameters out of it */ +{{#query_parameters}} + field = ast_json_object_get(body, "{{name}}"); + if (field) { +{{^allow_multiple}} + args.{{c_name}} = {{json_convert}}(field); +{{/allow_multiple}} +{{#allow_multiple}} + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args.{{c_name}}); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args.{{c_name}}_count = ast_json_array_size(field); + args.{{c_name}} = ast_malloc(sizeof(*args.{{c_name}}) * args.{{c_name}}_count); + + if (!args.{{c_name}}) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (i = 0; i < args.{{c_name}}_count; ++i) { + args.{{c_name}}[i] = {{json_convert}}(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args.{{c_name}}_count = 1; + args.{{c_name}} = ast_malloc(sizeof(*args.{{c_name}}) * args.{{c_name}}_count); + if (!args.{{c_name}}) { + ast_ari_response_alloc_failed(response); + goto fin; + } + args.{{c_name}}[0] = {{json_convert}}(field); + } +{{/allow_multiple}} + } +{{/query_parameters}} +{{/body_parameter}} +{{/parse_body}} +{{/is_websocket}} diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index 580ba1944..d2823a877 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -74,6 +74,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * \param[out] response Response to the HTTP request. */ static void ast_ari_{{c_name}}_{{c_nickname}}_cb( + struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { @@ -81,6 +82,12 @@ static void ast_ari_{{c_name}}_{{c_nickname}}_cb( {{#has_parameters}} struct ast_variable *i; {{/has_parameters}} + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +{{^body_parameter}} +{{#has_query_parameters}} + struct ast_json *field; +{{/has_query_parameters}} +{{/body_parameter}} #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py index 144f22bdb..01659d145 100644 --- a/rest-api-templates/swagger_model.py +++ b/rest-api-templates/swagger_model.py @@ -377,8 +377,9 @@ class Operation(Stringify): if self.is_websocket: self.websocket_protocol = op_json.get('websocketProtocol') if self.http_method != 'GET': - raise ValueError( - "upgrade: websocket is only valid on GET operations") + raise SwaggerError( + "upgrade: websocket is only valid on GET operations", + context) params_json = op_json.get('parameters') or [] self.parameters = [ @@ -394,6 +395,14 @@ class Operation(Stringify): self.has_header_parameters = self.header_parameters and True self.has_parameters = self.has_query_parameters or \ self.has_path_parameters or self.has_header_parameters + + # Body param is different, since there's at most one + self.body_parameter = [ + p for p in self.parameters if p.is_type('body')] + if len(self.body_parameter) > 1: + raise SwaggerError("Cannot have more than one body param", context) + self.body_parameter = self.body_parameter and self.body_parameter[0] + self.summary = op_json.get('summary') self.notes = op_json.get('notes') err_json = op_json.get('errorResponses') or [] diff --git a/tests/test_ari.c b/tests/test_ari.c index f984c3d2d..fc74544af 100644 --- a/tests/test_ari.c +++ b/tests/test_ari.c @@ -95,10 +95,11 @@ static void handler(const char *name, * Macro to reduce the handler definition boiler-plate. */ #define HANDLER(name, response_code) \ - static void name(struct ast_variable *get_params, \ - struct ast_variable *path_vars, \ - struct ast_variable *headers, \ - struct ast_ari_response *response) \ + static void name(struct ast_tcptls_session_instance *ser, \ + struct ast_variable *get_params, \ + struct ast_variable *path_vars, \ + struct ast_variable *headers, \ + struct ast_ari_response *response) \ { \ handler(#name, response_code, get_params, path_vars, headers, response); \ } |