--- mod_gzip.c-old Fri Jan 26 10:50:05 2001 +++ mod_gzip.c Fri Jan 26 15:08:26 2001 @@ -575,10 +575,15 @@ * The GZP request control structure... */ +#define GZIP_FORMAT (0) +#define DEFLATE_FORMAT (1) + typedef struct _GZP_CONTROL { int decompress; /* 0=Compress 1=Decompress */ + int compression_format; /* GZIP_FORMAT or DEFLATE_FORMAT */ + /* Input control... */ int input_ismem; /* Input source is memory buffer, not file */ @@ -2209,10 +2214,11 @@ mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn); #endif - if ( strstr( has_encoding, "gzip" ) ) + if ( strstr( has_encoding, "gzip" ) || + strstr( has_encoding, "deflate" ) ) { #ifdef MOD_GZIP_DEBUG1 - mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' designator...\n",cn); + mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn); mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif @@ -2237,7 +2243,7 @@ else /* 'gzip' designator not found... */ { #ifdef MOD_GZIP_DEBUG1 - mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' designator...\n",cn); + mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } @@ -2347,10 +2353,21 @@ if ( accept_encoding ) { /* ...and if it has the right 'gzip' indicator... */ - + /* We record the compression format in a request note, so we + * can get it again later, and so it can potentially be logged. + */ if ( strstr( accept_encoding, "gzip" ) ) { process = 1; /* ...set the 'process' flag TRUE */ + ap_table_setn( r->notes,"mod_gzip_compression_format", + ap_pstrdup(r->pool,"gzip")); + + } + else if ( strstr( accept_encoding, "deflate" ) ) + { + process = 1; /* ...set the 'process' flag TRUE */ + ap_table_setn( r->notes,"mod_gzip_compression_format", + ap_pstrdup(r->pool,"deflate")); } }/* End 'if( accept_encoding )' */ @@ -2388,7 +2405,7 @@ else /* 'gzip' designator was seen in 'Accept-Encoding:' field */ { #ifdef MOD_GZIP_DEBUG1 - mod_gzip_printf( "%s: 'gzip' capability specified by user-agent.\n",cn); + mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } @@ -4093,7 +4110,8 @@ char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */ - char actual_content_encoding_name[] = "gzip"; /* Adjustable */ + char *actual_content_encoding_name = "gzip"; /* Adjustable */ + const char *compression_format; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_encode_and_transmit()"; @@ -4470,6 +4488,18 @@ gzp->decompress = 0; /* Perform encoding */ + /* Recover the compression format we're supposed to use. */ + compression_format = ap_table_get(r->notes, "mod_gzip_compression_format"); + if (compression_format && strcmp(compression_format, "deflate") == 0) + { + actual_content_encoding_name = "deflate"; + gzp->compression_format = DEFLATE_FORMAT; + } + else + { + gzp->compression_format = GZIP_FORMAT; + } + if ( input_size <= (long) conf->maximum_inmem_size ) { /* The input source is small enough to compress directly */ @@ -4591,6 +4621,7 @@ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: gzp->decompress = %d\n" ,cn,gzp->decompress); + mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format); mod_gzip_printf( "%s: gzp->input_ismem = %d\n", cn,gzp->input_ismem); mod_gzip_printf( "%s: gzp->output_ismem = %d\n", cn,gzp->output_ismem); mod_gzip_printf( "%s: gzp->input_filename = [%s]\n",cn,gzp->input_filename); @@ -7256,6 +7287,8 @@ }; typedef struct _GZ1 { + long compression_format; + long versionid1; int state; int done; @@ -7345,6 +7378,7 @@ int dbits; ulg window_size; ulg crc; + ulg adler; uch dist_code[512]; uch length_code[MAX_MATCH-MIN_MATCH+1]; @@ -7449,6 +7483,15 @@ void error( char *msg ); +/* XXX - Precomputed zlib header. If you change the window size or + * compression level from the defaults, this will break badly. The + * algorithm to build this is fairly complex; you can find it in + * the file deflate.c from the zlib distribution. + */ +#define ZLIB_HEADER "\170œ" + +ulg adler32(ulg adler, uch *buf, unsigned len); + int zip( PGZ1 gz1, int in, @@ -9088,10 +9131,20 @@ if ( len == (unsigned)(-1) || len == 0 ) { gz1->crc = gz1->crc ^ 0xffffffffL; + /* XXX - Do we need to do something with Adler CRC's here? + * I don't think so--they don't seem to need postprocessing. */ return (int)len; } - updcrc( gz1, (uch*)buf, len ); + if (gz1->compression_format != DEFLATE_FORMAT) + { + updcrc( gz1, (uch*)buf, len ); + } + else + { + gz1->adler = adler32(gz1->adler, (uch*)buf, len); + } + gz1->bytes_in += (ulg)len; return (int)len; @@ -9288,6 +9341,7 @@ gz1->heap[k] = v; } + #define GZS_ZIP1 1 #define GZS_ZIP2 2 #define GZS_DEFLATE1 3 @@ -9317,6 +9371,7 @@ } gz1->decompress = gzp->decompress; + gz1->compression_format = gzp->compression_format; strcpy( gz1->ifname, gzp->input_filename ); strcpy( gz1->ofname, gzp->output_filename ); @@ -9489,6 +9544,7 @@ return( rc ); } + int gzs_zip1( PGZ1 gz1 ) { uch flags = 0; @@ -9499,21 +9555,40 @@ gz1->method = DEFLATED; - put_byte(GZIP_MAGIC[0]); - put_byte(GZIP_MAGIC[1]); - put_byte(DEFLATED); + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte(GZIP_MAGIC[0]); + put_byte(GZIP_MAGIC[1]); + put_byte(DEFLATED); + } + else + { + /* Yes, I know RFC 1951 doesn't mention any header at the start of + * a deflated document, but zlib absolutely requires one. And since nearly + * all "deflate" implementations use zlib, we need to play along with this + * brain damage. */ + put_byte(ZLIB_HEADER[0]); + put_byte(ZLIB_HEADER[1]); + } if ( gz1->save_orig_name ) { flags |= ORIG_NAME; } - put_byte(flags); - put_long(gz1->time_stamp); - - gz1->crc = -1; + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte(flags); + put_long(gz1->time_stamp); - updcrc( gz1, NULL, 0 ); + gz1->crc = -1; + updcrc( gz1, NULL, 0 ); + } + else + { + /* Deflate compression uses an Adler32 CRC, not a CRC32. */ + gz1->adler = 1L; + } gz1->state = GZS_ZIP2; @@ -9529,18 +9604,20 @@ bi_init( gz1, gz1->ofd ); ct_init( gz1, &attr, &gz1->method ); lm_init( gz1, gz1->level, &deflate_flags ); - put_byte((uch)deflate_flags); - - put_byte(OS_CODE); - if ( gz1->save_orig_name ) + if (gz1->compression_format != DEFLATE_FORMAT) { - char *p = gz1_basename( gz1, gz1->ifname ); + put_byte((uch)deflate_flags); + put_byte(OS_CODE); + if ( gz1->save_orig_name ) + { + char *p = gz1_basename( gz1, gz1->ifname ); - do { - put_char(*p); + do { + put_char(*p); - } while (*p++); + } while (*p++); + } } gz1->header_bytes = (long)gz1->outcnt; @@ -9674,10 +9751,25 @@ } #endif - put_long( gz1->crc ); - put_long( gz1->bytes_in ); - - gz1->header_bytes += 2*sizeof(long); + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_long( gz1->crc ); + put_long( gz1->bytes_in ); + gz1->header_bytes += 2*sizeof(long); + } + else + { + /* Append an Adler32 CRC to our deflated data. + * Yes, I know RFC 1951 doesn't mention any CRC at the end of a + * deflated document, but zlib absolutely requires one. And since nearly + * all "deflate" implementations use zlib, we need to play along with this + * brain damage. */ + put_byte( (gz1->adler >> 24) ); + put_byte( (gz1->adler >> 16) & 0xFF ); + put_byte( (gz1->adler >> 8) & 0xFF ); + put_byte( (gz1->adler ) & 0xFF ); + gz1->header_bytes += 4*sizeof(uch); + } flush_outbuf( gz1 ); @@ -9685,6 +9777,67 @@ return OK; } + + +/* ========================================================================= + adler32 -- compute the Adler-32 checksum of a data stream + Copyright (C) 1995-1998 Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Modified by Eric Kidd to play nicely with mod_gzip. + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +ulg adler32(ulg adler, uch *buf, unsigned len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + /* END OF FILE */