changeset 648:f200748c0ac8 NGINX_1_1_8

nginx 1.1.8 *) Change: the ngx_http_limit_zone_module was renamed to the ngx_http_limit_conn_module. *) Change: the "limit_zone" directive was superseded by the "limit_conn_zone" directive with a new syntax. *) Feature: support for multiple "limit_conn" limits on the same level. *) Feature: the "image_filter_sharpen" directive. *) Bugfix: a segmentation fault might occur in a worker process if resolver got a big DNS response. Thanks to Ben Hawkes. *) Bugfix: in cache key calculation if internal MD5 implementation was used; the bug had appeared in 1.0.4. *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request header lines might be passed to backend while caching; or not passed without caching if caching was enabled in another part of the configuration. *) Bugfix: the module ngx_http_mp4_module sent incorrect "Content-Length" response header line if the "start" argument was used. Thanks to Piotr Sikora.
author Igor Sysoev <http://sysoev.ru>
date Mon, 14 Nov 2011 00:00:00 +0400
parents bec017127243
children c5b99ec117cd
files CHANGES CHANGES.ru auto/modules auto/options auto/sources auto/summary conf/mime.types src/core/nginx.c src/core/nginx.h src/core/ngx_log.h src/core/ngx_md5.c src/core/ngx_resolver.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_limit_conn_module.c src/http/modules/ngx_http_limit_zone_module.c src/http/modules/ngx_http_mp4_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_uwsgi_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_request.h src/mail/ngx_mail_proxy_module.c src/os/unix/ngx_files.h
diffstat 27 files changed, 1305 insertions(+), 815 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,15 +1,45 @@
 
+Changes with nginx 1.1.8                                         14 Nov 2011
+
+    *) Change: the ngx_http_limit_zone_module was renamed to the
+       ngx_http_limit_conn_module.
+
+    *) Change: the "limit_zone" directive was superseded by the
+       "limit_conn_zone" directive with a new syntax.
+
+    *) Feature: support for multiple "limit_conn" limits on the same level.
+
+    *) Feature: the "image_filter_sharpen" directive.
+
+    *) Bugfix: a segmentation fault might occur in a worker process if
+       resolver got a big DNS response.
+       Thanks to Ben Hawkes.
+
+    *) Bugfix: in cache key calculation if internal MD5 implementation was
+       used; the bug had appeared in 1.0.4.
+
+    *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request
+       header lines might be passed to backend while caching; or not passed
+       without caching if caching was enabled in another part of the
+       configuration.
+
+    *) Bugfix: the module ngx_http_mp4_module sent incorrect
+       "Content-Length" response header line if the "start" argument was
+       used.
+       Thanks to Piotr Sikora.
+
+
 Changes with nginx 1.1.7                                         31 Oct 2011
 
-    *) Feature: support of several resolvers in the "resolver" directive.
+    *) Feature: support of several DNS servers in the "resolver" directive.
        Thanks to Kirill A. Korinskiy.
 
-    *) Bugfix: a segmentation fault occurred on start or while
+    *) Bugfix: a segmentation fault occurred on start or during
        reconfiguration if the "ssl" directive was used at http level and
        there was no "ssl_certificate" defined.
 
-    *) Bugfix: reduced memory consumption while proxying of big files if
-       they were buffered to disk.
+    *) Bugfix: reduced memory consumption while proxying big files if they
+       were buffered to disk.
 
     *) Bugfix: a segmentation fault might occur in a worker process if
        "proxy_http_version 1.1" directive was used.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,34 @@
 
+Изменения в nginx 1.1.8                                           14.11.2011
+
+    *) Изменение: модуль ngx_http_limit_zone_module переименован в
+       ngx_http_limit_conn_module.
+
+    *) Изменение: директива limit_zone заменена директивой limit_conn_zone с
+       новым синтаксисом.
+
+    *) Добавление: поддержка ограничения по нескольким limit_conn на одном
+       уровне.
+
+    *) Добавление: директива image_filter_sharpen.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault,
+       если resolver получил большой DNS-ответ.
+       Спасибо Ben Hawkes.
+
+    *) Исправление: в вычислении ключа для кэширования, если использовалась
+       внутренняя реализация MD5; ошибка появилась в 1.0.4.
+
+    *) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в
+       заголовке запроса клиента могли передаваться бэкенду при кэшировании;
+       или не передаваться при выключенном кэшировании, если кэширование
+       было включено в другой части конфигурации.
+
+    *) Исправление: модуль ngx_http_mp4_module выдавал неверную строку
+       "Content-Length" в заголовке ответа, использовался аргумент start.
+       Спасибо Piotr Sikora.
+
+
 Изменения в nginx 1.1.7                                           31.10.2011
 
     *) Добавление: поддержка нескольких DNS серверов в директиве "resolver".
--- a/auto/modules
+++ b/auto/modules
@@ -210,9 +210,9 @@ if [ $HTTP_ACCESS = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS"
 fi
 
-if [ $HTTP_LIMIT_ZONE = YES ]; then
-    HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_ZONE_MODULE"
-    HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_ZONE_SRCS"
+if [ $HTTP_LIMIT_CONN = YES ]; then
+    HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_CONN_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_CONN_SRCS"
 fi
 
 if [ $HTTP_LIMIT_REQ = YES ]; then
--- a/auto/options
+++ b/auto/options
@@ -85,7 +85,7 @@ HTTP_UWSGI=YES
 HTTP_SCGI=YES
 HTTP_PERL=NO
 HTTP_MEMCACHED=YES
-HTTP_LIMIT_ZONE=YES
+HTTP_LIMIT_CONN=YES
 HTTP_LIMIT_REQ=YES
 HTTP_EMPTY_GIF=YES
 HTTP_BROWSER=YES
@@ -143,6 +143,8 @@ NGX_LIBATOMIC=NO
 
 NGX_CPU_CACHE_LINE=
 
+NGX_POST_CONF_MSG=
+
 opt=
 
 for option
@@ -227,7 +229,13 @@ do
         --without-http_uwsgi_module)     HTTP_UWSGI=NO              ;;
         --without-http_scgi_module)      HTTP_SCGI=NO               ;;
         --without-http_memcached_module) HTTP_MEMCACHED=NO          ;;
-        --without-http_limit_zone_module) HTTP_LIMIT_ZONE=NO        ;;
+        --without-http_limit_zone_module)
+            HTTP_LIMIT_CONN=NO
+            NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
+$0: warning: the \"--without-http_limit_zone_module\" option is deprecated, \
+use the \"--without-http_limit_conn_module\" option instead"
+        ;;
+        --without-http_limit_conn_module) HTTP_LIMIT_CONN=NO        ;;
         --without-http_limit_req_module) HTTP_LIMIT_REQ=NO         ;;
         --without-http_empty_gif_module) HTTP_EMPTY_GIF=NO          ;;
         --without-http_browser_module)   HTTP_BROWSER=NO            ;;
@@ -364,7 +372,7 @@ cat << END
   --without-http_uwsgi_module        disable ngx_http_uwsgi_module
   --without-http_scgi_module         disable ngx_http_scgi_module
   --without-http_memcached_module    disable ngx_http_memcached_module
-  --without-http_limit_zone_module   disable ngx_http_limit_zone_module
+  --without-http_limit_conn_module   disable ngx_http_limit_conn_module
   --without-http_limit_req_module    disable ngx_http_limit_req_module
   --without-http_empty_gif_module    disable ngx_http_empty_gif_module
   --without-http_browser_module      disable ngx_http_browser_module
--- a/auto/sources
+++ b/auto/sources
@@ -435,8 +435,8 @@ HTTP_MEMCACHED_MODULE=ngx_http_memcached
 HTTP_MEMCACHED_SRCS=src/http/modules/ngx_http_memcached_module.c
 
 
-HTTP_LIMIT_ZONE_MODULE=ngx_http_limit_zone_module
-HTTP_LIMIT_ZONE_SRCS=src/http/modules/ngx_http_limit_zone_module.c
+HTTP_LIMIT_CONN_MODULE=ngx_http_limit_conn_module
+HTTP_LIMIT_CONN_SRCS=src/http/modules/ngx_http_limit_conn_module.c
 
 
 HTTP_LIMIT_REQ_MODULE=ngx_http_limit_req_module
--- a/auto/summary
+++ b/auto/summary
@@ -111,3 +111,5 @@ fi
 if [ $HTTP_SCGI = YES ]; then
     echo "  nginx http scgi temporary files: \"$NGX_HTTP_SCGI_TEMP_PATH\""
 fi
+
+echo "$NGX_POST_CONF_MSG"
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -22,6 +22,7 @@ types {
     image/x-jng                           jng;
     image/x-ms-bmp                        bmp;
     image/svg+xml                         svg;
+    image/webp                            webp;
 
     application/java-archive              jar war ear;
     application/mac-binhex40              hqx;
@@ -69,6 +70,7 @@ types {
     video/mp4                             mp4;
     video/mpeg                            mpeg mpg;
     video/quicktime                       mov;
+    video/webm                            webm;
     video/x-flv                           flv;
     video/x-m4v                           m4v;
     video/x-mng                           mng;
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -214,47 +214,49 @@ main(int argc, char *const *argv)
     }
 
     if (ngx_show_version) {
-        ngx_log_stderr(0, "nginx version: " NGINX_VER);
+        ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED);
 
         if (ngx_show_help) {
-            ngx_log_stderr(0,
+            ngx_write_stderr(
                 "Usage: nginx [-?hvVtq] [-s signal] [-c filename] "
-                             "[-p prefix] [-g directives]" CRLF CRLF
-                "Options:" CRLF
-                "  -?,-h         : this help" CRLF
-                "  -v            : show version and exit" CRLF
+                             "[-p prefix] [-g directives]" NGX_LINEFEED
+                             NGX_LINEFEED
+                "Options:" NGX_LINEFEED
+                "  -?,-h         : this help" NGX_LINEFEED
+                "  -v            : show version and exit" NGX_LINEFEED
                 "  -V            : show version and configure options then exit"
-                                   CRLF
-                "  -t            : test configuration and exit" CRLF
+                                   NGX_LINEFEED
+                "  -t            : test configuration and exit" NGX_LINEFEED
                 "  -q            : suppress non-error messages "
-                                   "during configuration testing" CRLF
+                                   "during configuration testing" NGX_LINEFEED
                 "  -s signal     : send signal to a master process: "
-                                   "stop, quit, reopen, reload" CRLF
+                                   "stop, quit, reopen, reload" NGX_LINEFEED
 #ifdef NGX_PREFIX
                 "  -p prefix     : set prefix path (default: "
-                                   NGX_PREFIX ")" CRLF
+                                   NGX_PREFIX ")" NGX_LINEFEED
 #else
-                "  -p prefix     : set prefix path (default: NONE)" CRLF
+                "  -p prefix     : set prefix path (default: NONE)" NGX_LINEFEED
 #endif
                 "  -c filename   : set configuration file (default: "
-                                   NGX_CONF_PATH ")" CRLF
+                                   NGX_CONF_PATH ")" NGX_LINEFEED
                 "  -g directives : set global directives out of configuration "
-                                   "file" CRLF
+                                   "file" NGX_LINEFEED NGX_LINEFEED
                 );
         }
 
         if (ngx_show_configure) {
+            ngx_write_stderr(
 #ifdef NGX_COMPILER
-            ngx_log_stderr(0, "built by " NGX_COMPILER);
+                "built by " NGX_COMPILER NGX_LINEFEED
 #endif
 #if (NGX_SSL)
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-            ngx_log_stderr(0, "TLS SNI support enabled");
+                "TLS SNI support enabled" NGX_LINEFEED
 #else
-            ngx_log_stderr(0, "TLS SNI support disabled");
+                "TLS SNI support disabled" NGX_LINEFEED
 #endif
 #endif
-            ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE);
+                "configure arguments:" NGX_CONFIGURE NGX_LINEFEED);
         }
 
         if (!ngx_test_config) {
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version      1001007
-#define NGINX_VERSION      "1.1.7"
+#define nginx_version      1001008
+#define NGINX_VERSION      "1.1.8"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -203,6 +203,22 @@ void ngx_cdecl ngx_log_stderr(ngx_err_t 
 u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err);
 
 
+/*
+ * ngx_write_stderr() cannot be implemented as macro, since
+ * MSVC does not allow to use #ifdef inside macro parameters.
+ *
+ * ngx_write_fd() is used instead of ngx_write_console(), since
+ * CharToOemBuff() inside ngx_write_console() cannot be used with
+ * read only buffer as destination and CharToOemBuff() is not needed
+ * for ngx_write_stderr() anyway.
+ */
+static ngx_inline void
+ngx_write_stderr(char *text)
+{
+    (void) ngx_write_fd(ngx_stderr, text, strlen(text));
+}
+
+
 extern ngx_module_t  ngx_errlog_module;
 extern ngx_uint_t    ngx_use_stderr;
 
--- a/src/core/ngx_md5.c
+++ b/src/core/ngx_md5.c
@@ -47,7 +47,8 @@ ngx_md5_update(ngx_md5_t *ctx, const voi
             return;
         }
 
-        data = ngx_cpymem(&ctx->buffer[used], data, free);
+        ngx_memcpy(&ctx->buffer[used], data, free);
+        data = (u_char *) data + free;
         size -= free;
         (void) ngx_md5_body(ctx, ctx->buffer, 64);
     }
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1952,7 +1952,13 @@ done:
     n = *src++;
 
     for ( ;; ) {
-        if (n != 0xc0) {
+        if (n & 0xc0) {
+            n = ((n & 0x3f) << 8) + *src;
+            src = &buf[n];
+
+            n = *src++;
+
+        } else {
             ngx_memcpy(dst, src, n);
             dst += n;
             src += n;
@@ -1962,12 +1968,6 @@ done:
             if (n != 0) {
                 *dst++ = '.';
             }
-
-        } else {
-            n = ((n & 0x3f) << 8) + *src;
-            src = &buf[n];
-
-            n = *src++;
         }
 
         if (n == 0) {
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -147,6 +147,9 @@ static ngx_int_t ngx_http_fastcgi_add_va
 static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
+static ngx_int_t ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
+    ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_loc_conf_t *prev);
+
 static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
@@ -436,7 +439,7 @@ static ngx_command_t  ngx_http_fastcgi_c
       &ngx_http_upstream_ignore_headers_masks },
 
     { ngx_string("fastcgi_catch_stderr"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_array_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
@@ -2085,17 +2088,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     ngx_http_fastcgi_loc_conf_t *prev = parent;
     ngx_http_fastcgi_loc_conf_t *conf = child;
 
-    u_char                       *p;
     size_t                        size;
-    uintptr_t                    *code;
-    ngx_uint_t                    i;
-    ngx_array_t                   headers_names;
-    ngx_keyval_t                 *src;
-    ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
     ngx_http_core_loc_conf_t     *clcf;
-    ngx_http_script_compile_t     sc;
-    ngx_http_script_copy_code_t  *copy;
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store,
@@ -2355,95 +2350,146 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     }
 #endif
 
-    if (conf->params_source == NULL) {
-        conf->flushes = prev->flushes;
-        conf->params_len = prev->params_len;
-        conf->params = prev->params;
-        conf->params_source = prev->params_source;
-        conf->headers_hash = prev->headers_hash;
-
+    if (ngx_http_fastcgi_merge_params(cf, conf, prev) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
+    ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_loc_conf_t *prev)
+{
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i, nsrc;
+    ngx_array_t                   headers_names;
 #if (NGX_HTTP_CACHE)
-
-        if (conf->params_source == NULL) {
-
-            if ((conf->upstream.cache == NULL)
-                == (prev->upstream.cache == NULL))
-            {
-                return NGX_CONF_OK;
-            }
-
-            /* 6 is a number of ngx_http_fastcgi_cache_headers entries */
-            conf->params_source = ngx_array_create(cf->pool, 6,
-                                                   sizeof(ngx_keyval_t));
-            if (conf->params_source == NULL) {
-                return NGX_CONF_ERROR;
-            }
+    ngx_array_t                   params_merged;
+#endif
+    ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
+    ngx_hash_init_t               hash;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
+
+    if (conf->params_source == NULL) {
+        conf->params_source = prev->params_source;
+
+        if (prev->headers_hash.buckets
+#if (NGX_HTTP_CACHE)
+            && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+#endif
+           )
+        {
+            conf->flushes = prev->flushes;
+            conf->params_len = prev->params_len;
+            conf->params = prev->params;
+            conf->headers_hash = prev->headers_hash;
+            conf->header_params = prev->header_params;
+
+            return NGX_OK;
         }
-#else
-
-        if (conf->params_source == NULL) {
-            return NGX_CONF_OK;
-        }
-
+    }
+
+    if (conf->params_source == NULL
+#if (NGX_HTTP_CACHE)
+        && (conf->upstream.cache == NULL)
 #endif
+       )
+    {
+        conf->headers_hash.buckets = (void *) 1;
+        return NGX_OK;
     }
 
     conf->params_len = ngx_array_create(cf->pool, 64, 1);
     if (conf->params_len == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     conf->params = ngx_array_create(cf->pool, 512, 1);
     if (conf->params == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
-    src = conf->params_source->elts;
+    if (conf->params_source) {
+        src = conf->params_source->elts;
+        nsrc = conf->params_source->nelts;
+
+    } else {
+        src = NULL;
+        nsrc = 0;
+    }
 
 #if (NGX_HTTP_CACHE)
 
     if (conf->upstream.cache) {
         ngx_keyval_t  *h, *s;
 
-        for (h = ngx_http_fastcgi_cache_headers; h->key.len; h++) {
-
-            for (i = 0; i < conf->params_source->nelts; i++) {
+        if (ngx_array_init(&params_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+            != NGX_OK)
+        {
+            return NGX_ERROR;
+        }
+
+        for (i = 0; i < nsrc; i++) {
+
+            s = ngx_array_push(&params_merged);
+            if (s == NULL) {
+                return NGX_ERROR;
+            }
+
+            *s = src[i];
+        }
+
+        h = ngx_http_fastcgi_cache_headers;
+
+        while (h->key.len) {
+
+            src = params_merged.elts;
+            nsrc = params_merged.nelts;
+
+            for (i = 0; i < nsrc; i++) {
                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                     goto next;
                 }
             }
 
-            s = ngx_array_push(conf->params_source);
+            s = ngx_array_push(&params_merged);
             if (s == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             *s = *h;
 
-            src = conf->params_source->elts;
-
         next:
 
             h++;
         }
+
+        src = params_merged.elts;
+        nsrc = params_merged.nelts;
     }
 
 #endif
 
-    for (i = 0; i < conf->params_source->nelts; i++) {
+    for (i = 0; i < nsrc; i++) {
 
         if (src[i].key.len > sizeof("HTTP_") - 1
             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
         {
             hk = ngx_array_push(&headers_names);
             if (hk == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             hk->key.len = src[i].key.len - 5;
@@ -2459,7 +2505,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         copy = ngx_array_push_n(conf->params_len,
                                 sizeof(ngx_http_script_copy_code_t));
         if (copy == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
@@ -2468,11 +2514,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
         size = (sizeof(ngx_http_script_copy_code_t)
                 + src[i].key.len + sizeof(uintptr_t) - 1)
-                & ~(sizeof(uintptr_t) - 1);
+               & ~(sizeof(uintptr_t) - 1);
 
         copy = ngx_array_push_n(conf->params, size);
         if (copy == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         copy->code = ngx_http_script_copy_code;
@@ -2491,12 +2537,12 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         sc.values = &conf->params;
 
         if (ngx_http_script_compile(&sc) != NGX_OK) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
         if (code == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         *code = (uintptr_t) NULL;
@@ -2504,7 +2550,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
         code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
         if (code == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         *code = (uintptr_t) NULL;
@@ -2512,12 +2558,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
     if (code == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     *code = (uintptr_t) NULL;
 
-
     conf->header_params = headers_names.nelts;
 
     hash.hash = &conf->headers_hash;
@@ -2528,12 +2573,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     hash.pool = cf->pool;
     hash.temp_pool = NULL;
 
-    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    return NGX_CONF_OK;
+    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
 }
 
 
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -41,6 +41,7 @@ typedef struct {
     ngx_uint_t                   height;
     ngx_uint_t                   angle;
     ngx_uint_t                   jpeg_quality;
+    ngx_uint_t                   sharpen;
 
     ngx_flag_t                   transparency;
 
@@ -48,6 +49,7 @@ typedef struct {
     ngx_http_complex_value_t    *hcv;
     ngx_http_complex_value_t    *acv;
     ngx_http_complex_value_t    *jqcv;
+    ngx_http_complex_value_t    *shcv;
 
     size_t                       buffer_size;
 } ngx_http_image_filter_conf_t;
@@ -105,6 +107,8 @@ static char *ngx_http_image_filter(ngx_c
     void *conf);
 static char *ngx_http_image_filter_jpeg_quality(ngx_conf_t *cf,
     ngx_command_t *cmd, void *conf);
+static char *ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf);
 
 
@@ -124,6 +128,13 @@ static ngx_command_t  ngx_http_image_fil
       0,
       NULL },
 
+    { ngx_string("image_filter_sharpen"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_image_filter_sharpen,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("image_filter_transparency"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -724,7 +735,7 @@ static ngx_buf_t *
 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
 {
     int                            sx, sy, dx, dy, ox, oy, ax, ay, size,
-                                   colors, palette, transparent,
+                                   colors, palette, transparent, sharpen,
                                    red, green, blue, t;
     u_char                        *out;
     ngx_buf_t                     *b;
@@ -948,6 +959,11 @@ transparent:
         gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
     }
 
+    sharpen = ngx_http_image_filter_get_value(r, conf->shcv, conf->sharpen);
+    if (sharpen > 0) {
+        gdImageSharpen(dst, sharpen);
+    }
+
     out = ngx_http_image_out(r, ctx->type, dst, &size);
 
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1156,6 +1172,7 @@ ngx_http_image_filter_create_conf(ngx_co
 
     conf->filter = NGX_CONF_UNSET_UINT;
     conf->jpeg_quality = NGX_CONF_UNSET_UINT;
+    conf->sharpen = NGX_CONF_UNSET_UINT;
     conf->angle = NGX_CONF_UNSET_UINT;
     conf->transparency = NGX_CONF_UNSET;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
@@ -1191,6 +1208,12 @@ ngx_http_image_filter_merge_conf(ngx_con
         conf->jqcv = prev->jqcv;
     }
 
+    ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0);
+
+    if (conf->shcv == NULL) {
+        conf->shcv = prev->shcv;
+    }
+
     ngx_conf_merge_uint_value(conf->angle, prev->angle, 0);
     if (conf->acv == NULL) {
         conf->acv = prev->acv;
@@ -1401,6 +1424,53 @@ ngx_http_image_filter_jpeg_quality(ngx_c
 }
 
 
+static char *
+ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf)
+{
+    ngx_http_image_filter_conf_t *imcf = conf;
+
+    ngx_str_t                         *value;
+    ngx_int_t                          n;
+    ngx_http_complex_value_t           cv;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = &cv;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (cv.lengths == NULL) {
+        n = ngx_http_image_filter_value(&value[1]);
+
+        if (n < 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        imcf->sharpen = (ngx_uint_t) n;
+
+    } else {
+        imcf->shcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->shcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->shcv = cv;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
 static ngx_int_t
 ngx_http_image_filter_init(ngx_conf_t *cf)
 {
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_limit_conn_module.c
@@ -0,0 +1,751 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    u_char              color;
+    u_char              len;
+    u_short             conn;
+    u_char              data[1];
+} ngx_http_limit_conn_node_t;
+
+
+typedef struct {
+    ngx_shm_zone_t     *shm_zone;
+    ngx_rbtree_node_t  *node;
+} ngx_http_limit_conn_cleanup_t;
+
+
+typedef struct {
+    ngx_rbtree_t       *rbtree;
+    ngx_int_t           index;
+    ngx_str_t           var;
+} ngx_http_limit_conn_ctx_t;
+
+
+typedef struct {
+    ngx_shm_zone_t     *shm_zone;
+    ngx_uint_t          conn;
+} ngx_http_limit_conn_limit_t;
+
+
+typedef struct {
+    ngx_array_t         limits;
+    ngx_uint_t          log_level;
+} ngx_http_limit_conn_conf_t;
+
+
+static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
+    ngx_http_variable_value_t *vv, uint32_t hash);
+static void ngx_http_limit_conn_cleanup(void *data);
+static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
+
+static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
+static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
+
+
+static ngx_conf_deprecated_t  ngx_conf_deprecated_limit_zone = {
+    ngx_conf_deprecated, "limit_zone", "limit_conn_zone"
+};
+
+
+static ngx_conf_enum_t  ngx_http_limit_conn_log_levels[] = {
+    { ngx_string("info"), NGX_LOG_INFO },
+    { ngx_string("notice"), NGX_LOG_NOTICE },
+    { ngx_string("warn"), NGX_LOG_WARN },
+    { ngx_string("error"), NGX_LOG_ERR },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_command_t  ngx_http_limit_conn_commands[] = {
+
+    { ngx_string("limit_conn_zone"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
+      ngx_http_limit_conn_zone,
+      0,
+      0,
+      NULL },
+
+    { ngx_string("limit_zone"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
+      ngx_http_limit_zone,
+      0,
+      0,
+      NULL },
+
+    { ngx_string("limit_conn"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_http_limit_conn,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("limit_conn_log_level"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_limit_conn_conf_t, log_level),
+      &ngx_http_limit_conn_log_levels },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_limit_conn_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_limit_conn_init,              /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_limit_conn_create_conf,       /* create location configration */
+    ngx_http_limit_conn_merge_conf         /* merge location configration */
+};
+
+
+ngx_module_t  ngx_http_limit_conn_module = {
+    NGX_MODULE_V1,
+    &ngx_http_limit_conn_module_ctx,       /* module context */
+    ngx_http_limit_conn_commands,          /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_limit_conn_handler(ngx_http_request_t *r)
+{
+    size_t                          len, n;
+    uint32_t                        hash;
+    ngx_uint_t                      i;
+    ngx_slab_pool_t                *shpool;
+    ngx_rbtree_node_t              *node;
+    ngx_pool_cleanup_t             *cln;
+    ngx_http_variable_value_t      *vv;
+    ngx_http_limit_conn_ctx_t      *ctx;
+    ngx_http_limit_conn_node_t     *lc;
+    ngx_http_limit_conn_conf_t     *lccf;
+    ngx_http_limit_conn_limit_t    *limits;
+    ngx_http_limit_conn_cleanup_t  *lccln;
+
+    if (r->main->limit_conn_set) {
+        return NGX_DECLINED;
+    }
+
+    r->main->limit_conn_set = 1;
+
+    lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
+    limits = lccf->limits.elts;
+
+    for (i = 0; i < lccf->limits.nelts; i++) {
+        ctx = limits[i].shm_zone->data;
+
+        vv = ngx_http_get_indexed_variable(r, ctx->index);
+
+        if (vv == NULL || vv->not_found) {
+            continue;
+        }
+
+        len = vv->len;
+
+        if (len == 0) {
+            continue;
+        }
+
+        if (len > 255) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "the value of the \"%V\" variable "
+                          "is more than 255 bytes: \"%v\"",
+                          &ctx->var, vv);
+            continue;
+        }
+
+        hash = ngx_crc32_short(vv->data, len);
+
+        shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
+
+        ngx_shmtx_lock(&shpool->mutex);
+
+        node = ngx_http_limit_conn_lookup(ctx->rbtree, vv, hash);
+
+        if (node == NULL) {
+
+            n = offsetof(ngx_rbtree_node_t, color)
+                + offsetof(ngx_http_limit_conn_node_t, data)
+                + len;
+
+            node = ngx_slab_alloc_locked(shpool, n);
+
+            if (node == NULL) {
+                ngx_shmtx_unlock(&shpool->mutex);
+                ngx_http_limit_conn_cleanup_all(r->pool);
+                return NGX_HTTP_SERVICE_UNAVAILABLE;
+            }
+
+            lc = (ngx_http_limit_conn_node_t *) &node->color;
+
+            node->key = hash;
+            lc->len = (u_char) len;
+            lc->conn = 1;
+            ngx_memcpy(lc->data, vv->data, len);
+
+            ngx_rbtree_insert(ctx->rbtree, node);
+
+        } else {
+
+            lc = (ngx_http_limit_conn_node_t *) &node->color;
+
+            if ((ngx_uint_t) lc->conn >= limits[i].conn) {
+
+                ngx_shmtx_unlock(&shpool->mutex);
+
+                ngx_log_error(lccf->log_level, r->connection->log, 0,
+                              "limiting connections by zone \"%V\"",
+                              &limits[i].shm_zone->shm.name);
+
+                ngx_http_limit_conn_cleanup_all(r->pool);
+                return NGX_HTTP_SERVICE_UNAVAILABLE;
+            }
+
+            lc->conn++;
+        }
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "limit zone: %08XD %d", node->key, lc->conn);
+
+        ngx_shmtx_unlock(&shpool->mutex);
+
+        cln = ngx_pool_cleanup_add(r->pool,
+                                   sizeof(ngx_http_limit_conn_cleanup_t));
+        if (cln == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        cln->handler = ngx_http_limit_conn_cleanup;
+        lccln = cln->data;
+
+        lccln->shm_zone = limits[i].shm_zone;
+        lccln->node = node;
+    }
+
+    return NGX_DECLINED;
+}
+
+
+static void
+ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_rbtree_node_t           **p;
+    ngx_http_limit_conn_node_t   *lcn, *lcnt;
+
+    for ( ;; ) {
+
+        if (node->key < temp->key) {
+
+            p = &temp->left;
+
+        } else if (node->key > temp->key) {
+
+            p = &temp->right;
+
+        } else { /* node->key == temp->key */
+
+            lcn = (ngx_http_limit_conn_node_t *) &node->color;
+            lcnt = (ngx_http_limit_conn_node_t *) &temp->color;
+
+            p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0)
+                ? &temp->left : &temp->right;
+        }
+
+        if (*p == sentinel) {
+            break;
+        }
+
+        temp = *p;
+    }
+
+    *p = node;
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}
+
+
+static ngx_rbtree_node_t *
+ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
+    uint32_t hash)
+{
+    ngx_int_t                    rc;
+    ngx_rbtree_node_t           *node, *sentinel;
+    ngx_http_limit_conn_node_t  *lcn;
+
+    node = rbtree->root;
+    sentinel = rbtree->sentinel;
+
+    while (node != sentinel) {
+
+        if (hash < node->key) {
+            node = node->left;
+            continue;
+        }
+
+        if (hash > node->key) {
+            node = node->right;
+            continue;
+        }
+
+        /* hash == node->key */
+
+        do {
+            lcn = (ngx_http_limit_conn_node_t *) &node->color;
+
+            rc = ngx_memn2cmp(vv->data, lcn->data,
+                              (size_t) vv->len, (size_t) lcn->len);
+            if (rc == 0) {
+                return node;
+            }
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
+    }
+
+    return NULL;
+}
+
+
+static void
+ngx_http_limit_conn_cleanup(void *data)
+{
+    ngx_http_limit_conn_cleanup_t  *lccln = data;
+
+    ngx_slab_pool_t             *shpool;
+    ngx_rbtree_node_t           *node;
+    ngx_http_limit_conn_ctx_t   *ctx;
+    ngx_http_limit_conn_node_t  *lc;
+
+    ctx = lccln->shm_zone->data;
+    shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
+    node = lccln->node;
+    lc = (ngx_http_limit_conn_node_t *) &node->color;
+
+    ngx_shmtx_lock(&shpool->mutex);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
+                   "limit zone cleanup: %08XD %d", node->key, lc->conn);
+
+    lc->conn--;
+
+    if (lc->conn == 0) {
+        ngx_rbtree_delete(ctx->rbtree, node);
+        ngx_slab_free_locked(shpool, node);
+    }
+
+    ngx_shmtx_unlock(&shpool->mutex);
+}
+
+
+static ngx_inline void
+ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool)
+{
+    ngx_pool_cleanup_t  *cln;
+
+    cln = pool->cleanup;
+
+    while (cln && cln->handler == ngx_http_limit_conn_cleanup) {
+        ngx_http_limit_conn_cleanup(cln->data);
+        cln = cln->next;
+    }
+
+    pool->cleanup = cln;
+}
+
+
+static ngx_int_t
+ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
+{
+    ngx_http_limit_conn_ctx_t  *octx = data;
+
+    size_t                      len;
+    ngx_slab_pool_t            *shpool;
+    ngx_rbtree_node_t          *sentinel;
+    ngx_http_limit_conn_ctx_t  *ctx;
+
+    ctx = shm_zone->data;
+
+    if (octx) {
+        if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
+            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
+                          "limit_conn_zone \"%V\" uses the \"%V\" variable "
+                          "while previously it used the \"%V\" variable",
+                          &shm_zone->shm.name, &ctx->var, &octx->var);
+            return NGX_ERROR;
+        }
+
+        ctx->rbtree = octx->rbtree;
+
+        return NGX_OK;
+    }
+
+    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+    if (shm_zone->shm.exists) {
+        ctx->rbtree = shpool->data;
+
+        return NGX_OK;
+    }
+
+    ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
+    if (ctx->rbtree == NULL) {
+        return NGX_ERROR;
+    }
+
+    shpool->data = ctx->rbtree;
+
+    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
+    if (sentinel == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_rbtree_init(ctx->rbtree, sentinel,
+                    ngx_http_limit_conn_rbtree_insert_value);
+
+    len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
+
+    shpool->log_ctx = ngx_slab_alloc(shpool, len);
+    if (shpool->log_ctx == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
+                &shm_zone->shm.name);
+
+    return NGX_OK;
+}
+
+
+static void *
+ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
+{
+    ngx_http_limit_conn_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->limits.elts = NULL;
+     */
+
+    conf->log_level = NGX_CONF_UNSET_UINT;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_limit_conn_conf_t *prev = parent;
+    ngx_http_limit_conn_conf_t *conf = child;
+
+    if (conf->limits.elts == NULL) {
+        *conf = *prev;
+    }
+
+    ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    u_char                     *p;
+    ssize_t                     size;
+    ngx_str_t                  *value, name, s;
+    ngx_uint_t                  i;
+    ngx_shm_zone_t             *shm_zone;
+    ngx_http_limit_conn_ctx_t  *ctx;
+
+    value = cf->args->elts;
+
+    ctx = NULL;
+    size = 0;
+    name.len = 0;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+
+        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
+
+            name.data = value[i].data + 5;
+
+            p = (u_char *) ngx_strchr(name.data, ':');
+
+            if (p == NULL) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid zone size \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            name.len = p - name.data;
+
+            s.data = p + 1;
+            s.len = value[i].data + value[i].len - s.data;
+
+            size = ngx_parse_size(&s);
+
+            if (size == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid zone size \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            if (size < (ssize_t) (8 * ngx_pagesize)) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "zone \"%V\" is too small", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
+        if (value[i].data[0] == '$') {
+
+            value[i].len--;
+            value[i].data++;
+
+            ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
+            if (ctx == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            ctx->index = ngx_http_get_variable_index(cf, &value[i]);
+            if (ctx->index == NGX_ERROR) {
+                return NGX_CONF_ERROR;
+            }
+
+            ctx->var = value[i];
+
+            continue;
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid parameter \"%V\"", &value[i]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (name.len == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "\"%V\" must have \"zone\" parameter",
+                           &cmd->name);
+        return NGX_CONF_ERROR;
+    }
+
+    if (ctx == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "no variable is defined for %V \"%V\"",
+                           &cmd->name, &name);
+        return NGX_CONF_ERROR;
+    }
+
+    shm_zone = ngx_shared_memory_add(cf, &name, size,
+                                     &ngx_http_limit_conn_module);
+    if (shm_zone == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (shm_zone->data) {
+        ctx = shm_zone->data;
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "%V \"%V\" is already bound to variable \"%V\"",
+                           &cmd->name, &name, &ctx->var);
+        return NGX_CONF_ERROR;
+    }
+
+    shm_zone->init = ngx_http_limit_conn_init_zone;
+    shm_zone->data = ctx;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ssize_t                     n;
+    ngx_str_t                  *value;
+    ngx_shm_zone_t             *shm_zone;
+    ngx_http_limit_conn_ctx_t  *ctx;
+
+    ngx_conf_deprecated(cf, &ngx_conf_deprecated_limit_zone, NULL);
+
+    value = cf->args->elts;
+
+    if (value[2].data[0] != '$') {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid variable name \"%V\"", &value[2]);
+        return NGX_CONF_ERROR;
+    }
+
+    value[2].len--;
+    value[2].data++;
+
+    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
+    if (ctx == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ctx->index = ngx_http_get_variable_index(cf, &value[2]);
+    if (ctx->index == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
+
+    ctx->var = value[2];
+
+    n = ngx_parse_size(&value[3]);
+
+    if (n == NGX_ERROR) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid size of limit_zone \"%V\"", &value[3]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (n < (ngx_int_t) (8 * ngx_pagesize)) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "limit_zone \"%V\" is too small", &value[1]);
+        return NGX_CONF_ERROR;
+    }
+
+
+    shm_zone = ngx_shared_memory_add(cf, &value[1], n,
+                                     &ngx_http_limit_conn_module);
+    if (shm_zone == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (shm_zone->data) {
+        ctx = shm_zone->data;
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                        "limit_zone \"%V\" is already bound to variable \"%V\"",
+                        &value[1], &ctx->var);
+        return NGX_CONF_ERROR;
+    }
+
+    shm_zone->init = ngx_http_limit_conn_init_zone;
+    shm_zone->data = ctx;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_shm_zone_t               *shm_zone;
+    ngx_http_limit_conn_conf_t   *lccf = conf;
+    ngx_http_limit_conn_limit_t  *limit, *limits;
+
+    ngx_str_t  *value;
+    ngx_int_t   n;
+    ngx_uint_t  i;
+
+    value = cf->args->elts;
+
+    shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
+                                     &ngx_http_limit_conn_module);
+    if (shm_zone == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    limits = lccf->limits.elts;
+
+    if (limits == NULL) {
+        if (ngx_array_init(&lccf->limits, cf->pool, 1,
+                           sizeof(ngx_http_limit_conn_limit_t))
+            != NGX_OK)
+        {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    for (i = 0; i < lccf->limits.nelts; i++) {
+        if (shm_zone == limits[i].shm_zone) {
+            return "is duplicate";
+        }
+    }
+
+    n = ngx_atoi(value[2].data, value[2].len);
+    if (n <= 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid number of connections \"%V\"", &value[2]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (n > 65535) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "connection limit must be less 65536");
+        return NGX_CONF_ERROR;
+    }
+
+    limit = ngx_array_push(&lccf->limits);
+    limit->conn = n;
+    limit->shm_zone = shm_zone;
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_limit_conn_init(ngx_conf_t *cf)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_limit_conn_handler;
+
+    return NGX_OK;
+}
deleted file mode 100644
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ /dev/null
@@ -1,556 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-typedef struct {
-    u_char              color;
-    u_char              len;
-    u_short             conn;
-    u_char              data[1];
-} ngx_http_limit_zone_node_t;
-
-
-typedef struct {
-    ngx_shm_zone_t     *shm_zone;
-    ngx_rbtree_node_t  *node;
-} ngx_http_limit_zone_cleanup_t;
-
-
-typedef struct {
-    ngx_rbtree_t       *rbtree;
-    ngx_int_t           index;
-    ngx_str_t           var;
-} ngx_http_limit_zone_ctx_t;
-
-
-typedef struct {
-    ngx_shm_zone_t     *shm_zone;
-    ngx_uint_t          conn;
-    ngx_uint_t          log_level;
-} ngx_http_limit_zone_conf_t;
-
-
-static void ngx_http_limit_zone_cleanup(void *data);
-
-static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf);
-static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent,
-    void *child);
-static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf);
-
-
-static ngx_conf_enum_t  ngx_http_limit_conn_log_levels[] = {
-    { ngx_string("info"), NGX_LOG_INFO },
-    { ngx_string("notice"), NGX_LOG_NOTICE },
-    { ngx_string("warn"), NGX_LOG_WARN },
-    { ngx_string("error"), NGX_LOG_ERR },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_command_t  ngx_http_limit_zone_commands[] = {
-
-    { ngx_string("limit_zone"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
-      ngx_http_limit_zone,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("limit_conn"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
-      ngx_http_limit_conn,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      0,
-      NULL },
-
-    { ngx_string("limit_conn_log_level"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_enum_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_limit_zone_conf_t, log_level),
-      &ngx_http_limit_conn_log_levels },
-
-      ngx_null_command
-};
-
-
-static ngx_http_module_t  ngx_http_limit_zone_module_ctx = {
-    NULL,                                  /* preconfiguration */
-    ngx_http_limit_zone_init,              /* postconfiguration */
-
-    NULL,                                  /* create main configuration */
-    NULL,                                  /* init main configuration */
-
-    NULL,                                  /* create server configuration */
-    NULL,                                  /* merge server configuration */
-
-    ngx_http_limit_zone_create_conf,       /* create location configration */
-    ngx_http_limit_zone_merge_conf         /* merge location configration */
-};
-
-
-ngx_module_t  ngx_http_limit_zone_module = {
-    NGX_MODULE_V1,
-    &ngx_http_limit_zone_module_ctx,       /* module context */
-    ngx_http_limit_zone_commands,          /* module directives */
-    NGX_HTTP_MODULE,                       /* module type */
-    NULL,                                  /* init master */
-    NULL,                                  /* init module */
-    NULL,                                  /* init process */
-    NULL,                                  /* init thread */
-    NULL,                                  /* exit thread */
-    NULL,                                  /* exit process */
-    NULL,                                  /* exit master */
-    NGX_MODULE_V1_PADDING
-};
-
-
-static ngx_int_t
-ngx_http_limit_zone_handler(ngx_http_request_t *r)
-{
-    size_t                          len, n;
-    uint32_t                        hash;
-    ngx_int_t                       rc;
-    ngx_slab_pool_t                *shpool;
-    ngx_rbtree_node_t              *node, *sentinel;
-    ngx_pool_cleanup_t             *cln;
-    ngx_http_variable_value_t      *vv;
-    ngx_http_limit_zone_ctx_t      *ctx;
-    ngx_http_limit_zone_node_t     *lz;
-    ngx_http_limit_zone_conf_t     *lzcf;
-    ngx_http_limit_zone_cleanup_t  *lzcln;
-
-    if (r->main->limit_zone_set) {
-        return NGX_DECLINED;
-    }
-
-    lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module);
-
-    if (lzcf->shm_zone == NULL) {
-        return NGX_DECLINED;
-    }
-
-    ctx = lzcf->shm_zone->data;
-
-    vv = ngx_http_get_indexed_variable(r, ctx->index);
-
-    if (vv == NULL || vv->not_found) {
-        return NGX_DECLINED;
-    }
-
-    len = vv->len;
-
-    if (len == 0) {
-        return NGX_DECLINED;
-    }
-
-    if (len > 255) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "the value of the \"%V\" variable "
-                      "is more than 255 bytes: \"%v\"",
-                      &ctx->var, vv);
-        return NGX_DECLINED;
-    }
-
-    r->main->limit_zone_set = 1;
-
-    hash = ngx_crc32_short(vv->data, len);
-
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t));
-    if (cln == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr;
-
-    ngx_shmtx_lock(&shpool->mutex);
-
-    node = ctx->rbtree->root;
-    sentinel = ctx->rbtree->sentinel;
-
-    while (node != sentinel) {
-
-        if (hash < node->key) {
-            node = node->left;
-            continue;
-        }
-
-        if (hash > node->key) {
-            node = node->right;
-            continue;
-        }
-
-        /* hash == node->key */
-
-        do {
-            lz = (ngx_http_limit_zone_node_t *) &node->color;
-
-            rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len);
-
-            if (rc == 0) {
-                if ((ngx_uint_t) lz->conn < lzcf->conn) {
-                    lz->conn++;
-                    goto done;
-                }
-
-                ngx_shmtx_unlock(&shpool->mutex);
-
-                ngx_log_error(lzcf->log_level, r->connection->log, 0,
-                              "limiting connections by zone \"%V\"",
-                              &lzcf->shm_zone->shm.name);
-
-                return NGX_HTTP_SERVICE_UNAVAILABLE;
-            }
-
-            node = (rc < 0) ? node->left : node->right;
-
-        } while (node != sentinel && hash == node->key);
-
-        break;
-    }
-
-    n = offsetof(ngx_rbtree_node_t, color)
-        + offsetof(ngx_http_limit_zone_node_t, data)
-        + len;
-
-    node = ngx_slab_alloc_locked(shpool, n);
-    if (node == NULL) {
-        ngx_shmtx_unlock(&shpool->mutex);
-        return NGX_HTTP_SERVICE_UNAVAILABLE;
-    }
-
-    lz = (ngx_http_limit_zone_node_t *) &node->color;
-
-    node->key = hash;
-    lz->len = (u_char) len;
-    lz->conn = 1;
-    ngx_memcpy(lz->data, vv->data, len);
-
-    ngx_rbtree_insert(ctx->rbtree, node);
-
-done:
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "limit zone: %08XD %d", node->key, lz->conn);
-
-    ngx_shmtx_unlock(&shpool->mutex);
-
-    cln->handler = ngx_http_limit_zone_cleanup;
-    lzcln = cln->data;
-
-    lzcln->shm_zone = lzcf->shm_zone;
-    lzcln->node = node;
-
-    return NGX_DECLINED;
-}
-
-
-static void
-ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp,
-    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
-{
-    ngx_rbtree_node_t           **p;
-    ngx_http_limit_zone_node_t   *lzn, *lznt;
-
-    for ( ;; ) {
-
-        if (node->key < temp->key) {
-
-            p = &temp->left;
-
-        } else if (node->key > temp->key) {
-
-            p = &temp->right;
-
-        } else { /* node->key == temp->key */
-
-            lzn = (ngx_http_limit_zone_node_t *) &node->color;
-            lznt = (ngx_http_limit_zone_node_t *) &temp->color;
-
-            p = (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0)
-                ? &temp->left : &temp->right;
-        }
-
-        if (*p == sentinel) {
-            break;
-        }
-
-        temp = *p;
-    }
-
-    *p = node;
-    node->parent = temp;
-    node->left = sentinel;
-    node->right = sentinel;
-    ngx_rbt_red(node);
-}
-
-
-static void
-ngx_http_limit_zone_cleanup(void *data)
-{
-    ngx_http_limit_zone_cleanup_t  *lzcln = data;
-
-    ngx_slab_pool_t             *shpool;
-    ngx_rbtree_node_t           *node;
-    ngx_http_limit_zone_ctx_t   *ctx;
-    ngx_http_limit_zone_node_t  *lz;
-
-    ctx = lzcln->shm_zone->data;
-    shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr;
-    node = lzcln->node;
-    lz = (ngx_http_limit_zone_node_t *) &node->color;
-
-    ngx_shmtx_lock(&shpool->mutex);
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0,
-                   "limit zone cleanup: %08XD %d", node->key, lz->conn);
-
-    lz->conn--;
-
-    if (lz->conn == 0) {
-        ngx_rbtree_delete(ctx->rbtree, node);
-        ngx_slab_free_locked(shpool, node);
-    }
-
-    ngx_shmtx_unlock(&shpool->mutex);
-}
-
-
-static ngx_int_t
-ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data)
-{
-    ngx_http_limit_zone_ctx_t  *octx = data;
-
-    size_t                      len;
-    ngx_slab_pool_t            *shpool;
-    ngx_rbtree_node_t          *sentinel;
-    ngx_http_limit_zone_ctx_t  *ctx;
-
-    ctx = shm_zone->data;
-
-    if (octx) {
-        if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
-            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
-                          "limit_zone \"%V\" uses the \"%V\" variable "
-                          "while previously it used the \"%V\" variable",
-                          &shm_zone->shm.name, &ctx->var, &octx->var);
-            return NGX_ERROR;
-        }
-
-        ctx->rbtree = octx->rbtree;
-
-        return NGX_OK;
-    }
-
-    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
-
-    if (shm_zone->shm.exists) {
-        ctx->rbtree = shpool->data;
-
-        return NGX_OK;
-    }
-
-    ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
-    if (ctx->rbtree == NULL) {
-        return NGX_ERROR;
-    }
-
-    shpool->data = ctx->rbtree;
-
-    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_rbtree_init(ctx->rbtree, sentinel,
-                    ngx_http_limit_zone_rbtree_insert_value);
-
-    len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len;
-
-    shpool->log_ctx = ngx_slab_alloc(shpool, len);
-    if (shpool->log_ctx == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z",
-                &shm_zone->shm.name);
-
-    return NGX_OK;
-}
-
-
-static void *
-ngx_http_limit_zone_create_conf(ngx_conf_t *cf)
-{
-    ngx_http_limit_zone_conf_t  *conf;
-
-    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t));
-    if (conf == NULL) {
-        return NULL;
-    }
-
-    /*
-     * set by ngx_pcalloc():
-     *
-     *     conf->shm_zone = NULL;
-     *     conf->conn = 0;
-     */
-
-    conf->log_level = NGX_CONF_UNSET_UINT;
-
-    return conf;
-}
-
-
-static char *
-ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child)
-{
-    ngx_http_limit_zone_conf_t *prev = parent;
-    ngx_http_limit_zone_conf_t *conf = child;
-
-    if (conf->shm_zone == NULL) {
-        *conf = *prev;
-    }
-
-    ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
-
-    return NGX_CONF_OK;
-}
-
-
-static char *
-ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ssize_t                     n;
-    ngx_str_t                  *value;
-    ngx_shm_zone_t             *shm_zone;
-    ngx_http_limit_zone_ctx_t  *ctx;
-
-    value = cf->args->elts;
-
-    if (value[2].data[0] != '$') {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "invalid variable name \"%V\"", &value[2]);
-        return NGX_CONF_ERROR;
-    }
-
-    value[2].len--;
-    value[2].data++;
-
-    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t));
-    if (ctx == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ctx->index = ngx_http_get_variable_index(cf, &value[2]);
-    if (ctx->index == NGX_ERROR) {
-        return NGX_CONF_ERROR;
-    }
-
-    ctx->var = value[2];
-
-    n = ngx_parse_size(&value[3]);
-
-    if (n == NGX_ERROR) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "invalid size of limit_zone \"%V\"", &value[3]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (n < (ngx_int_t) (8 * ngx_pagesize)) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "limit_zone \"%V\" is too small", &value[1]);
-        return NGX_CONF_ERROR;
-    }
-
-
-    shm_zone = ngx_shared_memory_add(cf, &value[1], n,
-                                     &ngx_http_limit_zone_module);
-    if (shm_zone == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (shm_zone->data) {
-        ctx = shm_zone->data;
-
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                        "limit_zone \"%V\" is already bound to variable \"%V\"",
-                        &value[1], &ctx->var);
-        return NGX_CONF_ERROR;
-    }
-
-    shm_zone->init = ngx_http_limit_zone_init_zone;
-    shm_zone->data = ctx;
-
-    return NGX_CONF_OK;
-}
-
-
-static char *
-ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_http_limit_zone_conf_t  *lzcf = conf;
-
-    ngx_int_t   n;
-    ngx_str_t  *value;
-
-    if (lzcf->shm_zone) {
-        return "is duplicate";
-    }
-
-    value = cf->args->elts;
-
-    lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
-                                           &ngx_http_limit_zone_module);
-    if (lzcf->shm_zone == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    n = ngx_atoi(value[2].data, value[2].len);
-    if (n <= 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "invalid number of connections \"%V\"", &value[2]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (n > 65535) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "connection limit must be less 65536");
-        return NGX_CONF_ERROR;
-    }
-
-    lzcf->conn = n;
-
-    return NGX_CONF_OK;
-}
-
-
-static ngx_int_t
-ngx_http_limit_zone_init(ngx_conf_t *cf)
-{
-    ngx_http_handler_pt        *h;
-    ngx_http_core_main_conf_t  *cmcf;
-
-    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
-
-    h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
-    if (h == NULL) {
-        return NGX_ERROR;
-    }
-
-    *h = ngx_http_limit_zone_handler;
-
-    return NGX_OK;
-}
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -1066,7 +1066,6 @@ ngx_http_mp4_update_mdat_atom(ngx_http_m
 
     atom_data_size = mp4->mdat_data.buf->file_last - start_offset;
     mp4->mdat_data.buf->file_pos = start_offset;
-    mp4->content_length += atom_data_size;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                    "mdat new offset @%O:%O", start_offset, atom_data_size);
@@ -1083,6 +1082,8 @@ ngx_http_mp4_update_mdat_atom(ngx_http_m
         atom_header_size = sizeof(ngx_mp4_atom_header_t);
     }
 
+    mp4->content_length += atom_header_size + atom_data_size;
+
     ngx_mp4_set_32value(atom_header, atom_size);
     ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'a', 't');
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -543,6 +543,7 @@ static ngx_keyval_t  ngx_http_proxy_cach
     { ngx_string("Connection"), ngx_string("close") },
     { ngx_string("Keep-Alive"), ngx_string("") },
     { ngx_string("Expect"), ngx_string("") },
+    { ngx_string("Upgrade"), ngx_string("") },
     { ngx_string("If-Modified-Since"), ngx_string("") },
     { ngx_string("If-Unmodified-Since"), ngx_string("") },
     { ngx_string("If-None-Match"), ngx_string("") },
@@ -2493,7 +2494,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
     u_char                     *p;
     size_t                      size;
-    ngx_keyval_t               *s;
     ngx_hash_init_t             hash;
     ngx_http_core_loc_conf_t   *clcf;
     ngx_http_proxy_redirect_t  *pr;
@@ -2841,22 +2841,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
         if (ngx_http_script_compile(&sc) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
-
-        if (conf->headers_source == NULL) {
-            conf->headers_source = ngx_array_create(cf->pool, 4,
-                                                    sizeof(ngx_keyval_t));
-            if (conf->headers_source == NULL) {
-                return NGX_CONF_ERROR;
-            }
-        }
-
-        s = ngx_array_push(conf->headers_source);
-        if (s == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        ngx_str_set(&s->key, "Content-Length");
-        ngx_str_set(&s->value, "$proxy_internal_body_length");
     }
 
     if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
@@ -2875,7 +2859,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     size_t                        size;
     uintptr_t                    *code;
     ngx_uint_t                    i;
-    ngx_array_t                   headers_names;
+    ngx_array_t                   headers_names, headers_merged;
     ngx_keyval_t                 *src, *s, *h;
     ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
@@ -2891,6 +2875,8 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     }
 
     if (conf->headers_set_hash.buckets
+        && ((conf->body_source.data == NULL)
+            == (prev->body_source.data == NULL))
 #if (NGX_HTTP_CACHE)
         && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
 #endif
@@ -2906,6 +2892,12 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
         return NGX_ERROR;
     }
 
+    if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
     if (conf->headers_source == NULL) {
         conf->headers_source = ngx_array_create(cf->pool, 4,
                                                 sizeof(ngx_keyval_t));
@@ -2925,8 +2917,6 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     }
 
 
-    src = conf->headers_source->elts;
-
 #if (NGX_HTTP_CACHE)
 
     h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
@@ -2937,31 +2927,51 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
 
 #endif
 
+    src = conf->headers_source->elts;
+    for (i = 0; i < conf->headers_source->nelts; i++) {
+
+        s = ngx_array_push(&headers_merged);
+        if (s == NULL) {
+            return NGX_ERROR;
+        }
+
+        *s = src[i];
+    }
+
     while (h->key.len) {
 
-        for (i = 0; i < conf->headers_source->nelts; i++) {
+        src = headers_merged.elts;
+        for (i = 0; i < headers_merged.nelts; i++) {
             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                 goto next;
             }
         }
 
-        s = ngx_array_push(conf->headers_source);
+        s = ngx_array_push(&headers_merged);
         if (s == NULL) {
             return NGX_ERROR;
         }
 
         *s = *h;
 
-        src = conf->headers_source->elts;
-
     next:
 
         h++;
     }
 
-
-    src = conf->headers_source->elts;
-    for (i = 0; i < conf->headers_source->nelts; i++) {
+    if (conf->body_source.data) {
+        s = ngx_array_push(&headers_merged);
+        if (s == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_str_set(&s->key, "Content-Length");
+        ngx_str_set(&s->value, "$proxy_internal_body_length");
+    }
+
+
+    src = headers_merged.elts;
+    for (i = 0; i < headers_merged.nelts; i++) {
 
         hk = ngx_array_push(&headers_names);
         if (hk == NULL) {
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -43,6 +43,8 @@ static void ngx_http_scgi_finalize_reque
 static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
     void *child);
+static ngx_int_t ngx_http_scgi_merge_params(ngx_conf_t *cf,
+    ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_loc_conf_t *prev);
 
 static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -1059,17 +1061,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
     ngx_http_scgi_loc_conf_t *prev = parent;
     ngx_http_scgi_loc_conf_t *conf = child;
 
-    u_char                       *p;
     size_t                        size;
-    uintptr_t                    *code;
-    ngx_uint_t                    i;
-    ngx_array_t                   headers_names;
-    ngx_keyval_t                 *src;
-    ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
     ngx_http_core_loc_conf_t     *clcf;
-    ngx_http_script_compile_t     sc;
-    ngx_http_script_copy_code_t  *copy;
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
@@ -1307,95 +1301,146 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
         }
     }
 
-    if (conf->params_source == NULL) {
-        conf->flushes = prev->flushes;
-        conf->params_len = prev->params_len;
-        conf->params = prev->params;
-        conf->params_source = prev->params_source;
-        conf->headers_hash = prev->headers_hash;
+    if (ngx_http_scgi_merge_params(cf, conf, prev) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
 
+static ngx_int_t
+ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
+    ngx_http_scgi_loc_conf_t *prev)
+{
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i, nsrc;
+    ngx_array_t                   headers_names;
 #if (NGX_HTTP_CACHE)
-
-        if (conf->params_source == NULL) {
+    ngx_array_t                   params_merged;
+#endif
+    ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
+    ngx_hash_init_t               hash;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
 
-            if ((conf->upstream.cache == NULL)
-                == (prev->upstream.cache == NULL))
-            {
-                return NGX_CONF_OK;
-            }
+    if (conf->params_source == NULL) {
+        conf->params_source = prev->params_source;
 
-            /* 6 is a number of ngx_http_scgi_cache_headers entries */
-            conf->params_source = ngx_array_create(cf->pool, 6,
-                                                   sizeof(ngx_keyval_t));
-            if (conf->params_source == NULL) {
-                return NGX_CONF_ERROR;
-            }
+        if (prev->headers_hash.buckets
+#if (NGX_HTTP_CACHE)
+            && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+#endif
+           )
+        {
+            conf->flushes = prev->flushes;
+            conf->params_len = prev->params_len;
+            conf->params = prev->params;
+            conf->headers_hash = prev->headers_hash;
+            conf->header_params = prev->header_params;
+
+            return NGX_OK;
         }
-#else
+    }
 
-        if (conf->params_source == NULL) {
-            return NGX_CONF_OK;
-        }
-
+    if (conf->params_source == NULL
+#if (NGX_HTTP_CACHE)
+        && (conf->upstream.cache == NULL)
 #endif
+       )
+    {
+        conf->headers_hash.buckets = (void *) 1;
+        return NGX_OK;
     }
 
     conf->params_len = ngx_array_create(cf->pool, 64, 1);
     if (conf->params_len == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     conf->params = ngx_array_create(cf->pool, 512, 1);
     if (conf->params == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
-    src = conf->params_source->elts;
+    if (conf->params_source) {
+        src = conf->params_source->elts;
+        nsrc = conf->params_source->nelts;
+
+    } else {
+        src = NULL;
+        nsrc = 0;
+    }
 
 #if (NGX_HTTP_CACHE)
 
     if (conf->upstream.cache) {
         ngx_keyval_t  *h, *s;
 
-        for (h = ngx_http_scgi_cache_headers; h->key.len; h++) {
+        if (ngx_array_init(&params_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+            != NGX_OK)
+        {
+            return NGX_ERROR;
+        }
+
+        for (i = 0; i < nsrc; i++) {
 
-            for (i = 0; i < conf->params_source->nelts; i++) {
+            s = ngx_array_push(&params_merged);
+            if (s == NULL) {
+                return NGX_ERROR;
+            }
+
+            *s = src[i];
+        }
+
+        h = ngx_http_scgi_cache_headers;
+
+        while (h->key.len) {
+
+            src = params_merged.elts;
+            nsrc = params_merged.nelts;
+
+            for (i = 0; i < nsrc; i++) {
                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                     goto next;
                 }
             }
 
-            s = ngx_array_push(conf->params_source);
+            s = ngx_array_push(&params_merged);
             if (s == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             *s = *h;
 
-            src = conf->params_source->elts;
-
         next:
 
             h++;
         }
+
+        src = params_merged.elts;
+        nsrc = params_merged.nelts;
     }
 
 #endif
 
-    for (i = 0; i < conf->params_source->nelts; i++) {
+    for (i = 0; i < nsrc; i++) {
 
         if (src[i].key.len > sizeof("HTTP_") - 1
             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
         {
             hk = ngx_array_push(&headers_names);
             if (hk == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             hk->key.len = src[i].key.len - 5;
@@ -1411,7 +1456,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
         copy = ngx_array_push_n(conf->params_len,
                                 sizeof(ngx_http_script_copy_code_t));
         if (copy == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
@@ -1424,7 +1469,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
 
         copy = ngx_array_push_n(conf->params, size);
         if (copy == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         copy->code = ngx_http_script_copy_code;
@@ -1443,12 +1488,12 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
         sc.values = &conf->params;
 
         if (ngx_http_script_compile(&sc) != NGX_OK) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
         if (code == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         *code = (uintptr_t) NULL;
@@ -1456,7 +1501,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
 
         code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
         if (code == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         *code = (uintptr_t) NULL;
@@ -1464,14 +1509,14 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
 
     code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
     if (code == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     *code = (uintptr_t) NULL;
 
     code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
     if (code == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     *code = (uintptr_t) NULL;
@@ -1486,12 +1531,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
     hash.pool = cf->pool;
     hash.temp_pool = NULL;
 
-    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    return NGX_CONF_OK;
+    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
 }
 
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -139,14 +139,14 @@ static ngx_command_t  ngx_http_ssi_filte
       NULL },
 
     { ngx_string("ssi_min_file_chunk"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      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_ssi_loc_conf_t, min_file_chunk),
       NULL },
 
     { ngx_string("ssi_value_length"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      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_ssi_loc_conf_t, value_len),
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -101,7 +101,7 @@ static ngx_command_t  ngx_http_ssl_comma
       NULL },
 
     { ngx_string("ssl_verify_client"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_enum_slot,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, verify),
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -50,6 +50,8 @@ static void ngx_http_uwsgi_finalize_requ
 static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
     void *child);
+static ngx_int_t ngx_http_uwsgi_merge_params(ngx_conf_t *cf,
+    ngx_http_uwsgi_loc_conf_t *conf, ngx_http_uwsgi_loc_conf_t *prev);
 
 static char *ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -1112,17 +1114,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
     ngx_http_uwsgi_loc_conf_t *prev = parent;
     ngx_http_uwsgi_loc_conf_t *conf = child;
 
-    u_char                       *p;
     size_t                        size;
-    uintptr_t                    *code;
-    ngx_uint_t                    i;
-    ngx_array_t                   headers_names;
-    ngx_keyval_t                 *src;
-    ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
     ngx_http_core_loc_conf_t     *clcf;
-    ngx_http_script_compile_t     sc;
-    ngx_http_script_copy_code_t  *copy;
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
@@ -1365,95 +1359,146 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
     ngx_conf_merge_uint_value(conf->modifier1, prev->modifier1, 0);
     ngx_conf_merge_uint_value(conf->modifier2, prev->modifier2, 0);
 
-    if (conf->params_source == NULL) {
-        conf->flushes = prev->flushes;
-        conf->params_len = prev->params_len;
-        conf->params = prev->params;
-        conf->params_source = prev->params_source;
-        conf->headers_hash = prev->headers_hash;
+    if (ngx_http_uwsgi_merge_params(cf, conf, prev) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
 
+static ngx_int_t
+ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
+    ngx_http_uwsgi_loc_conf_t *prev)
+{
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i, nsrc;
+    ngx_array_t                   headers_names;
 #if (NGX_HTTP_CACHE)
-
-        if (conf->params_source == NULL) {
+    ngx_array_t                   params_merged;
+#endif
+    ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
+    ngx_hash_init_t               hash;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
 
-            if ((conf->upstream.cache == NULL)
-                == (prev->upstream.cache == NULL))
-            {
-                return NGX_CONF_OK;
-            }
+    if (conf->params_source == NULL) {
+        conf->params_source = prev->params_source;
 
-            /* 6 is a number of ngx_http_uwsgi_cache_headers entries */
-            conf->params_source = ngx_array_create(cf->pool, 6,
-                                                   sizeof(ngx_keyval_t));
-            if (conf->params_source == NULL) {
-                return NGX_CONF_ERROR;
-            }
+        if (prev->headers_hash.buckets
+#if (NGX_HTTP_CACHE)
+            && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+#endif
+           )
+        {
+            conf->flushes = prev->flushes;
+            conf->params_len = prev->params_len;
+            conf->params = prev->params;
+            conf->headers_hash = prev->headers_hash;
+            conf->header_params = prev->header_params;
+
+            return NGX_OK;
         }
-#else
+    }
 
-        if (conf->params_source == NULL) {
-            return NGX_CONF_OK;
-        }
-
+    if (conf->params_source == NULL
+#if (NGX_HTTP_CACHE)
+        && (conf->upstream.cache == NULL)
 #endif
+       )
+    {
+        conf->headers_hash.buckets = (void *) 1;
+        return NGX_OK;
     }
 
     conf->params_len = ngx_array_create(cf->pool, 64, 1);
     if (conf->params_len == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     conf->params = ngx_array_create(cf->pool, 512, 1);
     if (conf->params == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
-    src = conf->params_source->elts;
+    if (conf->params_source) {
+        src = conf->params_source->elts;
+        nsrc = conf->params_source->nelts;
+
+    } else {
+        src = NULL;
+        nsrc = 0;
+    }
 
 #if (NGX_HTTP_CACHE)
 
     if (conf->upstream.cache) {
         ngx_keyval_t  *h, *s;
 
-        for (h = ngx_http_uwsgi_cache_headers; h->key.len; h++) {
+        if (ngx_array_init(&params_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+            != NGX_OK)
+        {
+            return NGX_ERROR;
+        }
+
+        for (i = 0; i < nsrc; i++) {
 
-            for (i = 0; i < conf->params_source->nelts; i++) {
+            s = ngx_array_push(&params_merged);
+            if (s == NULL) {
+                return NGX_ERROR;
+            }
+
+            *s = src[i];
+        }
+
+        h = ngx_http_uwsgi_cache_headers;
+
+        while (h->key.len) {
+
+            src = params_merged.elts;
+            nsrc = params_merged.nelts;
+
+            for (i = 0; i < nsrc; i++) {
                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                     goto next;
                 }
             }
 
-            s = ngx_array_push(conf->params_source);
+            s = ngx_array_push(&params_merged);
             if (s == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             *s = *h;
 
-            src = conf->params_source->elts;
-
         next:
 
             h++;
         }
+
+        src = params_merged.elts;
+        nsrc = params_merged.nelts;
     }
 
 #endif
 
-    for (i = 0; i < conf->params_source->nelts; i++) {
+    for (i = 0; i < nsrc; i++) {
 
         if (src[i].key.len > sizeof("HTTP_") - 1
             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
         {
             hk = ngx_array_push(&headers_names);
             if (hk == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
             hk->key.len = src[i].key.len - 5;
@@ -1469,7 +1514,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
         copy = ngx_array_push_n(conf->params_len,
                                 sizeof(ngx_http_script_copy_code_t));
         if (copy == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
@@ -1482,7 +1527,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
 
         copy = ngx_array_push_n(conf->params, size);
         if (copy == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         copy->code = ngx_http_script_copy_code;
@@ -1501,12 +1546,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
         sc.values = &conf->params;
 
         if (ngx_http_script_compile(&sc) != NGX_OK) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
         if (code == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         *code = (uintptr_t) NULL;
@@ -1514,7 +1559,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
 
         code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
         if (code == NULL) {
-            return NGX_CONF_ERROR;
+            return NGX_ERROR;
         }
 
         *code = (uintptr_t) NULL;
@@ -1522,7 +1567,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
 
     code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
     if (code == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     *code = (uintptr_t) NULL;
@@ -1537,12 +1582,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
     hash.pool = cf->pool;
     hash.temp_pool = NULL;
 
-    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    return NGX_CONF_OK;
+    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
 }
 
 
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -48,7 +48,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '1.1.7';
+our $VERSION = '1.1.8';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -143,7 +143,7 @@ static ngx_conf_enum_t  ngx_http_core_if
 };
 
 
-static ngx_conf_enum_t  ngx_http_core_keepalive_disable[] = {
+static ngx_conf_bitmask_t  ngx_http_core_keepalive_disable[] = {
     { ngx_string("none"), NGX_HTTP_KEEPALIVE_DISABLE_NONE },
     { ngx_string("msie6"), NGX_HTTP_KEEPALIVE_DISABLE_MSIE6 },
     { ngx_string("safari"), NGX_HTTP_KEEPALIVE_DISABLE_SAFARI },
@@ -513,8 +513,8 @@ static ngx_command_t  ngx_http_core_comm
       NULL },
 
     { ngx_string("keepalive_disable"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_enum_slot,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+      ngx_conf_set_bitmask_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, keepalive_disable),
       &ngx_http_core_keepalive_disable },
@@ -3475,9 +3475,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_msec_value(conf->client_body_timeout,
                               prev->client_body_timeout, 60000);
 
-    ngx_conf_merge_uint_value(conf->keepalive_disable, prev->keepalive_disable,
-                              NGX_HTTP_KEEPALIVE_DISABLE_MSIE6
-                              |NGX_HTTP_KEEPALIVE_DISABLE_SAFARI);
+    ngx_conf_merge_bitmask_value(conf->keepalive_disable,
+                              prev->keepalive_disable,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6
+                               |NGX_HTTP_KEEPALIVE_DISABLE_SAFARI));
     ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
                               NGX_HTTP_SATISFY_ALL);
     ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
@@ -4398,7 +4400,7 @@ ngx_http_core_open_file_cache(ngx_conf_t
         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
 
             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
-            if (max == NGX_ERROR) {
+            if (max <= 0) {
                 goto failed;
             }
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -480,7 +480,7 @@ struct ngx_http_request_s {
      * ngx_http_limit_zone_module and ngx_http_limit_req_module
      * we use the single bits in the request structure
      */
-    unsigned                          limit_zone_set:1;
+    unsigned                          limit_conn_set:1;
     unsigned                          limit_req_set:1;
 
 #if 0
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -60,7 +60,7 @@ static ngx_command_t  ngx_mail_proxy_com
       NULL },
 
     { ngx_string("proxy_pass_error_message"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_proxy_conf_t, pass_error_message),
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -128,6 +128,7 @@ ngx_write_fd(ngx_fd_t fd, void *buf, siz
 
 #define ngx_linefeed(p)          *p++ = LF;
 #define NGX_LINEFEED_SIZE        1
+#define NGX_LINEFEED             "\x0a"
 
 
 #define ngx_rename_file(o, n)    rename((const char *) o, (const char *) n)