[PATCH] deflate support for gunzip module

Serge Sitnikov serge.sitnikov at gmail.com
Fri Feb 25 09:11:26 MSK 2011


Adds deflate decompression support for gunzip module:

--- ngx_http_gunzip_filter_module.c
+++ ngx_http_gunzip_filter_module.c	2011-02-24 09:07:08.000000000 +0100
@@ -30,6 +30,8 @@
     ngx_buf_t           *out_buf;
     ngx_int_t            bufs;

+    unsigned             deflate:1;
+
     unsigned             started:1;
     unsigned             flush:4;
     unsigned             redo:1;
@@ -122,42 +124,45 @@
 {
     ngx_http_gunzip_ctx_t   *ctx;
     ngx_http_gunzip_conf_t  *conf;
+    int deflate = 0, client_deflate = 0;

     conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module);

-    /* TODO support multiple content-codings */
+    /* TODO support even more encodings */
     /* TODO always gunzip - due to configuration or module request */
     /* TODO ignore content encoding? */

-    if (!conf->enable
-        || r->headers_out.content_encoding == NULL
-        || r->headers_out.content_encoding->value.len != 4
-        || ngx_strncasecmp(r->headers_out.content_encoding->value.data,
-                           (u_char *) "gzip", 4) != 0)
-    {
+    if (!conf->enable || r->headers_out.content_encoding == NULL) {
         return ngx_http_next_header_filter(r);
+    } else if (r->headers_out.content_encoding->value.len != 4 ||
+        ngx_strncasecmp(r->headers_out.content_encoding->value.data,
(u_char *) "gzip", 4) != 0)
+    {
+        deflate = r->headers_out.content_encoding->value.len == 7 &&
+            ngx_strncasecmp(r->headers_out.content_encoding->value.data,
(u_char *) "deflate", 7) == 0;
+
+        if (!deflate) return ngx_http_next_header_filter(r);
+        else client_deflate = r->headers_in.accept_encoding != NULL ?
+            ngx_strcasestrn(r->headers_in.accept_encoding->value.data,
"deflate", 7 - 1) != NULL : 0;
     }

 #if (nginx_version >= 8025 || (nginx_version >= 7065 && nginx_version < 8000))

     r->gzip_vary = 1;
+    int ok = r->gzip_tested ? r->gzip_ok : ngx_http_gzip_ok(r) == NGX_OK;

-    if (!r->gzip_tested) {
-        if (ngx_http_gzip_ok(r) == NGX_OK) {
-            return ngx_http_next_header_filter(r);
-        }
+#else

-    } else if (!r->gzip_ok) {
-        return ngx_http_next_header_filter(r);
-    }
+    int ok = ngx_http_gzip_ok(r) == NGX_OK;

-#else
+#endif

-    if (ngx_http_gzip_ok(r) == NGX_OK) {
-        return ngx_http_next_header_filter(r);
+    if (deflate) {
+        if (ok && client_deflate) return ngx_http_next_header_filter(r);
+    } else {
+        if (ok) return ngx_http_next_header_filter(r);
     }

-#endif
+    // --

     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gunzip_ctx_t));
     if (ctx == NULL) {
@@ -167,6 +172,7 @@
     ngx_http_set_ctx(r, ctx, ngx_http_gunzip_filter_module);

     ctx->request = r;
+    ctx->deflate = deflate;

     r->filter_need_in_memory = 1;

@@ -314,8 +320,8 @@
     ctx->zstream.zfree = ngx_http_gunzip_filter_free;
     ctx->zstream.opaque = ctx;

-    /* windowBits +16 to decode gzip, zlib 1.2.0.4+ */
-    rc = inflateInit2(&ctx->zstream, MAX_WBITS + 16);
+    /* windowBits +32 to auto decode gzip and deflate */
+    rc = inflateInit2(&ctx->zstream, MAX_WBITS + 32);

     if (rc != Z_OK) {
         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
@@ -328,6 +334,33 @@
     ctx->last_out = &ctx->out;
     ctx->flush = Z_NO_FLUSH;

+    // --
+
+    if (!ctx->deflate) return NGX_OK;
+
+    /* Header inflation should not produce any output, so all
+       these hacks below are valid. */
+
+    static unsigned char deflate_header[] = { 0x78, 0x9C };
+    unsigned char temp;
+
+    ctx->zstream.next_in = deflate_header;
+    ctx->zstream.avail_in = 2;
+    ctx->zstream.next_out = &temp;
+    ctx->zstream.avail_out = 1;
+
+    rc = inflate(&ctx->zstream, Z_NO_FLUSH);
+    if (rc != Z_OK) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+            "deflate: inflate() failed: %d, %d", ctx->flush, rc);
+        return NGX_ERROR;
+    }
+
+    ctx->zstream.next_in = Z_NULL;
+    ctx->zstream.avail_in = 0;
+    ctx->zstream.next_out = Z_NULL;
+    ctx->zstream.avail_out = 0;
+
     return NGX_OK;
 }

--
Sergei Sitnikov



More information about the nginx-devel mailing list