ARI: Allow specifying channel variables during a POST /channels
authorKevin Harwell <kharwell@digium.com>
Fri, 13 Dec 2013 17:19:23 +0000 (17:19 +0000)
committerKevin Harwell <kharwell@digium.com>
Fri, 13 Dec 2013 17:19:23 +0000 (17:19 +0000)
Added the ability to specify channel variables when creating/originating a
channel in ARI.  The variables are sent in the body of the request and should
be formatted as a single level JSON object.  No nested objects allowed.
For example: {"variable1": "foo", "variable2": "bar"}.

(closes issue ASTERISK-22872)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/3052/
........

Merged revisions 403752 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403757 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/http.c
res/ari/resource_channels.c
res/ari/resource_channels.h
res/res_ari_channels.c
rest-api/api-docs/channels.json

index 0c9b09a..ebe0a63 100644 (file)
@@ -608,18 +608,30 @@ 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)
+/*!
+ * \brief Retrieves the content type specified in the "Content-Type" header.
+ *
+ * This function only returns the "type/subtype" and any trailing parameter is
+ * not included.
+ *
+ * \note the return value is an allocated string that needs to be freed.
+ *
+ * \retval the content type/subtype or NULL if the header is not found.
+ */
+static 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;
+                       const char *param = strchr(v->value, ';');
+                       size_t size = (param ? param - v->value :
+                                      strlen(v->value)) + 1;
+                       return ast_strndup(v->value, size);
                }
        }
 
-       /* Missing content type; assume empty string */
-       return "";
+       return NULL;
 }
 
 static int get_content_length(struct ast_variable *headers)
@@ -643,11 +655,12 @@ struct ast_json *ast_http_get_json(
        int res;
        struct ast_json *body;
        RAII_VAR(char *, buf, NULL, ast_free);
+       RAII_VAR(char *, type, get_content_type(headers), ast_free);
 
        /* Use errno to distinguish errors from no body */
        errno = 0;
 
-       if (strcasecmp(get_content_type(headers), "application/json") != 0) {
+       if (ast_strlen_zero(type) || strcasecmp(type, "application/json")) {
                /* Content type is not JSON */
                return NULL;
        }
@@ -704,12 +717,14 @@ struct ast_variable *ast_http_get_post_vars(
        struct ast_variable *v, *post_vars=NULL, *prev = NULL;
        char *var, *val;
        RAII_VAR(char *, buf, NULL, ast_free_ptr);
+       RAII_VAR(char *, type, get_content_type(headers), ast_free);
        int res;
 
        /* Use errno to distinguish errors from no params */
        errno = 0;
 
-       if (strcasecmp(get_content_type(headers), "application/x-www-form-urlencoded") != 0) {
+       if (ast_strlen_zero(type) ||
+           strcasecmp(type, "application/x-www-form-urlencoded")) {
                /* Content type is not form data */
                return NULL;
        }
index 824c5e6..6d85781 100644 (file)
@@ -688,6 +688,43 @@ void ast_ari_channels_list(struct ast_variable *headers,
        ast_ari_response_ok(response, ast_json_ref(json));
 }
 
+static int ari_channels_set_channel_var(struct ast_channel *chan,
+       const char *variable, const char *value, struct ast_ari_response *response)
+{
+       if (pbx_builtin_setvar_helper(chan, variable, value)) {
+               ast_ari_response_error(
+                       response, 400, "Bad Request",
+                       "Unable to set channel variable %s=%s", variable, value);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ari_channels_set_channel_vars(struct ast_channel *chan,
+       struct ast_json *variables, struct ast_ari_response *response)
+{
+       struct ast_json_iter *i;
+
+       if (!variables) {
+               /* nothing to do */
+               return 0;
+       }
+
+       for (i = ast_json_object_iter(variables); i;
+            i = ast_json_object_iter_next(variables, i)) {
+               if (ari_channels_set_channel_var(
+                       chan, ast_json_object_iter_key(i),
+                       ast_json_string_get(ast_json_object_iter_value(i)),
+                       response)) {
+                       /* response filled in by called function */
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
 void ast_ari_channels_originate(struct ast_variable *headers,
        struct ast_ari_channels_originate_args *args,
        struct ast_ari_response *response)
@@ -768,6 +805,11 @@ void ast_ari_channels_originate(struct ast_variable *headers,
                return;
        }
 
+       if (ari_channels_set_channel_vars(chan, args->variables, response)) {
+               /* response filled in by called function */
+               return;
+       }
+
        snapshot = ast_channel_snapshot_create(chan);
        ast_channel_unlock(chan);
 
@@ -917,4 +959,4 @@ void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari
 
        snapshot = ast_channel_snapshot_create(snoop);
        ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
-}
\ No newline at end of file
+}
index 49ab8eb..36c7339 100644 (file)
@@ -68,6 +68,8 @@ struct ast_ari_channels_originate_args {
        const char *caller_id;
        /*! \brief Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
        int timeout;
+       /*! \brief Variables to be set on the channel. */
+       struct ast_json *variables;
 };
 /*!
  * \brief Create a new channel (originate).
index 40ad32b..6b741b0 100644 (file)
@@ -117,7 +117,6 @@ static void ast_ari_channels_originate_cb(
        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;
@@ -165,39 +164,7 @@ static void ast_ari_channels_originate_cb(
                        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);
-       }
+       args.variables = ast_json_ref(body);
        ast_ari_channels_originate(headers, &args, response);
 #if defined(AST_DEVMODE)
        code = response->response_code;
index 3958668..263d5ad 100644 (file)
                                                        "allowMultiple": false,
                                                        "dataType": "int",
                                                        "defaultValue": 30
+                                               },
+                                               {
+                                                       "name": "variables",
+                                                       "description": "Variables to be set on the channel.",
+                                                       "paramType": "body",
+                                                       "required": false,
+                                                       "allowMultiple": false,
+                                                       "dataType": "containers"
                                                }
                                        ],
                                        "errorResponses": [