X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=parsers.c;h=a8d368380318e43b1830ce11c642c5a064328168;hb=63728b12fd2e66db3f948a2ef5422b007825944c;hp=dbaa80986014b77c1fa0001110816cf9770302c8;hpb=8cdf45dfe8ce13cc8f0f5e20af73efd5fb5c0a3a;p=privoxy.git diff --git a/parsers.c b/parsers.c index dbaa8098..a8d36838 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.170 2009/06/01 15:14:40 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.185 2009/06/27 11:25:33 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -67,6 +67,15 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.170 2009/06/01 15:14:40 fabiankei #ifdef FEATURE_ZLIB #include + +#define GZIP_IDENTIFIER_1 0x1f +#define GZIP_IDENTIFIER_2 0x8b + +#define GZIP_FLAG_CHECKSUM 0x02 +#define GZIP_FLAG_EXTRA_FIELDS 0x04 +#define GZIP_FLAG_FILE_NAME 0x08 +#define GZIP_FLAG_COMMENT 0x10 +#define GZIP_FLAG_RESERVED_BITS 0xe0 #endif #if !defined(_WIN32) && !defined(__OS2__) @@ -163,6 +172,8 @@ static jb_err create_fake_referrer(char **header, const char *fake_referrer); static jb_err handle_conditional_hide_referrer_parameter(char **header, const char *host, const int parameter_conditional_block); static const char *get_appropiate_connection_header(const struct client_state *csp); +static void create_content_length_header(unsigned long long content_length, + char *header, size_t buffer_length); /* * List of functions to run on a list of headers. @@ -423,8 +434,8 @@ jb_err decompress_iob(struct client_state *csp) * Strip off the gzip header. Please see RFC 1952 for more * explanation of the appropriate fields. */ - if ((*cur++ != (char)0x1f) - || (*cur++ != (char)0x8b) + if (((*cur++ & 0xff) != GZIP_IDENTIFIER_1) + || ((*cur++ & 0xff) != GZIP_IDENTIFIER_2) || (*cur++ != Z_DEFLATED)) { log_error(LOG_LEVEL_ERROR, "Invalid gzip header when decompressing"); @@ -433,20 +444,21 @@ jb_err decompress_iob(struct client_state *csp) else { int flags = *cur++; - /* - * XXX: These magic numbers should be replaced - * with macros to give a better idea what they do. - */ - if (flags & 0xe0) + if (flags & GZIP_FLAG_RESERVED_BITS) { /* The gzip header has reserved bits set; bail out. */ log_error(LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing"); return JB_ERR_COMPRESS; } + + /* + * Skip mtime (4 bytes), extra flags (1 byte) + * and OS type (1 byte). + */ cur += 6; /* Skip extra fields if necessary. */ - if (flags & 0x04) + if (flags & GZIP_FLAG_EXTRA_FIELDS) { /* * Skip a given number of bytes, specified @@ -476,22 +488,21 @@ jb_err decompress_iob(struct client_state *csp) } /* Skip the filename if necessary. */ - if (flags & 0x08) + if (flags & GZIP_FLAG_FILE_NAME) { /* A null-terminated string is supposed to follow. */ while (*cur++ && (cur < csp->iob->eod)); - } /* Skip the comment if necessary. */ - if (flags & 0x10) + if (flags & GZIP_FLAG_COMMENT) { /* A null-terminated string is supposed to follow. */ while (*cur++ && (cur < csp->iob->eod)); } /* Skip the CRC if necessary. */ - if (flags & 0x02) + if (flags & GZIP_FLAG_CHECKSUM) { cur += 2; } @@ -582,14 +593,15 @@ jb_err decompress_iob(struct client_state *csp) char *tmpbuf; /* used for realloc'ing the buffer */ size_t oldbufsize = bufsize; /* keep track of the old bufsize */ - /* - * If zlib wants more data then there's a problem, because - * the complete compressed file should have been buffered. - */ if (0 == zstr.avail_in) { - log_error(LOG_LEVEL_ERROR, "Unexpected end of compressed iob"); - return JB_ERR_COMPRESS; + /* + * If zlib wants more data then there's a problem, because + * the complete compressed file should have been buffered. + */ + log_error(LOG_LEVEL_ERROR, + "Unexpected end of compressed iob. Using what we got so far."); + break; } /* @@ -659,11 +671,15 @@ jb_err decompress_iob(struct client_state *csp) */ } - if (status != Z_STREAM_END) + if ((status != Z_STREAM_END) && (0 != zstr.avail_in)) { - /* We failed to decompress the stream. */ + /* + * We failed to decompress the stream and it's + * not simply because of missing data. + */ log_error(LOG_LEVEL_ERROR, - "Error in decompressing to the buffer (iob): %s", zstr.msg); + "Unexpected error while decompressing to the buffer (iob): %s", + zstr.msg); return JB_ERR_COMPRESS; } @@ -1137,6 +1153,25 @@ jb_err update_server_headers(struct client_state *csp) } } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if ((JB_ERR_OK == err) + && (csp->flags & CSP_FLAG_MODIFIED) + && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) + && !(csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET)) + { + char header[50]; + + create_content_length_header(csp->content_length, header, sizeof(header)); + err = enlist(csp->headers, header); + if (JB_ERR_OK == err) + { + log_error(LOG_LEVEL_HEADER, + "Content modified with no Content-Length header set. " + "Created: %s.", header); + } + } +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + return err; } @@ -1545,7 +1580,11 @@ static jb_err filter_header(struct client_state *csp, char **header) *********************************************************************/ static jb_err server_connection(struct client_state *csp, char **header) { - if (!strcmpic(*header, "Connection: keep-alive")) + if (!strcmpic(*header, "Connection: keep-alive") +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) +#endif + ) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) @@ -2030,22 +2069,19 @@ static jb_err server_content_encoding(struct client_state *csp, char **header) *********************************************************************/ static jb_err server_adjust_content_length(struct client_state *csp, char **header) { - const size_t max_header_length = 80; - /* Regenerate header if the content was modified. */ if (csp->flags & CSP_FLAG_MODIFIED) { + const size_t header_length = 50; freez(*header); - *header = (char *) zalloc(max_header_length); + *header = malloc(header_length); if (*header == NULL) { return JB_ERR_MEMORY; } - - snprintf(*header, max_header_length, "Content-Length: %d", - (int)csp->content_length); - log_error(LOG_LEVEL_HEADER, "Adjusted Content-Length to %d", - (int)csp->content_length); + create_content_length_header(csp->content_length, *header, header_length); + log_error(LOG_LEVEL_HEADER, + "Adjusted Content-Length to %llu", csp->content_length); } return JB_ERR_OK; @@ -2084,6 +2120,7 @@ static jb_err server_save_content_length(struct client_state *csp, char **header else { csp->expected_content_length = content_length; + csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; } @@ -2301,7 +2338,16 @@ static jb_err server_last_modified(struct client_state *csp, char **header) #else timeptr = gmtime(&last_modified); #endif - strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr); + if ((NULL == timeptr) || !strftime(newheader, + sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) + { + log_error(LOG_LEVEL_ERROR, + "Randomizing '%s' failed. Crunching the header without replacement.", + *header); + freez(*header); + return JB_ERR_OK; + } + freez(*header); *header = strdup("Last-Modified: "); string_append(header, newheader); @@ -3020,7 +3066,15 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) #else timeptr = gmtime(&tm); #endif - strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr); + if ((NULL == timeptr) || !strftime(newheader, + sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) + { + log_error(LOG_LEVEL_ERROR, + "Randomizing '%s' failed. Crunching the header without replacement.", + *header); + freez(*header); + return JB_ERR_OK; + } freez(*header); *header = strdup("If-Modified-Since: "); @@ -3353,7 +3407,11 @@ static jb_err server_connection_adder(struct client_state *csp) if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && (NULL != response_status_line) - && !strncmpic(response_status_line, "HTTP/1.1", 8)) + && !strncmpic(response_status_line, "HTTP/1.1", 8) +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) +#endif + ) { log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response " "without Connection header implies keep-alive."); @@ -3387,7 +3445,8 @@ static jb_err server_proxy_connection_adder(struct client_state *csp) static const char proxy_connection_header[] = "Proxy-Connection: keep-alive"; jb_err err = JB_ERR_OK; - if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)) + if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header); err = enlist(csp->headers, proxy_connection_header); @@ -3422,11 +3481,14 @@ static jb_err client_connection_header_adder(struct client_state *csp) return JB_ERR_OK; } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) - && (csp->http->ssl == 0)) + && (csp->http->ssl == 0) + && !strcmpic(csp->http->ver, "HTTP/1.1")) { csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } +#endif /* FEATURE_CONNECTION_KEEP_ALIVE */ log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header); @@ -3995,12 +4057,38 @@ static const char *get_appropiate_connection_header(const struct client_state *c static const char connection_close[] = "Connection: close"; if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) +#endif && (csp->http->ssl == 0)) { return connection_keep_alive; } return connection_close; } + + +/********************************************************************* + * + * Function : create_content_length_header + * + * Description : Creates a Content-Length header. + * + * Parameters : + * 1 : content_length = The content length to be used in the header. + * 2 : header = Allocated space to safe the header. + * 3 : buffer_length = The length of the allocated space. + * + * Returns : void + * + *********************************************************************/ +static void create_content_length_header(unsigned long long content_length, + char *header, size_t buffer_length) +{ + snprintf(header, buffer_length, "Content-Length: %llu", content_length); +} + + /* Local Variables: tab-width: 3