properly deal with client sending chunked data

this fixes OPTIONS requests sent from apache SVN client using their
native HTTP proxy support.

closes #421

tested with `svn info http://svnmir.bme.freebsd.org/ports/`
This commit is contained in:
rofl0r 2022-02-13 21:11:37 +00:00
parent 17d3733be3
commit eced6822f8

View File

@ -523,7 +523,7 @@ fail:
* server headers can be processed. * server headers can be processed.
* - rjkaes * - rjkaes
*/ */
static int pull_client_data (struct conn_s *connptr, long int length) static int pull_client_data (struct conn_s *connptr, long int length, int iehack)
{ {
char *buffer; char *buffer;
ssize_t len; ssize_t len;
@ -548,6 +548,7 @@ static int pull_client_data (struct conn_s *connptr, long int length)
length -= len; length -= len;
} while (length > 0); } while (length > 0);
if (iehack) {
/* /*
* BUG FIX: Internet Explorer will leave two bytes (carriage * BUG FIX: Internet Explorer will leave two bytes (carriage
* return and line feed) at the end of a POST message. These * return and line feed) at the end of a POST message. These
@ -582,6 +583,41 @@ static int pull_client_data (struct conn_s *connptr, long int length)
"Could not read two bytes from POST message"); "Could not read two bytes from POST message");
} }
} }
}
safefree (buffer);
return 0;
ERROR_EXIT:
safefree (buffer);
return -1;
}
/* pull chunked client data */
static int pull_client_data_chunked (struct conn_s *connptr) {
char *buffer = 0;
ssize_t len;
long chunklen;
while(1) {
if (buffer) safefree(buffer);
len = readline (connptr->client_fd, &buffer);
if (len <= 0)
goto ERROR_EXIT;
if (!connptr->error_variables) {
if (safe_write (connptr->server_fd, buffer, len) < 0)
goto ERROR_EXIT;
}
chunklen = strtol (buffer, (char**)0, 16);
if (pull_client_data (connptr, chunklen+2, 0) < 0)
goto ERROR_EXIT;
if(!chunklen) break;
}
safefree (buffer); safefree (buffer);
return 0; return 0;
@ -787,7 +823,7 @@ static int remove_connection_headers (orderedmap hashofheaders)
/* /*
* If there is a Content-Length header, then return the value; otherwise, return * If there is a Content-Length header, then return the value; otherwise, return
* a negative number. * -1.
*/ */
static long get_content_length (orderedmap hashofheaders) static long get_content_length (orderedmap hashofheaders)
{ {
@ -802,6 +838,13 @@ static long get_content_length (orderedmap hashofheaders)
return content_length; return content_length;
} }
static int is_chunked_transfer (orderedmap hashofheaders)
{
char *data;
data = orderedmap_find (hashofheaders, "transfer-encoding");
return data ? !strcmp (data, "chunked") : 0;
}
/* /*
* Search for Via header in a hash of headers and either write a new Via * Search for Via header in a hash of headers and either write a new Via
* header, or append our information to the end of an existing Via header. * header, or append our information to the end of an existing Via header.
@ -896,6 +939,10 @@ process_client_headers (struct conn_s *connptr, orderedmap hashofheaders)
*/ */
connptr->content_length.client = get_content_length (hashofheaders); connptr->content_length.client = get_content_length (hashofheaders);
/* Check whether client sends chunked data. */
if (connptr->content_length.client == -1 && is_chunked_transfer (hashofheaders))
connptr->content_length.client = -2;
/* /*
* See if there is a "Connection" header. If so, we need to do a bit * See if there is a "Connection" header. If so, we need to do a bit
* of processing. :) * of processing. :)
@ -960,8 +1007,9 @@ process_client_headers (struct conn_s *connptr, orderedmap hashofheaders)
PULL_CLIENT_DATA: PULL_CLIENT_DATA:
if (connptr->content_length.client > 0) { if (connptr->content_length.client > 0) {
ret = pull_client_data (connptr, ret = pull_client_data (connptr,
connptr->content_length.client); connptr->content_length.client, 1);
} } else if (connptr->content_length.client == -2)
ret = pull_client_data_chunked (connptr);
return ret; return ret;
} }