X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=5f8c68616c649b68893f35f5c7818575496acfa0;hp=11d28c71dc12e2d3c9cbf76b846d9d72a3dbca34;hb=60dff0012ee6f796d27559389da794c674346d5e;hpb=54debef090db214715953499571b8d7ec77980db diff --git a/parsers.c b/parsers.c index 11d28c71..5f8c6861 100644 --- a/parsers.c +++ b/parsers.c @@ -64,6 +64,9 @@ #define GZIP_FLAG_COMMENT 0x10 #define GZIP_FLAG_RESERVED_BITS 0xe0 #endif +#ifdef FEATURE_BROTLI +#include +#endif #if !defined(_WIN32) && !defined(__OS2__) #include @@ -390,6 +393,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 %d 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: %d, new size: %d.", + 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 @@ -445,6 +529,13 @@ jb_err decompress_iob(struct client_state *csp) 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) { /* @@ -2409,6 +2500,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 +2575,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, @@ -2748,9 +2853,8 @@ static jb_err server_last_modified(struct client_state *csp, char **header) time_t now; struct tm *timeptr = NULL; long int rtime; -#ifdef HAVE_GMTIME_R struct tm gmt; -#endif + now = time(NULL); rtime = (long int)difftime(now, last_modified); if (rtime) @@ -2769,29 +2873,16 @@ static jb_err server_last_modified(struct client_state *csp, char **header) rtime *= -1; } last_modified += rtime; -#ifdef HAVE_GMTIME_R - timeptr = gmtime_r(&last_modified, &gmt); -#elif defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_lock(&gmtime_mutex); - timeptr = gmtime(&last_modified); -#else - timeptr = gmtime(&last_modified); -#endif + timeptr = privoxy_gmtime_r(&last_modified, &gmt); if ((NULL == timeptr) || !strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) { -#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_unlock(&gmtime_mutex); -#endif log_error(LOG_LEVEL_ERROR, "Randomizing '%s' failed. Crunching the header without replacement.", *header); freez(*header); return JB_ERR_OK; } -#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_unlock(&gmtime_mutex); -#endif freez(*header); *header = strdup("Last-Modified: "); string_append(header, newheader); @@ -3417,9 +3508,7 @@ static jb_err client_host(struct client_state *csp, char **header) static jb_err client_if_modified_since(struct client_state *csp, char **header) { char newheader[50]; -#ifdef HAVE_GMTIME_R struct tm gmt; -#endif struct tm *timeptr = NULL; time_t tm = 0; const char *newval; @@ -3477,29 +3566,16 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) *header); } tm += rtime * (negative_range ? -1 : 1); -#ifdef HAVE_GMTIME_R - timeptr = gmtime_r(&tm, &gmt); -#elif defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_lock(&gmtime_mutex); - timeptr = gmtime(&tm); -#else - timeptr = gmtime(&tm); -#endif + timeptr = privoxy_gmtime_r(&tm, &gmt); if ((NULL == timeptr) || !strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) { -#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_unlock(&gmtime_mutex); -#endif log_error(LOG_LEVEL_ERROR, "Randomizing '%s' failed. Crunching the header without replacement.", *header); freez(*header); return JB_ERR_OK; } -#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_unlock(&gmtime_mutex); -#endif freez(*header); *header = strdup("If-Modified-Since: "); string_append(header, newheader); @@ -4040,29 +4116,15 @@ static void add_cookie_expiry_date(char **cookie, time_t lifetime) char tmp[50]; struct tm *timeptr = NULL; time_t expiry_date = time(NULL) + lifetime; -#ifdef HAVE_GMTIME_R struct tm gmt; - timeptr = gmtime_r(&expiry_date, &gmt); -#elif defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_lock(&gmtime_mutex); - timeptr = gmtime(&expiry_date); -#else - timeptr = gmtime(&expiry_date); -#endif - + timeptr = privoxy_gmtime_r(&expiry_date, &gmt); if (NULL == timeptr) { -#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_unlock(&gmtime_mutex); -#endif log_error(LOG_LEVEL_FATAL, "Failed to get the time in add_cooky_expiry_date()"); } strftime(tmp, sizeof(tmp), "; expires=%a, %d-%b-%Y %H:%M:%S GMT", timeptr); -#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_unlock(&gmtime_mutex); -#endif if (JB_ERR_OK != string_append(cookie, tmp)) { log_error(LOG_LEVEL_FATAL, "Out of memory in add_cooky_expiry()"); @@ -4399,9 +4461,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)) {