X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=06f1ae8bfc3db61f5051400c91c2c2c05b38282b;hp=6b93b7478c2008bfe0cd5078a17c4e59125a6d3c;hb=57c5f16af5d991b814d96fcb8e7b58c706a93c62;hpb=988422b1a6d68cb306bc50ff1860be82d47445ba diff --git a/parsers.c b/parsers.c index 6b93b747..06f1ae8b 100644 --- a/parsers.c +++ b/parsers.c @@ -64,8 +64,11 @@ #define GZIP_FLAG_COMMENT 0x10 #define GZIP_FLAG_RESERVED_BITS 0xe0 #endif +#ifdef FEATURE_BROTLI +#include +#endif -#if !defined(_WIN32) && !defined(__OS2__) +#if !defined(_WIN32) #include #endif @@ -84,6 +87,9 @@ #include "list.h" #include "actions.h" #include "filters.h" +#ifdef FEATURE_HTTPS_INSPECTION +#include "ssl.h" +#endif #ifndef HAVE_STRPTIME #include "strptime.h" @@ -135,10 +141,10 @@ static jb_err server_save_content_length(struct client_state *csp, char **header static jb_err server_keep_alive(struct client_state *csp, char **header); static jb_err server_proxy_connection(struct client_state *csp, char **header); static jb_err client_keep_alive(struct client_state *csp, char **header); -static jb_err client_save_content_length(struct client_state *csp, char **header); static jb_err client_proxy_connection(struct client_state *csp, char **header); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +static jb_err client_save_content_length(struct client_state *csp, char **header); static jb_err client_host_adder (struct client_state *csp); static jb_err client_xtra_adder (struct client_state *csp); static jb_err client_x_forwarded_for_adder(struct client_state *csp); @@ -182,9 +188,9 @@ static const struct parsers client_patterns[] = { { "TE:", 3, client_te }, { "Host:", 5, client_host }, { "if-modified-since:", 18, client_if_modified_since }, + { "Content-Length:", 15, client_save_content_length }, #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Keep-Alive:", 11, client_keep_alive }, - { "Content-Length:", 15, client_save_content_length }, { "Proxy-Connection:", 17, client_proxy_connection }, #else { "Keep-Alive:", 11, crumble }, @@ -320,7 +326,7 @@ jb_err add_to_iob(struct iob *iob, const size_t buffer_limit, char *src, long n) if (need > buffer_limit) { log_error(LOG_LEVEL_INFO, - "Buffer limit reached while extending the buffer (iob). Needed: %d. Limit: %d", + "Buffer limit reached while extending the buffer (iob). Needed: %lu. Limit: %lu", need, buffer_limit); return JB_ERR_MEMORY; } @@ -378,8 +384,7 @@ jb_err add_to_iob(struct iob *iob, const size_t buffer_limit, char *src, long n) * Parameters : * 1 : iob = I/O buffer to clear. * - * Returns : JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory - * or buffer limit reached. + * Returns : N/A * *********************************************************************/ void clear_iob(struct iob *iob) @@ -390,6 +395,87 @@ void clear_iob(struct iob *iob) #ifdef FEATURE_ZLIB +#ifdef FEATURE_BROTLI +/********************************************************************* + * + * Function : decompress_iob_with_brotli + * + * Description : Decompress buffered page using Brotli. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : JB_ERR_OK on success, + * JB_ERR_MEMORY if out-of-memory limit reached, and + * JB_ERR_COMPRESS if error decompressing buffer. + * + *********************************************************************/ +static jb_err decompress_iob_with_brotli(struct client_state *csp) +{ + BrotliDecoderResult result; + char *decoded_buffer; + size_t decoded_size; + size_t decoded_buffer_size; + size_t encoded_size; + enum { MAX_COMPRESSION_FACTOR = 15 }; + + encoded_size = (size_t)(csp->iob->eod - csp->iob->cur); + /* + * The BrotliDecoderDecompress() api is a bit unfortunate + * and requires the caller to reserve enough memory for + * the decompressed content. Hopefully reserving + * MAX_COMPRESSION_FACTOR times the original size is + * sufficient. If not, BrotliDecoderDecompress() will fail. + */ + decoded_buffer_size = encoded_size * MAX_COMPRESSION_FACTOR; + + if (decoded_buffer_size > csp->config->buffer_limit) + { + log_error(LOG_LEVEL_ERROR, + "Buffer limit reached before decompressing iob with Brotli"); + return JB_ERR_MEMORY; + } + + decoded_buffer = malloc(decoded_buffer_size); + if (decoded_buffer == NULL) + { + log_error(LOG_LEVEL_ERROR, + "Failed to allocate %lu bytes for Brotli decompression", + decoded_buffer_size); + return JB_ERR_MEMORY; + } + + decoded_size = decoded_buffer_size; + result = BrotliDecoderDecompress(encoded_size, + (const uint8_t *)csp->iob->cur, &decoded_size, + (uint8_t *)decoded_buffer); + if (result == BROTLI_DECODER_RESULT_SUCCESS) + { + /* + * Update the iob, since the decompression was successful. + */ + freez(csp->iob->buf); + csp->iob->buf = decoded_buffer; + csp->iob->cur = csp->iob->buf; + csp->iob->eod = csp->iob->cur + decoded_size; + csp->iob->size = decoded_buffer_size; + + log_error(LOG_LEVEL_RE_FILTER, + "Decompression successful. Old size: %lu, new size: %lu.", + encoded_size, decoded_size); + + return JB_ERR_OK; + } + else + { + log_error(LOG_LEVEL_ERROR, "Failed to decompress buffer with Brotli"); + freez(decoded_buffer); + + return JB_ERR_COMPRESS; + } +} +#endif + /********************************************************************* * * Function : decompress_iob @@ -440,11 +526,18 @@ jb_err decompress_iob(struct client_state *csp) * but it should(?) be valid for deflated data also. */ log_error(LOG_LEVEL_ERROR, - "Insufficient data to start decompression. Bytes in buffer: %d", + "Insufficient data to start decompression. Bytes in buffer: %ld", csp->iob->eod - csp->iob->cur); return JB_ERR_COMPRESS; } +#ifdef FEATURE_BROTLI + if (csp->content_type & CT_BROTLI) + { + return decompress_iob_with_brotli(csp); + } +#endif + if (csp->content_type & CT_GZIP) { /* @@ -634,6 +727,7 @@ jb_err decompress_iob(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob"); freez(buf); + inflateEnd(&zstr); return JB_ERR_MEMORY; } @@ -652,6 +746,7 @@ jb_err decompress_iob(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob"); freez(buf); + inflateEnd(&zstr); return JB_ERR_MEMORY; } else @@ -722,7 +817,7 @@ jb_err decompress_iob(struct client_state *csp) * Make sure the new uncompressed iob obeys some minimal * consistency conditions. */ - if ((csp->iob->buf <= csp->iob->cur) + if ((csp->iob->buf <= csp->iob->cur) && (csp->iob->cur <= csp->iob->eod) && (csp->iob->eod <= csp->iob->buf + csp->iob->size)) { @@ -730,22 +825,20 @@ jb_err decompress_iob(struct client_state *csp) if (new_size > (size_t)0) { log_error(LOG_LEVEL_RE_FILTER, - "Decompression successful. Old size: %d, new size: %d.", + "Decompression successful. Old size: %lu, new size: %lu.", old_size, new_size); } else { - /* zlib thinks this is OK, so lets do the same. */ - log_error(LOG_LEVEL_INFO, "Decompression didn't result in any content."); + /* zlib thinks this is OK, so let's do the same. */ + log_error(LOG_LEVEL_RE_FILTER, + "Decompression didn't result in any content."); } } else { /* It seems that zlib did something weird. */ - log_error(LOG_LEVEL_ERROR, - "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d", - csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf, - csp->iob->eod, csp->iob->buf + csp->iob->size); + log_error(LOG_LEVEL_ERROR, "Inconsistent buffer after decompression"); return JB_ERR_COMPRESS; } @@ -1423,7 +1516,7 @@ static jb_err header_tagger(struct client_state *csp, char *header) assert(NULL != header); log_error(LOG_LEVEL_ERROR, "Problems with tagger \'%s\' and header \'%s\': %s", - b->name, *header, pcrs_strerror(hits)); + b->name, header, pcrs_strerror(hits)); } freez(modified_tag); } @@ -1454,7 +1547,7 @@ static jb_err header_tagger(struct client_state *csp, char *header) log_error(LOG_LEVEL_ERROR, "Insufficient memory to add tag \'%s\', " "based on tagger \'%s\' and header \'%s\'", - tag, b->name, *header); + tag, b->name, header); } else { @@ -1574,7 +1667,7 @@ static jb_err filter_header(struct client_state *csp, char **header) continue; } - log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %d) with \'%s\' ...", + log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %lu) with \'%s\' ...", *header, size, b->name); /* Apply all jobs from the joblist */ @@ -1608,7 +1701,8 @@ static jb_err filter_header(struct client_state *csp, char **header) if (b->dynamic) pcrs_free_joblist(joblist); - log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size); + log_error(LOG_LEVEL_RE_FILTER, + "... produced %d hits (new size %lu).", current_hits, size); hits += current_hits; } @@ -1756,6 +1850,7 @@ static jb_err server_proxy_connection(struct client_state *csp, char **header) csp->flags |= CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET; return JB_ERR_OK; } +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* @@ -1788,6 +1883,7 @@ static jb_err proxy_authentication(struct client_state *csp, char **header) } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : client_keep_alive @@ -1854,6 +1950,7 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) return JB_ERR_OK; } +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* @@ -1926,8 +2023,6 @@ static jb_err client_save_content_length(struct client_state *csp, char **header return JB_ERR_OK; } -#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - /********************************************************************* @@ -1956,7 +2051,11 @@ static jb_err client_connection(struct client_state *csp, char **header) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) - && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) +#ifdef FEATURE_HTTPS_INSPECTION + && !client_use_ssl(csp) +#endif + ) { if (!strcmpic(csp->http->version, "HTTP/1.1")) { @@ -2409,6 +2508,15 @@ static jb_err server_content_encoding(struct client_state *csp, char **header) /* Mark for zlib decompression */ csp->content_type |= CT_DEFLATE; } + else if (strstr(*header, "br")) + { +#ifdef FEATURE_BROTLI + /* Mark for Brotli decompression */ + csp->content_type |= CT_BROTLI; +#else + csp->content_type |= CT_TABOO; +#endif + } else if (strstr(*header, "compress")) { /* @@ -2475,7 +2583,12 @@ static jb_err server_content_encoding(struct client_state *csp, char **header) static jb_err server_adjust_content_encoding(struct client_state *csp, char **header) { if ((csp->flags & CSP_FLAG_MODIFIED) - && (csp->content_type & (CT_GZIP | CT_DEFLATE))) + && ((csp->content_type & (CT_GZIP | CT_DEFLATE)) +#ifdef FEATURE_BROTLI + || (csp->content_type & CT_BROTLI) +#endif + ) + ) { /* * We successfully decompressed the content, @@ -2794,7 +2907,7 @@ static jb_err server_last_modified(struct client_state *csp, char **header) seconds = rtime % 60; log_error(LOG_LEVEL_HEADER, - "Randomized: %s (added %d da%s %d hou%s %d minut%s %d second%s", + "Randomized: %s (added %ld da%s %ld hou%s %ld minut%s %ld second%s", *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)"); } @@ -3446,7 +3559,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) if (rtime) { - log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)", + log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %ld minut%s)", *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es"); if (negative_range) { @@ -3457,8 +3570,8 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) } else { - log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.", - *header); + log_error(LOG_LEVEL_ERROR, + "Random range is 0. Assuming time transformation test."); } tm += rtime * (negative_range ? -1 : 1); timeptr = privoxy_gmtime_r(&tm, &gmt); @@ -3486,7 +3599,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) seconds = rtime % 60; log_error(LOG_LEVEL_HEADER, - "Randomized: %s (%s %d hou%s %d minut%s %d second%s", + "Randomized: %s (%s %ld hou%s %ld minut%s %ld second%s", *header, (negative_range) ? "subtracted" : "added", hours, (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)"); @@ -3828,7 +3941,12 @@ static jb_err server_proxy_connection_adder(struct client_state *csp) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) && !(csp->flags & CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET) && ((csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET) - || (csp->flags & CSP_FLAG_CHUNKED))) + || (csp->flags & CSP_FLAG_CHUNKED)) +#ifdef FEATURE_HTTPS_INSPECTION + && !client_use_ssl(csp) + && !csp->http->ssl +#endif + ) { log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header); err = enlist(csp->headers, proxy_connection_header); @@ -4356,9 +4474,10 @@ static jb_err parse_header_time(const char *header_time, time_t *result) { char recreated_date[100]; struct tm *tm; + struct tm storage; time_t result2; - tm = gmtime(result); + tm = privoxy_gmtime_r(result, &storage); if (!strftime(recreated_date, sizeof(recreated_date), time_formats[i], tm)) { @@ -4378,7 +4497,7 @@ static jb_err parse_header_time(const char *header_time, time_t *result) if (*result != result2) { log_error(LOG_LEVEL_ERROR, "strftime() and strptime() disagree. " - "Format: '%s'. In: '%s', out: '%s'. %d != %d. Rejecting.", + "Format: '%s'. In: '%s', out: '%s'. %ld != %ld. Rejecting.", time_formats[i], header_time, recreated_date, *result, result2); continue; } @@ -4765,7 +4884,6 @@ static void create_content_length_header(unsigned long long content_length, } -#ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : get_expected_content_length @@ -4797,7 +4915,7 @@ unsigned long long get_expected_content_length(struct list *headers) return content_length; } -#endif + /* Local Variables: