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:
parent
17d3733be3
commit
eced6822f8
120
src/reqs.c
120
src/reqs.c
@ -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,39 +548,75 @@ 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
|
/*
|
||||||
* return and line feed) at the end of a POST message. These
|
* BUG FIX: Internet Explorer will leave two bytes (carriage
|
||||||
* need to be eaten for tinyproxy to work correctly.
|
* return and line feed) at the end of a POST message. These
|
||||||
*/
|
* need to be eaten for tinyproxy to work correctly.
|
||||||
ret = socket_nonblocking (connptr->client_fd);
|
*/
|
||||||
if (ret != 0) {
|
ret = socket_nonblocking (connptr->client_fd);
|
||||||
log_message(LOG_ERR, "Failed to set the client socket "
|
if (ret != 0) {
|
||||||
"to non-blocking: %s", strerror(errno));
|
log_message(LOG_ERR, "Failed to set the client socket "
|
||||||
goto ERROR_EXIT;
|
"to non-blocking: %s", strerror(errno));
|
||||||
}
|
goto ERROR_EXIT;
|
||||||
|
|
||||||
len = recv (connptr->client_fd, buffer, 2, MSG_PEEK);
|
|
||||||
|
|
||||||
ret = socket_blocking (connptr->client_fd);
|
|
||||||
if (ret != 0) {
|
|
||||||
log_message(LOG_ERR, "Failed to set the client socket "
|
|
||||||
"to blocking: %s", strerror(errno));
|
|
||||||
goto ERROR_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < 0 && errno != EAGAIN)
|
|
||||||
goto ERROR_EXIT;
|
|
||||||
|
|
||||||
if ((len == 2) && CHECK_CRLF (buffer, len)) {
|
|
||||||
ssize_t bytes_read;
|
|
||||||
|
|
||||||
bytes_read = read (connptr->client_fd, buffer, 2);
|
|
||||||
if (bytes_read == -1) {
|
|
||||||
log_message
|
|
||||||
(LOG_WARNING,
|
|
||||||
"Could not read two bytes from POST message");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
len = recv (connptr->client_fd, buffer, 2, MSG_PEEK);
|
||||||
|
|
||||||
|
ret = socket_blocking (connptr->client_fd);
|
||||||
|
if (ret != 0) {
|
||||||
|
log_message(LOG_ERR, "Failed to set the client socket "
|
||||||
|
"to blocking: %s", strerror(errno));
|
||||||
|
goto ERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 0 && errno != EAGAIN)
|
||||||
|
goto ERROR_EXIT;
|
||||||
|
|
||||||
|
if ((len == 2) && CHECK_CRLF (buffer, len)) {
|
||||||
|
ssize_t bytes_read;
|
||||||
|
|
||||||
|
bytes_read = read (connptr->client_fd, buffer, 2);
|
||||||
|
if (bytes_read == -1) {
|
||||||
|
log_message
|
||||||
|
(LOG_WARNING,
|
||||||
|
"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);
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user