From c02b2427e8d266c51d246bcb5ed410f3f0ae338f Mon Sep 17 00:00:00 2001
From: Seven Du <dujinfang@gmail.com>
Date: Sat, 6 Sep 2014 19:35:05 +0800
Subject: [PATCH] refactor http parsing and prevent read body more than
 content-length

---
 src/include/switch_utils.h              |  5 +++--
 src/mod/endpoints/mod_verto/mod_verto.c | 27 +++++++++++++++++--------
 src/switch_utils.c                      | 11 +++++-----
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index 67fee60c3c..d7c07e7171 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -1116,13 +1116,14 @@ typedef struct switch_http_request_s {
 	switch_bool_t keepalive;
 	const char *content_type;
 	switch_size_t content_length;
+	switch_size_t bytes_header;
+	switch_size_t bytes_read;
+	switch_size_t bytes_buffered;
 	switch_event_t *headers;
 	void *user_data;           /* private user data */
 
 	/* private members used by the parser internally */
 	char *_buffer;
-	const char *_unparsed_data;
-	switch_size_t _unparsed_len;
 	switch_bool_t _destroy_headers;
 } switch_http_request_t;
 
diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c
index 1f3ff1bad3..2a08473f72 100644
--- a/src/mod/endpoints/mod_verto/mod_verto.c
+++ b/src/mod/endpoints/mod_verto/mod_verto.c
@@ -1287,17 +1287,29 @@ static uint8_t *http_stream_read(switch_stream_handle_t *handle, int *len)
 	jsock_t *jsock = r->user_data;
 	wsh_t *wsh = &jsock->ws;
 
-	*len = r->_unparsed_len;
+	*len = r->bytes_buffered - r->bytes_read;
 
-	if (*len) { // we already read part of the body
-		r->_unparsed_len = 0; // reset for the next read
-		return (uint8_t *)r->_unparsed_data;
+	if (*len > 0) { // we already read part of the body
+		uint8_t *data = (uint8_t *)wsh->buffer + r->bytes_read;
+		r->bytes_read = r->bytes_buffered;
+		return data;
 	}
 
-	if ((*len = ws_raw_read(wsh, wsh->buffer, 4096, wsh->block)) < 0) {
+	if (r->content_length && (r->bytes_read - r->bytes_header) >= r->content_length) {
+		*len = 0;
 		return NULL;
 	}
 
+	*len = r->content_length - (r->bytes_read - r->bytes_header);
+	*len = *len > sizeof(wsh->buffer) ? sizeof(wsh->buffer) : *len;
+
+	if ((*len = ws_raw_read(wsh, wsh->buffer, *len, wsh->block)) <= 0) {
+		*len = 0;
+		return NULL;
+	}
+
+	r->bytes_read += *len;
+
 	return (uint8_t *)wsh->buffer;
 }
 
@@ -1453,9 +1465,8 @@ static void http_run(jsock_t *jsock)
 			goto request_err;
 		}
 
-		if (request._unparsed_len) {
-			bytes += request._unparsed_len;
-			memcpy(buffer, request._unparsed_data, bytes);
+		if ((bytes = request.bytes_buffered - (request.bytes_read - request.bytes_header)) > 0) {
+			memcpy(buffer, jsock->ws.buffer + request.bytes_read, bytes);
 		}
 
 		while(bytes < request.content_length) {
diff --git a/src/switch_utils.c b/src/switch_utils.c
index c08b5ff27d..c3e044bbaf 100644
--- a/src/switch_utils.c
+++ b/src/switch_utils.c
@@ -3675,10 +3675,10 @@ SWITCH_DECLARE(switch_status_t) switch_http_parse_header(char *buffer, uint32_t
 
 	request->_buffer = strdup(buffer);
 	request->method = request->_buffer;
-	if (body && *body) {
-		request->_unparsed_data = body;
-		request->_unparsed_len = datalen - (body - buffer);
-		switch_assert(request->_unparsed_len > 0);
+	request->bytes_buffered = datalen;
+	if (body) {
+		request->bytes_header = body - buffer;
+		request->bytes_read = body - buffer;
 	}
 
 	p = strchr(request->method, ' ');
@@ -3796,7 +3796,8 @@ SWITCH_DECLARE(void) switch_http_dump_request(switch_http_request_t *request)
 	if (request->referer) printf("referer: %s\n", request->referer);
 	if (request->user) printf("user: %s\n", request->user);
 	if (request->keepalive) printf("uri: %d\n", request->keepalive);
-	if (request->_unparsed_data) printf("body: %p\n", request->_unparsed_data);
+	if (request->content_type) printf("uri: %s\n", request->content_type);
+	if (request->content_length) printf("uri: %" SWITCH_SIZE_T_FMT "\n", request->content_length);
 
 	{
 		switch_event_header_t *header = request->headers->headers;