[svn-commits] rmudgett: branch rmudgett/http_persistent r417742 - /team/rmudgett/http_persi...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 1 20:44:05 CDT 2014


Author: rmudgett
Date: Tue Jul  1 20:44:01 2014
New Revision: 417742

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=417742
Log:
Refactor ast_http_body_discard() and ast_http_get_contents().

Modified:
    team/rmudgett/http_persistent/main/http.c

Modified: team/rmudgett/http_persistent/main/http.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/main/http.c?view=diff&rev=417742&r1=417741&r2=417742
==============================================================================
--- team/rmudgett/http_persistent/main/http.c (original)
+++ team/rmudgett/http_persistent/main/http.c Tue Jul  1 20:44:01 2014
@@ -769,59 +769,6 @@
 }
 
 /*!
- * \brief decode chunked mode hexadecimal value
- *
- * \param s string to decode
- * \param len length of string
- *
- * \retval length on success.
- * \retval -1 on error.
- */
-static int chunked_atoh(const char *s, int len)
-{
-	int value = 0;
-	char c;
-
-	if (*s < '0') {
-		/* zero value must be 0\n not just \n */
-		return -1;
-	}
-
-	while (len--) {
-		c = *s++;
-		if (c == '\x0D') {
-			return value;
-		}
-		if (c == ';') {
-			/* We have a chunk-extension that we don't care about. */
-			while (len--) {
-				if (*s++ == '\x0D') {
-					return value;
-				}
-			}
-			break;
-		}
-		value <<= 4;
-		if (c >= '0' && c <= '9') {
-			value += c - '0';
-			continue;
-		}
-		if (c >= 'a' && c <= 'f') {
-			value += 10 + c - 'a';
-			continue;
-		}
-		if (c >= 'A' && c <= 'F') {
-			value += 10 + c - 'A';
-			continue;
-		}
-		/* invalid character */
-		return -1;
-	}
-	/* end of string */
-	return -1;
-}
-
-/*!
  * \internal
  * \brief Determine if the HTTP peer wants the connection closed.
  *
@@ -920,12 +867,215 @@
 	}
 }
 
-int ast_http_body_discard(struct ast_tcptls_session_instance *ser)
-{
-	struct http_worker_private_data *request;
-	int length;
+/*!
+ * \internal
+ * \brief Read the next length bytes from the HTTP body.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ * \param buf Where to put the contents reading.
+ * \param length How much contents to read.
+ * \param what_getting Name of the contents reading.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int http_body_read_contents(struct ast_tcptls_session_instance *ser, char *buf, int length, const char *what_getting)
+{
+	int res;
+
+	/* Stay in fread until get all the expected data or timeout. */
+	res = fread(buf, length, 1, ser->f);
+	if (res < 1) {
+		ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d)\n",
+			what_getting, length);
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Read and discard the next length bytes from the HTTP body.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ * \param length How much contents to discard
+ * \param what_getting Name of the contents discarding.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int http_body_discard_contents(struct ast_tcptls_session_instance *ser, int length, const char *what_getting)
+{
 	int res;
 	char buf[MAX_HTTP_LINE_LENGTH];/* Discard buffer */
+
+	/* Stay in fread until get all the expected data or timeout. */
+	while (sizeof(buf) < length) {
+		res = fread(buf, sizeof(buf), 1, ser->f);
+		if (res < 1) {
+			ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d of remaining %d)\n",
+				what_getting, (int) sizeof(buf), length);
+			return -1;
+		}
+		length -= sizeof(buf);
+	}
+	res = fread(buf, length, 1, ser->f);
+	if (res < 1) {
+		ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d of remaining %d)\n",
+			what_getting, length, length);
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief decode chunked mode hexadecimal value
+ *
+ * \param s string to decode
+ * \param len length of string
+ *
+ * \retval length on success.
+ * \retval -1 on error.
+ */
+static int chunked_atoh(const char *s, int len)
+{
+	int value = 0;
+	char c;
+
+	if (*s < '0') {
+		/* zero value must be 0\n not just \n */
+		return -1;
+	}
+
+	while (len--) {
+		c = *s++;
+		if (c == '\x0D') {
+			return value;
+		}
+		if (c == ';') {
+			/* We have a chunk-extension that we don't care about. */
+			while (len--) {
+				if (*s++ == '\x0D') {
+					return value;
+				}
+			}
+			break;
+		}
+		value <<= 4;
+		if (c >= '0' && c <= '9') {
+			value += c - '0';
+			continue;
+		}
+		if (c >= 'a' && c <= 'f') {
+			value += 10 + c - 'a';
+			continue;
+		}
+		if (c >= 'A' && c <= 'F') {
+			value += 10 + c - 'A';
+			continue;
+		}
+		/* invalid character */
+		return -1;
+	}
+	/* end of string */
+	return -1;
+}
+
+/*!
+ * \internal
+ * \brief Read and convert the chunked body header length.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ *
+ * \retval length Size of chunk to expect.
+ * \retval -1 on error.
+ */
+static int http_body_get_chunk_length(struct ast_tcptls_session_instance *ser)
+{
+	int length;
+	char header_line[MAX_HTTP_LINE_LENGTH];
+
+	/* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */
+	if (!fgets(header_line, sizeof(header_line), ser->f)) {
+		ast_log(LOG_WARNING, "Short HTTP read of chunked header\n");
+		return -1;
+	}
+	length = chunked_atoh(header_line, strlen(header_line));
+	if (length < 0) {
+		ast_log(LOG_WARNING, "Invalid HTTP chunk size\n");
+		return -1;
+	}
+	return length;
+}
+
+/*!
+ * \internal
+ * \brief Read and check the chunk contents line termination.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int http_body_check_chunk_sync(struct ast_tcptls_session_instance *ser)
+{
+	int res;
+	char chunk_sync[2];
+
+	/* Stay in fread until get the expected CRLF or timeout. */
+	res = fread(chunk_sync, sizeof(chunk_sync), 1, ser->f);
+	if (res < 1) {
+		ast_log(LOG_WARNING, "Short HTTP chunk sync read (Wanted %d)\n",
+			(int) sizeof(chunk_sync));
+		return -1;
+	}
+	if (chunk_sync[0] != 0x0D || chunk_sync[1] != 0x0A) {
+		ast_log(LOG_WARNING, "HTTP chunk sync bytes wrong (0x%02X, 0x%02X)\n",
+			chunk_sync[0], chunk_sync[1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Read and discard any chunked trailer entity-header lines.
+ * \since 12.4.0
+ *
+ * \param ser HTTP TCP/TLS session object.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int http_body_discard_chunk_trailer_headers(struct ast_tcptls_session_instance *ser)
+{
+	char header_line[MAX_HTTP_LINE_LENGTH];
+
+	for (;;) {
+		if (!fgets(header_line, sizeof(header_line), ser->f)) {
+			ast_log(LOG_WARNING, "Short HTTP read of chunked trailer header\n");
+			return -1;
+		}
+
+		/* Trim trailing whitespace */
+		ast_trim_blanks(header_line);
+		if (ast_strlen_zero(header_line)) {
+			/* A blank line ends the chunked-body */
+			break;
+		}
+	}
+	return 0;
+}
+
+int ast_http_body_discard(struct ast_tcptls_session_instance *ser)
+{
+	struct http_worker_private_data *request;
 
 	request = ser->private_data;
 	if (!ast_test_flag(&request->flags, HTTP_FLAG_HAS_BODY)
@@ -939,25 +1089,7 @@
 
 	ast_assert(request->body_length != 0);
 	if (0 < request->body_length) {
-		length = request->body_length;
-
-		/* Stay in fread until get all the expected data or timeout. */
-		while (sizeof(buf) < length) {
-			res = fread(buf, sizeof(buf), 1, ser->f);
-			if (res < 1) {
-				ast_log(LOG_WARNING,
-					"Short HTTP request body (Wanted %d of remaining %d)\n",
-					(int) sizeof(buf), length);
-				ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-				return -1;
-			}
-			length -= sizeof(buf);
-		}
-		res = fread(buf, length, 1, ser->f);
-		if (res < 1) {
-			ast_log(LOG_WARNING,
-				"Short HTTP request body (Wanted %d of remaining %d)\n",
-				length, length);
+		if (http_body_discard_contents(ser, request->body_length, "body")) {
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			return -1;
 		}
@@ -966,16 +1098,10 @@
 
 	/* parse chunked-body */
 	for (;;) {
-		/* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */
-		if (!fgets(buf, sizeof(buf), ser->f)) {
-			ast_log(LOG_WARNING,
-				"Short HTTP read of chunked header\n");
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
-		length = chunked_atoh(buf, sizeof(buf));
+		int length;
+
+		length = http_body_get_chunk_length(ser);
 		if (length < 0) {
-			ast_log(LOG_WARNING, "Invalid HTTP chunk size\n");
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			return -1;
 		}
@@ -984,59 +1110,17 @@
 			break;
 		}
 
-		/* Stay in fread until get all the expected chunk-data or timeout. */
-		while (sizeof(buf) < length) {
-			res = fread(buf, sizeof(buf), 1, ser->f);
-			if (res < 1) {
-				ast_log(LOG_WARNING,
-					"Short HTTP request chunk-data (Wanted %d of remaining %d)\n",
-					(int) sizeof(buf), length);
-				ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-				return -1;
-			}
-			length -= sizeof(buf);
-		}
-		res = fread(buf, length, 1, ser->f);
-		if (res < 1) {
-			ast_log(LOG_WARNING,
-				"Short HTTP request chunk-data (Wanted %d of remaining %d)\n",
-				length, length);
+		if (http_body_discard_contents(ser, length, "chunk-data")
+			|| http_body_check_chunk_sync(ser)) {
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			return -1;
 		}
-
-		/* Stay in fread until get the expected CRLF or timeout. */
-		res = fread(buf, 2, 1, ser->f);
-		if (res < 1) {
-			ast_log(LOG_WARNING,
-				"Short HTTP chunk sync read (Wanted 2)\n");
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
-		if (buf[0] != 0x0D || buf[1] != 0x0A) {
-			ast_log(LOG_WARNING,
-				"HTTP chunk sync bytes wrong (%d, %d)\n",
-				buf[0], buf[1]);
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
 	}
 
 	/* Read and discard any trailer entity-header lines. */
-	for (;;) {
-		if (!fgets(buf, sizeof(buf), ser->f)) {
-			ast_log(LOG_WARNING,
-				"Short HTTP read of chunked trailer header\n");
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
-
-		/* Trim trailing whitespace */
-		ast_trim_blanks(buf);
-		if (ast_strlen_zero(buf)) {
-			/* A blank line ends the chunked-body */
-			break;
-		}
+	if (http_body_discard_chunk_trailer_headers(ser)) {
+		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
+		return -1;
 	}
 	return 0;
 }
@@ -1054,11 +1138,8 @@
 	struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
 {
 	struct http_worker_private_data *request;
-	int res;
 	int content_length;
-	int chunk_length;
-	char header_line[MAX_HTTP_LINE_LENGTH];
-	int bufsize = 250;
+	int bufsize;
 	char *buf;
 
 	request = ser->private_data;
@@ -1080,8 +1161,7 @@
 		/* handle regular non-chunked content */
 		content_length = request->body_length;
 		if (content_length > MAX_CONTENT_LENGTH) {
-			ast_log(LOG_WARNING,
-				"Excessively long HTTP content. (%d > %d)\n",
+			ast_log(LOG_WARNING, "Excessively long HTTP content. (%d > %d)\n",
 				content_length, MAX_CONTENT_LENGTH);
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			errno = EFBIG;
@@ -1094,13 +1174,7 @@
 			return NULL;
 		}
 
-		/* Stay in fread until get all the expected data or timeout. */
-		res = fread(buf, content_length, 1, ser->f);
-		if (res < 1) {
-			/* 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 (Wanted %d)\n",
-				content_length);
+		if (http_body_read_contents(ser, buf, content_length, "body")) {
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			errno = EIO;
 			ast_free(buf);
@@ -1113,6 +1187,7 @@
 	}
 
 	/* pre-allocate buffer */
+	bufsize = 250;
 	buf = ast_malloc(bufsize);
 	if (!buf) {
 		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
@@ -1122,30 +1197,22 @@
 	/* parse chunked-body */
 	content_length = 0;
 	for (;;) {
-		/* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */
-		if (!fgets(header_line, sizeof(header_line), ser->f)) {
-			ast_log(LOG_WARNING,
-				"Short HTTP read of chunked header\n");
+		int chunk_length;
+
+		chunk_length = http_body_get_chunk_length(ser);
+		if (chunk_length < 0) {
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			errno = EIO;
 			ast_free(buf);
 			return NULL;
 		}
-		chunk_length = chunked_atoh(header_line, sizeof(header_line));
-		if (chunk_length < 0) {
-			ast_log(LOG_WARNING, "Invalid HTTP chunk size\n");
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
 		if (chunk_length == 0) {
 			/* parsed last-chunk */
 			break;
 		}
 		if (content_length + chunk_length > MAX_CONTENT_LENGTH) {
 			ast_log(LOG_WARNING,
-				"Excessively long HTTP chunk. (%d + %d > %d)\n",
+				"Excessively long HTTP accumulated chunked body. (%d + %d > %d)\n",
 				content_length, chunk_length, MAX_CONTENT_LENGTH);
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			errno = EFBIG;
@@ -1171,37 +1238,14 @@
 			buf = new_buf;
 		}
 
-		/* Stay in fread until get all the expected chunk-data or timeout. */
-		res = fread(buf + content_length, chunk_length, 1, ser->f);
-		if (res < 1) {
-			ast_log(LOG_WARNING, "Short HTTP chunk read (Wanted %d)\n",
-				chunk_length);
+		if (http_body_read_contents(ser, buf + content_length, chunk_length, "chunk-data")
+			|| http_body_check_chunk_sync(ser)) {
 			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
 			errno = EIO;
 			ast_free(buf);
 			return NULL;
 		}
 		content_length += chunk_length;
-
-		/* Stay in fread until get the expected CRLF or timeout. */
-		res = fread(header_line, 2, 1, ser->f);
-		if (res < 1) {
-			ast_log(LOG_WARNING,
-				"Short HTTP chunk sync read (Wanted 2)\n");
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
-		if (header_line[0] != 0x0D || header_line[1] != 0x0A) {
-			ast_log(LOG_WARNING,
-				"HTTP chunk sync bytes wrong (%d, %d)\n",
-				header_line[0], header_line[1]);
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
 	}
 
 	/*
@@ -1211,22 +1255,11 @@
 	 * XXX In the future we may need to add the trailer headers
 	 * to the passed in headers list rather than discarding them.
 	 */
-	for (;;) {
-		if (!fgets(header_line, sizeof(header_line), ser->f)) {
-			ast_log(LOG_WARNING,
-				"Short HTTP read of chunked trailer header\n");
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
-
-		/* Trim trailing whitespace */
-		ast_trim_blanks(header_line);
-		if (ast_strlen_zero(header_line)) {
-			/* A blank line ends the chunked-body */
-			break;
-		}
+	if (http_body_discard_chunk_trailer_headers(ser)) {
+		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
+		errno = EIO;
+		ast_free(buf);
+		return NULL;
 	}
 
 	buf[content_length] = 0;




More information about the svn-commits mailing list