[svn-commits] dlee: branch 12 r402555 - in /branches/12: main/ res/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Nov 8 11:28:43 CST 2013


Author: dlee
Date: Fri Nov  8 11:28:40 2013
New Revision: 402555

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=402555
Log:
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/

Modified:
    branches/12/main/http.c
    branches/12/main/manager.c
    branches/12/res/res_ari.c

Modified: branches/12/main/http.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/http.c?view=diff&rev=402555&r1=402554&r2=402555
==============================================================================
--- branches/12/main/http.c (original)
+++ branches/12/main/http.c Fri Nov  8 11:28:40 2013
@@ -616,8 +616,12 @@
 {
 	int content_length = 0;
 	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;
+
+	/* Use errno to distinguish errors from no params */
+	errno = 0;
 
 	for (v = headers; v; v = v->next) {
 		if (!strcasecmp(v->name, "Content-Type")) {
@@ -640,22 +644,25 @@
 	}
 
 	if (content_length > MAX_POST_CONTENT - 1) {
-		ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
-				content_length, MAX_POST_CONTENT);
-		ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
+		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 + 1);
 	if (!buf) {
+		/* malloc sets errno to 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. */
-		goto done;
+		 * is good. Treat either one as I/O error */
+		errno = EIO;
+		return NULL;
 	}
 	buf[content_length] = '\0';
 
@@ -677,8 +684,6 @@
 		}
 	}
 
-done:
-	ast_free(buf);
 	return post_vars;
 }
 

Modified: branches/12/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/manager.c?view=diff&rev=402555&r1=402554&r2=402555
==============================================================================
--- branches/12/main/manager.c (original)
+++ branches/12/main/manager.c Fri Nov  8 11:28:40 2013
@@ -6723,6 +6723,20 @@
 		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) {
 		hdrlen = strlen(v->name) + strlen(v->value) + 3;
 		m.headers[m.hdrcount] = ast_malloc(hdrlen);

Modified: branches/12/res/res_ari.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_ari.c?view=diff&rev=402555&r1=402554&r2=402555
==============================================================================
--- branches/12/res/res_ari.c (original)
+++ branches/12/res/res_ari.c Fri Nov  8 11:28:40 2013
@@ -844,6 +844,7 @@
 	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
 	struct ast_ari_response response = {};
 	int ret = 0;
+	RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
 
 	if (!response_headers || !response_body) {
 		return -1;
@@ -861,8 +862,46 @@
 
 	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);
-	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
 		 * message is used by an origin server to challenge the
 		 * authorization of a user agent. This response MUST include a




More information about the svn-commits mailing list