]> granicus.if.org Git - apache/blobdiff - modules/filters/mod_deflate.c
* Rather use a pool cleanup function than calling deflateEnd before every
[apache] / modules / filters / mod_deflate.c
index ecd4d1d16c15aae72e71d823efd5f3e5b9784739..a1b456bb81c60c0af0a51ccf852a3c369a3f19b0 100644 (file)
@@ -212,8 +212,55 @@ typedef struct deflate_ctx_t
     unsigned char *buffer;
     unsigned long crc;
     apr_bucket_brigade *bb, *proc_bb;
+    int (*libz_end_func)(z_streamp);
 } deflate_ctx;
 
+static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
+                             struct apr_bucket_alloc_t *bucket_alloc,
+                             int (*libz_func)(z_streamp, int), int flush)
+{
+    int zRC = Z_OK;
+    int done = 0;
+    unsigned int deflate_len;
+    apr_bucket *b;
+
+    for (;;) {
+         deflate_len = c->bufferSize - ctx->stream.avail_out;
+
+         if (deflate_len != 0) {
+             b = apr_bucket_heap_create((char *)ctx->buffer,
+                                        deflate_len, NULL,
+                                        bucket_alloc);
+             APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+             ctx->stream.next_out = ctx->buffer;
+             ctx->stream.avail_out = c->bufferSize;
+         }
+
+         if (done)
+             break;
+
+         zRC = libz_func(&ctx->stream, flush);
+
+         if (deflate_len == 0 && zRC == Z_BUF_ERROR)
+             zRC = Z_OK;
+
+         done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
+
+         if (zRC != Z_OK && zRC != Z_STREAM_END)
+             break;
+    }
+    return zRC;
+}
+
+static apr_status_t deflate_ctx_cleanup(void *data)
+{
+    deflate_ctx *ctx = (deflate_ctx *)data;
+
+    if (ctx)
+        ctx->libz_end_func(&ctx->stream);
+    return APR_SUCCESS;
+}
+
 static apr_status_t deflate_out_filter(ap_filter_t *f,
                                        apr_bucket_brigade *bb)
 {
@@ -226,7 +273,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
 
     /* Do nothing if asked to filter nothing. */
     if (APR_BRIGADE_EMPTY(bb)) {
-        return APR_SUCCESS;
+        return ap_pass_brigade(f->next, bb);
     }
 
     /* If we don't have a context, we need to ensure that it is okay to send
@@ -362,19 +409,31 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
         ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
         ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
         ctx->buffer = apr_palloc(r->pool, c->bufferSize);
+        ctx->libz_end_func = deflateEnd;
 
         zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
                            c->windowSize, c->memlevel,
                            Z_DEFAULT_STRATEGY);
 
         if (zRC != Z_OK) {
-            f->ctx = NULL;
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                           "unable to init Zlib: "
                           "deflateInit2 returned %d: URL %s",
                           zRC, r->uri);
+            /*
+             * Remove ourselves as it does not make sense to return:
+             * We are not able to init libz and pass data down the chain
+             * uncompressed.
+             */
+            ap_remove_output_filter(f);
             return ap_pass_brigade(f->next, bb);
         }
+        /*
+         * Register a cleanup function to ensure that we cleanup the internal
+         * libz resources.
+         */
+        apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
+                                  apr_pool_cleanup_null);
 
         /* add immortal gzip header */
         e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
@@ -400,43 +459,15 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
         const char *data;
         apr_bucket *b;
         apr_size_t len;
-        int done = 0;
 
         e = APR_BRIGADE_FIRST(bb);
 
         if (APR_BUCKET_IS_EOS(e)) {
             char *buf;
-            unsigned int deflate_len;
 
             ctx->stream.avail_in = 0; /* should be zero already anyway */
-            for (;;) {
-                deflate_len = c->bufferSize - ctx->stream.avail_out;
-
-                if (deflate_len != 0) {
-                    b = apr_bucket_heap_create((char *)ctx->buffer,
-                                               deflate_len, NULL,
-                                               f->c->bucket_alloc);
-                    APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
-                    ctx->stream.next_out = ctx->buffer;
-                    ctx->stream.avail_out = c->bufferSize;
-                }
-
-                if (done) {
-                    break;
-                }
-
-                zRC = deflate(&ctx->stream, Z_FINISH);
-
-                if (deflate_len == 0 && zRC == Z_BUF_ERROR) {
-                    zRC = Z_OK;
-                }
-
-                done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
-
-                if (zRC != Z_OK && zRC != Z_STREAM_END) {
-                    break;
-                }
-            }
+            /* flush the remaining data from the zlib buffers */
+            flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH);
 
             buf = apr_palloc(r->pool, 8);
             putLong((unsigned char *)&buf[0], ctx->crc);
@@ -476,6 +507,8 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
             }
 
             deflateEnd(&ctx->stream);
+            /* No need for cleanup any longer */
+            apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
 
             /* Remove EOS from the old list, and insert into the new. */
             APR_BUCKET_REMOVE(e);
@@ -488,28 +521,18 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
         }
 
         if (APR_BUCKET_IS_FLUSH(e)) {
-            apr_bucket *bkt;
             apr_status_t rv;
 
-            apr_bucket_delete(e);
-
-            if (ctx->stream.avail_in > 0) {
-                zRC = deflate(&(ctx->stream), Z_SYNC_FLUSH);
-                if (zRC != Z_OK) {
-                    return APR_EGENERAL;
-                }
+            /* flush the remaining data from the zlib buffers */
+            zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
+                                    Z_SYNC_FLUSH);
+            if (zRC != Z_OK) {
+                return APR_EGENERAL;
             }
 
-            ctx->stream.next_out = ctx->buffer;
-            len = c->bufferSize - ctx->stream.avail_out;
-
-            b = apr_bucket_heap_create((char *)ctx->buffer, len,
-                                       NULL, f->c->bucket_alloc);
-            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
-            ctx->stream.avail_out = c->bufferSize;
-
-            bkt = apr_bucket_flush_create(f->c->bucket_alloc);
-            APR_BRIGADE_INSERT_TAIL(ctx->bb, bkt);
+            /* Remove flush bucket from old brigade anf insert into the new. */
+            APR_BUCKET_REMOVE(e);
+            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
             rv = ap_pass_brigade(f->next, ctx->bb);
             if (rv != APR_SUCCESS) {
                 return rv;
@@ -549,8 +572,9 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
 
             zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
 
-            if (zRC != Z_OK)
+            if (zRC != Z_OK) {
                 return APR_EGENERAL;
+            }
         }
 
         apr_bucket_delete(e);
@@ -841,7 +865,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
 
     /* Do nothing if asked to filter nothing. */
     if (APR_BRIGADE_EMPTY(bb)) {
-        return APR_SUCCESS;
+        return ap_pass_brigade(f->next, bb);
     }
 
     c = ap_get_module_config(r->server->module_config, &deflate_module);