changeset 546:e19e5f542878 NGINX_0_8_25

nginx 0.8.25 *) Change: now no message is written in an error log if a variable is not found by $r->variable() method. *) Feature: the ngx_http_degradation_module. *) Feature: regular expression named captures. *) Feature: now URI part is not required a "proxy_pass" directive if variables are used. *) Feature: now the "msie_padding" directive works for Chrome too. *) Bugfix: a segmentation fault occurred in a worker process on low memory condition; the bug had appeared in 0.8.18. *) Bugfix: nginx sent gzipped responses to clients those do not support gzip, if "gzip_static on" and "gzip_vary off"; the bug had appeared in 0.8.16.
author Igor Sysoev <http://sysoev.ru>
date Mon, 16 Nov 2009 00:00:00 +0300
parents 91e4b06e1a01
children 43154840419e
files CHANGES CHANGES.ru auto/modules auto/options auto/sources src/core/nginx.h src/core/ngx_core.h src/core/ngx_palloc.c src/core/ngx_regex.c src/core/ngx_regex.h src/http/modules/ngx_http_degradation_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_gzip_static_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_referer_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/nginx.xs src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_script.c src/http/ngx_http_script.h src/http/ngx_http_special_response.c src/http/ngx_http_variables.c src/http/ngx_http_variables.h src/os/unix/ngx_alloc.c src/os/unix/ngx_files.c src/os/unix/ngx_files.h
diffstat 33 files changed, 945 insertions(+), 491 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,26 @@
 
+Changes with nginx 0.8.25                                        16 Nov 2009
+
+    *) Change: now no message is written in an error log if a variable is 
+       not found by $r->variable() method.
+
+    *) Feature: the ngx_http_degradation_module.
+
+    *) Feature: regular expression named captures.
+
+    *) Feature: now URI part is not required a "proxy_pass" directive if 
+       variables are used.
+
+    *) Feature: now the "msie_padding" directive works for Chrome too.
+
+    *) Bugfix: a segmentation fault occurred in a worker process on low 
+       memory condition; the bug had appeared in 0.8.18.
+
+    *) Bugfix: nginx sent gzipped responses to clients those do not support 
+       gzip, if "gzip_static on" and "gzip_vary off"; the bug had appeared 
+       in 0.8.16.
+
+
 Changes with nginx 0.8.24                                        11 Nov 2009
 
     *) Bugfix: nginx always added "Content-Encoding: gzip" response header 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,26 @@
 
+Изменения в nginx 0.8.25                                          16.11.2009
+
+    *) Изменение: теперь в лог ошибок не пишется сообщение, если переменная 
+       не найдена с помощью метода $r->variable().
+
+    *) Добавление: модуль ngx_http_degradation_module.
+
+    *) Добавление: именованные выделения в регулярных выражениях.
+
+    *) Добавление: теперь при использовании переменных в директиве 
+       proxy_pass не требуется задавать URI.
+
+    *) Добавление: теперь директива msie_padding работает и для Chrome.
+
+    *) Исправление: в рабочем процессе происходил segmentation fault при 
+       недостатке памяти; ошибка появилась в 0.8.18.
+
+    *) Исправление: nginx передавал сжатые ответы клиентам, не 
+       поддерживающим сжатие при настройках gzip_static on и gzip_vary off; 
+       ошибка появилась в 0.8.16.
+
+
 Изменения в nginx 0.8.24                                          11.11.2009
 
     *) Исправление: nginx всегда добавлял строку "Content-Encoding: gzip" в 
--- a/auto/modules
+++ b/auto/modules
@@ -316,6 +316,11 @@ if [ $HTTP_SECURE_LINK = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_SECURE_LINK_SRCS"
 fi
 
+if [ $HTTP_DEGRADATION = YES ]; then
+    HTTP_MODULES="$HTTP_MODULES $HTTP_DEGRADATION_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_DEGRADATION_SRCS"
+fi
+
 if [ $HTTP_FLV = YES ]; then
     HTTP_MODULES="$HTTP_MODULES $HTTP_FLV_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS"
--- a/auto/options
+++ b/auto/options
@@ -85,6 +85,7 @@ HTTP_LIMIT_REQ=YES
 HTTP_EMPTY_GIF=YES
 HTTP_BROWSER=YES
 HTTP_SECURE_LINK=NO
+HTTP_DEGRADATION=NO
 HTTP_FLV=NO
 HTTP_GZIP_STATIC=NO
 HTTP_UPSTREAM_IP_HASH=YES
@@ -194,6 +195,7 @@ do
         --with-http_gzip_static_module)  HTTP_GZIP_STATIC=YES       ;;
         --with-http_random_index_module) HTTP_RANDOM_INDEX=YES      ;;
         --with-http_secure_link_module)  HTTP_SECURE_LINK=YES       ;;
+        --with-http_degradation_module)  HTTP_DEGRADATION=YES       ;;
 
         --without-http_charset_module)   HTTP_CHARSET=NO            ;;
         --without-http_gzip_module)      HTTP_GZIP=NO               ;;
@@ -322,6 +324,7 @@ cat << END
   --with-http_gzip_static_module     enable ngx_http_gzip_static_module
   --with-http_random_index_module    enable ngx_http_random_index_module
   --with-http_secure_link_module     enable ngx_http_secure_link_module
+  --with-http_degradation_module     enable ngx_http_degradation_module
   --with-http_stub_status_module     enable ngx_http_stub_status_module
 
   --without-http_charset_module      disable ngx_http_charset_module
--- a/auto/sources
+++ b/auto/sources
@@ -438,6 +438,10 @@ HTTP_SECURE_LINK_MODULE=ngx_http_secure_
 HTTP_SECURE_LINK_SRCS=src/http/modules/ngx_http_secure_link_module.c
 
 
+HTTP_DEGRADATION_MODULE=ngx_http_degradation_module
+HTTP_DEGRADATION_SRCS=src/http/modules/ngx_http_degradation_module.c
+
+
 HTTP_FLV_MODULE=ngx_http_flv_module
 HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8024
-#define NGINX_VERSION      "0.8.24"
+#define nginx_version         8025
+#define NGINX_VERSION      "0.8.25"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -83,7 +83,9 @@ typedef void (*ngx_connection_handler_pt
 #define CRLF   "\x0d\x0a"
 
 
-#define ngx_abs(value)   (((value) >= 0) ? (value) : - (value))
+#define ngx_abs(value)       (((value) >= 0) ? (value) : - (value))
+#define ngx_max(val1, val2)  ((val1 < val2) ? (val2) : (val1))
+#define ngx_min(val1, val2)  ((val1 > val2) ? (val2) : (val1))
 
 void ngx_cpuinfo(void);
 
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -17,7 +17,7 @@ ngx_create_pool(size_t size, ngx_log_t *
 {
     ngx_pool_t  *p;
 
-    p = ngx_memalign(ngx_pagesize, size, log);
+    p = ngx_memalign(ngx_min(ngx_pagesize, size), size, log);
     if (p == NULL) {
         return NULL;
     }
@@ -181,7 +181,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_
 
     psize = (size_t) (pool->d.end - (u_char *) pool);
 
-    m = ngx_memalign(ngx_pagesize, psize, pool->log);
+    m = ngx_memalign(ngx_min(ngx_pagesize, psize), psize, pool->log);
     if (m == NULL) {
         return NULL;
     }
@@ -219,7 +219,7 @@ ngx_palloc_large(ngx_pool_t *pool, size_
     ngx_uint_t         n;
     ngx_pool_large_t  *large;
 
-    p = ngx_memalign(ngx_pagesize, size, pool->log);
+    p = ngx_alloc(size, pool->log);
     if (p == NULL) {
         return NULL;
     }
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -23,25 +23,16 @@ ngx_regex_init(void)
 }
 
 
-ngx_regex_t *
-ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, ngx_pool_t *pool,
-    ngx_str_t *err)
+static ngx_inline void
+ngx_regex_malloc_init(ngx_pool_t *pool)
 {
-    int              erroff;
-    const char      *errstr;
-    ngx_regex_t     *re;
 #if (NGX_THREADS)
     ngx_core_tls_t  *tls;
 
-#if (NGX_SUPPRESS_WARN)
-    tls = NULL;
-#endif
-
     if (ngx_threaded) {
         tls = ngx_thread_get_tls(ngx_core_tls_key);
         tls->pool = pool;
-    } else {
-        ngx_pcre_pool = pool;
+        return;
     }
 
 #else
@@ -49,35 +40,103 @@ ngx_regex_compile(ngx_str_t *pattern, ng
     ngx_pcre_pool = pool;
 
 #endif
+}
 
-    re = pcre_compile((const char *) pattern->data, (int) options,
+
+static ngx_inline void
+ngx_regex_malloc_done(void)
+{
+#if (NGX_THREADS)
+    ngx_core_tls_t  *tls;
+
+    if (ngx_threaded) {
+        tls = ngx_thread_get_tls(ngx_core_tls_key);
+        tls->pool = NULL;
+        return;
+    }
+
+#else
+
+    ngx_pcre_pool = NULL;
+
+#endif
+}
+
+
+ngx_int_t
+ngx_regex_compile(ngx_regex_compile_t *rc)
+{
+    int           n, erroff;
+    char         *p;
+    const char   *errstr;
+    ngx_regex_t  *re;
+
+    ngx_regex_malloc_init(rc->pool);
+
+    re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
                       &errstr, &erroff, NULL);
 
+    /* ensure that there is no current pool */
+    ngx_regex_malloc_done();
+
     if (re == NULL) {
-       if ((size_t) erroff == pattern->len) {
-           ngx_snprintf(err->data, err->len - 1,
-                        "pcre_compile() failed: %s in \"%s\"%Z",
-                        errstr, pattern->data);
+        if ((size_t) erroff == rc->pattern.len) {
+           rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                              "pcre_compile() failed: %s in \"%V\"",
+                               errstr, &rc->pattern)
+                      - rc->err.data;
+
         } else {
-           ngx_snprintf(err->data, err->len - 1,
-                        "pcre_compile() failed: %s in \"%s\" at \"%s\"%Z",
-                        errstr, pattern->data, pattern->data + erroff);
+           rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                              "pcre_compile() failed: %s in \"%V\" at \"%s\"",
+                               errstr, &rc->pattern, rc->pattern.data + erroff)
+                      - rc->err.data;
         }
+
+        return NGX_ERROR;
+    }
+
+    rc->regex = re;
+
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
+        goto failed;
+    }
+
+    if (rc->captures == 0) {
+        return NGX_OK;
     }
 
-    /* ensure that there is no current pool */
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d";
+        goto failed;
+    }
+
+    if (rc->named_captures == 0) {
+        return NGX_OK;
+    }
 
-#if (NGX_THREADS)
-    if (ngx_threaded) {
-        tls->pool = NULL;
-    } else {
-        ngx_pcre_pool = NULL;
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d";
+        goto failed;
     }
-#else
-    ngx_pcre_pool = NULL;
-#endif
+
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d";
+        goto failed;
+    }
 
-    return re;
+    return NGX_OK;
+
+failed:
+
+    rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
+                  - rc->err.data;
+    return NGX_OK;
 }
 
 
@@ -99,22 +158,6 @@ ngx_regex_capture_count(ngx_regex_t *re)
 
 
 ngx_int_t
-ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_int_t size)
-{
-    int  rc;
-
-    rc = pcre_exec(re, NULL, (const char *) s->data, s->len, 0, 0,
-                   captures, size);
-
-    if (rc == -1) {
-        return NGX_REGEX_NO_MATCHED;
-    }
-
-    return rc;
-}
-
-
-ngx_int_t
 ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
 {
     ngx_int_t         n;
@@ -133,7 +176,7 @@ ngx_regex_exec_array(ngx_array_t *a, ngx
 
         if (n < 0) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
-                          ngx_regex_exec_n " failed: %d on \"%V\" using \"%s\"",
+                          ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"",
                           n, s, re[i].name);
             return NGX_ERROR;
         }
@@ -157,11 +200,15 @@ ngx_regex_malloc(size_t size)
     if (ngx_threaded) {
         tls = ngx_thread_get_tls(ngx_core_tls_key);
         pool = tls->pool;
+
     } else {
         pool = ngx_pcre_pool;
     }
+
 #else
+
     pool = ngx_pcre_pool;
+
 #endif
 
     if (pool) {
--- a/src/core/ngx_regex.h
+++ b/src/core/ngx_regex.h
@@ -14,29 +14,42 @@
 #include <pcre.h>
 
 
-#define NGX_REGEX_NO_MATCHED  -1000
+#define NGX_REGEX_NO_MATCHED  PCRE_ERROR_NOMATCH   /* -1 */
 
 #define NGX_REGEX_CASELESS    PCRE_CASELESS
 
 typedef pcre  ngx_regex_t;
 
+
 typedef struct {
-    ngx_regex_t   *regex;
-    u_char        *name;
+    ngx_str_t     pattern;
+    ngx_pool_t   *pool;
+    ngx_int_t     options;
+
+    ngx_regex_t  *regex;
+    int           captures;
+    int           named_captures;
+    int           name_size;
+    u_char       *names;
+    ngx_str_t     err;
+} ngx_regex_compile_t;
+
+
+typedef struct {
+    ngx_regex_t  *regex;
+    u_char       *name;
 } ngx_regex_elt_t;
 
 
 void ngx_regex_init(void);
-ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options,
-    ngx_pool_t *pool, ngx_str_t *err);
-ngx_int_t ngx_regex_capture_count(ngx_regex_t *re);
-ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures,
-    ngx_int_t size);
+ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc);
+
+#define ngx_regex_exec(re, s, captures, size)                                \
+    pcre_exec(re, NULL, (const char *) (s)->data, (s)->len, 0, 0,            \
+              captures, size)
+#define ngx_regex_exec_n      "pcre_exec()"
+
 ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
 
 
-#define ngx_regex_exec_n           "pcre_exec()"
-#define ngx_regex_capture_count_n  "pcre_fullinfo()"
-
-
 #endif /* _NGX_REGEX_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_degradation_module.c
@@ -0,0 +1,223 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    size_t      sbrk_size;
+} ngx_http_degradation_main_conf_t;
+
+
+typedef struct {
+    ngx_uint_t  degrade;
+} ngx_http_degradation_loc_conf_t;
+
+
+static ngx_conf_enum_t  ngx_http_degrade[] = {
+    { ngx_string("204"), 204 },
+    { ngx_string("444"), 444 },
+    { ngx_null_string, 0 }
+};
+
+
+static void *ngx_http_degradation_create_main_conf(ngx_conf_t *cf);
+static void *ngx_http_degradation_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_degradation_merge_loc_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+static char *ngx_http_degradation(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static ngx_int_t ngx_http_degradation_init(ngx_conf_t *cf);
+
+
+static ngx_command_t  ngx_http_degradation_commands[] = {
+
+    { ngx_string("degradation"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_http_degradation,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("degrade"),
+      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_degradation_loc_conf_t, degrade),
+      &ngx_http_degrade },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_degradation_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_degradation_init,             /* postconfiguration */
+
+    ngx_http_degradation_create_main_conf, /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_degradation_create_loc_conf,  /* create location configuration */
+    ngx_http_degradation_merge_loc_conf    /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_degradation_module = {
+    NGX_MODULE_V1,
+    &ngx_http_degradation_module_ctx,      /* module context */
+    ngx_http_degradation_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_degradation_handler(ngx_http_request_t *r)
+{
+    time_t                             now;
+    static size_t                      sbrk_size;
+    static time_t                      sbrk_time;
+    ngx_http_degradation_loc_conf_t   *dlcf;
+    ngx_http_degradation_main_conf_t  *dmcf;
+
+    dlcf = ngx_http_get_module_loc_conf(r, ngx_http_degradation_module);
+
+    if (dlcf->degrade == 0) {
+        return NGX_DECLINED;
+    }
+
+    dmcf = ngx_http_get_module_main_conf(r, ngx_http_degradation_module);
+
+    if (dmcf->sbrk_size) {
+
+        now = ngx_time();
+
+        /* lock mutex */
+
+        if (now != sbrk_time) {
+
+            /*
+             * ELF/i386 is loaded at 0x08000000, 128M
+             * ELF/amd64 is loaded at 0x00400000, 4M
+             *
+             * use a function address to substract the loading address
+             */
+
+            sbrk_size = (size_t) sbrk(0) - ((uintptr_t) ngx_palloc & ~0x3FFFFF);
+            sbrk_time = now;
+        }
+
+        /* unlock mutex */
+
+        if (sbrk_size >= dmcf->sbrk_size) {
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "degradation sbrk: %uz", sbrk_size);
+
+            return dlcf->degrade;
+        }
+    }
+
+    return NGX_DECLINED;
+}
+
+
+static void *
+ngx_http_degradation_create_main_conf(ngx_conf_t *cf)
+{
+    ngx_http_degradation_main_conf_t  *dmcf;
+
+    dmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_degradation_main_conf_t));
+    if (dmcf == NULL) {
+        return NULL;
+    }
+
+    return dmcf;
+}
+
+
+static void *
+ngx_http_degradation_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_degradation_loc_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_degradation_loc_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    conf->degrade = NGX_CONF_UNSET_UINT;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_degradation_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_degradation_loc_conf_t  *prev = parent;
+    ngx_http_degradation_loc_conf_t  *conf = child;
+
+    ngx_conf_merge_uint_value(conf->degrade, prev->degrade, 0);
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_degradation(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_degradation_main_conf_t  *dmcf = conf;
+
+    ngx_str_t  *value, s;
+
+    value = cf->args->elts;
+
+    if (ngx_strncmp(value[1].data, "sbrk=", 5) == 0) {
+
+        s.len = value[1].len - 5;
+        s.data = value[1].data + 5;
+
+        dmcf->sbrk_size = ngx_parse_size(&s);
+        if (dmcf->sbrk_size == (size_t) NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid sbrk size \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_degradation_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_degradation_handler;
+
+    return NGX_OK;
+}
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2407,27 +2407,25 @@ ngx_http_fastcgi_split(ngx_http_request_
 
     n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
 
+    if (n >= 0) { /* match */
+        f->script_name.len = captures[3] - captures[2];
+        f->script_name.data = r->uri.data;
+
+        f->path_info.len = captures[5] - captures[4];
+        f->path_info.data = r->uri.data + f->script_name.len;
+
+        return f;
+    }
+
     if (n == NGX_REGEX_NO_MATCHED) {
         f->script_name = r->uri;
         return f;
     }
 
-    if (n < 0) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
-                      n, &r->uri, &flcf->split_name);
-        return NULL;
-    }
-
-    /* match */
-
-    f->script_name.len = captures[3] - captures[2];
-    f->script_name.data = r->uri.data;
-
-    f->path_info.len = captures[5] - captures[4];
-    f->path_info.data = r->uri.data + f->script_name.len;
-
-    return f;
+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                  ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
+                  n, &r->uri, &flcf->split_name);
+    return NULL;
 
 #else
 
@@ -2518,39 +2516,34 @@ ngx_http_fastcgi_split_path_info(ngx_con
 #if (NGX_PCRE)
     ngx_http_fastcgi_loc_conf_t *flcf = conf;
 
-    ngx_int_t   n;
-    ngx_str_t  *value, err;
-    u_char      errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t            *value;
+    ngx_regex_compile_t   rc;
+    u_char                errstr[NGX_MAX_CONF_ERRSTR];
 
     value = cf->args->elts;
 
     flcf->split_name = value[1];
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
-
-    flcf->split_regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
-
-    if (flcf->split_regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pattern = value[1];
+    rc.pool = cf->pool;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
+
+    if (ngx_regex_compile(&rc) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
         return NGX_CONF_ERROR;
     }
 
-    n = ngx_regex_capture_count(flcf->split_regex);
-
-    if (n < 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           ngx_regex_capture_count_n " failed for "
-                           "pattern \"%V\"", &value[1]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (n != 2) {
+    if (rc.captures != 2) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "pattern \"%V\" must have 2 captures", &value[1]);
         return NGX_CONF_ERROR;
     }
 
+    flcf->split_regex = rc.regex;
+
     return NGX_CONF_OK;
 
 #else
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -243,20 +243,30 @@ ngx_http_gzip_header_filter(ngx_http_req
     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
     if (!conf->enable
+        || r->header_only
         || (r->headers_out.status != NGX_HTTP_OK
             && r->headers_out.status != NGX_HTTP_FORBIDDEN
             && r->headers_out.status != NGX_HTTP_NOT_FOUND)
-        || r->header_only
         || (r->headers_out.content_encoding
             && r->headers_out.content_encoding->value.len)
         || (r->headers_out.content_length_n != -1
             && r->headers_out.content_length_n < conf->min_length)
-        || ngx_http_test_content_type(r, &conf->types) == NULL
-        || ngx_http_gzip_ok(r) != NGX_OK)
+        || ngx_http_test_content_type(r, &conf->types) == NULL)
     {
         return ngx_http_next_header_filter(r);
     }
 
+    r->gzip_vary = 1;
+
+    if (!r->gzip_tested) {
+        if (ngx_http_gzip_ok(r) != NGX_OK) {
+            return ngx_http_next_header_filter(r);
+        }
+
+    } else if (!r->gzip_ok) {
+        return ngx_http_next_header_filter(r);
+    }
+
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -99,9 +99,11 @@ ngx_http_gzip_static_handler(ngx_http_re
         return NGX_DECLINED;
     }
 
+    rc = ngx_http_gzip_ok(r);
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) {
+    if (!clcf->gzip_vary && rc != NGX_OK) {
         return NGX_DECLINED;
     }
 
@@ -143,7 +145,6 @@ ngx_http_gzip_static_handler(ngx_http_re
         case NGX_ENOTDIR:
         case NGX_ENAMETOOLONG:
 
-            r->gzip = 0;
             return NGX_DECLINED;
 
         case NGX_EACCES:
@@ -163,6 +164,12 @@ ngx_http_gzip_static_handler(ngx_http_re
         return NGX_DECLINED;
     }
 
+    r->gzip_vary = 1;
+
+    if (rc != NGX_OK) {
+        return NGX_DECLINED;
+    }
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
 
     if (of.is_dir) {
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -724,17 +724,22 @@ ngx_http_proxy_eval(ngx_http_request_t *
         return NGX_ERROR;
     }
 
-    if (url.uri.len && url.uri.data[0] == '?') {
-        p = ngx_pnalloc(r->pool, url.uri.len + 1);
-        if (p == NULL) {
-            return NGX_ERROR;
+    if (url.uri.len) {
+        if (url.uri.data[0] == '?') {
+            p = ngx_pnalloc(r->pool, url.uri.len + 1);
+            if (p == NULL) {
+                return NGX_ERROR;
+            }
+
+            *p++ = '/';
+            ngx_memcpy(p, url.uri.data, url.uri.len);
+
+            url.uri.len++;
+            url.uri.data = p - 1;
         }
 
-        *p++ = '/';
-        ngx_memcpy(p, url.uri.data, url.uri.len);
-
-        url.uri.len++;
-        url.uri.data = p - 1;
+    } else {
+        url.uri = r->unparsed_uri;
     }
 
     ctx->vars.key_start = u->schema;
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -412,7 +412,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
                 if (sn[n].regex) {
 
                     if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name,
-                                                   sn[n].regex)
+                                                   sn[n].regex->regex)
                         != NGX_OK)
                     {
                         return NGX_CONF_ERROR;
@@ -502,9 +502,9 @@ ngx_http_add_regex_referer(ngx_conf_t *c
     ngx_str_t *name, ngx_regex_t *regex)
 {
 #if (NGX_PCRE)
-    ngx_str_t         err;
-    ngx_regex_elt_t  *re;
-    u_char            errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_regex_elt_t      *re;
+    ngx_regex_compile_t   rc;
+    u_char                errstr[NGX_MAX_CONF_ERRSTR];
 
     if (name->len == 1) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name);
@@ -530,19 +530,23 @@ ngx_http_add_regex_referer(ngx_conf_t *c
         return NGX_CONF_OK;
     }
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
-
     name->len--;
     name->data++;
 
-    re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err);
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
 
-    if (re->regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+    rc.pattern = *name;
+    rc.pool = cf->pool;
+    rc.options = NGX_REGEX_CASELESS;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
+
+    if (ngx_regex_compile(&rc) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
         return NGX_CONF_ERROR;
     }
 
+    re->regex = rc.regex;
     re->name = name->data;
 
     return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -294,9 +294,9 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 {
     ngx_http_rewrite_loc_conf_t  *lcf = conf;
 
-    ngx_str_t                         *value, err;
-    ngx_int_t                          n;
+    ngx_str_t                         *value;
     ngx_uint_t                         last;
+    ngx_regex_compile_t                rc;
     ngx_http_script_code_pt           *code;
     ngx_http_script_compile_t          sc;
     ngx_http_script_regex_code_t      *regex;
@@ -313,15 +313,16 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 
     value = cf->args->elts;
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pattern = value[1];
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
 
     /* TODO: NGX_REGEX_CASELESS */
 
-    regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
-
+    regex->regex = ngx_http_regex_compile(cf, &rc);
     if (regex->regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
         return NGX_CONF_ERROR;
     }
 
@@ -394,7 +395,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 
     regex = sc.main;
 
-    regex->ncaptures = sc.ncaptures;
     regex->size = sc.size;
     regex->args = sc.args;
 
@@ -402,31 +402,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
         regex->lengths = NULL;
     }
 
-    n = ngx_regex_capture_count(regex->regex);
-
-    if (n < 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           ngx_regex_capture_count_n " failed for "
-                           "pattern \"%V\"", &value[1]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (regex->ncaptures > (ngx_uint_t) n) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "pattern \"%V\" has less captures "
-                           "than referrenced in substitution \"%V\"",
-                           &value[1], &value[2]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (regex->ncaptures < (ngx_uint_t) n) {
-        regex->ncaptures = (ngx_uint_t) n;
-    }
-
-    if (regex->ncaptures) {
-        regex->ncaptures = (regex->ncaptures + 1) * 3;
-    }
-
     regex_end = ngx_http_script_add_code(lcf->codes,
                                       sizeof(ngx_http_script_regex_end_code_t),
                                       &regex);
@@ -624,8 +599,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t
 {
     u_char                        *p;
     size_t                         len;
-    ngx_str_t                     *value, err;
-    ngx_uint_t                     cur, last, n;
+    ngx_str_t                     *value;
+    ngx_uint_t                     cur, last;
+    ngx_regex_compile_t            rc;
     ngx_http_script_code_pt       *code;
     ngx_http_script_file_code_t   *fop;
     ngx_http_script_regex_code_t  *regex;
@@ -733,15 +709,15 @@ ngx_http_rewrite_if_condition(ngx_conf_t
 
             ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
 
-            err.len = NGX_MAX_CONF_ERRSTR;
-            err.data = errstr;
+            ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
 
-            regex->regex = ngx_regex_compile(&value[last],
-                                  (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0,
-                                   cf->pool, &err);
+            rc.pattern = value[last];
+            rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
+            rc.err.len = NGX_MAX_CONF_ERRSTR;
+            rc.err.data = errstr;
 
+            regex->regex = ngx_http_regex_compile(cf, &rc);
             if (regex->regex == NULL) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
                 return NGX_CONF_ERROR;
             }
 
@@ -753,12 +729,6 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             }
             regex->name = value[last];
 
-            n = ngx_regex_capture_count(regex->regex);
-
-            if (n) {
-                regex->ncaptures = (n + 1) * 3;
-            }
-
             return NGX_CONF_OK;
         }
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -2450,27 +2450,28 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
 
     } else {
 #if (NGX_PCRE)
-        ngx_str_t     err;
-        ngx_regex_t  *regex;
-        u_char        errstr[NGX_MAX_CONF_ERRSTR];
-
-        err.len = NGX_MAX_CONF_ERRSTR;
-        err.data = errstr;
+        ngx_regex_compile_t  rgc;
+        u_char               errstr[NGX_MAX_CONF_ERRSTR];
 
         right.data[right.len] = '\0';
 
-        regex = ngx_regex_compile(&right, 0, r->pool, &err);
-
-        if (regex == NULL) {
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", err.data);
+        ngx_memzero(&rgc, sizeof(ngx_regex_compile_t));
+
+        rgc.pattern = right;
+        rgc.pool = r->pool;
+        rgc.err.len = NGX_MAX_CONF_ERRSTR;
+        rgc.err.data = errstr;
+
+        if (ngx_regex_compile(&rgc) != NGX_OK) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err);
             return NGX_HTTP_SSI_ERROR;
         }
 
-        rc = ngx_regex_exec(regex, &left, NULL, 0);
-
-        if (rc != NGX_REGEX_NO_MATCHED && rc < 0) {
+        rc = ngx_regex_exec(rgc.regex, &left, NULL, 0);
+
+        if (rc < NGX_REGEX_NO_MATCHED) {
             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                          ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
+                          ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
                           rc, &left, &right);
             return NGX_HTTP_SSI_ERROR;
         }
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.24';
+our $VERSION = '0.8.25';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -902,9 +902,6 @@ variable(r, name, value = NULL)
             XSRETURN_UNDEF;
         }
 
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "variable \"%V\" not found", &var);
-
         XSRETURN_UNDEF;
     }
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -812,7 +812,11 @@ ngx_http_handler(ngx_http_request_t *r)
     }
 
     r->valid_location = 1;
-    r->gzip = 0;
+#if (NGX_HTTP_GZIP)
+    r->gzip_tested = 0;
+    r->gzip_ok = 0;
+    r->gzip_vary = 0;
+#endif
 
     r->write_event_handler = ngx_http_core_run_phases;
     ngx_http_core_run_phases(r);
@@ -1416,7 +1420,7 @@ ngx_http_core_find_location(ngx_http_req
     ngx_int_t                  rc;
     ngx_http_core_loc_conf_t  *pclcf;
 #if (NGX_PCRE)
-    ngx_int_t                  n, len;
+    ngx_int_t                  n;
     ngx_uint_t                 noregex;
     ngx_http_core_loc_conf_t  *clcf, **clcfp;
 
@@ -1450,51 +1454,28 @@ ngx_http_core_find_location(ngx_http_req
 
     if (noregex == 0 && pclcf->regex_locations) {
 
-        len = 0;
-
         for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) {
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "test location: ~ \"%V\"", &(*clcfp)->name);
 
-            if ((*clcfp)->captures) {
-
-                len = (NGX_HTTP_MAX_CAPTURES + 1) * 3;
-
-                if (r->captures == NULL) {
-                    r->captures = ngx_palloc(r->pool, len * sizeof(int));
-                    if (r->captures == NULL) {
-                        return NGX_ERROR;
-                    }
-                }
+            n = ngx_http_regex_exec(r, (*clcfp)->regex, &r->uri);
+
+            if (n == NGX_OK) {
+                r->loc_conf = (*clcfp)->loc_conf;
+
+                /* look up nested locations */
+
+                rc = ngx_http_core_find_location(r);
+
+                return (rc == NGX_ERROR) ? rc : NGX_OK;
             }
 
-            n = ngx_regex_exec((*clcfp)->regex, &r->uri, r->captures, len);
-
-            if (n == NGX_REGEX_NO_MATCHED) {
+            if (n == NGX_DECLINED) {
                 continue;
             }
 
-            if (n < 0) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                              ngx_regex_exec_n
-                              " failed: %d on \"%V\" using \"%V\"",
-                              n, &r->uri, &(*clcfp)->name);
-                return NGX_ERROR;
-            }
-
-            /* match */
-
-            r->loc_conf = (*clcfp)->loc_conf;
-
-            r->ncaptures = len;
-            r->captures_data = r->uri.data;
-
-            /* look up nested locations */
-
-            rc = ngx_http_core_find_location(r);
-
-            return (rc == NGX_ERROR) ? rc : NGX_OK;
+            return NGX_ERROR;
         }
     }
 #endif
@@ -1774,7 +1755,7 @@ ngx_http_map_uri_to_path(ngx_http_reques
 #if (NGX_PCRE)
         ngx_uint_t  captures;
 
-        captures = alias && clcf->captures;
+        captures = alias && clcf->regex;
         reserved += captures ? 1 : r->uri.len - alias + 1;
 #else
         reserved += r->uri.len - alias + 1;
@@ -1891,15 +1872,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
     ngx_table_elt_t           *e, *d;
     ngx_http_core_loc_conf_t  *clcf;
 
-    if (r->gzip == 1) {
-        return NGX_OK;
-    }
-
-    if (r->gzip == 2) {
-        return NGX_DECLINED;
-    }
-
-    r->gzip = 2;
+    r->gzip_tested = 1;
 
     if (r != r->main
         || r->headers_in.accept_encoding == NULL
@@ -2034,7 +2007,7 @@ ok:
 
 #endif
 
-    r->gzip = 1;
+    r->gzip_ok = 1;
 
     return NGX_OK;
 }
@@ -2600,26 +2573,25 @@ ngx_http_core_regex_location(ngx_conf_t 
     ngx_str_t *regex, ngx_uint_t caseless)
 {
 #if (NGX_PCRE)
-    ngx_str_t  err;
-    u_char     errstr[NGX_MAX_CONF_ERRSTR];
-
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
+    ngx_regex_compile_t  rc;
+    u_char               errstr[NGX_MAX_CONF_ERRSTR];
+
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pattern = *regex;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
 
 #if (NGX_HAVE_CASELESS_FILESYSTEM)
-    caseless = 1;
+    rc.options = NGX_REGEX_CASELESS;
 #endif
 
-    clcf->regex = ngx_regex_compile(regex, caseless ? NGX_REGEX_CASELESS: 0,
-                                    cf->pool, &err);
-
+    clcf->regex = ngx_http_regex_compile(cf, &rc);
     if (clcf->regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
         return NGX_ERROR;
     }
 
     clcf->name = *regex;
-    clcf->captures = (ngx_regex_capture_count(clcf->regex) > 0);
 
     return NGX_OK;
 
@@ -2637,14 +2609,14 @@ ngx_http_core_regex_location(ngx_conf_t 
 static char *
 ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     char        *rv;
     ngx_conf_t   save;
 
-    if (lcf->types == NULL) {
-        lcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
-        if (lcf->types == NULL) {
+    if (clcf->types == NULL) {
+        clcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
+        if (clcf->types == NULL) {
             return NGX_CONF_ERROR;
         }
     }
@@ -2664,7 +2636,7 @@ ngx_http_core_types(ngx_conf_t *cf, ngx_
 static char *
 ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t       *value, *content_type, *old, file;
     ngx_uint_t       i, n, hash;
@@ -2695,8 +2667,8 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c
 
         hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
 
-        type = lcf->types->elts;
-        for (n = 0; n < lcf->types->nelts; n++) {
+        type = clcf->types->elts;
+        for (n = 0; n < clcf->types->nelts; n++) {
             if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {
                 old = type[n].value;
                 type[n].value = content_type;
@@ -2711,7 +2683,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c
         }
 
 
-        type = ngx_array_push(lcf->types);
+        type = ngx_array_push(clcf->types);
         if (type == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -2916,89 +2888,89 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
 static void *
 ngx_http_core_create_loc_conf(ngx_conf_t *cf)
 {
-    ngx_http_core_loc_conf_t  *lcf;
-
-    lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
-    if (lcf == NULL) {
+    ngx_http_core_loc_conf_t  *clcf;
+
+    clcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
+    if (clcf == NULL) {
         return NULL;
     }
 
     /*
      * set by ngx_pcalloc():
      *
-     *     lcf->root = { 0, NULL };
-     *     lcf->limit_except = 0;
-     *     lcf->post_action = { 0, NULL };
-     *     lcf->types = NULL;
-     *     lcf->default_type = { 0, NULL };
-     *     lcf->error_log = NULL;
-     *     lcf->error_pages = NULL;
-     *     lcf->try_files = NULL;
-     *     lcf->client_body_path = NULL;
-     *     lcf->regex = NULL;
-     *     lcf->exact_match = 0;
-     *     lcf->auto_redirect = 0;
-     *     lcf->alias = 0;
-     *     lcf->gzip_proxied = 0;
+     *     clcf->root = { 0, NULL };
+     *     clcf->limit_except = 0;
+     *     clcf->post_action = { 0, NULL };
+     *     clcf->types = NULL;
+     *     clcf->default_type = { 0, NULL };
+     *     clcf->error_log = NULL;
+     *     clcf->error_pages = NULL;
+     *     clcf->try_files = NULL;
+     *     clcf->client_body_path = NULL;
+     *     clcf->regex = NULL;
+     *     clcf->exact_match = 0;
+     *     clcf->auto_redirect = 0;
+     *     clcf->alias = 0;
+     *     clcf->gzip_proxied = 0;
      */
 
-    lcf->client_max_body_size = NGX_CONF_UNSET;
-    lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
-    lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
-    lcf->satisfy = NGX_CONF_UNSET_UINT;
-    lcf->if_modified_since = NGX_CONF_UNSET_UINT;
-    lcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
-    lcf->client_body_in_single_buffer = NGX_CONF_UNSET;
-    lcf->internal = NGX_CONF_UNSET;
-    lcf->sendfile = NGX_CONF_UNSET;
-    lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
+    clcf->client_max_body_size = NGX_CONF_UNSET;
+    clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
+    clcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->satisfy = NGX_CONF_UNSET_UINT;
+    clcf->if_modified_since = NGX_CONF_UNSET_UINT;
+    clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
+    clcf->client_body_in_single_buffer = NGX_CONF_UNSET;
+    clcf->internal = NGX_CONF_UNSET;
+    clcf->sendfile = NGX_CONF_UNSET;
+    clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
 #if (NGX_HAVE_FILE_AIO)
-    lcf->aio = NGX_CONF_UNSET;
+    clcf->aio = NGX_CONF_UNSET;
 #endif
-    lcf->read_ahead = NGX_CONF_UNSET_SIZE;
-    lcf->directio = NGX_CONF_UNSET;
-    lcf->directio_alignment = NGX_CONF_UNSET;
-    lcf->tcp_nopush = NGX_CONF_UNSET;
-    lcf->tcp_nodelay = NGX_CONF_UNSET;
-    lcf->send_timeout = NGX_CONF_UNSET_MSEC;
-    lcf->send_lowat = NGX_CONF_UNSET_SIZE;
-    lcf->postpone_output = NGX_CONF_UNSET_SIZE;
-    lcf->limit_rate = NGX_CONF_UNSET_SIZE;
-    lcf->limit_rate_after = NGX_CONF_UNSET_SIZE;
-    lcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
-    lcf->keepalive_header = NGX_CONF_UNSET;
-    lcf->keepalive_requests = NGX_CONF_UNSET_UINT;
-    lcf->lingering_time = NGX_CONF_UNSET_MSEC;
-    lcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
-    lcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
-    lcf->reset_timedout_connection = NGX_CONF_UNSET;
-    lcf->server_name_in_redirect = NGX_CONF_UNSET;
-    lcf->port_in_redirect = NGX_CONF_UNSET;
-    lcf->msie_padding = NGX_CONF_UNSET;
-    lcf->msie_refresh = NGX_CONF_UNSET;
-    lcf->log_not_found = NGX_CONF_UNSET;
-    lcf->log_subrequest = NGX_CONF_UNSET;
-    lcf->recursive_error_pages = NGX_CONF_UNSET;
-    lcf->server_tokens = NGX_CONF_UNSET;
-    lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
-    lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
-
-    lcf->open_file_cache = NGX_CONF_UNSET_PTR;
-    lcf->open_file_cache_valid = NGX_CONF_UNSET;
-    lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
-    lcf->open_file_cache_errors = NGX_CONF_UNSET;
-    lcf->open_file_cache_events = NGX_CONF_UNSET;
+    clcf->read_ahead = NGX_CONF_UNSET_SIZE;
+    clcf->directio = NGX_CONF_UNSET;
+    clcf->directio_alignment = NGX_CONF_UNSET;
+    clcf->tcp_nopush = NGX_CONF_UNSET;
+    clcf->tcp_nodelay = NGX_CONF_UNSET;
+    clcf->send_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->send_lowat = NGX_CONF_UNSET_SIZE;
+    clcf->postpone_output = NGX_CONF_UNSET_SIZE;
+    clcf->limit_rate = NGX_CONF_UNSET_SIZE;
+    clcf->limit_rate_after = NGX_CONF_UNSET_SIZE;
+    clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->keepalive_header = NGX_CONF_UNSET;
+    clcf->keepalive_requests = NGX_CONF_UNSET_UINT;
+    clcf->lingering_time = NGX_CONF_UNSET_MSEC;
+    clcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->reset_timedout_connection = NGX_CONF_UNSET;
+    clcf->server_name_in_redirect = NGX_CONF_UNSET;
+    clcf->port_in_redirect = NGX_CONF_UNSET;
+    clcf->msie_padding = NGX_CONF_UNSET;
+    clcf->msie_refresh = NGX_CONF_UNSET;
+    clcf->log_not_found = NGX_CONF_UNSET;
+    clcf->log_subrequest = NGX_CONF_UNSET;
+    clcf->recursive_error_pages = NGX_CONF_UNSET;
+    clcf->server_tokens = NGX_CONF_UNSET;
+    clcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
+    clcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
+
+    clcf->open_file_cache = NGX_CONF_UNSET_PTR;
+    clcf->open_file_cache_valid = NGX_CONF_UNSET;
+    clcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
+    clcf->open_file_cache_errors = NGX_CONF_UNSET;
+    clcf->open_file_cache_events = NGX_CONF_UNSET;
 
 #if (NGX_HTTP_GZIP)
-    lcf->gzip_vary = NGX_CONF_UNSET;
-    lcf->gzip_http_version = NGX_CONF_UNSET_UINT;
+    clcf->gzip_vary = NGX_CONF_UNSET;
+    clcf->gzip_http_version = NGX_CONF_UNSET_UINT;
 #if (NGX_PCRE)
-    lcf->gzip_disable = NGX_CONF_UNSET_PTR;
-    lcf->gzip_disable_msie6 = 3;
+    clcf->gzip_disable = NGX_CONF_UNSET_PTR;
+    clcf->gzip_disable_msie6 = 3;
 #endif
 #endif
 
-    return lcf;
+    return clcf;
 }
 
 
@@ -3539,8 +3511,8 @@ ngx_http_core_server_name(ngx_conf_t *cf
 
 #if (NGX_PCRE)
         {
-        ngx_str_t  err;
-        u_char     errstr[NGX_MAX_CONF_ERRSTR];
+        ngx_regex_compile_t  rc;
+        u_char               errstr[NGX_MAX_CONF_ERRSTR];
 
         if (value[i].len == 1) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3548,21 +3520,22 @@ ngx_http_core_server_name(ngx_conf_t *cf
             return NGX_CONF_ERROR;
         }
 
-        err.len = NGX_MAX_CONF_ERRSTR;
-        err.data = errstr;
-
         value[i].len--;
         value[i].data++;
 
-        sn->regex = ngx_regex_compile(&value[i], 0, cf->pool, &err);
-
+        ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+        rc.pattern = value[i];
+        rc.err.len = NGX_MAX_CONF_ERRSTR;
+        rc.err.data = errstr;
+
+        sn->regex = ngx_http_regex_compile(cf, &rc);
         if (sn->regex == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
             return NGX_CONF_ERROR;
         }
 
         sn->name = value[i];
-        cscf->captures = (ngx_regex_capture_count(sn->regex) > 0);
+        cscf->captures = (rc.captures > 0);
         }
 #else
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3580,7 +3553,7 @@ ngx_http_core_server_name(ngx_conf_t *cf
 static char *
 ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t                  *value;
     ngx_uint_t                  alias, n;
@@ -3588,11 +3561,11 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
 
     alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0;
 
-    if (lcf->root.data) {
+    if (clcf->root.data) {
 
         /* the (ngx_uint_t) cast is required by gcc 2.7.2.3 */
 
-        if ((ngx_uint_t) lcf->alias == alias) {
+        if ((ngx_uint_t) clcf->alias == alias) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"%V\" directive is duplicate",
                                &cmd->name);
@@ -3600,13 +3573,13 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"%V\" directive is duplicate, "
                                "\"%s\" directive is specified before",
-                               &cmd->name, lcf->alias ? "alias" : "root");
+                               &cmd->name, clcf->alias ? "alias" : "root");
         }
 
         return NGX_CONF_ERROR;
     }
 
-    if (lcf->named && alias) {
+    if (clcf->named && alias) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "the \"alias\" directive may not be used "
                            "inside named location");
@@ -3638,28 +3611,28 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
-    lcf->alias = alias;
-    lcf->root = value[1];
-
-    if (!alias && lcf->root.data[lcf->root.len - 1] == '/') {
-        lcf->root.len--;
+    clcf->alias = alias;
+    clcf->root = value[1];
+
+    if (!alias && clcf->root.data[clcf->root.len - 1] == '/') {
+        clcf->root.len--;
     }
 
-    if (lcf->root.data[0] != '$') {
-        if (ngx_conf_full_name(cf->cycle, &lcf->root, 0) != NGX_OK) {
+    if (clcf->root.data[0] != '$') {
+        if (ngx_conf_full_name(cf->cycle, &clcf->root, 0) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
     }
 
-    n = ngx_http_script_variables_count(&lcf->root);
+    n = ngx_http_script_variables_count(&clcf->root);
 
     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
 
     if (n) {
         sc.cf = cf;
-        sc.source = &lcf->root;
-        sc.lengths = &lcf->root_lengths;
-        sc.values = &lcf->root_values;
+        sc.source = &clcf->root;
+        sc.lengths = &clcf->root_lengths;
+        sc.values = &clcf->root_values;
         sc.variables = n;
         sc.complete_lengths = 1;
         sc.complete_values = 1;
@@ -3669,20 +3642,6 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         }
     }
 
-#if (NGX_PCRE)
-
-    if (alias && lcf->regex
-        && (ngx_regex_capture_count(lcf->regex) <= 0 || sc.ncaptures == 0))
-    {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "the \"alias\" directive must use captures "
-                           "inside location given by regular expression");
-
-        return NGX_CONF_ERROR;
-    }
-
-#endif
-
     return NGX_CONF_OK;
 }
 
@@ -3834,7 +3793,7 @@ ngx_http_core_directio(ngx_conf_t *cf, n
 static char *
 ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     u_char                            *p;
     ngx_int_t                          overwrite;
@@ -3844,10 +3803,10 @@ ngx_http_core_error_page(ngx_conf_t *cf,
     ngx_http_complex_value_t           cv;
     ngx_http_compile_complex_value_t   ccv;
 
-    if (lcf->error_pages == NULL) {
-        lcf->error_pages = ngx_array_create(cf->pool, 4,
-                                            sizeof(ngx_http_err_page_t));
-        if (lcf->error_pages == NULL) {
+    if (clcf->error_pages == NULL) {
+        clcf->error_pages = ngx_array_create(cf->pool, 4,
+                                             sizeof(ngx_http_err_page_t));
+        if (clcf->error_pages == NULL) {
             return NGX_CONF_ERROR;
         }
     }
@@ -3911,7 +3870,7 @@ ngx_http_core_error_page(ngx_conf_t *cf,
     }
 
     for (i = 1; i < cf->args->nelts - n; i++) {
-        err = ngx_array_push(lcf->error_pages);
+        err = ngx_array_push(clcf->error_pages);
         if (err == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -4039,14 +3998,14 @@ ngx_http_core_try_files(ngx_conf_t *cf, 
 static char *
 ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     time_t       inactive;
     ngx_str_t   *value, s;
     ngx_int_t    max;
     ngx_uint_t   i;
 
-    if (lcf->open_file_cache != NGX_CONF_UNSET_PTR) {
+    if (clcf->open_file_cache != NGX_CONF_UNSET_PTR) {
         return "is duplicate";
     }
 
@@ -4082,7 +4041,7 @@ ngx_http_core_open_file_cache(ngx_conf_t
 
         if (ngx_strcmp(value[i].data, "off") == 0) {
 
-            lcf->open_file_cache = NULL;
+            clcf->open_file_cache = NULL;
 
             continue;
         }
@@ -4095,7 +4054,7 @@ ngx_http_core_open_file_cache(ngx_conf_t
         return NGX_CONF_ERROR;
     }
 
-    if (lcf->open_file_cache == NULL) {
+    if (clcf->open_file_cache == NULL) {
         return NGX_CONF_OK;
     }
 
@@ -4105,8 +4064,8 @@ ngx_http_core_open_file_cache(ngx_conf_t
         return NGX_CONF_ERROR;
     }
 
-    lcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
-    if (lcf->open_file_cache) {
+    clcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
+    if (clcf->open_file_cache) {
         return NGX_CONF_OK;
     }
 
@@ -4117,50 +4076,50 @@ ngx_http_core_open_file_cache(ngx_conf_t
 static char *
 ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t  *value;
 
-    if (lcf->error_log) {
+    if (clcf->error_log) {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    lcf->error_log = ngx_log_create(cf->cycle, &value[1]);
-    if (lcf->error_log == NULL) {
+    clcf->error_log = ngx_log_create(cf->cycle, &value[1]);
+    if (clcf->error_log == NULL) {
         return NGX_CONF_ERROR;
     }
 
     if (cf->args->nelts == 2) {
-        lcf->error_log->log_level = NGX_LOG_ERR;
+        clcf->error_log->log_level = NGX_LOG_ERR;
         return NGX_CONF_OK;
     }
 
-    return ngx_log_set_levels(cf, lcf->error_log);
+    return ngx_log_set_levels(cf, clcf->error_log);
 }
 
 
 static char *
 ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t  *value;
 
-    if (lcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) {
+    if (clcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    lcf->keepalive_timeout = ngx_parse_time(&value[1], 0);
-
-    if (lcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) {
+    clcf->keepalive_timeout = ngx_parse_time(&value[1], 0);
+
+    if (clcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) {
         return "invalid value";
     }
 
-    if (lcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
+    if (clcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
         return "value must be less than 597 hours";
     }
 
@@ -4168,13 +4127,13 @@ ngx_http_core_keepalive(ngx_conf_t *cf, 
         return NGX_CONF_OK;
     }
 
-    lcf->keepalive_header = ngx_parse_time(&value[2], 1);
-
-    if (lcf->keepalive_header == NGX_ERROR) {
+    clcf->keepalive_header = ngx_parse_time(&value[2], 1);
+
+    if (clcf->keepalive_header == NGX_ERROR) {
         return "invalid value";
     }
 
-    if (lcf->keepalive_header == NGX_PARSE_LARGE_TIME) {
+    if (clcf->keepalive_header == NGX_PARSE_LARGE_TIME) {
         return "value must be less than 68 years";
     }
 
@@ -4185,13 +4144,13 @@ ngx_http_core_keepalive(ngx_conf_t *cf, 
 static char *
 ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
-
-    if (lcf->internal != NGX_CONF_UNSET) {
+    ngx_http_core_loc_conf_t *clcf = conf;
+
+    if (clcf->internal != NGX_CONF_UNSET) {
         return "is duplicate";
     }
 
-    lcf->internal = 1;
+    clcf->internal = 1;
 
     return NGX_CONF_OK;
 }
@@ -4239,10 +4198,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
 
 #if (NGX_PCRE)
 
-    ngx_str_t         err, *value;
-    ngx_uint_t        i;
-    ngx_regex_elt_t  *re;
-    u_char            errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t            *value;
+    ngx_uint_t            i;
+    ngx_regex_elt_t      *re;
+    ngx_regex_compile_t   rc;
+    u_char                errstr[NGX_MAX_CONF_ERRSTR];
 
     if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) {
         clcf->gzip_disable = ngx_array_create(cf->pool, 2,
@@ -4254,8 +4214,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
 
     value = cf->args->elts;
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pool = cf->pool;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
 
     for (i = 1; i < cf->args->nelts; i++) {
 
@@ -4269,14 +4232,15 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
             return NGX_CONF_ERROR;
         }
 
-        re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool,
-                                      &err);
-
-        if (re->regex == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+        rc.pattern = value[1];
+        rc.options = NGX_REGEX_CASELESS;
+
+        if (ngx_regex_compile(&rc) != NGX_OK) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
             return NGX_CONF_ERROR;
         }
 
+        re->regex = rc.regex;
         re->name = value[i].data;
     }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -126,6 +126,7 @@ typedef struct {
     ngx_hash_t                 variables_hash;
 
     ngx_array_t                variables;       /* ngx_http_variable_t */
+    ngx_uint_t                 ncaptures;
 
     ngx_uint_t                 server_names_hash_max_size;
     ngx_uint_t                 server_names_hash_bucket_size;
@@ -238,7 +239,7 @@ typedef struct {
 
 struct ngx_http_server_name_s {
 #if (NGX_PCRE)
-    ngx_regex_t               *regex;
+    ngx_http_regex_t          *regex;
 #endif
     ngx_http_core_srv_conf_t  *server;   /* virtual name server conf */
     ngx_str_t                  name;
@@ -267,9 +268,7 @@ struct ngx_http_core_loc_conf_s {
     ngx_str_t     name;          /* location name */
 
 #if (NGX_PCRE)
-    ngx_regex_t  *regex;
-
-    unsigned      captures:1;
+    ngx_http_regex_t  *regex;
 #endif
 
     unsigned      noname:1;   /* "if () {}" block or limit_except */
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -399,8 +399,13 @@ ngx_http_header_filter(ngx_http_request_
     }
 
 #if (NGX_HTTP_GZIP)
-    if (r->gzip && clcf->gzip_vary) {
-        len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
+    if (r->gzip_vary) {
+        if (clcf->gzip_vary) {
+            len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
+
+        } else {
+            r->gzip_vary = 0;
+        }
     }
 #endif
 
@@ -559,7 +564,7 @@ ngx_http_header_filter(ngx_http_request_
     }
 
 #if (NGX_HTTP_GZIP)
-    if (r->gzip && clcf->gzip_vary) {
+    if (r->gzip_vary) {
         b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
                              sizeof("Vary: Accept-Encoding" CRLF) - 1);
     }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1445,6 +1445,9 @@ ngx_http_process_user_agent(ngx_http_req
         if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
             r->headers_in.gecko = 1;
 
+        } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) {
+            r->headers_in.chrome = 1;
+
         } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
             r->headers_in.konqueror = 1;
         }
@@ -1697,7 +1700,6 @@ ngx_http_find_virtual_server(ngx_http_re
 #if (NGX_PCRE)
 
     if (len && r->virtual_names->nregex) {
-        size_t                   ncaptures;
         ngx_int_t                n;
         ngx_uint_t               i;
         ngx_str_t                name;
@@ -1706,44 +1708,22 @@ ngx_http_find_virtual_server(ngx_http_re
         name.len = len;
         name.data = host;
 
-        ncaptures = 0;
-
         sn = r->virtual_names->regex;
 
         for (i = 0; i < r->virtual_names->nregex; i++) {
 
-            if (sn[i].server->captures && r->captures == NULL) {
-
-                ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3;
-
-                r->captures = ngx_palloc(r->pool, ncaptures * sizeof(int));
-                if (r->captures == NULL) {
-                    return NGX_ERROR;
-                }
+            n = ngx_http_regex_exec(r, sn[i].regex, &name);
+
+            if (n == NGX_OK) {
+                cscf = sn[i].server;
+                goto found;
             }
 
-            n = ngx_regex_exec(sn[i].regex, &name, r->captures, ncaptures);
-
-            if (n == NGX_REGEX_NO_MATCHED) {
+            if (n == NGX_DECLINED) {
                 continue;
             }
 
-            if (n < 0) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                              ngx_regex_exec_n
-                              " failed: %d on \"%V\" using \"%V\"",
-                              n, &name, &sn[i].name);
-                return NGX_ERROR;
-            }
-
-            /* match */
-
-            cscf = sn[i].server;
-
-            r->ncaptures = ncaptures;
-            r->captures_data = host;
-
-            goto found;
+            return NGX_ERROR;
         }
     }
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -10,7 +10,6 @@
 
 #define NGX_HTTP_MAX_URI_CHANGES           10
 #define NGX_HTTP_MAX_SUBREQUESTS           50
-#define NGX_HTTP_MAX_CAPTURES              9
 
 /* must be 2^n */
 #define NGX_HTTP_LC_HEADER_LEN             32
@@ -220,6 +219,7 @@ typedef struct {
     unsigned                          msie6:1;
     unsigned                          opera:1;
     unsigned                          gecko:1;
+    unsigned                          chrome:1;
     unsigned                          konqueror:1;
 } ngx_http_headers_in_t;
 
@@ -457,7 +457,12 @@ struct ngx_http_request_s {
 #if (NGX_HTTP_CACHE)
     unsigned                          cached:1;
 #endif
-    unsigned                          gzip:2;
+
+#if (NGX_HTTP_GZIP)
+    unsigned                          gzip_tested:1;
+    unsigned                          gzip_ok:1;
+    unsigned                          gzip_vary:1;
+#endif
 
     unsigned                          proxy:1;
     unsigned                          bypass_cache:1;
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -251,8 +251,6 @@ ngx_http_script_compile(ngx_http_script_
             {
             ngx_uint_t  n;
 
-            /* NGX_HTTP_MAX_CAPTURES is 9 */
-
             if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
 
                 n = sc->source->data[i] - '0';
@@ -828,20 +826,9 @@ ngx_http_script_regex_start_code(ngx_htt
         e->line.data = e->sp->data;
     }
 
-    if (code->ncaptures && r->captures == NULL) {
+    rc = ngx_http_regex_exec(r, code->regex, &e->line);
 
-        r->captures = ngx_palloc(r->pool,
-                                 (NGX_HTTP_MAX_CAPTURES + 1) * 3 * sizeof(int));
-        if (r->captures == NULL) {
-            e->ip = ngx_http_script_exit;
-            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            return;
-        }
-    }
-
-    rc = ngx_regex_exec(code->regex, &e->line, r->captures, code->ncaptures);
-
-    if (rc == NGX_REGEX_NO_MATCHED) {
+    if (rc == NGX_DECLINED) {
         if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
             ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
                           "\"%V\" does not match \"%V\"",
@@ -870,11 +857,7 @@ ngx_http_script_regex_start_code(ngx_htt
         return;
     }
 
-    if (rc < 0) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
-                      rc, &e->line, &code->name);
-
+    if (rc == NGX_ERROR) {
         e->ip = ngx_http_script_exit;
         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
         return;
@@ -885,9 +868,6 @@ ngx_http_script_regex_start_code(ngx_htt
                       "\"%V\" matches \"%V\"", &code->name, &e->line);
     }
 
-    r->ncaptures = code->ncaptures;
-    r->captures_data = e->line.data;
-
     if (code->test) {
         if (code->negative_test) {
             e->sp->len = 0;
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -114,10 +114,9 @@ typedef struct {
 
 typedef struct {
     ngx_http_script_code_pt     code;
-    ngx_regex_t                *regex;
+    ngx_http_regex_t           *regex;
     ngx_array_t                *lengths;
     uintptr_t                   size;
-    uintptr_t                   ncaptures;
     uintptr_t                   status;
     uintptr_t                   next;
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -31,13 +31,13 @@ static u_char ngx_http_error_tail[] =
 ;
 
 
-static u_char ngx_http_msie_stub[] =
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+static u_char ngx_http_msie_padding[] =
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
 ;
 
 
@@ -598,12 +598,12 @@ ngx_http_send_special_response(ngx_http_
             r->headers_out.content_length_n = ngx_http_error_pages[err].len
                                               + len;
             if (clcf->msie_padding
-                && r->headers_in.msie
+                && (r->headers_in.msie || r->headers_in.chrome)
                 && r->http_version >= NGX_HTTP_VERSION_10
                 && err >= NGX_HTTP_LEVEL_300)
             {
                 r->headers_out.content_length_n +=
-                                                sizeof(ngx_http_msie_stub) - 1;
+                                             sizeof(ngx_http_msie_padding) - 1;
                 msie_padding = 1;
             }
 
@@ -671,8 +671,8 @@ ngx_http_send_special_response(ngx_http_
         }
 
         b->memory = 1;
-        b->pos = ngx_http_msie_stub;
-        b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1;
+        b->pos = ngx_http_msie_padding;
+        b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;
 
         out[1].next = &out[2];
         out[2].buf = b;
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -1666,6 +1666,157 @@ ngx_http_variable_pid(ngx_http_request_t
 }
 
 
+static ngx_int_t
+ngx_http_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v,
+    uintptr_t data)
+{
+    v->not_found = 1;
+    return NGX_OK;
+}
+
+
+ngx_http_regex_t *
+ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
+{
+    u_char                     *p;
+    size_t                      size;
+    ngx_str_t                   name;
+    ngx_uint_t                  i, n;
+    ngx_http_variable_t        *v;
+    ngx_http_regex_t           *re;
+    ngx_http_regex_variable_t  *rv;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    rc->pool = cf->pool;
+
+    if (ngx_regex_compile(rc) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
+        return NULL;
+    }
+
+    re = ngx_pcalloc(cf->pool, sizeof(ngx_http_regex_t));
+    if (re == NULL) {
+        return NULL;
+    }
+
+    re->regex = rc->regex;
+    re->ncaptures = rc->captures;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+    cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
+
+    n = (ngx_uint_t) rc->named_captures;
+
+    if (n == 0) {
+        return re;
+    }
+
+    rv = ngx_palloc(rc->pool, n * sizeof(ngx_http_regex_variable_t));
+    if (rv == NULL) {
+        return NULL;
+    }
+
+    re->variables = rv;
+    re->nvariables = n;
+    re->name = rc->pattern;
+
+    size = rc->name_size;
+    p = rc->names;
+
+    for (i = 0; i < n; i++) {
+        rv[i].capture = 2 * ((p[0] << 8) + p[1]);
+
+        name.data = &p[2];
+        name.len = ngx_strlen(name.data);
+
+        v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
+        if (v == NULL) {
+            return NULL;
+        }
+
+        rv[i].index = ngx_http_get_variable_index(cf, &name);
+        if (rv[i].index == NGX_ERROR) {
+            return NULL;
+        }
+
+        v->get_handler = ngx_http_variable_not_found;
+
+        p += i + size;
+    }
+
+    return re;
+}
+
+
+ngx_int_t
+ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s)
+{
+    ngx_int_t                   rc, index;
+    ngx_uint_t                  i, n, len;
+    ngx_http_variable_value_t  *vv;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    if (re->ncaptures) {
+        len = (cmcf->ncaptures + 1) * 3;
+
+        if (r->captures == NULL) {
+            r->captures = ngx_palloc(r->pool, len * sizeof(int));
+            if (r->captures == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
+    } else {
+        len = 0;
+    }
+
+    rc = ngx_regex_exec(re->regex, s, r->captures, len);
+
+    if (rc == NGX_REGEX_NO_MATCHED) {
+        return NGX_DECLINED;
+    }
+
+    if (rc < 0) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
+                      rc, s, &re->name);
+        return NGX_ERROR;
+    }
+
+    for (i = 0; i < re->nvariables; i++) {
+
+        n = re->variables[i].capture;
+        index = re->variables[i].index;
+        vv = &r->variables[index];
+
+        vv->len = r->captures[n + 1] - r->captures[n];
+        vv->valid = 1;
+        vv->no_cacheable = 0;
+        vv->not_found = 0;
+        vv->data = &s->data[r->captures[n]];
+
+#if (NGX_DEBUG)
+        {
+        ngx_http_variable_t  *v;
+
+        v = cmcf->variables.elts;
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http regex set $%V to \"%*s\"",
+                       &v[index].name, vv->len, vv->data);
+        }
+#endif
+    }
+
+    r->ncaptures = len;
+    r->captures_data = s->data;
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -41,6 +41,21 @@ struct ngx_http_variable_s {
 };
 
 
+typedef struct {
+    ngx_uint_t                    capture;
+    ngx_int_t                     index;
+} ngx_http_regex_variable_t;
+
+
+typedef struct {
+    ngx_regex_t                  *regex;
+    ngx_uint_t                    ncaptures;
+    ngx_http_regex_variable_t    *variables;
+    ngx_uint_t                    nvariables;
+    ngx_str_t                     name;
+} ngx_http_regex_t;
+
+
 ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name,
     ngx_uint_t flags);
 ngx_int_t ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name);
@@ -59,6 +74,12 @@ ngx_int_t ngx_http_variable_unknown_head
 #define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL;
 
 
+ngx_http_regex_t *ngx_http_regex_compile(ngx_conf_t *cf,
+    ngx_regex_compile_t *rc);
+ngx_int_t ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re,
+    ngx_str_t *s);
+
+
 ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf);
 ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf);
 
--- a/src/os/unix/ngx_alloc.c
+++ b/src/os/unix/ngx_alloc.c
@@ -21,7 +21,7 @@ ngx_alloc(size_t size, ngx_log_t *log)
     p = malloc(size);
     if (p == NULL) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "malloc() %uz bytes failed", size);
+                      "malloc(%uz) failed", size);
     }
 
     ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);
@@ -51,15 +51,18 @@ void *
 ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
 {
     void  *p;
+    int    err;
 
-    if (posix_memalign(&p, alignment, size) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "posix_memalign() %uz bytes aligned to %uz failed",
-                      size, alignment);
+    err = posix_memalign(&p, alignment, size);
+
+    if (err) {
+        ngx_log_error(NGX_LOG_EMERG, log, err,
+                      "posix_memalign(%uz, %uz) failed", alignment, size);
+        p = NULL;
     }
 
     ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0,
-                   "posix_memalign: %p:%uz", p, size);
+                   "posix_memalign: %p:%uz @%uz", p, size, alignment);
 
     return p;
 }
@@ -74,12 +77,11 @@ ngx_memalign(size_t alignment, size_t si
     p = memalign(alignment, size);
     if (p == NULL) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "memalign() %uz bytes aligned to %uz failed",
-                      size, alignment);
+                      "memalign(%uz, %uz) failed", alignment, size);
     }
 
     ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0,
-                   "memalign: %p:%uz", p, size);
+                   "memalign: %p:%uz @%uz", p, size, alignment);
 
     return p;
 }
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -402,6 +402,26 @@ ngx_unlock_fd(ngx_fd_t fd)
 }
 
 
+#if (NGX_HAVE_POSIX_FADVISE)
+
+ngx_int_t
+ngx_read_ahead(ngx_fd_t fd, size_t n)
+{
+    int  err;
+
+    err = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+
+    if (err == 0) {
+        return 0;
+    }
+
+    ngx_set_errno(err);
+    return NGX_FILE_ERROR;
+}
+
+#endif
+
+
 #if (NGX_HAVE_O_DIRECT)
 
 ngx_int_t
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -264,7 +264,7 @@ ngx_err_t ngx_unlock_fd(ngx_fd_t fd);
 
 #define NGX_HAVE_READ_AHEAD      1
 
-#define ngx_read_ahead(fd, n)    posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL)
+ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n);
 #define ngx_read_ahead_n         "posix_fadvise(POSIX_FADV_SEQUENTIAL)"
 
 #else