diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h index 69539525e58aa9276eeb6b888cad47ef635b02e1..d2f316a6bcc6496dcc2c5e92ee4d98c4de20d8d2 100644 --- a/res/ari/resource_asterisk.h +++ b/res/ari/resource_asterisk.h @@ -41,8 +41,12 @@ /*! \brief Argument struct for ast_ari_get_asterisk_info() */ struct ast_get_asterisk_info_args { - /*! \brief Filter information returned */ - const char *only; + /*! \brief Array of Filter information returned */ + const char **only; + /*! \brief Length of only array. */ + size_t only_count; + /*! \brief Parsing context for only. */ + char *only_parse; }; /*! * \brief Gets Asterisk system information. diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 7730d0cd9d1c8607ba465ad97b72b82ffe6ef96a..e4c7194ff2b06e7daa018776891152d27683ba18 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -1,4 +1,4 @@ -/* -*- C -*- +/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 2012 - 2013, Digium, Inc. @@ -107,33 +107,95 @@ static struct stasis_app_control *find_channel_control( return control; } +struct control_list { + size_t count; + struct stasis_app_control *controls[]; +}; + +static void control_list_dtor(void *obj) { + struct control_list *list = obj; + size_t i; + + for (i = 0; i < list->count; ++i) { + ao2_cleanup(list->controls[i]); + list->controls[i] = NULL; + } +} + +static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) { + RAII_VAR(struct control_list *, list, NULL, ao2_cleanup); + size_t i; + + if (count == 0 || !channels) { + ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel"); + return NULL; + } + + list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor); + if (!list) { + ast_ari_response_alloc_failed(response); + return NULL; + } + + for (i = 0; i < count; ++i) { + if (ast_strlen_zero(channels[i])) { + continue; + } + list->controls[list->count] = + find_channel_control(response, channels[i]); + if (!list->controls[list->count]) { + return NULL; + } + ++list->count; + } + + if (list->count == 0) { + ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel"); + return NULL; + } + + ao2_ref(list, +1); + return list; +} + void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response) { RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup); - RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); + RAII_VAR(struct control_list *, list, NULL, ao2_cleanup); + size_t i; + if (!bridge) { + /* Response filled in by find_bridge */ return; } - control = find_channel_control(response, args->channel); - if (!control) { + list = control_list_create(response, args->channel_count, args->channel); + if (!list) { + /* Response filled in by control_list_create() */ return; } - stasis_app_control_add_channel_to_bridge(control, bridge); + for (i = 0; i < list->count; ++i) { + stasis_app_control_add_channel_to_bridge(list->controls[i], bridge); + } + ast_ari_response_no_content(response); } void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response) { RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup); - RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); + RAII_VAR(struct control_list *, list, NULL, ao2_cleanup); + size_t i; + if (!bridge) { + /* Response filled in by find_bridge */ return; } - control = find_channel_control(response, args->channel); - if (!control) { + list = control_list_create(response, args->channel_count, args->channel); + if (!list) { + /* Response filled in by control_list_create() */ return; } @@ -141,9 +203,14 @@ void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast * the bridge the channel is in. This will be possible once the bridge uniqueid * is added to the channel snapshot. A 409 response should be issued if the bridge * uniqueids don't match */ - if (stasis_app_control_remove_channel_from_bridge(control, bridge)) { - ast_ari_response_error(response, 500, "Internal Error", - "Could not remove channel from bridge"); + for (i = 0; i < list->count; ++i) { + if (stasis_app_control_remove_channel_from_bridge(list->controls[i], bridge)) { + ast_ari_response_error(response, 500, "Internal Error", + "Could not remove channel from bridge"); + } + } + + if (response->response_code) { return; } diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h index 892a3f2696d626afcc7aadf0a4ab9322c7b84f59..d124324133f786b189d4f2348287ac8ed105225d 100644 --- a/res/ari/resource_bridges.h +++ b/res/ari/resource_bridges.h @@ -97,8 +97,12 @@ void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridg struct ast_add_channel_to_bridge_args { /*! \brief Bridge's id */ const char *bridge_id; - /*! \brief Channel's id */ - const char *channel; + /*! \brief Array of Ids of channels to add to bridge */ + const char **channel; + /*! \brief Length of channel array. */ + size_t channel_count; + /*! \brief Parsing context for channel. */ + char *channel_parse; }; /*! * \brief Add a channel to a bridge. @@ -112,8 +116,12 @@ void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_ struct ast_remove_channel_from_bridge_args { /*! \brief Bridge's id */ const char *bridge_id; - /*! \brief Channel's id */ - const char *channel; + /*! \brief Array of Ids of channels to remove from bridge */ + const char **channel; + /*! \brief Length of channel array. */ + size_t channel_count; + /*! \brief Parsing context for channel. */ + char *channel_parse; }; /*! * \brief Remove a channel from a bridge. diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c index e5490b54618eecfb4e43ab2081453486636b62e1..dd474c3ce52c49ba02603f0df57eab2b59aacf85 100644 --- a/res/ari/resource_events.c +++ b/res/ari/resource_events.c @@ -143,35 +143,28 @@ static void app_handler(void *data, const char *app_name, /*! * \brief Register for all of the apps given. * \param session Session info struct. - * \param app_list Comma seperated list of app names to register. + * \param app_name Name of application to register. */ -static int session_register_apps(struct event_session *session, - const char *app_list) +static int session_register_app(struct event_session *session, + const char *app_name) { - RAII_VAR(char *, to_free, NULL, ast_free); - char *apps, *app_name; SCOPED_AO2LOCK(lock, session); ast_assert(session->ws_session != NULL); ast_assert(session->websocket_apps != NULL); - if (!app_list) { + if (ast_strlen_zero(app_name)) { return -1; } - to_free = apps = ast_strdup(app_list); - if (!apps) { - ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json()); + if (ast_str_container_add(session->websocket_apps, app_name)) { + ast_ari_websocket_session_write(session->ws_session, + ast_ari_oom_json()); return -1; } - while ((app_name = strsep(&apps, ","))) { - if (ast_str_container_add(session->websocket_apps, app_name)) { - ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json()); - return -1; - } - stasis_app_register(app_name, app_handler, session); - } + stasis_app_register(app_name, app_handler, session); + return 0; } @@ -182,6 +175,7 @@ void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_sess RAII_VAR(struct event_session *, session, NULL, session_cleanup); struct ast_json *msg; int res; + size_t i; ast_debug(3, "/events WebSocket connection\n"); @@ -191,7 +185,15 @@ void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_sess return; } - if (!args->app) { + res = 0; + for (i = 0; i < args->app_count; ++i) { + if (ast_strlen_zero(args->app[i])) { + continue; + } + res |= session_register_app(session, args->app[i]); + } + + if (ao2_container_count(session->websocket_apps) == 0) { RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref); msg = ast_json_pack("{s: s, s: [s]}", @@ -205,7 +207,6 @@ void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_sess return; } - res = session_register_apps(session, args->app); if (res != 0) { ast_ari_websocket_session_write(ws_session, ast_ari_oom_json()); return; diff --git a/res/ari/resource_events.h b/res/ari/resource_events.h index 554ed9a87a5709c8c5a8d6846765a5cae7880737..ac7600e03ed9545eceb108f6f90279cf976b64b3 100644 --- a/res/ari/resource_events.h +++ b/res/ari/resource_events.h @@ -41,8 +41,12 @@ /*! \brief Argument struct for ast_ari_event_websocket() */ struct ast_event_websocket_args { - /*! \brief Comma seperated list of applications to subscribe to. */ - const char *app; + /*! \brief Array of Applications to subscribe to. */ + const char **app; + /*! \brief Length of app array. */ + size_t app_count; + /*! \brief Parsing context for app. */ + char *app_parse; }; /*! * \brief WebSocket connection for events. diff --git a/res/ari/resource_sounds.h b/res/ari/resource_sounds.h index 7cb22fb716420524cae07b2550dc4f7a7509d059..fa7cda23cedd2c451caa8a06903909b205a892b5 100644 --- a/res/ari/resource_sounds.h +++ b/res/ari/resource_sounds.h @@ -41,7 +41,9 @@ /*! \brief Argument struct for ast_ari_get_sounds() */ struct ast_get_sounds_args { + /*! \brief Lookup sound for a specific language. */ const char *lang; + /*! \brief Lookup sound in a specific format. */ const char *format; }; /*! diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 2c125188be416c0dbda5ce92b4d3fb4e3b6bc439..dce634e8ae802d0405b88b1aa085bbd218eae2a5 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_asterisk.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /asterisk/info. * \param get_params GET parameters in the HTTP request. @@ -59,17 +62,48 @@ static void ast_ari_get_asterisk_info_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_asterisk_info_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_asterisk_info_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "only") == 0) { - args.only = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.only_parse = ast_strdup(i->value); + if (!args.only_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + args.only_count = ast_app_separate_args( + args.only_parse, ',', vals, ARRAY_LEN(vals)); + if (args.only_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.only_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for only"); + goto fin; + } + + args.only = ast_malloc(sizeof(*args.only) * args.only_count); + if (!args.only) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.only_count; ++j) { + args.only[j] = (vals[j]); + } } else {} } @@ -101,6 +135,11 @@ static void ast_ari_get_asterisk_info_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + ast_free(args.only_parse); + ast_free(args.only); + return; } /*! * \brief Parameter parsing callback for /asterisk/variable. @@ -113,14 +152,13 @@ static void ast_ari_get_global_var_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_global_var_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_global_var_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "variable") == 0) { args.variable = (i->value); @@ -155,6 +193,9 @@ static void ast_ari_get_global_var_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /asterisk/variable. @@ -167,14 +208,13 @@ static void ast_ari_set_global_var_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_set_global_var_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_set_global_var_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "variable") == 0) { args.variable = (i->value); @@ -212,6 +252,9 @@ static void ast_ari_set_global_var_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/asterisk.{format} */ diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index f2ee8c03add101d95423789606b4435bbf40b055..57dc6a48da77bfa3a7c4ccbd89c368ce2eb08135 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_bridges.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /bridges. * \param get_params GET parameters in the HTTP request. @@ -59,12 +62,12 @@ static void ast_ari_get_bridges_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_bridges_args args = {}; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_bridges_args args = {}; ast_ari_get_bridges(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -93,6 +96,9 @@ static void ast_ari_get_bridges_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /bridges. @@ -105,14 +111,13 @@ static void ast_ari_new_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_new_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_new_bridge_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "type") == 0) { args.type = (i->value); @@ -147,6 +152,9 @@ static void ast_ari_new_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /bridges/{bridgeId}. @@ -159,14 +167,13 @@ static void ast_ari_get_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_bridge_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "bridgeId") == 0) { args.bridge_id = (i->value); @@ -202,6 +209,9 @@ static void ast_ari_get_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /bridges/{bridgeId}. @@ -214,14 +224,13 @@ static void ast_ari_delete_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_delete_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_delete_bridge_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "bridgeId") == 0) { args.bridge_id = (i->value); @@ -257,6 +266,9 @@ static void ast_ari_delete_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /bridges/{bridgeId}/addChannel. @@ -269,17 +281,48 @@ static void ast_ari_add_channel_to_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_add_channel_to_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_add_channel_to_bridge_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "channel") == 0) { - args.channel = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.channel_parse = ast_strdup(i->value); + if (!args.channel_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + args.channel_count = ast_app_separate_args( + args.channel_parse, ',', vals, ARRAY_LEN(vals)); + if (args.channel_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.channel_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for channel"); + goto fin; + } + + args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count); + if (!args.channel) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.channel_count; ++j) { + args.channel[j] = (vals[j]); + } } else {} } @@ -320,6 +363,11 @@ static void ast_ari_add_channel_to_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + ast_free(args.channel_parse); + ast_free(args.channel); + return; } /*! * \brief Parameter parsing callback for /bridges/{bridgeId}/removeChannel. @@ -332,17 +380,48 @@ static void ast_ari_remove_channel_from_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_remove_channel_from_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_remove_channel_from_bridge_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "channel") == 0) { - args.channel = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.channel_parse = ast_strdup(i->value); + if (!args.channel_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + args.channel_count = ast_app_separate_args( + args.channel_parse, ',', vals, ARRAY_LEN(vals)); + if (args.channel_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.channel_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for channel"); + goto fin; + } + + args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count); + if (!args.channel) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.channel_count; ++j) { + args.channel[j] = (vals[j]); + } } else {} } @@ -380,6 +459,11 @@ static void ast_ari_remove_channel_from_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + ast_free(args.channel_parse); + ast_free(args.channel); + return; } /*! * \brief Parameter parsing callback for /bridges/{bridgeId}/play. @@ -392,14 +476,13 @@ static void ast_ari_play_on_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_play_on_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_play_on_bridge_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "media") == 0) { args.media = (i->value); @@ -451,6 +534,9 @@ static void ast_ari_play_on_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /bridges/{bridgeId}/record. @@ -463,14 +549,13 @@ static void ast_ari_record_bridge_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_record_bridge_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_record_bridge_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "name") == 0) { args.name = (i->value); @@ -529,6 +614,9 @@ static void ast_ari_record_bridge_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/bridges.{format} */ diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 4c322ea2a0e26febfa649853865cbfaf0e0bc3bd..8a6687bc202b4e11493f25e340b3b27c6c484161 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_channels.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /channels. * \param get_params GET parameters in the HTTP request. @@ -59,12 +62,12 @@ static void ast_ari_get_channels_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_channels_args args = {}; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_channels_args args = {}; ast_ari_get_channels(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -93,6 +96,9 @@ static void ast_ari_get_channels_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels. @@ -105,14 +111,13 @@ static void ast_ari_originate_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_originate_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_originate_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "endpoint") == 0) { args.endpoint = (i->value); @@ -169,6 +174,9 @@ static void ast_ari_originate_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}. @@ -181,14 +189,13 @@ static void ast_ari_get_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_channel_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "channelId") == 0) { args.channel_id = (i->value); @@ -224,6 +231,9 @@ static void ast_ari_get_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}. @@ -236,14 +246,13 @@ static void ast_ari_delete_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_delete_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_delete_channel_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "channelId") == 0) { args.channel_id = (i->value); @@ -279,6 +288,9 @@ static void ast_ari_delete_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/dial. @@ -291,14 +303,13 @@ static void ast_ari_dial_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_dial_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_dial_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "endpoint") == 0) { args.endpoint = (i->value); @@ -350,6 +361,9 @@ static void ast_ari_dial_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/continue. @@ -362,14 +376,13 @@ static void ast_ari_continue_in_dialplan_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_continue_in_dialplan_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_continue_in_dialplan_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "context") == 0) { args.context = (i->value); @@ -418,6 +431,9 @@ static void ast_ari_continue_in_dialplan_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/answer. @@ -430,14 +446,13 @@ static void ast_ari_answer_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_answer_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_answer_channel_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "channelId") == 0) { args.channel_id = (i->value); @@ -474,6 +489,9 @@ static void ast_ari_answer_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/mute. @@ -486,14 +504,13 @@ static void ast_ari_mute_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_mute_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_mute_channel_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "direction") == 0) { args.direction = (i->value); @@ -536,6 +553,9 @@ static void ast_ari_mute_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/unmute. @@ -548,14 +568,13 @@ static void ast_ari_unmute_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_unmute_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_unmute_channel_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "direction") == 0) { args.direction = (i->value); @@ -598,6 +617,9 @@ static void ast_ari_unmute_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/hold. @@ -610,14 +632,13 @@ static void ast_ari_hold_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_hold_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_hold_channel_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "channelId") == 0) { args.channel_id = (i->value); @@ -654,6 +675,9 @@ static void ast_ari_hold_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/unhold. @@ -666,14 +690,13 @@ static void ast_ari_unhold_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_unhold_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_unhold_channel_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "channelId") == 0) { args.channel_id = (i->value); @@ -710,6 +733,9 @@ static void ast_ari_unhold_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/mohstart. @@ -722,14 +748,13 @@ static void ast_ari_moh_start_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_moh_start_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_moh_start_channel_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "mohClass") == 0) { args.moh_class = (i->value); @@ -772,6 +797,9 @@ static void ast_ari_moh_start_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/mohstop. @@ -784,14 +812,13 @@ static void ast_ari_moh_stop_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_moh_stop_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_moh_stop_channel_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "channelId") == 0) { args.channel_id = (i->value); @@ -828,6 +855,9 @@ static void ast_ari_moh_stop_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/play. @@ -840,14 +870,13 @@ static void ast_ari_play_on_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_play_on_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_play_on_channel_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "media") == 0) { args.media = (i->value); @@ -899,6 +928,9 @@ static void ast_ari_play_on_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/record. @@ -911,14 +943,13 @@ static void ast_ari_record_channel_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_record_channel_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_record_channel_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "name") == 0) { args.name = (i->value); @@ -980,6 +1011,9 @@ static void ast_ari_record_channel_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/variable. @@ -992,14 +1026,13 @@ static void ast_ari_get_channel_var_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_channel_var_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_channel_var_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "variable") == 0) { args.variable = (i->value); @@ -1042,6 +1075,9 @@ static void ast_ari_get_channel_var_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /channels/{channelId}/variable. @@ -1054,14 +1090,13 @@ static void ast_ari_set_channel_var_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_set_channel_var_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_set_channel_var_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "variable") == 0) { args.variable = (i->value); @@ -1107,6 +1142,9 @@ static void ast_ari_set_channel_var_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/channels.{format} */ diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index 8aa758929ebf7d3c36f0b9f2e32fbbf7a866cd4b..a1dd759eb639434ef701b5c5504f59b4e10fac8c 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_endpoints.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /endpoints. * \param get_params GET parameters in the HTTP request. @@ -59,12 +62,12 @@ static void ast_ari_get_endpoints_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_endpoints_args args = {}; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_endpoints_args args = {}; ast_ari_get_endpoints(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -93,6 +96,9 @@ static void ast_ari_get_endpoints_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /endpoints/{tech}. @@ -105,14 +111,13 @@ static void ast_ari_get_endpoints_by_tech_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_endpoints_by_tech_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_endpoints_by_tech_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "tech") == 0) { args.tech = (i->value); @@ -147,6 +152,9 @@ static void ast_ari_get_endpoints_by_tech_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /endpoints/{tech}/{resource}. @@ -159,14 +167,13 @@ static void ast_ari_get_endpoint_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_endpoint_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_endpoint_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "tech") == 0) { args.tech = (i->value); @@ -204,6 +211,9 @@ static void ast_ari_get_endpoint_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/endpoints.{format} */ diff --git a/res/res_ari_events.c b/res/res_ari_events.c index c310fa5f98311adafbda2a29b074e84fb4f1b82e..5cea06f0ed019bf2de1a29943ddffce5cca452e0 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_events.h" @@ -48,20 +49,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + static void ast_ari_event_websocket_ws_cb(struct ast_websocket *ws_session, struct ast_variable *get_params, struct ast_variable *headers) { - RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref); - RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup); struct ast_event_websocket_args args = {}; + RAII_VAR(struct ast_ari_response *, response, NULL, ast_free); struct ast_variable *i; + RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref); + RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup); - for (i = get_params; i; i = i->next) { - if (strcmp(i->name, "app") == 0) { - args.app = (i->value); - } else - {} + response = ast_calloc(1, sizeof(*response)); + if (!response) { + ast_log(LOG_ERROR, "Failed to create response.\n"); + goto fin; } + #if defined(AST_DEVMODE) session = ast_ari_websocket_session_create(ws_session, ast_ari_validate_message_fn()); @@ -70,9 +74,69 @@ static void ast_ari_event_websocket_ws_cb(struct ast_websocket *ws_session, #endif if (!session) { ast_log(LOG_ERROR, "Failed to create ARI session\n"); - return; + goto fin; + } + + for (i = get_params; i; i = i->next) { + if (strcmp(i->name, "app") == 0) { + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.app_parse = ast_strdup(i->value); + if (!args.app_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + args.app_count = ast_app_separate_args( + args.app_parse, ',', vals, ARRAY_LEN(vals)); + if (args.app_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.app_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for app"); + goto fin; + } + + args.app = ast_malloc(sizeof(*args.app) * args.app_count); + if (!args.app) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.app_count; ++j) { + args.app[j] = (vals[j]); + } + } else + {} } + ast_ari_websocket_event_websocket(session, headers, &args); + +fin: __attribute__((unused)) + if (response && response->response_code != 0) { + /* Param parsing failure */ + /* TODO - ideally, this would return the error code to the + * HTTP client; but we've already done the WebSocket + * negotiation. Param parsing should happen earlier, but we + * need a way to pass it through the WebSocket code to the + * callback */ + RAII_VAR(char *, msg, NULL, ast_free); + if (response->message) { + msg = ast_json_dump_string(response->message); + } else { + msg = ast_strdup("?"); + } + ast_websocket_write(ws_session, AST_WEBSOCKET_OPCODE_TEXT, msg, + strlen(msg)); + } + ast_free(args.app_parse); + ast_free(args.app); } /*! \brief REST handler for /api-docs/events.{format} */ diff --git a/res/res_ari_playback.c b/res/res_ari_playback.c index 0dc76aff9b9ae110c142a8a6a007a82a3dba9f29..55da058a85242087776dc58a4693b412b444d7f6 100644 --- a/res/res_ari_playback.c +++ b/res/res_ari_playback.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_playback.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /playback/{playbackId}. * \param get_params GET parameters in the HTTP request. @@ -59,14 +62,13 @@ static void ast_ari_get_playback_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_playback_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_playback_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "playbackId") == 0) { args.playback_id = (i->value); @@ -101,6 +103,9 @@ static void ast_ari_get_playback_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /playback/{playbackId}. @@ -113,14 +118,13 @@ static void ast_ari_stop_playback_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_stop_playback_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_stop_playback_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "playbackId") == 0) { args.playback_id = (i->value); @@ -155,6 +159,9 @@ static void ast_ari_stop_playback_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /playback/{playbackId}/control. @@ -167,14 +174,13 @@ static void ast_ari_control_playback_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_control_playback_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_control_playback_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "operation") == 0) { args.operation = (i->value); @@ -218,6 +224,9 @@ static void ast_ari_control_playback_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/playback.{format} */ diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index a63f37b18018891de5bd15b2ce503cf00d1acb61..01ad49a653f5dcc4de1b690fe3d7d55da65ff11c 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_recordings.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /recordings/stored. * \param get_params GET parameters in the HTTP request. @@ -59,12 +62,12 @@ static void ast_ari_get_stored_recordings_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_stored_recordings_args args = {}; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_stored_recordings_args args = {}; ast_ari_get_stored_recordings(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -93,6 +96,9 @@ static void ast_ari_get_stored_recordings_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/stored/{recordingName}. @@ -105,14 +111,13 @@ static void ast_ari_get_stored_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_stored_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_stored_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -147,6 +152,9 @@ static void ast_ari_get_stored_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/stored/{recordingName}. @@ -159,14 +167,13 @@ static void ast_ari_delete_stored_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_delete_stored_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_delete_stored_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -201,6 +208,9 @@ static void ast_ari_delete_stored_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live. @@ -213,12 +223,12 @@ static void ast_ari_get_live_recordings_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_live_recordings_args args = {}; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_live_recordings_args args = {}; ast_ari_get_live_recordings(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; @@ -247,6 +257,9 @@ static void ast_ari_get_live_recordings_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}. @@ -259,14 +272,13 @@ static void ast_ari_get_live_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_live_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_live_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -301,6 +313,9 @@ static void ast_ari_get_live_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}. @@ -313,14 +328,13 @@ static void ast_ari_cancel_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_cancel_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_cancel_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -355,6 +369,9 @@ static void ast_ari_cancel_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}/stop. @@ -367,14 +384,13 @@ static void ast_ari_stop_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_stop_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_stop_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -409,6 +425,9 @@ static void ast_ari_stop_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}/pause. @@ -421,14 +440,13 @@ static void ast_ari_pause_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_pause_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_pause_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -463,6 +481,9 @@ static void ast_ari_pause_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}/unpause. @@ -475,14 +496,13 @@ static void ast_ari_unpause_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_unpause_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_unpause_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -517,6 +537,9 @@ static void ast_ari_unpause_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}/mute. @@ -529,14 +552,13 @@ static void ast_ari_mute_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_mute_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_mute_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -571,6 +593,9 @@ static void ast_ari_mute_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /recordings/live/{recordingName}/unmute. @@ -583,14 +608,13 @@ static void ast_ari_unmute_recording_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_unmute_recording_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_unmute_recording_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); @@ -625,6 +649,9 @@ static void ast_ari_unmute_recording_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/recordings.{format} */ diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index a7411b5bfaf007f5f21e4e63f7773987fba8ef3e..0b817c309133a74e33a8ac96840ecb1b4b854fca 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_sounds.h" @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + /*! * \brief Parameter parsing callback for /sounds. * \param get_params GET parameters in the HTTP request. @@ -59,14 +62,13 @@ static void ast_ari_get_sounds_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_sounds_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_sounds_args args = {}; - struct ast_variable *i; - for (i = get_params; i; i = i->next) { if (strcmp(i->name, "lang") == 0) { args.lang = (i->value); @@ -104,6 +106,9 @@ static void ast_ari_get_sounds_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! * \brief Parameter parsing callback for /sounds/{soundId}. @@ -116,14 +121,13 @@ static void ast_ari_get_stored_sound_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_get_stored_sound_args args = {}; + struct ast_variable *i; #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ - struct ast_get_stored_sound_args args = {}; - struct ast_variable *i; - for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "soundId") == 0) { args.sound_id = (i->value); @@ -158,6 +162,9 @@ static void ast_ari_get_stored_sound_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; } /*! \brief REST handler for /api-docs/sounds.{format} */ diff --git a/rest-api-templates/ari_resource.h.mustache b/rest-api-templates/ari_resource.h.mustache index 6396e2b73e7f148d4dd8201001f792b54848d812..8b4b0acec5405fd2e894af7ff9a8f8801a343bd7 100644 --- a/rest-api-templates/ari_resource.h.mustache +++ b/rest-api-templates/ari_resource.h.mustache @@ -43,10 +43,22 @@ /*! \brief Argument struct for ast_ari_{{c_nickname}}() */ struct ast_{{c_nickname}}_args { {{#parameters}} +{{#description}} +{{/description}} +{{^allow_multiple}} {{#description}} /*! \brief {{{description}}} */ {{/description}} {{c_data_type}}{{c_space}}{{c_name}}; +{{/allow_multiple}} +{{#allow_multiple}} + /*! \brief Array of {{{description}}} */ + {{c_data_type}}{{c_space}}*{{c_name}}; + /*! \brief Length of {{c_name}} array. */ + size_t {{c_name}}_count; + /*! \brief Parsing context for {{c_name}}. */ + char *{{c_name}}_parse; +{{/allow_multiple}} {{/parameters}} }; {{#is_req}} diff --git a/rest-api-templates/param_cleanup.mustache b/rest-api-templates/param_cleanup.mustache new file mode 100644 index 0000000000000000000000000000000000000000..46edb417ceefc98649ef9f918d16e8a164ee264f --- /dev/null +++ b/rest-api-templates/param_cleanup.mustache @@ -0,0 +1,26 @@ +{{! + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * David M. Lee, II <dlee@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. +}} +{{! + * Snippet for cleaning up an _args struct. +}} +{{#query_parameters}} +{{#allow_multiple}} + ast_free(args.{{c_name}}_parse); + ast_free(args.{{c_name}}); +{{/allow_multiple}} +{{/query_parameters}} diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache index d43dcdce2676104f62bd0640449d1070b7414ef5..59c59e958e932abdb59d9d84e010f26022ca2330 100644 --- a/rest-api-templates/param_parsing.mustache +++ b/rest-api-templates/param_parsing.mustache @@ -18,15 +18,48 @@ {{! * Snippet for decoding parameters into an _args struct. }} - struct ast_{{c_nickname}}_args args = {}; -{{#has_parameters}} - struct ast_variable *i; - {{#has_query_parameters}} for (i = get_params; i; i = i->next) { {{#query_parameters}} if (strcmp(i->name, "{{name}}") == 0) { +{{^allow_multiple}} args.{{c_name}} = {{c_convert}}(i->value); +{{/allow_multiple}} +{{#allow_multiple}} + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.{{c_name}}_parse = ast_strdup(i->value); + if (!args.{{c_name}}_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + args.{{c_name}}_count = ast_app_separate_args( + args.{{c_name}}_parse, ',', vals, ARRAY_LEN(vals)); + if (args.{{c_name}}_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.{{c_name}}_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for {{c_name}}"); + goto fin; + } + + 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 (j = 0; j < args.{{c_name}}_count; ++j) { + args.{{c_name}}[j] = {{c_convert}}(vals[j]); + } +{{/allow_multiple}} } else {{/query_parameters}} {} @@ -42,4 +75,3 @@ {} } {{/has_path_parameters}} -{{/has_parameters}} diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index 4f1986c7d49b660e787d75ab4d93fae694ef3a25..906d55f0dc15669338090216ce7df6da551307fc 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_{{name}}.h" @@ -53,6 +54,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "ari/ari_model_validators.h" #endif +#define MAX_VALS 128 + {{#apis}} {{#operations}} {{#is_req}} @@ -67,6 +70,10 @@ static void ast_ari_{{c_nickname}}_cb( struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { + struct ast_{{c_nickname}}_args args = {}; +{{#has_parameters}} + struct ast_variable *i; +{{/has_parameters}} #if defined(AST_DEVMODE) int is_valid; int code; @@ -112,12 +119,21 @@ static void ast_ari_{{c_nickname}}_cb( "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) +{{> param_cleanup}} + return; } {{/is_req}} {{#is_websocket}} static void ast_ari_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session, struct ast_variable *get_params, struct ast_variable *headers) { + struct ast_{{c_nickname}}_args args = {}; +{{#has_parameters}} + RAII_VAR(struct ast_ari_response *, response, NULL, ast_free); + struct ast_variable *i; +{{/has_parameters}} RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref); RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup); {{#has_path_parameters}} @@ -126,7 +142,15 @@ static void ast_ari_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session, * just punt. */ struct ast_variable *path_vars = NULL; {{/has_path_parameters}} -{{> param_parsing}} + +{{#has_parameters}} + response = ast_calloc(1, sizeof(*response)); + if (!response) { + ast_log(LOG_ERROR, "Failed to create response.\n"); + goto fin; + } +{{/has_parameters}} + #if defined(AST_DEVMODE) session = ast_ari_websocket_session_create(ws_session, ast_ari_validate_{{response_class.c_name}}_fn()); @@ -135,9 +159,31 @@ static void ast_ari_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session, #endif if (!session) { ast_log(LOG_ERROR, "Failed to create ARI session\n"); - return; + goto fin; } + +{{> param_parsing}} + ast_ari_websocket_{{c_nickname}}(session, headers, &args); + +fin: __attribute__((unused)) + if (response && response->response_code != 0) { + /* Param parsing failure */ + /* TODO - ideally, this would return the error code to the + * HTTP client; but we've already done the WebSocket + * negotiation. Param parsing should happen earlier, but we + * need a way to pass it through the WebSocket code to the + * callback */ + RAII_VAR(char *, msg, NULL, ast_free); + if (response->message) { + msg = ast_json_dump_string(response->message); + } else { + msg = ast_strdup("?"); + } + ast_websocket_write(ws_session, AST_WEBSOCKET_OPCODE_TEXT, msg, + strlen(msg)); + } +{{> param_cleanup}} } {{/is_websocket}} {{/operations}} diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index 7b3c4a37b9140ea68911dadb02144a7dac020229..57954dd277b74f02ad19881795fc7fa15a09a640 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -114,7 +114,7 @@ }, { "name": "channel", - "description": "Channel's id", + "description": "Ids of channels to add to bridge", "paramType": "query", "required": true, "allowMultiple": true, @@ -158,7 +158,7 @@ }, { "name": "channel", - "description": "Channel's id", + "description": "Ids of channels to remove from bridge", "paramType": "query", "required": true, "allowMultiple": true, @@ -277,7 +277,7 @@ "description": "Format to encode audio in", "paramType": "query", "required": true, - "allowMultiple": true, + "allowMultiple": false, "dataType": "string" }, { @@ -389,7 +389,7 @@ }, "channels": { "type": "List[string]", - "description": "Id's of channels participating in this bridge", + "description": "Ids of channels participating in this bridge", "required": true } } diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index e54b02772945d505fc8589e8a743fa3a804af5ca..41b6cc08c61fc42218b745a0e155e174f1a2dfd6 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -634,7 +634,7 @@ "description": "Format to encode audio in", "paramType": "query", "required": true, - "allowMultiple": true, + "allowMultiple": false, "dataType": "string" }, { diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json index 519bb7ae79e60f81867bd25551907f0d7bb48498..a2ac0b3d03143d39e8345473f043c2bd26a0c034 100644 --- a/rest-api/api-docs/events.json +++ b/rest-api/api-docs/events.json @@ -21,7 +21,7 @@ "parameters": [ { "name": "app", - "description": "Comma seperated list of applications to subscribe to.", + "description": "Applications to subscribe to.", "paramType": "query", "required": true, "allowMultiple": true, diff --git a/rest-api/api-docs/sounds.json b/rest-api/api-docs/sounds.json index 103738c45ae6d614ec06c245d5c10d391603fcc4..fe0b09fd49bf30c336e8c3dc5ed7f68adcdb022e 100644 --- a/rest-api/api-docs/sounds.json +++ b/rest-api/api-docs/sounds.json @@ -19,12 +19,14 @@ "parameters": [ { "name": "lang", + "description": "Lookup sound for a specific language.", "paramType": "query", "dataType": "string", "required": false }, { "name": "format", + "description": "Lookup sound in a specific format.", "paramType": "query", "dataType": "string", "required": false,