changeset 156:afc333135a6b

nginx-0.0.1-2003-10-23-10:13:16 import
author Igor Sysoev <igor@sysoev.ru>
date Thu, 23 Oct 2003 06:13:16 +0000
parents 46eb23d9471d
children 70b36c805682
files src/core/ngx_alloc.c src/core/ngx_alloc.h src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_file.c src/http/modules/ngx_http_gzip_filter.c src/http/modules/proxy/ngx_http_proxy_handler.c src/os/win32/ngx_types.h
diffstat 8 files changed, 368 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_alloc.c
+++ b/src/core/ngx_alloc.c
@@ -20,6 +20,7 @@ void *ngx_alloc(size_t size, ngx_log_t *
     return p;
 }
 
+
 void *ngx_calloc(size_t size, ngx_log_t *log)
 {
     void *p;
@@ -32,6 +33,7 @@ void *ngx_calloc(size_t size, ngx_log_t 
     return p;
 }
 
+
 ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log)
 {
     ngx_pool_t *p;
@@ -47,6 +49,7 @@ ngx_pool_t *ngx_create_pool(size_t size,
     return p;
 }
 
+
 void ngx_destroy_pool(ngx_pool_t *pool)
 {
     ngx_pool_t        *p, *n;
@@ -56,7 +59,9 @@ void ngx_destroy_pool(ngx_pool_t *pool)
 #if (NGX_DEBUG_ALLOC)
         ngx_log_debug(pool->log, "free: %08x" _ l->alloc);
 #endif
-        free(l->alloc);
+        if (l->alloc) {
+            free(l->alloc);
+        }
     }
 
     /*
@@ -85,6 +90,7 @@ void ngx_destroy_pool(ngx_pool_t *pool)
     pool = NULL;
 }
 
+
 void *ngx_palloc(ngx_pool_t *pool, size_t size)
 {
     char              *m;
@@ -107,53 +113,71 @@ void *ngx_palloc(ngx_pool_t *pool, size_
             }
         }
 
-        /* alloc new pool block */
+        /* alloc a new pool block */
+
         ngx_test_null(n, ngx_create_pool(p->end - (char *) p, p->log), NULL);
         p->next = n;
         m = n->last;
         n->last += size;
+
         return m;
+    }
 
-    /* alloc large block */
-    } else {
-        large = NULL;
-        last = NULL;
+    /* alloc a large block */
+
+    large = NULL;
+    last = NULL;
 
-        if (pool->large) {
-            for (last = pool->large; /* void */; last = last->next) {
-                if (last->alloc == NULL) {
-                    large = last;
-                    last = NULL;
-                    break;
-                }
+    if (pool->large) {
+        for (last = pool->large; /* void */; last = last->next) {
+            if (last->alloc == NULL) {
+                large = last;
+                last = NULL;
+                break;
+            }
 
-                if (last->next == NULL) {
-                    break;
-                }
+            if (last->next == NULL) {
+                break;
             }
         }
+    }
 
-        if (large == NULL) {
-            ngx_test_null(large, ngx_palloc(pool, sizeof(ngx_pool_large_t)),
-                          NULL);
-            large->next = NULL;
-        }
+    if (large == NULL) {
+        ngx_test_null(large, ngx_palloc(pool, sizeof(ngx_pool_large_t)), NULL);
+        large->next = NULL;
+    }
+
+    ngx_test_null(p, ngx_alloc(size, pool->log), NULL);
 
-        ngx_test_null(p, ngx_alloc(size, pool->log), NULL);
+    if (pool->large == NULL) {
+        pool->large = large;
+
+    } else if (last) {
+        last->next = large;
+    }
 
-        if (pool->large == NULL) {
-            pool->large = large;
+    large->alloc = p;
+
+    return p;
+}
+
 
-        } else if (last) {
-            last->next = large;
-        }
+void ngx_pfree(ngx_pool_t *pool, void *p)
+{
+    ngx_pool_large_t  *l;
 
-        large->alloc = p;
-
-        return p;
+    for (l = pool->large; l; l = l->next) {
+        if (p == l->alloc) {
+#if (NGX_DEBUG_ALLOC)
+            ngx_log_debug(pool->log, "free: %08x" _ l->alloc);
+#endif
+            free(l->alloc);
+            l->alloc = NULL;
+        }
     }
 }
 
+
 void *ngx_pcalloc(ngx_pool_t *pool, size_t size)
 {
     void *p;
--- a/src/core/ngx_alloc.h
+++ b/src/core/ngx_alloc.h
@@ -6,9 +6,10 @@
 #include <ngx_core.h>
 
 
-/* NGX_MAX_ALLOC_FROM_POOL should be (PAGE_SIZE - 1), i.e. 4095 on x86.
-   On FreeBSD 5.x it allows to use zero copy send.
-   On Windows NT it decreases number of locked pages in kernel.
+/*
+ * NGX_MAX_ALLOC_FROM_POOL should be (PAGE_SIZE - 1), i.e. 4095 on x86.
+ * On FreeBSD 5.x it allows to use zero copy send.
+ * On Windows NT it decreases number of locked pages in kernel.
  */
 #define NGX_MAX_ALLOC_FROM_POOL 4095
 
@@ -44,6 +45,8 @@ void ngx_destroy_pool(ngx_pool_t *pool);
 
 void *ngx_palloc(ngx_pool_t *pool, size_t size);
 void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
+void ngx_pfree(ngx_pool_t *pool, void *p);
+
 
 #define ngx_free   free
 
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -546,6 +546,7 @@ char *ngx_conf_set_flag_slot(ngx_conf_t 
     int         flag;
     ngx_str_t  *value;
 
+
     if (*(int *) (p + cmd->offset) != NGX_CONF_UNSET) {
         return "is duplicate";
     }
@@ -596,23 +597,25 @@ char *ngx_conf_set_num_slot(ngx_conf_t *
 {
     char  *p = conf;
 
-    int         num, len;
+    int        *np;
     ngx_str_t  *value;
 
-    if (*(int *) (p + cmd->offset) != NGX_CONF_UNSET) {
+
+    np = (int *) (p + cmd->offset);
+
+    if (*np != NGX_CONF_UNSET) {
         return "is duplicate";
     }
 
     value = (ngx_str_t *) cf->args->elts;
-
-    len = value[1].len;
-
-    num = ngx_atoi(value[1].data, len);
-    if (num == NGX_ERROR) {
+    *np = ngx_atoi(value[1].data, value[1].len);
+    if (*np == NGX_ERROR) {
         return "invalid number";
     }
 
-    *(int *) (p + cmd->offset) = num;
+    if (cmd->bounds) {
+        return cmd->bounds->check(cf, cmd->bounds, np);
+    }
 
     return NGX_CONF_OK;
 }
@@ -622,11 +625,14 @@ char *ngx_conf_set_size_slot(ngx_conf_t 
 {
     char  *p = conf;
 
-    int         size, len, scale;
+    int         size, len, scale, *np;
     char        last;
     ngx_str_t  *value;
 
-    if (*(int *) (p + cmd->offset) != NGX_CONF_UNSET) {
+
+    np = (int *) (p + cmd->offset);
+
+    if (*np != NGX_CONF_UNSET) {
         return "is duplicate";
     }
 
@@ -658,8 +664,11 @@ char *ngx_conf_set_size_slot(ngx_conf_t 
     }
 
     size *= scale;
+    *np = size;
 
-    *(int *) (p + cmd->offset) = size;
+    if (cmd->bounds) {
+        return cmd->bounds->check(cf, cmd->bounds, np);
+    }
 
     return NGX_CONF_OK;
 }
@@ -669,12 +678,15 @@ char *ngx_conf_set_msec_slot(ngx_conf_t 
 {
     char  *p = conf;
 
-    int         size, total, len, scale;
+    int         size, total, len, scale, *np;
     u_int       max, i;
     char        last, *start;
     ngx_str_t  *value;
 
-    if (*(int *) (p + cmd->offset) != NGX_CONF_UNSET) {
+
+    np = (int *) (p + cmd->offset);
+
+    if (*np != NGX_CONF_UNSET) {
         return "is duplicate";
     }
 
@@ -756,7 +768,11 @@ char *ngx_conf_set_msec_slot(ngx_conf_t 
         start = &value[1].data[i + 1];
     }
 
-    *(int *) (p + cmd->offset) = total;
+    *np = total;
+
+    if (cmd->bounds) {
+        return cmd->bounds->check(cf, cmd->bounds, np);
+    }
 
     return NGX_CONF_OK;
 }
@@ -766,12 +782,15 @@ char *ngx_conf_set_sec_slot(ngx_conf_t *
 {
     char  *p = conf;
 
-    int         size, total, len, scale;
+    int         size, total, len, scale, *np;
     u_int       max, i;
     char        last, *start;
     ngx_str_t  *value;
 
-    if (*(int *) (p + cmd->offset) != NGX_CONF_UNSET) {
+
+    np = (int *) (p + cmd->offset);
+
+    if (*np != NGX_CONF_UNSET) {
         return "is duplicate";
     }
 
@@ -865,7 +884,11 @@ char *ngx_conf_set_sec_slot(ngx_conf_t *
         start = &value[1].data[i + 1];
     }
 
-    *(int *) (p + cmd->offset) = total;
+    *np = total;
+
+    if (cmd->bounds) {
+        return cmd->bounds->check(cf, cmd->bounds, np);
+    }
 
     return NGX_CONF_OK;
 }
@@ -929,3 +952,17 @@ char *ngx_conf_unsupported(ngx_conf_t *c
 {
     return "unsupported on this platform";
 }
+
+
+char *ngx_conf_check_num_bounds(ngx_conf_t *cf, ngx_conf_bounds_t *bounds,
+                                void *conf)
+{
+    int *num = conf;
+
+    if (*num >= bounds->type.num.low && *num <= bounds->type.num.high) {
+        return NGX_CONF_OK;
+
+    }
+
+    return "invalid value";
+}
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -52,17 +52,37 @@
 #define NGX_CONF_MODULE      0x464E4F43  /* "CONF" */
 
 
+typedef struct ngx_conf_bounds_s ngx_conf_bounds_t;
+
+struct ngx_conf_bounds_s {
+    char     *(*check)(ngx_conf_t *cf, ngx_conf_bounds_t *bounds, void *conf);
+
+    union {
+        struct {
+           int  low;
+           int  high;
+        } num;
+
+        struct num {
+           int  low_num;
+           int  high_num;
+           int  low_size;
+           int  high_size;
+        } bufs;
+   } type;
+};
+
 
 struct ngx_command_s {
-    ngx_str_t  name;
-    int        type;
-    char    *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-    int        conf;
-    int        offset;
-    void      *bounds;
+    ngx_str_t           name;
+    int                 type;
+    char             *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+    int                 conf;
+    int                 offset;
+    ngx_conf_bounds_t  *bounds;
 };
 
-#define ngx_null_command   {ngx_null_string, 0, NULL, 0, 0, NULL}
+#define ngx_null_command   { ngx_null_string, 0, NULL, 0, 0, NULL }
 
 
 struct ngx_open_file_s {
@@ -221,6 +241,9 @@ char *ngx_conf_set_bufs_slot(ngx_conf_t 
 char *ngx_conf_set_core_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd,
                                   void *conf);
 
+char *ngx_conf_check_num_bounds(ngx_conf_t *cf, ngx_conf_bounds_t *bounds,
+                                void *conf);
+
 
 extern ngx_module_t     *ngx_modules[];
 extern ngx_cycle_t      *ngx_cycle;
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -203,5 +203,5 @@ char *ngx_conf_set_path_slot(ngx_conf_t 
         path->level[i++] = 0;
     }
 
-    return NULL;
+    return NGX_CONF_OK;
 }
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -7,38 +7,55 @@
 
 
 typedef struct {
-    int            enable;
-    ngx_bufs_t     bufs;
-    int            no_buffer;
+    int                  enable;
+    ngx_bufs_t           bufs;
+    int                  level;
+    int                  wbits;
+    int                  memlevel;
+    int                  no_buffer;
 } ngx_http_gzip_conf_t;
 
 
 typedef struct {
-    ngx_chain_t   *in;
-    ngx_chain_t   *free;
-    ngx_chain_t   *busy;
-    ngx_chain_t   *out;
-    ngx_chain_t  **last_out;
-    ngx_hunk_t    *in_hunk;
-    ngx_hunk_t    *out_hunk;
-    int            hunks;
+    ngx_chain_t         *in;
+    ngx_chain_t         *free;
+    ngx_chain_t         *busy;
+    ngx_chain_t         *out;
+    ngx_chain_t        **last_out;
+    ngx_hunk_t          *in_hunk;
+    ngx_hunk_t          *out_hunk;
+    int                  hunks;
+
+    off_t                length;
 
-    off_t          length;
-    void          *alloc;
+    void                *preallocated;
+    char                *free_mem;
+    int                  allocated;
 
-    unsigned       flush:4;
-    unsigned       redo:1;
+    unsigned             flush:4;
+    unsigned             redo:1;
 
-    u_int          crc32;
-    z_stream       zstream;
+    u_int                crc32;
+    z_stream             zstream;
+    ngx_http_request_t  *request;
 } ngx_http_gzip_ctx_t;
 
 
+static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
+                                        u_int size);
+static void ngx_http_gzip_filter_free(void *opaque, void *address);
+
 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 char *ngx_http_gzip_set_window(ngx_conf_t *cf, ngx_command_t *cmd,
+                                      void *conf);
+static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, ngx_command_t *cmd,
+                                    void *conf);
+
+static ngx_conf_bounds_t ngx_http_gzip_comp_level_bounds;
 
 
 static ngx_command_t  ngx_http_gzip_filter_commands[] = {
@@ -57,6 +74,27 @@ static ngx_command_t  ngx_http_gzip_filt
      offsetof(ngx_http_gzip_conf_t, bufs),
      NULL},
 
+    {ngx_string("gzip_comp_level"),
+     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, level),
+     &ngx_http_gzip_comp_level_bounds},
+
+    {ngx_string("gzip_window"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_http_gzip_set_window,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_gzip_conf_t, wbits),
+     NULL},
+
+    {ngx_string("gzip_hash"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_http_gzip_set_hash,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_gzip_conf_t, memlevel),
+     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,
@@ -90,9 +128,12 @@ ngx_module_t  ngx_http_gzip_filter_modul
 };
 
 
-static char gzheader[10] = { 0x1f,
-                             (char) 0x8b,  /* suppress MSVC warning */
-                             Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
+static ngx_conf_bounds_t ngx_http_gzip_comp_level_bounds = {
+    ngx_conf_check_num_bounds, { { 1, 9 } }
+};
+
+
+static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
 
 #if (HAVE_LITTLE_ENDIAN)
 
@@ -104,8 +145,8 @@ struct gztrailer {
 #else /* HAVE_BIG_ENDIAN */
 
 struct gztrailer {
-    unsigned char crc32[4];
-    unsigned char zlen[4];
+    u_char crc32[4];
+    u_char zlen[4];
 };
 
 #endif
@@ -146,6 +187,7 @@ static int ngx_http_gzip_header_filter(n
 
     ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module,
                         sizeof(ngx_http_gzip_ctx_t), NGX_ERROR);
+    ctx->request = r;
 
     ngx_test_null(r->headers_out.content_encoding,
                   ngx_push_table(r->headers_out.headers),
@@ -167,7 +209,7 @@ 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, wbits, mem_level, zin, zout, last;
+    int                    rc, wbits, memlevel, zin, zout, last;
     struct gztrailer      *trailer;
     ngx_hunk_t            *h;
     ngx_chain_t           *cl;
@@ -182,9 +224,9 @@ static int ngx_http_gzip_body_filter(ngx
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
-    if (ctx->alloc == NULL) {
-        wbits = MAX_WBITS;
-        mem_level = MAX_MEM_LEVEL - 1;
+    if (ctx->preallocated == NULL) {
+        wbits = conf->wbits;
+        memlevel = conf->memlevel;
 
         if (ctx->length > 0) {
 
@@ -192,18 +234,34 @@ static int ngx_http_gzip_body_filter(ngx
 
             while (ctx->length < ((1 << (wbits - 1)) - 262)) {
                 wbits--;
-                mem_level--;
+                memlevel--;
             }
         }
 
-#if 0
-        ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR);
-#else
-        ctx->alloc = (void *) -1;
-#endif
+        /*
+         * We preallocate a memory for zlib in one hunk (200K-400K), this
+         * dicreases number of malloc() and free() calls and probably
+         * syscalls.
+         * Besides we free() this memory as soon as the gzipping will complete
+         * and do not wait while a whole response will be sent to a client.
+         *
+         * 8K is for zlib deflate_state (~6K).
+         *
+         * TODO: 64-bit, round to PAGE_SIZE
+         */
 
-        rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED,
-                          -wbits, mem_level, Z_DEFAULT_STRATEGY);
+        ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
+
+        ngx_test_null(ctx->preallocated, ngx_palloc(r->pool, ctx->allocated),
+                      NGX_ERROR);
+        ctx->free_mem = ctx->preallocated;
+
+        ctx->zstream.zalloc = ngx_http_gzip_filter_alloc;
+        ctx->zstream.zfree = ngx_http_gzip_filter_free;
+        ctx->zstream.opaque = ctx;
+
+        rc = deflateInit2(&ctx->zstream, conf->level, Z_DEFLATED,
+                          -wbits, memlevel, Z_DEFAULT_STRATEGY);
 
         if (rc != Z_OK) {
             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
@@ -214,7 +272,7 @@ static int ngx_http_gzip_body_filter(ngx
         ngx_test_null(h, ngx_calloc_hunk(r->pool), ngx_http_gzip_error(ctx));
 
         h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_MEMORY;
-        h->pos = gzheader;
+        h->pos = (char *) gzheader;
         h->last = h->pos + 10;
 
         ngx_alloc_link_and_set_hunk(cl, h, r->pool, ngx_http_gzip_error(ctx));
@@ -250,7 +308,7 @@ static int ngx_http_gzip_body_filter(ngx
                 ctx->in_hunk = ctx->in->hunk;
                 ctx->in = ctx->in->next;
 
-                ctx->zstream.next_in = (unsigned char *) ctx->in_hunk->pos;
+                ctx->zstream.next_in = (u_char *) ctx->in_hunk->pos;
                 ctx->zstream.avail_in = ctx->in_hunk->last - ctx->in_hunk->pos;
 
                 if (ctx->in_hunk->type & NGX_HUNK_LAST) {
@@ -292,7 +350,7 @@ static int ngx_http_gzip_body_filter(ngx
                     break;
                 }
 
-                ctx->zstream.next_out = (unsigned char *) ctx->out_hunk->pos;
+                ctx->zstream.next_out = (u_char *) ctx->out_hunk->pos;
                 ctx->zstream.avail_out = conf->bufs.size;
             }
 
@@ -337,6 +395,7 @@ ngx_log_debug(r->connection->log, "DEFLA
                     break;
 
                 } else if (ctx->flush == Z_FINISH) {
+
                     /* rc == Z_STREAM_END */
 
                     zin = ctx->zstream.total_in;
@@ -349,6 +408,8 @@ ngx_log_debug(r->connection->log, "DEFLA
                         return ngx_http_gzip_error(ctx);
                     }
 
+                    ngx_pfree(r->pool, ctx->preallocated);
+
                     ctx->flush = Z_NO_FLUSH;
 
                     ngx_alloc_link_and_set_hunk(cl, ctx->out_hunk, r->pool,
@@ -385,9 +446,7 @@ ngx_log_debug(r->connection->log, "DEFLA
 
                     ctx->zstream.avail_in = 0;
                     ctx->zstream.avail_out = 0;
-#if 0
-                    ngx_free(ctx->alloc);
-#endif
+
                     ngx_http_delete_ctx(r, ngx_http_gzip_filter_module);
 
                     break;
@@ -420,13 +479,61 @@ ngx_log_debug(r->connection->log, "DEFLA
 }
 
 
+static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size)
+{
+    ngx_http_gzip_ctx_t *ctx = opaque;
+
+    int    alloc;
+    void  *p;
+
+
+    alloc = items * size;
+    if (alloc % 512 != 0) {
+
+        /* we allocate 8K for zlib deflate_state (~6K) */
+        /* TODO: PAGE_SIZE */
+
+        alloc = (alloc + 4095) & ~4095;
+    }
+
+    if (alloc <= ctx->allocated) {
+        p = ctx->free_mem;
+        ctx->free_mem += alloc;
+        ctx->allocated -= alloc;
+
+#if 0
+        ngx_log_debug(ctx->request->connection->log, "ALLOC: %d:%d:%d:%08X" _
+                      items _ size _ alloc _ p);
+#endif
+
+        return p;
+    }
+
+    ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0,
+                  "gzip filter failed to use preallocated memory: %d of %d",
+                  items * size, ctx->allocated);
+
+    p = ngx_palloc(ctx->request->pool, items * size);
+
+    return p;
+}
+
+
+static void ngx_http_gzip_filter_free(void *opaque, void *address)
+{
+    ngx_http_gzip_ctx_t *ctx = opaque;
+
+#if 0
+    ngx_log_debug(ctx->request->connection->log, "FREE: %08X" _ address);
+#endif
+}
+
+
 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx)
 {
-#if 0
-    ngx_free(ctx->alloc);
-#else
     deflateEnd(&ctx->zstream);
-#endif
+
+    ngx_pfree(ctx->request->pool, ctx->preallocated);
 
     ctx->zstream.avail_in = 0;
     ctx->zstream.avail_out = 0;
@@ -456,8 +563,11 @@ static void *ngx_http_gzip_create_conf(n
                   NGX_CONF_ERROR);
 
     conf->enable = NGX_CONF_UNSET;
-/*  conf->bufs.num = 0; */
+ /* conf->bufs.num = 0; */
     conf->no_buffer = NGX_CONF_UNSET;
+    conf->level = NGX_CONF_UNSET;
+    conf->wbits = NGX_CONF_UNSET;
+    conf->memlevel = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -472,7 +582,74 @@ static char *ngx_http_gzip_merge_conf(ng
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4,
                               /* STUB: PAGE_SIZE */ 4096);
+    ngx_conf_merge_value(conf->level, prev->level, 1);
+    ngx_conf_merge_value(conf->wbits, prev->wbits, MAX_WBITS);
+    ngx_conf_merge_value(conf->memlevel, prev->memlevel, MAX_MEM_LEVEL - 1);
     ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
 
     return NGX_CONF_OK;
 }
+
+
+static char *ngx_http_gzip_set_window(ngx_conf_t *cf, ngx_command_t *cmd,
+                                      void *conf)
+{
+    ngx_http_gzip_conf_t *lcf = conf;
+
+    int    wbits, wsize;
+    char  *rv;
+
+
+    rv = ngx_conf_set_size_slot(cf, cmd, conf);
+    if (rv) {
+        return rv;
+    }
+
+ngx_conf_log_error(NGX_LOG_INFO, cf, 0, "WBITS: %d", lcf->wbits);
+
+    wbits = 15;
+    for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) {
+
+        if (wsize == lcf->wbits) {
+            lcf->wbits = wbits;
+ngx_conf_log_error(NGX_LOG_INFO, cf, 0, "WBITS: %d", lcf->wbits);
+            return NULL;
+        }
+
+        wbits--;
+    }
+
+    return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k";
+}
+
+
+static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, ngx_command_t *cmd,
+                                    void *conf)
+{
+    ngx_http_gzip_conf_t *lcf = conf;
+
+    int    memlevel, hsize;
+    char  *rv;
+
+
+    rv = ngx_conf_set_size_slot(cf, cmd, conf);
+    if (rv) {
+        return rv;
+    }
+
+ngx_conf_log_error(NGX_LOG_INFO, cf, 0, "MEMLEVEL: %d", lcf->memlevel);
+
+    memlevel = 9;
+    for (hsize = 128 * 1024; hsize > 256; hsize >>= 1) {
+
+        if (hsize == lcf->memlevel) {
+            lcf->memlevel = memlevel;
+ngx_conf_log_error(NGX_LOG_INFO, cf, 0, "MEMLEVEL: %d", lcf->memlevel);
+            return NULL;
+        }
+
+        memlevel--;
+    }
+
+    return "must be 512, 1k, 2k, 4k, 8k, 16k, 32k, 64k, or 128k";
+}
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -1200,7 +1200,6 @@ static size_t ngx_http_proxy_log_error(v
 
 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
 {
-    int                         i;
     ngx_http_proxy_loc_conf_t  *conf;
 
     ngx_test_null(conf,
--- a/src/os/win32/ngx_types.h
+++ b/src/os/win32/ngx_types.h
@@ -7,6 +7,7 @@
 
 
 typedef unsigned __int32            u_int32_t;
+typedef __int64                     int64_t;
 
 typedef int                         ssize_t;
 typedef long                        time_t;