diff --git a/src/reqs.c b/src/reqs.c index 2be8e24..cdc3b61 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -523,7 +523,7 @@ fail: * server headers can be processed. * - 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; ssize_t len; @@ -548,39 +548,75 @@ static int pull_client_data (struct conn_s *connptr, long int length) length -= len; } while (length > 0); - /* - * BUG FIX: Internet Explorer will leave two bytes (carriage - * 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) { - log_message(LOG_ERR, "Failed to set the client socket " - "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"); + if (iehack) { + /* + * BUG FIX: Internet Explorer will leave two bytes (carriage + * 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) { + log_message(LOG_ERR, "Failed to set the client socket " + "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"); + } + } + } + + 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); @@ -787,7 +823,7 @@ static int remove_connection_headers (orderedmap hashofheaders) /* * If there is a Content-Length header, then return the value; otherwise, return - * a negative number. + * -1. */ static long get_content_length (orderedmap hashofheaders) { @@ -802,6 +838,13 @@ static long get_content_length (orderedmap hashofheaders) 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 * 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); + /* 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 * of processing. :) @@ -960,8 +1007,9 @@ process_client_headers (struct conn_s *connptr, orderedmap hashofheaders) PULL_CLIENT_DATA: if (connptr->content_length.client > 0) { 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; }