mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-30 10:33:13 +00:00
ari: Add application/x-www-form-urlencoded parameter support
ARI POST calls only accept parameters via the URL's query string. While this works, it's atypical for HTTP API's in general, and specifically frowned upon with RESTful API's. This patch adds parsing for application/x-www-form-urlencoded request bodies if they are sent in with the request. Any variables parsed this way are prepended to the variable list supplied by the query string. (closes issue ASTERISK-22743) Review: https://reviewboard.asterisk.org/r/2986/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@402555 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
21
main/http.c
21
main/http.c
@@ -616,9 +616,13 @@ struct ast_variable *ast_http_get_post_vars(
|
|||||||
{
|
{
|
||||||
int content_length = 0;
|
int content_length = 0;
|
||||||
struct ast_variable *v, *post_vars=NULL, *prev = NULL;
|
struct ast_variable *v, *post_vars=NULL, *prev = NULL;
|
||||||
char *buf, *var, *val;
|
char *var, *val;
|
||||||
|
RAII_VAR(char *, buf, NULL, ast_free_ptr);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
/* Use errno to distinguish errors from no params */
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
for (v = headers; v; v = v->next) {
|
for (v = headers; v; v = v->next) {
|
||||||
if (!strcasecmp(v->name, "Content-Type")) {
|
if (!strcasecmp(v->name, "Content-Type")) {
|
||||||
if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
|
if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
|
||||||
@@ -640,22 +644,25 @@ struct ast_variable *ast_http_get_post_vars(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (content_length > MAX_POST_CONTENT - 1) {
|
if (content_length > MAX_POST_CONTENT - 1) {
|
||||||
ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
|
ast_log(LOG_WARNING,
|
||||||
content_length, MAX_POST_CONTENT);
|
"Excessively long HTTP content. (%d > %d)\n",
|
||||||
ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
|
content_length, MAX_POST_CONTENT);
|
||||||
|
errno = EFBIG;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = ast_malloc(content_length + 1);
|
buf = ast_malloc(content_length + 1);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
|
/* malloc sets errno to ENOMEM */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fread(buf, 1, content_length, ser->f);
|
res = fread(buf, 1, content_length, ser->f);
|
||||||
if (res < content_length) {
|
if (res < content_length) {
|
||||||
/* Error, distinguishable by ferror() or feof(), but neither
|
/* Error, distinguishable by ferror() or feof(), but neither
|
||||||
* is good. */
|
* is good. Treat either one as I/O error */
|
||||||
goto done;
|
errno = EIO;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
buf[content_length] = '\0';
|
buf[content_length] = '\0';
|
||||||
|
|
||||||
@@ -677,8 +684,6 @@ struct ast_variable *ast_http_get_post_vars(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
|
||||||
ast_free(buf);
|
|
||||||
return post_vars;
|
return post_vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6723,6 +6723,20 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
|
|||||||
params = ast_http_get_post_vars(ser, headers);
|
params = ast_http_get_post_vars(ser, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!params) {
|
||||||
|
switch (errno) {
|
||||||
|
case EFBIG:
|
||||||
|
ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
|
||||||
|
break;
|
||||||
|
case ENOMEM:
|
||||||
|
ast_http_send(ser, AST_HTTP_POST, 500, "Internal Server Error", NULL, NULL, 0, 0);
|
||||||
|
break;
|
||||||
|
case EIO:
|
||||||
|
ast_http_send(ser, AST_HTTP_POST, 400, "Bad Request", NULL, NULL, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
|
for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
|
||||||
hdrlen = strlen(v->name) + strlen(v->value) + 3;
|
hdrlen = strlen(v->name) + strlen(v->value) + 3;
|
||||||
m.headers[m.hdrcount] = ast_malloc(hdrlen);
|
m.headers[m.hdrcount] = ast_malloc(hdrlen);
|
||||||
|
@@ -844,6 +844,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
|
|||||||
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
|
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
|
||||||
struct ast_ari_response response = {};
|
struct ast_ari_response response = {};
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
|
||||||
|
|
||||||
if (!response_headers || !response_body) {
|
if (!response_headers || !response_body) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -861,8 +862,46 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
|
|||||||
|
|
||||||
process_cors_request(headers, &response);
|
process_cors_request(headers, &response);
|
||||||
|
|
||||||
|
/* Process form data from a POST. It could be mixed with query
|
||||||
|
* parameters, which seems a bit odd. But it's allowed, so that's okay
|
||||||
|
* with us.
|
||||||
|
*/
|
||||||
|
post_vars = ast_http_get_post_vars(ser, headers);
|
||||||
|
if (get_params == NULL) {
|
||||||
|
switch (errno) {
|
||||||
|
case EFBIG:
|
||||||
|
ast_ari_response_error(&response, 413,
|
||||||
|
"Request Entity Too Large",
|
||||||
|
"Request body too large");
|
||||||
|
break;
|
||||||
|
case ENOMEM:
|
||||||
|
ast_ari_response_error(&response, 500,
|
||||||
|
"Internal Server Error",
|
||||||
|
"Error processing request");
|
||||||
|
break;
|
||||||
|
case EIO:
|
||||||
|
ast_ari_response_error(&response, 400,
|
||||||
|
"Bad Request", "Error parsing request body");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
get_params = post_vars;
|
||||||
|
} else if (get_params && post_vars) {
|
||||||
|
/* Has both post_vars and get_params */
|
||||||
|
struct ast_variable *last_var = post_vars;
|
||||||
|
while (last_var->next) {
|
||||||
|
last_var = last_var->next;
|
||||||
|
}
|
||||||
|
/* The duped get_params will get freed when post_vars gets
|
||||||
|
* ast_variables_destroyed.
|
||||||
|
*/
|
||||||
|
last_var->next = ast_variables_dup(get_params);
|
||||||
|
get_params = post_vars;
|
||||||
|
}
|
||||||
|
|
||||||
user = authenticate_user(get_params, headers);
|
user = authenticate_user(get_params, headers);
|
||||||
if (!user) {
|
if (response.response_code > 0) {
|
||||||
|
/* POST parameter processing error. Do nothing. */
|
||||||
|
} else if (!user) {
|
||||||
/* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
|
/* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
|
||||||
* message is used by an origin server to challenge the
|
* message is used by an origin server to challenge the
|
||||||
* authorization of a user agent. This response MUST include a
|
* authorization of a user agent. This response MUST include a
|
||||||
|
Reference in New Issue
Block a user