As discussed previously, here are my updates as a patch against 2.0.49.
They serve to enable working with compressed data coming from a proxy
(or other backend) and processing content in the output filter chain.

-- 
Nick Kew

Nick's manifesto: http://www.htmlhelp.com/~nick/
--- mod_deflate.c.old   2004-04-15 23:35:38.000000000 +0100
+++ mod_deflate.c       2004-04-15 23:38:02.000000000 +0100
@@ -23,6 +23,12 @@
  *
  * Written by Ian Holsman
  *
+ * Modified by Nick Kew, April 2004
+ *
+ * FIX:        deflate html content based on a NOTE from html-parse filter.
+ * ADD:        inflate_out_filter to decompress content for output filters
+ *     in a proxy with compressed backend.  I don't understand the
+ *     zlib stuff, so it's modified "blind" from the input filter.
  */
 
 #include "httpd.h"
@@ -339,6 +345,11 @@
 
         /* if they don't have the line, then they can't play */
         accepts = apr_table_get(r->headers_in, "Accept-Encoding");
+
+       /* NRK: accept it if we removed Accept-Encoding earlier */
+        if (accepts == NULL) {
+               accepts = apr_table_get(r->notes, "Accept-Encoding");
+       }
         if (accepts == NULL) {
             ap_remove_output_filter(f);
             return ap_pass_brigade(f->next, bb);
@@ -834,10 +845,224 @@
     return APR_SUCCESS;
 }
 
+
+/* Filter to inflate for a content-transforming proxy.  */
+static apr_status_t inflate_out_filter(ap_filter_t *f,
+                                      apr_bucket_brigade *bb)
+{
+    int deflate_init = 1 ;
+    apr_bucket *bkt;
+    request_rec *r = f->r;
+    deflate_ctx *ctx = f->ctx;
+    int zRC;
+    apr_status_t rv;
+    deflate_filter_config *c;
+
+    c = ap_get_module_config(r->server->module_config, &deflate_module);
+
+    if (!ctx) {
+        int found = 0;
+        char *token, deflate_hdr[10];
+        const char *encoding;
+        apr_size_t len;
+
+        /* only work on main request/no subrequests */
+        if (r->main) {
+            ap_remove_output_filter(f);
+            return ap_pass_brigade(f->next, bb);
+        }
+
+        /* Let's see what our current Content-Encoding is.
+         * If gzip is present, don't gzip again.  (We could, but let's not.)
+         */
+        encoding = apr_table_get(r->headers_out, "Content-Encoding");
+        if (encoding) {
+            const char *tmp = encoding;
+
+            token = ap_get_token(r->pool, &tmp, 0);
+            while (token && token[0]) {
+                if (!strcasecmp(token, "gzip")) {
+                    found = 1;
+                    break;
+                }
+                /* Otherwise, skip token */
+                tmp++;
+                token = ap_get_token(r->pool, &tmp, 0);
+            }
+        }
+
+        if (found == 0) {
+            ap_remove_output_filter(f);
+            return ap_pass_brigade(f->next, bb);
+        }
+
+        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
+        ctx->proc_bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
+        ctx->buffer = apr_palloc(r->pool, c->bufferSize);
+
+
+        zRC = inflateInit2(&ctx->stream, c->windowSize);
+
+        if (zRC != Z_OK) {
+            f->ctx = NULL;
+            inflateEnd(&ctx->stream);
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                          "unable to init Zlib: "
+                          "inflateInit2 returned %d: URL %s",
+                          zRC, r->uri);
+            ap_remove_output_filter(f);
+            return ap_pass_brigade(f->next, bb);
+        }
+
+        /* initialize deflate output buffer */
+        ctx->stream.next_out = ctx->buffer;
+        ctx->stream.avail_out = c->bufferSize;
+
+       deflate_init = 0 ;
+    }
+
+
+        APR_BRIGADE_FOREACH(bkt, bb) {
+            const char *data;
+            apr_size_t len;
+
+            /* If we actually see the EOS, that means we screwed up! */
+            if (APR_BUCKET_IS_EOS(bkt)) {
+                inflateEnd(&ctx->stream);
+                return APR_EGENERAL;
+            }
+
+            if (APR_BUCKET_IS_FLUSH(bkt)) {
+                apr_bucket *tmp_heap;
+                zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
+                if (zRC != Z_OK) {
+                    inflateEnd(&ctx->stream);
+                    return APR_EGENERAL;
+                }
+
+                ctx->stream.next_out = ctx->buffer;
+                len = c->bufferSize - ctx->stream.avail_out;
+
+                ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
+                tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
+                                                 NULL, f->c->bucket_alloc);
+                APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
+                ctx->stream.avail_out = c->bufferSize;
+
+                /* Move everything to the returning brigade. */
+                APR_BUCKET_REMOVE(bkt);
+                break;
+            }
+
+            /* read */
+            apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
+
+       /* first bucket contains zlib header */
+           if ( ! deflate_init++ ) {
+             if ( len < 10 ) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Insufficient data for inflate") ;
+               return APR_EGENERAL ;
+             } else  {
+                if (   data[0] != deflate_magic[0] ||
+                       data[1] != deflate_magic[1]) {
+                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "deflate: bad header") ;
+                   return APR_EGENERAL ;
+               }
+               data += 10 ;
+               len -= 10 ;
+             }
+           }
+
+            /* pass through zlib inflate. */
+            ctx->stream.next_in = (unsigned char *)data;
+            ctx->stream.avail_in = len;
+
+            zRC = Z_OK;
+
+            while (ctx->stream.avail_in != 0) {
+                if (ctx->stream.avail_out == 0) {
+                    apr_bucket *tmp_heap;
+                    ctx->stream.next_out = ctx->buffer;
+                    len = c->bufferSize - ctx->stream.avail_out;
+
+                    ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
+                    tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
+                                                      NULL, f->c->bucket_alloc);
+                    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) {
+                    break;
+                }
+
+                if (zRC != Z_OK) {
+                    inflateEnd(&ctx->stream);
+                    return APR_EGENERAL;
+                }
+            }
+            if (zRC == Z_STREAM_END) {
+                apr_bucket *tmp_heap, *eos;
+
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                              "Zlib: Inflated %ld to %ld : URL %s",
+                              ctx->stream.total_in, ctx->stream.total_out,
+                              r->uri);
+
+                len = c->bufferSize - ctx->stream.avail_out;
+
+                ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
+                tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
+                                                  NULL, f->c->bucket_alloc);
+                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;
+                    }
+                    ctx->stream.next_in += 4;
+                    compLen = getLong(ctx->stream.next_in);
+                    if (ctx->stream.total_out != compLen) {
+                        inflateEnd(&ctx->stream);
+                        return APR_EGENERAL;
+                    }
+                }
+                else {
+                    /* FIXME: We need to grab the 8 verification bytes
+                     * from the wire! */
+                    inflateEnd(&ctx->stream);
+                    return APR_EGENERAL;
+                }
+
+                inflateEnd(&ctx->stream);
+
+                eos = apr_bucket_eos_create(f->c->bucket_alloc);
+                APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, eos); 
+                break;
+            }
+
+        }
+
+      rv = ap_pass_brigade(f->next, ctx->proc_bb) ;
+      apr_brigade_cleanup(ctx->proc_bb) ;
+      return rv ;
+}
+
 static void register_hooks(apr_pool_t *p)
 {
     ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,
                               AP_FTYPE_CONTENT_SET);
+    ap_register_output_filter("INFLATE", inflate_out_filter, NULL,
+                              AP_FTYPE_RESOURCE-1);
     ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL,
                               AP_FTYPE_CONTENT_SET);
 }

Reply via email to