[asterisk-commits] rmudgett: branch rmudgett/http_persistent r417742 - /team/rmudgett/http_persi...
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list