From: Fabian Keil Date: Thu, 23 Jun 2011 14:01:01 +0000 (+0000) Subject: Add support for (re-)compression of buffered content and CGI responses. X-Git-Tag: v_3_0_18~213 X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=commitdiff_plain;h=291f91036dabb40b2323a118dd34c368ae2c6848;ds=sidebyside Add support for (re-)compression of buffered content and CGI responses. For now it has to be explicitly enabled with the configure option --enable-compression. --- diff --git a/cgi.c b/cgi.c index 024a6e41..0583f88a 100644 --- a/cgi.c +++ b/cgi.c @@ -1,4 +1,4 @@ -const char cgi_rcs[] = "$Id: cgi.c,v 1.129 2010/05/24 11:38:22 fabiankeil Exp $"; +const char cgi_rcs[] = "$Id: cgi.c,v 1.130 2011/04/19 13:00:47 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgi.c,v $ @@ -49,6 +49,10 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.129 2010/05/24 11:38:22 fabiankeil Exp $" #include #include +#ifdef FEATURE_COMPRESSION +#include +#endif + #include "project.h" #include "cgi.h" #include "list.h" @@ -1479,6 +1483,59 @@ static void get_locale_time(char *buf, size_t buffer_size) } + +#ifdef FEATURE_COMPRESSION +/********************************************************************* + * + * Function : compress_buffer + * + * Description : Compresses the content of a buffer with zlib's deflate + * Allocates a new buffer for the result, free'ing it is + * up to the caller. + * + * XXX: We should add a config option for the + * compression level. + * + * + * Parameters : + * 1 : buffer = buffer whose content should be compressed + * 2 : buffer_length = length of the buffer + * + * Returns : NULL on error, otherwise a pointer to the compressed + * content of the input buffer. + * + *********************************************************************/ +char *compress_buffer(char *buffer, size_t *buffer_length) +{ + char *compressed_buffer; + size_t new_length = *buffer_length; + + compressed_buffer = malloc(new_length); + if (NULL == compressed_buffer) + { + log_error(LOG_LEVEL_FATAL, + "Out of memory allocation compression buffer."); + } + + if (Z_OK != compress2((Bytef *)compressed_buffer, &new_length, + (Bytef *)buffer, *buffer_length, Z_DEFAULT_COMPRESSION)) + { + log_error(LOG_LEVEL_ERROR, "Error in compress2()"); + freez(compressed_buffer); + return NULL; + } + + log_error(LOG_LEVEL_RE_FILTER, + "Compressed content from %d to %d bytes.", *buffer_length, new_length); + + *buffer_length = new_length; + + return compressed_buffer; + +} +#endif + + /********************************************************************* * * Function : finish_http_response @@ -1524,6 +1581,23 @@ struct http_response *finish_http_response(const struct client_state *csp, struc { rsp->content_length = rsp->body ? strlen(rsp->body) : 0; } + +#ifdef FEATURE_COMPRESSION + if (!err && (csp->flags & CSP_FLAG_CLIENT_SUPPORTS_DEFLATE) + && (rsp->content_length > LOWER_LENGTH_LIMIT_FOR_COMRPESSION)) + { + char *compressed_content; + + compressed_content = compress_buffer(rsp->body, &rsp->content_length); + if (NULL != compressed_content) + { + freez(rsp->body); + rsp->body = compressed_content; + } + err = enlist_unique_header(rsp->headers, "Content-Encoding", "deflate"); + } +#endif + if (!err) { snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length); diff --git a/cgi.h b/cgi.h index 19893863..4cd21fcf 100644 --- a/cgi.h +++ b/cgi.h @@ -1,6 +1,6 @@ #ifndef CGI_H_INCLUDED #define CGI_H_INCLUDED -#define CGI_H_VERSION "$Id: cgi.h,v 1.36 2009/05/16 13:27:20 fabiankeil Exp $" +#define CGI_H_VERSION "$Id: cgi.h,v 1.37 2009/06/11 11:44:25 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgi.h,v $ @@ -101,6 +101,9 @@ extern jb_err get_string_param(const struct map *parameters, const char **pparam); extern char get_char_param(const struct map *parameters, const char *param_name); +#ifdef FEATURE_COMPRESSION +extern char *compress_buffer(char *buffer, size_t *buffer_length); +#endif /* * Text generators diff --git a/configure.in b/configure.in index b55b8eca..583ede89 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. dnl -dnl $Id: configure.in,v 1.156 2011/05/27 11:37:45 fabiankeil Exp $ +dnl $Id: configure.in,v 1.157 2011/05/27 11:37:57 fabiankeil Exp $ dnl dnl Written by and Copyright (C) 2001-2010 the dnl Privoxy team. http://www.privoxy.org/ @@ -32,7 +32,7 @@ dnl ================================================================= dnl AutoConf Initialization dnl ================================================================= -AC_REVISION($Revision: 1.156 $) +AC_REVISION($Revision: 1.157 $) AC_INIT(jcc.c) if test ! -f config.h.in; then @@ -935,6 +935,19 @@ if test $enableval2 = yes; then fi fi +AC_ARG_ENABLE(compression, +[ --enable-compression Allow Privoxy to compress buffered content if the client supports it. Requires zlib support.], +[enableval2=$enableval], +[enableval2=no]) +if test $enableval2 = yes; then + if test $have_zlib = "yes"; then + echo Enabling compression support. + AC_DEFINE(FEATURE_COMPRESSION,1,[Define to 1 to use compression through the zlib library.]) + else + AC_MSG_WARN([No zlib found. Privoxy will not be able to (re-)compressed buffered content.]) + fi +fi + # If we have libpcre and either we also have pcreposix or # we don't need pcreposix, then link pcre dynamically; else diff --git a/jcc.c b/jcc.c index f8f281f9..56e07d8c 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.351 2011/05/03 10:15:54 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.352 2011/05/27 11:34:39 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -2061,6 +2061,19 @@ static void chat(struct client_state *csp) { csp->content_length = (size_t)(csp->iob->eod - csp->iob->cur); } +#ifdef FEATURE_COMPRESSION + else if ((csp->flags & CSP_FLAG_CLIENT_SUPPORTS_DEFLATE) + && (csp->content_length > LOWER_LENGTH_LIMIT_FOR_COMRPESSION)) + { + char *compressed_content = compress_buffer(p, (size_t *)&csp->content_length); + if (compressed_content != NULL) + { + freez(p); + p = compressed_content; + csp->flags |= CSP_FLAG_BUFFERED_CONTENT_DEFLATED; + } + } +#endif if (JB_ERR_OK != update_server_headers(csp)) { diff --git a/parsers.c b/parsers.c index 11845600..a9730786 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.222 2011/04/19 13:00:47 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.223 2011/06/23 13:57:47 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -1187,6 +1187,18 @@ jb_err update_server_headers(struct client_state *csp) } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +#ifdef FEATURE_COMPRESSION + if ((JB_ERR_OK == err) + && (csp->flags & CSP_FLAG_BUFFERED_CONTENT_DEFLATED)) + { + err = enlist_unique_header(csp->headers, "Content-Encoding", "deflate"); + if (JB_ERR_OK == err) + { + log_error(LOG_LEVEL_HEADER, "Added header: Content-Encoding: deflate"); + } + } +#endif + return err; } @@ -2607,6 +2619,12 @@ static jb_err server_last_modified(struct client_state *csp, char **header) *********************************************************************/ static jb_err client_accept_encoding(struct client_state *csp, char **header) { +#ifdef FEATURE_COMPRESSION + if (strstr(*header, "deflate")) + { + csp->flags |= CSP_FLAG_CLIENT_SUPPORTS_DEFLATE; + } +#endif if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) { log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content"); diff --git a/project.h b/project.h index 8b0e68cd..dd38cf88 100644 --- a/project.h +++ b/project.h @@ -1,7 +1,7 @@ #ifndef PROJECT_H_INCLUDED #define PROJECT_H_INCLUDED /** Version string. */ -#define PROJECT_H_VERSION "$Id: project.h,v 1.163 2011/02/19 13:58:48 fabiankeil Exp $" +#define PROJECT_H_VERSION "$Id: project.h,v 1.164 2011/04/19 13:00:47 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/project.h,v $ @@ -187,6 +187,12 @@ typedef int jb_err; */ #define CGI_PARAM_LEN_MAX 500U +/** + * Minimum length which a buffer has to reach before + * Privoxy bothers to (re-)compress it. Completely arbitrary. + */ +#define LOWER_LENGTH_LIMIT_FOR_COMRPESSION 1024U + /** * Buffer size for capturing struct hostent data in the * gethostby(name|addr)_r library calls. Since we don't @@ -810,6 +816,17 @@ struct reusable_connection */ #define CSP_FLAG_REUSED_CLIENT_CONNECTION 0x00100000U +/** + * Flag for csp->flags: Set if the supports deflate compression. + */ +#define CSP_FLAG_CLIENT_SUPPORTS_DEFLATE 0x00200000U + +/** + * Flag for csp->flags: Set if the content has been deflated by Privoxy + */ +#define CSP_FLAG_BUFFERED_CONTENT_DEFLATED 0x00400000U + + /* * Flags for use in return codes of child processes */