changeset 134:d57c6835225c

nginx-0.0.1-2003-09-26-09:45:21 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 26 Sep 2003 05:45:21 +0000
parents b27548f540ad
children e29909bd9b8a
files src/core/ngx_hunk.c src/core/ngx_hunk.h src/core/ngx_modules.c src/http/modules/ngx_http_gzip_filter.c src/os/unix/ngx_freebsd_config.h
diffstat 5 files changed, 250 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -99,6 +99,30 @@ ngx_hunk_t *ngx_create_hunk_after(ngx_po
 }
 
 
+int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **ch, ngx_chain_t *in)
+{
+    ngx_chain_t  *ce, **le;
+
+    le = ch;
+
+    for (ce = *ch; ce; ce = ce->next) {
+        le = &ce->next;
+    }
+
+    while (in) {
+        ngx_test_null(ce, ngx_alloc_chain_entry(pool), NGX_ERROR);
+
+        ce->hunk = in->hunk;
+        ce->next = NULL;
+        *le = ce;
+        le = &ce->next;
+        in = in->next;
+    }
+
+    return NGX_OK;
+}
+
+
 void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
                              ngx_chain_t **out)
 {
--- a/src/core/ngx_hunk.h
+++ b/src/core/ngx_hunk.h
@@ -86,5 +86,10 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_poo
                 chain->next = NULL;                                          \
             } while (0);
 
+int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **ch, ngx_chain_t *in);
+void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
+                             ngx_chain_t **out);
+
+
 
 #endif /* _NGX_HUNK_H_INCLUDED_ */
--- a/src/core/ngx_modules.c
+++ b/src/core/ngx_modules.c
@@ -33,6 +33,7 @@ extern ngx_module_t  ngx_http_output_fil
 extern ngx_module_t  ngx_http_header_filter_module;
 
 extern ngx_module_t  ngx_http_chunked_filter_module;
+extern ngx_module_t  ngx_http_gzip_filter_module;
 extern ngx_module_t  ngx_http_range_filter_module;
 extern ngx_module_t  ngx_http_charset_filter_module;
 
@@ -81,7 +82,7 @@ ngx_module_t *ngx_modules[] = {
     &ngx_http_header_filter_module,
 
     &ngx_http_chunked_filter_module,
-    /* &ngx_http_gzip_filter_module, */
+    &ngx_http_gzip_filter_module,
     &ngx_http_range_filter_module,
     /* &ngx_http_ssi_filter_module, */
     &ngx_http_charset_filter_module,
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -7,8 +7,9 @@
 
 
 typedef struct {
+    int  enable;
     int  hunk_size;
-    int  max_hunks;
+    int  hunks;
     int  no_buffer;
 } ngx_http_gzip_conf_t;
 
@@ -21,13 +22,56 @@ typedef struct {
     ngx_chain_t  **last_out;
     ngx_hunk_t    *in_hunk;
     ngx_hunk_t    *out_hunk;
+    int            hunks;
+
+    int            length;
     void          *alloc;
 
+    int            flush;
+    u_int          crc32;
     z_stream       zstream;
 } ngx_http_gzip_ctx_t;
 
 
+ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);
 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle);
+static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
+static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
+                                      void *parent, void *child);
+
+
+static ngx_command_t  ngx_http_gzip_filter_commands[] = {
+
+    {ngx_string("gzip"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+     ngx_conf_set_flag_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_gzip_conf_t, enable),
+     NULL},
+
+    {ngx_string("gzip_hunk_size"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_size_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_gzip_conf_t, hunk_size),
+     NULL},
+
+    {ngx_string("gzip_hunks"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_num_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_gzip_conf_t, hunks),
+     NULL},
+
+    {ngx_string("gzip_no_buffer"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+     ngx_conf_set_flag_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_gzip_conf_t, no_buffer),
+     NULL},
+
+    ngx_null_command
+};
 
 
 static ngx_http_module_t  ngx_http_gzip_filter_module_ctx = {
@@ -37,23 +81,39 @@ static ngx_http_module_t  ngx_http_gzip_
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
 
-    NULL,                                  /* create location configuration */
-    NULL,                                  /* merge location configuration */
+    ngx_http_gzip_create_conf,             /* create location configuration */
+    ngx_http_gzip_merge_conf,              /* merge location configuration */
 };
 
 
 ngx_module_t  ngx_http_gzip_filter_module = {
     NGX_MODULE,
     &ngx_http_gzip_filter_module_ctx,      /* module context */
-    NULL,                                  /* module directives */
+    ngx_http_gzip_filter_commands,         /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     ngx_http_gzip_filter_init,             /* init module */
     NULL                                   /* init child */
 };
 
 
-static const char gzheader[10] =
-                               { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
+static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
+
+#if (HAVE_LITTLE_ENDIAN)
+
+struct gztrailer {
+    u_int crc32;
+    u_int zlen;
+};
+
+#else /* HAVE_BIG_ENDIAN */
+
+struct gztrailer {
+    unsigned char crc32[4];
+    unsigned char zlen[4];
+};
+
+#endif
+
 
 
 static int (*next_header_filter) (ngx_http_request_t *r);
@@ -62,18 +122,35 @@ static int (*next_body_filter) (ngx_http
 
 static int ngx_http_gzip_header_filter(ngx_http_request_t *r)
 {
+    ngx_http_gzip_ctx_t   *ctx;
+    ngx_http_gzip_conf_t  *conf;
+
     if (r->headers_out.status != NGX_HTTP_OK
-        || (ngx_strncasecmp(r->headers_out.content_type->value.data,
+        || r->header_only
+        /* || r->content_encoding */
+        /* || r->accept_encoding == NULL */
+        || r->main)
+    {
+        return next_header_filter(r);
+    }
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
+
+    if (!conf->enable
+        /* TODO: conf->version */
+        /* TODO: "text/" -> custom types */
+        || ngx_strncasecmp(r->headers_out.content_type->value.data,
                             "text/", 5) != 0)
     {
         return next_header_filter(r);
     }
 
     ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module,
-                        sizeof(ngx_http_gzip_filter_ctx_t), NGX_ERROR);
+                        sizeof(ngx_http_gzip_ctx_t), NGX_ERROR);
 
     ctx->length = r->headers_out.content_length;
     r->headers_out.content_length = -1;
+    r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY;
 
     return next_header_filter(r);
 }
@@ -81,13 +158,17 @@ static int ngx_http_gzip_header_filter(n
 
 static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
+    int                    rc, zin, zout;
+    struct gztrailer      *trailer;
+    ngx_hunk_t            *h;
+    ngx_chain_t           *ce;
     ngx_http_gzip_ctx_t   *ctx;
     ngx_http_gzip_conf_t  *conf;
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
 
     if (ctx == NULL) {
-        next_body_filter(r, in);
+        return next_body_filter(r, in);
     }
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
@@ -96,14 +177,14 @@ static int ngx_http_gzip_body_filter(ngx
 #if 0
         ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR);
 #else
-        ctx->alloc = ~NULL;
+        ctx->alloc = (void *) ~NULL;
 #endif
         rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED,
                           /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1,
                           Z_DEFAULT_STRATEGY);
 
         if (rc != Z_OK) {
-            ngx_log_error(NGX_LOG_ALERT, r->log, 0,
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                           "deflateInit2() failed: %d", rc);
             return ngx_http_gzip_error(ctx);
         }
@@ -126,100 +207,153 @@ static int ngx_http_gzip_body_filter(ngx
     }
 
     if (in) {
-        add_to_chain(ctx->in, in)
+        if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
+            return ngx_http_gzip_error(ctx);
+        }
     }
 
-    for ( ;; ) {
-
+    while (ctx->in || ctx->out
+           || ctx->zstream.avail_in || ctx->zstream.avail_out
+           || ctx->flush != Z_NO_FLUSH)
+    {
         for ( ;; ) {
 
-            if (ctx->flush == Z_NO_FLUSH
-                && ctx->zstream->avail_in == 0
-                && ctx->in)
-             {
+            if (ctx->in
+                && ctx->zstream.avail_in == 0
+                && ctx->flush == Z_NO_FLUSH)
+            {
                 ctx->in_hunk = ctx->in->hunk;
                 ctx->in = ctx->in->next;
 
-                ctx->zstream->next_in = ctx->in_hunk->pos;
-                ctx->zstream->avail_in = ctx->in_hunk->last - ctx->in_hunk->pos;
+                ctx->zstream.avail_in = ctx->in_hunk->last - ctx->in_hunk->pos;
+
+                if (ctx->zstream.avail_in == 0) {
+                    continue;
+                }
+
+                ctx->zstream.next_in = ctx->in_hunk->pos;
+
+                ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
+                                   ctx->zstream.avail_in);
 
                 if (ctx->in_hunk->type & NGX_HUNK_LAST) {
                     ctx->flush = Z_FINISH;
 
                 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) {
-                    ctx->flush = Z_SYNC_FINISH;
+                    ctx->flush = Z_SYNC_FLUSH;
                 }
             }
 
-            if (ctx->zstream->avail_out == 0) {
+            if (ctx->zstream.avail_out == 0) {
                 if (ctx->free) {
                     ctx->out_hunk = ctx->free->hunk;
                     ctx->free = ctx->free->next;
 
-                } else if (ctx->max_hunks < ctx->cur_hunks) {
+                } else if (ctx->hunks < conf->hunks) {
                     ngx_test_null(ctx->out_hunk,
-                                  ngx_create_temp_hunk(r->pool, conf->size,
+                                  ngx_create_temp_hunk(r->pool, conf->hunk_size,
                                                        0, 0),
                                   ngx_http_gzip_error(ctx));
-                    ctx->cur_hunks++;
+                    ctx->hunks++;
 
                 } else {
                      break;
                 }
 
-                ctx->zstream->next_out = ctx->out_hunk->pos;
-                ctx->zstream->avail_out = conf->size;
+                ctx->zstream.next_out = ctx->out_hunk->pos;
+                ctx->zstream.avail_out = conf->hunk_size;
             }
 
-            rc = deflate(ctx->zstream, ctx->flush);
+            rc = deflate(&ctx->zstream, ctx->flush);
             if (rc != Z_OK && rc != Z_STREAM_END) {
-                ngx_log_error(NGX_LOG_ALERT, r->log, 0,
+                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                               "deflate() failed: %d, %d", ctx->flush, rc);
                 return ngx_http_gzip_error(ctx);
             }
 
-            ctx->in_hunk->pos = ctx->zstream->next_in;
+ngx_log_debug(r->connection->log, "deflate(): %d %d" _ ctx->flush _ rc);
+
+            ctx->in_hunk->pos = ctx->zstream.next_in;
 
-            if (rc == Z_STREAM_END) {
-                deflateEnd(ctx->zstream);
-                ngx_free();
-            }
-
-            if (ctx->zstream->avail_out == 0) {
-                ctx->out_hunk->last += conf->size;
-                ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk,
-                                      r->pool, ngx_http_gzip_error(ctx));
+            if (ctx->zstream.avail_out == 0) {
+                ctx->out_hunk->last += conf->hunk_size;
+                ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
+                                      ngx_http_gzip_error(ctx));
+                *ctx->last_out = ce;
+                ctx->last_out = &ce->next;
 
             } else {
-                ctx->out_hunk->last = ctx->zstream->next_out;
+                ctx->out_hunk->last = ctx->zstream.next_out;
 
                 if (ctx->flush == Z_SYNC_FLUSH) {
                     ctx->out_hunk->type |= NGX_HUNK_FLUSH;
-                    ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk,
-                                          r->pool, ngx_http_gzip_error(ctx));
                     ctx->flush = Z_NO_FLUSH;
+
+                    ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
+                                          ngx_http_gzip_error(ctx));
+                    *ctx->last_out = ce;
+                    ctx->last_out = &ce->next;
+
                     break;
 
                 } else if (ctx->flush == Z_FINISH) {
-                    ctx->out_hunk->type |= NGX_HUNK_LAST;
-                    ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk,
-                                          r->pool, ngx_http_gzip_error(ctx));
+                    /* rc == Z_STREAM_END */
+
+                    zin = ctx->zstream.total_in;
+                    zout = 10 + ctx->zstream.total_out + 8;
+
+                    ctx->flush = Z_NO_FLUSH;
+
+                    ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
+                                          ngx_http_gzip_error(ctx));
+                    *ctx->last_out = ce;
+                    ctx->last_out = &ce->next;
+
+                    if (ctx->zstream.avail_out >= 8) {
+                        trailer = (struct gztrailer *) &ctx->zstream.avail_in;
+                        ctx->out_hunk->type |= NGX_HUNK_LAST;
+                        ctx->out_hunk->last += 8;
+
+                    } else {
+                        /* STUB */ trailer = NULL;
+                    }
+
+#if (HAVE_LITTLE_ENDIAN)
+                    trailer->crc32 = ctx->crc32;
+                    trailer->zlen = zin;
+#else
+                    /* STUB */
+#endif
+
+                    deflateEnd(&ctx->zstream);
+#if 0
+                    ngx_free();
+                    set ctx = NULL;
+#endif
                     break;
 
                 } else if (conf->no_buffer && ctx->in == NULL) {
-                    ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk,
-                                          r->pool, ngx_http_gzip_error(ctx));
+                    ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
+                                          ngx_http_gzip_error(ctx));
+                    *ctx->last_out = ce;
+                    ctx->last_out = &ce->next;
+
                     break;
                 }
             }
         }
 
-        if (next_body_filter(r, ctx->out) == NGX_ERROR) {
+        rc = next_body_filter(r, ctx->out);
+        if (rc == NGX_ERROR) {
             return ngx_http_gzip_error(ctx);
         }
 
         ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out);
+        ctx->last_out = &ctx->out;
     }
+
+    /* STUB */
+    return next_body_filter(r, NULL);
 }
 
 
@@ -243,3 +377,36 @@ static int ngx_http_gzip_filter_init(ngx
 
     return NGX_OK;
 }
+
+
+static void *ngx_http_gzip_create_conf(ngx_conf_t *cf)
+{
+    ngx_http_gzip_conf_t  *conf;
+
+    ngx_test_null(conf,
+                  ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)),
+                  NGX_CONF_ERROR);
+
+    conf->enable = NGX_CONF_UNSET;
+    conf->hunk_size = NGX_CONF_UNSET;
+    conf->hunks = NGX_CONF_UNSET;
+    conf->no_buffer = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+
+static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
+                                      void *parent, void *child)
+{
+    ngx_http_gzip_conf_t *prev = parent;
+    ngx_http_gzip_conf_t *conf = child;
+
+    ngx_conf_merge_value(conf->enable, prev->enable, 0);
+    ngx_conf_merge_size_value(conf->hunk_size, prev->hunk_size,
+                              /* STUB: PAGE_SIZE */ 4096);
+    ngx_conf_merge_value(conf->hunks, prev->hunks, 4);
+    ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
+
+    return NGX_CONF_OK;
+}
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -130,4 +130,8 @@
 #endif
 
 
+/* STUB */
+#define HAVE_LITTLE_ENDIAN  1
+
+
 #endif /* _NGX_FREEBSD_CONFIG_H_INCLUDED_ */