--- mod_deflate.c	2007-10-12 17:36:54.000000000 -0400
+++ mod_deflate_bbw.c	2007-10-12 17:37:59.000000000 -0400
@@ -283,6 +283,13 @@
 
     return NULL;
 }
+/*bbw- This indicates what stage of inflation we are currently on. */
+typedef enum deflate_ctx_inflatestate_enum_t
+{
+        READING_GZIP_CONTENT,
+        READING_GZIP_FOOTER,
+        DONE_INFLATING  
+}deflate_ctx_inflatestate_enum;
 
 typedef struct deflate_ctx_t
 {
@@ -294,8 +301,14 @@
     unsigned char *validation_buffer;
     apr_size_t validation_buffer_length;
     int inflate_init;
+    unsigned char    gzipFooter[8]; 
+    int              numGzipFooterBytesRead;
+    deflate_ctx_inflatestate_enum              inflateState;
 } deflate_ctx;
 
+
+
+
 /* Number of validation bytes (CRC and length) after the compressed data */
 #define VALIDATION_SIZE 8
 /* Do not update ctx->crc, see comment in flush_libz_buffer */
@@ -836,7 +849,7 @@
         /* initialize deflate output buffer */
         ctx->stream.next_out = ctx->buffer;
         ctx->stream.avail_out = c->bufferSize;
-
+        ctx->inflateState=READING_GZIP_CONTENT;
         apr_brigade_cleanup(ctx->bb);
     }
 
@@ -853,9 +866,8 @@
              bkt != APR_BRIGADE_SENTINEL(ctx->bb);
              bkt = APR_BUCKET_NEXT(bkt))
         {
-            const char *data;
-            apr_size_t len;
-
+            /*bbw- Manages whether we have already read the content from this bucket or not. */
+            int alreadyReadBucket = 0;
             /* If we actually see the EOS, that means we screwed up! */
             if (APR_BUCKET_IS_EOS(bkt)) {
                 inflateEnd(&ctx->stream);
@@ -863,6 +875,7 @@
             }
 
             if (APR_BUCKET_IS_FLUSH(bkt)) {
+                apr_size_t len;                          
                 apr_bucket *tmp_heap;
                 zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
                 if (zRC != Z_OK) {
@@ -885,10 +898,15 @@
                 break;
             }
 
+            /* pass through zlib inflate. */            
+            /*bbw- Only enter this if we are still inflating the data and not just validating. */
+            if(ctx->inflateState==READING_GZIP_CONTENT)
+            {            
+                const char *data;
+                apr_size_t len;
             /* read */
             apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
-
-            /* pass through zlib inflate. */
+                alreadyReadBucket = 1;
             ctx->stream.next_in = (unsigned char *)data;
             ctx->stream.avail_in = len;
 
@@ -906,7 +924,6 @@
                     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
                     ctx->stream.avail_out = c->bufferSize;
                 }
-
                 zRC = inflate(&ctx->stream, Z_NO_FLUSH);
 
                 if (zRC == Z_STREAM_END) {
@@ -919,7 +936,7 @@
                 }
             }
             if (zRC == Z_STREAM_END) {
-                apr_bucket *tmp_heap, *eos;
+                    apr_bucket *tmp_heap;
 
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                               "Zlib: Inflated %ld to %ld : URL %s",
@@ -934,35 +951,103 @@
                 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
                 ctx->stream.avail_out = c->bufferSize;
 
-                /* Is the remaining 8 bytes already in the avail stream? */
-                if (ctx->stream.avail_in >= 8) {
-                    unsigned long compCRC, compLen;
-                    compCRC = getLong(ctx->stream.next_in);
-                    if (ctx->crc != compCRC) {
-                        inflateEnd(&ctx->stream);
-                        return APR_EGENERAL;
+                    /*bbw- set the state to reading gzip footer, so we can resume there later. */
+                    ctx->inflateState =READING_GZIP_FOOTER;                    
                     }
-                    ctx->stream.next_in += 4;
-                    compLen = getLong(ctx->stream.next_in);
-                    if (ctx->stream.total_out != compLen) {
+            }
+            /*bbw- Enter this area of code to start/resume reading gzip footer. */
+            if(ctx->inflateState==READING_GZIP_FOOTER)
+            {
+                apr_size_t len=0;
+                const char* input;
+                const char *data;
+                int inputLength = 0;
+                int maxLen;
+                maxLen = VALIDATION_SIZE-ctx->numGzipFooterBytesRead;
+                len = VALIDATION_SIZE-ctx->numGzipFooterBytesRead;
+                /*
+                 *  bbw- Validation bytes could be located in our avail_in stream.
+                 *       This is the case if there are bytes left over after inflating.
+                 *       Otherwise, we need to get them from the next bucket. If 
+                 *       we already used a bucked for inflating and there are no 
+                 *       more bytes available use the next bucket because this bucket
+                 *       has already already been used.
+                 */
+                if(ctx->stream.avail_in==0)
+                {
+                    if (alreadyReadBucket)
+                    {
+                         len = 0;
+                    }
+                    else
+                    {
+                       /* read */
+                       apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
+                       alreadyReadBucket = 1;
+                       input = data;
+                       inputLength = len;                       
+                       if (len > maxLen)
+                       {
+                         len = maxLen;
+                       }
+                    }                    
+                }
+                else
+                {
+                    if(len > ctx->stream.avail_in)
+                    {
+                         len = ctx->stream.avail_in;             
+                    }          
+                    input = (char*)ctx->stream.next_in;
+                    inputLength =  ctx->stream.avail_in;
+                    ctx->stream.next_in  += len;
+                    ctx->stream.avail_in -= len;
+                    if (len > maxLen)
+                    {
+                       len = maxLen;
+                    }
+                }                
+                /*bbw- We have bytes to read for the gzip footer. */
+                if(len>0)
+                {                         
+                    memcpy(ctx->gzipFooter+ctx->numGzipFooterBytesRead, input, sizeof(char)*len);      
+                    ctx->numGzipFooterBytesRead+=len;                    
+
+                    /* bbw- Finished reading now process the gzip footer.  */
+                    if(ctx->numGzipFooterBytesRead == VALIDATION_SIZE)
+                    {                                                 
+                        unsigned long compCRC, compLen;
+                        apr_bucket  *eos;
+                        /* do we need to read in more data ?*/
+                        compCRC = getLong(ctx->gzipFooter);
+                        compLen = getLong(ctx->gzipFooter+4);
+                        if (ctx->crc != compCRC) 
+                        {                                 
                         inflateEnd(&ctx->stream);
+                            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,"deflate_in_filter: CRC error %08x != %08x ", (int)ctx->crc , (int)compCRC );
+                            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,"deflate_in_filter: total_out %d compLen   %d", (int)ctx->stream.total_out , (int)compLen);
+                            ctx->inflateState=DONE_INFLATING;   
                         return APR_EGENERAL;
                     }
-                }
-                else {
-                    /* FIXME: We need to grab the 8 verification bytes
-                     * from the wire! */
+                        if (ctx->stream.total_out != compLen) 
+                        {  
                     inflateEnd(&ctx->stream);
+                            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,"deflate_in_filter: total_out != compLen %d != %d", (int)ctx->stream.total_out ,(int) compLen);                          
+                            ctx->inflateState=DONE_INFLATING;   
                     return APR_EGENERAL;
                 }
-
                 inflateEnd(&ctx->stream);
-
                 eos = apr_bucket_eos_create(f->c->bucket_alloc);
                 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, eos);
+                        ctx->inflateState=DONE_INFLATING;                        
+                    }
+                }
+            }             
+            /* Indicates that our inflation is done. Probably shouldn't ever happen after the first time.*/
+            if(ctx->inflateState==DONE_INFLATING)
+            {                 
                 break;
             }
-
         }
         apr_brigade_cleanup(ctx->bb);
     }
