changeset 656:9d21dad0b5a1 NGINX_1_1_12

nginx 1.1.12 *) Change: a "proxy_pass" directive without URI part now uses changed URI after redirection with the "error_page" directive; Thanks to Lanshun Zhou. *) Feature: the "proxy/fastcgi/scgi/uwsgi_cache_lock", "proxy/fastcgi/scgi/uwsgi_cache_lock_timeout" directives. *) Feature: the "pcre_jit" directive. *) Feature: the "if" SSI command supports captures in regular expressions. *) Bugfix: the "if" SSI command did not work inside the "block" command. *) Bugfix: the "limit_conn_log_level" and "limit_req_log_level" directives might not work. *) Bugfix: the "limit_rate" directive did not allow to use full throughput, even if limit value was very high. *) Bugfix: the "sendfile_max_chunk" directive did not work, if the "limit_rate" directive was used. *) Bugfix: a "proxy_pass" directive without URI part always used original request URI if variables were used. *) Bugfix: a "proxy_pass" directive without URI part might use original request after redirection with the "try_files" directive; Thanks to Lanshun Zhou. *) Bugfix: in the ngx_http_scgi_module. *) Bugfix: in the ngx_http_mp4_module. *) Bugfix: nginx could not be built on Solaris; the bug had appeared in 1.1.9.
author Igor Sysoev <http://sysoev.ru>
date Mon, 26 Dec 2011 00:00:00 +0400
parents 189afff6503f
children e1296af53cc0
files CHANGES CHANGES.ru auto/install auto/lib/pcre/conf auto/lib/pcre/make auto/modules auto/options auto/sources conf/fastcgi.conf src/core/nginx.h src/core/ngx_regex.c src/core/ngx_regex.h src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_limit_conn_module.c src/http/modules/ngx_http_limit_req_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_ssi_filter_module.h src/http/modules/ngx_http_uwsgi_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_cache.h src/http/ngx_http_core_module.c src/http/ngx_http_file_cache.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_write_filter_module.c
diffstat 28 files changed, 768 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,44 @@
 
+Changes with nginx 1.1.12                                        26 Dec 2011
+
+    *) Change: a "proxy_pass" directive without URI part now uses changed
+       URI after redirection with the "error_page" directive;
+       Thanks to Lanshun Zhou.
+
+    *) Feature: the "proxy/fastcgi/scgi/uwsgi_cache_lock",
+       "proxy/fastcgi/scgi/uwsgi_cache_lock_timeout" directives.
+
+    *) Feature: the "pcre_jit" directive.
+
+    *) Feature: the "if" SSI command supports captures in regular
+       expressions.
+
+    *) Bugfix: the "if" SSI command did not work inside the "block" command.
+
+    *) Bugfix: the "limit_conn_log_level" and "limit_req_log_level"
+       directives might not work.
+
+    *) Bugfix: the "limit_rate" directive did not allow to use full
+       throughput, even if limit value was very high.
+
+    *) Bugfix: the "sendfile_max_chunk" directive did not work, if the
+       "limit_rate" directive was used.
+
+    *) Bugfix: a "proxy_pass" directive without URI part always used
+       original request URI if variables were used.
+
+    *) Bugfix: a "proxy_pass" directive without URI part might use original
+       request after redirection with the "try_files" directive;
+       Thanks to Lanshun Zhou.
+
+    *) Bugfix: in the ngx_http_scgi_module.
+
+    *) Bugfix: in the ngx_http_mp4_module.
+
+    *) Bugfix: nginx could not be built on Solaris; the bug had appeared in
+       1.1.9.
+
+
 Changes with nginx 1.1.11                                        12 Dec 2011
 
     *) Feature: the "so_keepalive" parameter of the "listen" directive.
@@ -4564,8 +4604,8 @@ Changes with nginx 0.3.6                
     *) Bugfix: if at least in one server was no the "listen" directive, then
        nginx did not listen on the 80 port; the bug had appeared in 0.3.3.
 
-    *) Bugfix: if the URI part is omitted in "proxy_pass" directive, the the
-       80 port was always used.
+    *) Bugfix: if the URI part is omitted in "proxy_pass" directive, the 80
+       port was always used.
 
 
 Changes with nginx 0.3.5                                         21 Oct 2005
@@ -4810,7 +4850,7 @@ Changes with nginx 0.1.43               
     *) Bugfix: the segmentation fault occurred or the worker process may got
        caught in an endless loop if the proxied or FastCGI server sent the
        "Cache-Control" header line and the "expires" directive was used; in
-       the proxied mode the the bug had appeared in 0.1.29.
+       the proxied mode the bug had appeared in 0.1.29.
 
 
 Changes with nginx 0.1.42                                        23 Aug 2005
@@ -4885,8 +4925,8 @@ Changes with nginx 0.1.39               
 
 Changes with nginx 0.1.38                                        08 Jul 2005
 
-    *) Feature: the "limit_rate" directive is supported in in proxy and
-       FastCGI mode.
+    *) Feature: the "limit_rate" directive is supported in proxy and FastCGI
+       mode.
 
     *) Feature: the "X-Accel-Limit-Rate" response header line is supported
        in proxy and FastCGI mode.
@@ -5038,8 +5078,7 @@ Changes with nginx 0.1.30               
 
     *) Bugfix: if the length of the response part received at once from
        proxied or FastCGI server was equal to 500, then nginx returns the
-       500 response code; in proxy mode the the bug had appeared in 0.1.29
-       only.
+       500 response code; in proxy mode the bug had appeared in 0.1.29 only.
 
     *) Bugfix: nginx did not consider the directives with 8 or 9 parameters
        as invalid.
@@ -5282,7 +5321,7 @@ Changes with nginx 0.1.19               
 
     *) Bugfix: nginx could not be built on NetBSD 2.0.
 
-    *) Bugfix: the timeout may occur while reading of the the client request
+    *) Bugfix: the timeout may occur while reading of the client request
        body via SSL connections.
 
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,45 @@
 
+Изменения в nginx 1.1.12                                          26.12.2011
+
+    *) Изменение: после перенаправления запроса с помощью директивы
+       error_page директива proxy_pass без URI теперь использует изменённый
+       URI;
+       Спасибо Lanshun Zhou.
+
+    *) Добавление: директивы proxy/fastcgi/scgi/uwsgi_cache_lock,
+       proxy/fastcgi/scgi/uwsgi_cache_lock_timeout.
+
+    *) Добавление: директива pcre_jit.
+
+    *) Добавление: SSI команда if поддерживает выделения в регулярных
+       выражениях.
+
+    *) Исправление: SSI команда if не работала внутри команды block.
+
+    *) Исправление: директивы limit_conn_log_level и limit_req_log_level
+       могли не работать.
+
+    *) Исправление: директива limit_rate не позволяла передавать на полной
+       скорости, даже если был указан очень большой лимит.
+
+    *) Исправление: директива sendfile_max_chunk не работала, если
+       использовалась директива limit_rate.
+
+    *) Исправление: если в директиве proxy_pass использовались переменные и
+       не был указан URI, всегда использовался URI исходного запроса.
+
+    *) Исправление: после перенаправления запроса с помощью директивы
+       try_files директива proxy_pass без URI могла использовать URI
+       исходного запроса;
+       Спасибо Lanshun Zhou.
+
+    *) Исправление: в модуле ngx_http_scgi_module.
+
+    *) Исправление: в модуле ngx_http_mp4_module.
+
+    *) Исправление: nginx не собирался на Solaris; ошибка появилась в 1.1.9.
+
+
 Изменения в nginx 1.1.11                                          12.12.2011
 
     *) Добавление: параметр so_keepalive в директиве listen.
--- a/auto/install
+++ b/auto/install
@@ -72,7 +72,7 @@ case ".$NGX_HTTP_LOG_PATH" in
 esac
 
 
-if test -e man/nginx.8 ; then
+if test -f man/nginx.8 ; then
     NGX_MAN=man/nginx.8
 else
     NGX_MAN=docs/man/nginx.8
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -4,8 +4,6 @@
 
 if [ $PCRE != NONE ]; then
     CORE_INCS="$CORE_INCS $PCRE"
-    CORE_DEPS="$CORE_DEPS $REGEX_DEPS"
-    CORE_SRCS="$CORE_SRCS $REGEX_SRCS"
 
     case "$NGX_CC_NAME" in
 
@@ -81,6 +79,12 @@ if [ $PCRE != NONE ]; then
 
     esac
 
+
+    if [ $PCRE_JIT = YES ]; then
+        have=NGX_HAVE_PCRE_JIT . auto/have
+        PCRE_CONF_OPT="$PCRE_CONF_OPT --enable-jit"
+    fi
+
 else
 
     if [ "$NGX_PLATFORM" != win32 ]; then
@@ -156,12 +160,23 @@ else
         fi
 
         if [ $ngx_found = yes ]; then
-            CORE_DEPS="$CORE_DEPS $REGEX_DEPS"
-            CORE_SRCS="$CORE_SRCS $REGEX_SRCS"
             CORE_INCS="$CORE_INCS $ngx_feature_path"
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             PCRE=YES
         fi
+
+        if [ $PCRE == YES ]; then
+            ngx_feature="PCRE JIT support"
+            ngx_feature_name="NGX_HAVE_PCRE_JIT"
+            ngx_feature_test="int jit = 0;
+                              pcre_config(PCRE_CONFIG_JIT, &jit);
+                              if (jit != 1) return 1;"
+            . auto/feature
+
+            if [ $ngx_found = yes ]; then
+                PCRE_JIT=YES
+            fi
+        fi
     fi
 
     if [ $PCRE != YES ]; then
--- a/auto/lib/pcre/make
+++ b/auto/lib/pcre/make
@@ -50,7 +50,7 @@ END
 	cd $PCRE \\
 	&& if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
 	&& CC="\$(CC)" CFLAGS="$PCRE_OPT" \\
-	./configure --disable-shared
+	./configure --disable-shared $PCRE_CONF_OPT
 
 $PCRE/.libs/libpcre.a:	$PCRE/Makefile
 	cd $PCRE \\
--- a/auto/modules
+++ b/auto/modules
@@ -396,6 +396,12 @@ if [ $USE_OPENSSL = YES ]; then
     CORE_SRCS="$CORE_SRCS $OPENSSL_SRCS"
 fi
 
+if [ $USE_PCRE = YES ]; then
+    modules="$modules $REGEX_MODULE"
+    CORE_DEPS="$CORE_DEPS $REGEX_DEPS"
+    CORE_SRCS="$CORE_SRCS $REGEX_SRCS"
+fi
+
 if [ $HTTP = YES ]; then
     modules="$modules $HTTP_MODULES $HTTP_FILTER_MODULES \
              $HTTP_HEADERS_FILTER_MODULE \
--- a/auto/options
+++ b/auto/options
@@ -111,6 +111,8 @@ NGX_ADDONS=
 USE_PCRE=NO
 PCRE=NONE
 PCRE_OPT=
+PCRE_CONF_OPT=
+PCRE_JIT=NO
 
 USE_OPENSSL=NO
 OPENSSL=NONE
@@ -274,6 +276,7 @@ use the \"--without-http_limit_conn_modu
         --with-pcre)                     USE_PCRE=YES               ;;
         --with-pcre=*)                   PCRE="$value"              ;;
         --with-pcre-opt=*)               PCRE_OPT="$value"          ;;
+        --with-pcre-jit)                 PCRE_JIT=YES               ;;
 
         --with-openssl=*)                OPENSSL="$value"           ;;
         --with-openssl-opt=*)            OPENSSL_OPT="$value"       ;;
@@ -421,6 +424,7 @@ cat << END
   --with-pcre                        force PCRE library usage
   --with-pcre=DIR                    set path to PCRE library sources
   --with-pcre-opt=OPTIONS            set additional build options for PCRE
+  --with-pcre-jit                    build PCRE with JIT compilation support
 
   --with-md5=DIR                     set path to md5 library sources
   --with-md5-opt=OPTIONS             set additional build options for md5
--- a/auto/sources
+++ b/auto/sources
@@ -69,6 +69,7 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_crypt.c"
 
 
+REGEX_MODULE=ngx_regex_module
 REGEX_DEPS=src/core/ngx_regex.h
 REGEX_SRCS=src/core/ngx_regex.c
 
--- a/conf/fastcgi.conf
+++ b/conf/fastcgi.conf
@@ -10,6 +10,7 @@ fastcgi_param  REQUEST_URI        $reque
 fastcgi_param  DOCUMENT_URI       $document_uri;
 fastcgi_param  DOCUMENT_ROOT      $document_root;
 fastcgi_param  SERVER_PROTOCOL    $server_protocol;
+fastcgi_param  HTTPS              $https if_not_empty;
 
 fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
 fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,7 +9,7 @@
 
 
 #define nginx_version      1001011
-#define NGINX_VERSION      "1.1.11"
+#define NGINX_VERSION      "1.1.12"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -8,11 +8,61 @@
 #include <ngx_core.h>
 
 
+typedef struct {
+    ngx_flag_t  pcre_jit;
+} ngx_regex_conf_t;
+
+
 static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
 static void ngx_libc_cdecl ngx_regex_free(void *p);
 
+static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);
+
+static void *ngx_regex_create_conf(ngx_cycle_t *cycle);
+static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data);
+static ngx_conf_post_t  ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit };
+
+
+static ngx_command_t  ngx_regex_commands[] = {
+
+    { ngx_string("pcre_jit"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_flag_slot,
+      0,
+      offsetof(ngx_regex_conf_t, pcre_jit),
+      &ngx_regex_pcre_jit_post },
+
+      ngx_null_command
+};
+
+
+static ngx_core_module_t  ngx_regex_module_ctx = {
+    ngx_string("regex"),
+    ngx_regex_create_conf,
+    ngx_regex_init_conf
+};
+
+
+ngx_module_t  ngx_regex_module = {
+    NGX_MODULE_V1,
+    &ngx_regex_module_ctx,                 /* module context */
+    ngx_regex_commands,                    /* module directives */
+    NGX_CORE_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    ngx_regex_module_init,                 /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
 
 static ngx_pool_t  *ngx_pcre_pool;
+static ngx_list_t  *ngx_pcre_studies;
 
 
 void
@@ -62,10 +112,11 @@ ngx_regex_malloc_done(void)
 ngx_int_t
 ngx_regex_compile(ngx_regex_compile_t *rc)
 {
-    int           n, erroff;
-    char         *p;
-    const char   *errstr;
-    ngx_regex_t  *re;
+    int               n, erroff;
+    char             *p;
+    pcre             *re;
+    const char       *errstr;
+    ngx_regex_elt_t  *elt;
 
     ngx_regex_malloc_init(rc->pool);
 
@@ -92,7 +143,24 @@ ngx_regex_compile(ngx_regex_compile_t *r
         return NGX_ERROR;
     }
 
-    rc->regex = re;
+    rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t));
+    if (rc->regex == NULL) {
+        return NGX_ERROR;
+    }
+
+    rc->regex->pcre = re;
+
+    /* do not study at runtime */
+
+    if (ngx_pcre_studies != NULL) {
+        elt = ngx_list_push(ngx_pcre_studies);
+        if (elt == NULL) {
+            return NGX_ERROR;
+        }
+
+        elt->regex = rc->regex;
+        elt->name = rc->pattern.data;
+    }
 
     n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
     if (n < 0) {
@@ -203,3 +271,140 @@ ngx_regex_free(void *p)
 {
     return;
 }
+
+
+static ngx_int_t
+ngx_regex_module_init(ngx_cycle_t *cycle)
+{
+    int               opt;
+    const char       *errstr;
+    ngx_uint_t        i;
+    ngx_list_part_t  *part;
+    ngx_regex_elt_t  *elts;
+
+    opt = 0;
+
+#if (NGX_HAVE_PCRE_JIT)
+    {
+    ngx_regex_conf_t  *rcf;
+
+    rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);
+
+    if (rcf->pcre_jit) {
+        opt = PCRE_STUDY_JIT_COMPILE;
+    }
+    }
+#endif
+
+    ngx_regex_malloc_init(cycle->pool);
+
+    part = &ngx_pcre_studies->part;
+    elts = part->elts;
+
+    for (i = 0 ; /* void */ ; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+
+            part = part->next;
+            elts = part->elts;
+            i = 0;
+        }
+
+        elts[i].regex->extra = pcre_study(elts[i].regex->pcre, opt, &errstr);
+
+        if (errstr != NULL) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                          "pcre_study() failed: %s in \"%s\"",
+                          errstr, elts[i].name);
+        }
+
+#if (NGX_HAVE_PCRE_JIT)
+        if (opt & PCRE_STUDY_JIT_COMPILE) {
+            int jit, n;
+
+            jit = 0;
+            n = pcre_fullinfo(elts[i].regex->pcre, elts[i].regex->extra,
+                              PCRE_INFO_JIT, &jit);
+
+            if (n != 0 || jit != 1) {
+                ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                              "JIT compiler does not support pattern: \"%s\"",
+                              elts[i].name);
+            }
+        }
+#endif
+    }
+
+    ngx_regex_malloc_done();
+
+    ngx_pcre_studies = NULL;
+
+    return NGX_OK;
+}
+
+
+static void *
+ngx_regex_create_conf(ngx_cycle_t *cycle)
+{
+    ngx_regex_conf_t  *rcf;
+
+    rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
+    if (rcf == NULL) {
+        return NULL;
+    }
+
+    rcf->pcre_jit = NGX_CONF_UNSET;
+
+    ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
+    if (ngx_pcre_studies == NULL) {
+        return NULL;
+    }
+
+    return rcf;
+}
+
+
+static char *
+ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+    ngx_regex_conf_t *rcf = conf;
+
+    ngx_conf_init_value(rcf->pcre_jit, 0);
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data)
+{
+    ngx_flag_t  *fp = data;
+
+    if (*fp == 0) {
+        return NGX_CONF_OK;
+    }
+
+#if (NGX_HAVE_PCRE_JIT)
+    {
+    int  jit, r;
+
+    jit = 0;
+    r = pcre_config(PCRE_CONFIG_JIT, &jit);
+
+    if (r != 0 || jit != 1) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "PCRE library does not support JIT");
+        *fp = 0;
+    }
+    }
+#else
+    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                       "nginx was build without PCRE JIT support");
+    *fp = 0;
+#endif
+
+    return NGX_CONF_OK;
+}
--- a/src/core/ngx_regex.h
+++ b/src/core/ngx_regex.h
@@ -18,7 +18,11 @@
 
 #define NGX_REGEX_CASELESS    PCRE_CASELESS
 
-typedef pcre  ngx_regex_t;
+
+typedef struct {
+    pcre        *pcre;
+    pcre_extra  *extra;
+} ngx_regex_t;
 
 
 typedef struct {
@@ -45,7 +49,7 @@ void ngx_regex_init(void);
 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,            \
+    pcre_exec(re->pcre, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \
               captures, size)
 #define ngx_regex_exec_n      "pcre_exec()"
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -380,6 +380,20 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
       &ngx_http_upstream_cache_method_mask },
 
+    { ngx_string("fastcgi_cache_lock"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock),
+      NULL },
+
+    { ngx_string("fastcgi_cache_lock_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
+      NULL },
+
 #endif
 
     { ngx_string("fastcgi_temp_path"),
@@ -2086,6 +2100,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_lock = NGX_CONF_UNSET;
+    conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
 #endif
 
     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2323,6 +2339,12 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         conf->cache_key = prev->cache_key;
     }
 
+    ngx_conf_merge_value(conf->upstream.cache_lock,
+                              prev->upstream.cache_lock, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+                              prev->upstream.cache_lock_timeout, 5000);
+
 #endif
 
     ngx_conf_merge_value(conf->upstream.pass_request_headers,
--- a/src/http/modules/ngx_http_limit_conn_module.c
+++ b/src/http/modules/ngx_http_limit_conn_module.c
@@ -483,7 +483,7 @@ ngx_http_limit_conn_merge_conf(ngx_conf_
     ngx_http_limit_conn_conf_t *conf = child;
 
     if (conf->limits.elts == NULL) {
-        *conf = *prev;
+        conf->limits = prev->limits;
     }
 
     ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -569,7 +569,7 @@ ngx_http_limit_req_merge_conf(ngx_conf_t
     ngx_http_limit_req_conf_t *conf = child;
 
     if (conf->shm_zone == NULL) {
-        *conf = *prev;
+        conf->shm_zone = prev->shm_zone;
     }
 
     ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level,
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -2382,6 +2382,8 @@ found:
     data->pos = (u_char *) entry;
     atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos);
 
+    ngx_mp4_set_32value(entry->chunk, 1);
+
     if (trak->chunk_samples) {
 
         first = &trak->stsc_chunk_entry;
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -402,6 +402,20 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
       &ngx_http_upstream_cache_method_mask },
 
+    { ngx_string("proxy_cache_lock"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
+      NULL },
+
+    { ngx_string("proxy_cache_lock_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
+      NULL },
+
 #endif
 
     { ngx_string("proxy_temp_path"),
@@ -736,9 +750,6 @@ ngx_http_proxy_eval(ngx_http_request_t *
             url.uri.len++;
             url.uri.data = p - 1;
         }
-
-    } else {
-        url.uri = r->unparsed_uri;
     }
 
     ctx->vars.key_start = u->schema;
@@ -806,7 +817,7 @@ ngx_http_proxy_create_key(ngx_http_reque
         return NGX_ERROR;
     }
 
-    if (plcf->proxy_lengths) {
+    if (plcf->proxy_lengths && ctx->vars.uri.len) {
 
         *key = ctx->vars.uri;
         u->uri = ctx->vars.uri;
@@ -916,7 +927,7 @@ ngx_http_proxy_create_request(ngx_http_r
     loc_len = 0;
     unparsed_uri = 0;
 
-    if (plcf->proxy_lengths) {
+    if (plcf->proxy_lengths && ctx->vars.uri.len) {
         uri_len = ctx->vars.uri.len;
 
     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
@@ -1022,7 +1033,7 @@ ngx_http_proxy_create_request(ngx_http_r
 
     u->uri.data = b->last;
 
-    if (plcf->proxy_lengths) {
+    if (plcf->proxy_lengths && ctx->vars.uri.len) {
         b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
 
     } else if (unparsed_uri) {
@@ -2438,6 +2449,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_lock = NGX_CONF_UNSET;
+    conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
 #endif
 
     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2684,6 +2697,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
         conf->cache_key = prev->cache_key;
     }
 
+    ngx_conf_merge_value(conf->upstream.cache_lock,
+                              prev->upstream.cache_lock, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+                              prev->upstream.cache_lock_timeout, 5000);
+
 #endif
 
     if (conf->method.len == 0) {
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -36,7 +36,6 @@ static ngx_int_t ngx_http_scgi_create_re
 static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
 static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
-static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
 static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
 static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
 
@@ -247,6 +246,20 @@ static ngx_command_t ngx_http_scgi_comma
       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods),
       &ngx_http_upstream_cache_method_mask },
 
+    { ngx_string("scgi_cache_lock"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock),
+      NULL },
+
+    { ngx_string("scgi_cache_lock_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
+      NULL },
+
 #endif
 
     { ngx_string("scgi_temp_path"),
@@ -857,11 +870,7 @@ ngx_http_scgi_process_status_line(ngx_ht
     }
 
     if (rc == NGX_ERROR) {
-
-        r->http_version = NGX_HTTP_VERSION_9;
-
         u->process_header = ngx_http_scgi_process_header;
-
         return ngx_http_scgi_process_header(r);
     }
 
@@ -961,12 +970,12 @@ ngx_http_scgi_process_header(ngx_http_re
             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "http scgi header done");
 
-            if (r->http_version > NGX_HTTP_VERSION_9) {
+            u = r->upstream;
+
+            if (u->headers_in.status_n) {
                 return NGX_OK;
             }
 
-            u = r->upstream;
-
             if (u->headers_in.status) {
                 status_line = &u->headers_in.status->value;
 
@@ -978,20 +987,15 @@ ngx_http_scgi_process_header(ngx_http_re
                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
                 }
 
-                r->http_version = NGX_HTTP_VERSION_10;
                 u->headers_in.status_n = status;
                 u->headers_in.status_line = *status_line;
 
             } else if (u->headers_in.location) {
-                r->http_version = NGX_HTTP_VERSION_10;
                 u->headers_in.status_n = 302;
                 ngx_str_set(&u->headers_in.status_line,
                             "302 Moved Temporarily");
 
             } else {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "upstream sent neither valid HTTP/1.0 header "
-                              "nor \"Status\" header line");
                 u->headers_in.status_n = 200;
                 ngx_str_set(&u->headers_in.status_line, "200 OK");
             }
@@ -1072,6 +1076,8 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_lock = NGX_CONF_UNSET;
+    conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
 #endif
 
     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1299,6 +1305,12 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t 
         conf->cache_key = prev->cache_key;
     }
 
+    ngx_conf_merge_value(conf->upstream.cache_lock,
+                              prev->upstream.cache_lock, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+                              prev->upstream.cache_lock_timeout, 5000);
+
 #endif
 
     ngx_conf_merge_value(conf->upstream.pass_request_headers,
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -78,6 +78,8 @@ static ngx_str_t *ngx_http_ssi_get_varia
     ngx_str_t *name, ngx_uint_t key);
 static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags);
+static ngx_int_t ngx_http_ssi_regex_match(ngx_http_request_t *r,
+    ngx_str_t *pattern, ngx_str_t *str);
 
 static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
@@ -624,16 +626,6 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     continue;
                 }
 
-                if (cmd->conditional
-                    && (ctx->conditional == 0
-                        || ctx->conditional > cmd->conditional))
-                {
-                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                                  "invalid context of SSI command: \"%V\"",
-                                  &ctx->command);
-                    goto ssi_error;
-                }
-
                 if (!ctx->output && !cmd->block) {
 
                     if (ctx->block) {
@@ -709,6 +701,16 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     }
                 }
 
+                if (cmd->conditional
+                    && (ctx->conditional == 0
+                        || ctx->conditional > cmd->conditional))
+                {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "invalid context of SSI command: \"%V\"",
+                                  &ctx->command);
+                    goto ssi_error;
+                }
+
                 if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) {
                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                   "too many SSI command paramters: \"%V\"",
@@ -1531,6 +1533,30 @@ ngx_http_ssi_get_variable(ngx_http_reque
 
     ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module);
 
+#if (NGX_PCRE)
+    {
+    ngx_str_t  *value;
+
+    if (key >= '0' && key <= '9') {
+        i = key - '0';
+
+        if (i < ctx->ncaptures) {
+            value = ngx_palloc(r->pool, sizeof(ngx_str_t));
+            if (value == NULL) {
+                return NULL;
+            }
+
+            i *= 2;
+
+            value->data = ctx->captures_data + ctx->captures[i];
+            value->len = ctx->captures[i + 1] - ctx->captures[i];
+
+            return value;
+        }
+    }
+    }
+#endif
+
     if (ctx->variables == NULL) {
         return NULL;
     }
@@ -1820,6 +1846,115 @@ invalid_variable:
 
 
 static ngx_int_t
+ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern,
+    ngx_str_t *str)
+{
+#if (NGX_PCRE)
+    int                   rc, *captures;
+    u_char               *p, errstr[NGX_MAX_CONF_ERRSTR];
+    size_t                size;
+    ngx_int_t             key;
+    ngx_str_t            *vv, name, value;
+    ngx_uint_t            i, n;
+    ngx_http_ssi_ctx_t   *ctx;
+    ngx_http_ssi_var_t   *var;
+    ngx_regex_compile_t   rgc;
+
+    ngx_memzero(&rgc, sizeof(ngx_regex_compile_t));
+
+    rgc.pattern = *pattern;
+    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;
+    }
+
+    n = (rgc.captures + 1) * 3;
+
+    captures = ngx_palloc(r->pool, n * sizeof(int));
+    if (captures == NULL) {
+        return NGX_ERROR;
+    }
+
+    rc = ngx_regex_exec(rgc.regex, str, captures, n);
+
+    if (rc < NGX_REGEX_NO_MATCHED) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
+                      rc, str, pattern);
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    if (rc == NGX_REGEX_NO_MATCHED) {
+        return NGX_DECLINED;
+    }
+
+    ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module);
+
+    ctx->ncaptures = rc;
+    ctx->captures = captures;
+    ctx->captures_data = str->data;
+
+    if (rgc.named_captures > 0) {
+
+        if (ctx->variables == NULL) {
+            ctx->variables = ngx_list_create(r->pool, 4,
+                                             sizeof(ngx_http_ssi_var_t));
+            if (ctx->variables == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
+        size = rgc.name_size;
+        p = rgc.names;
+
+        for (i = 0; i < (ngx_uint_t) rgc.named_captures; i++, p += size) {
+
+            name.data = &p[2];
+            name.len = ngx_strlen(name.data);
+
+            n = 2 * ((p[0] << 8) + p[1]);
+
+            value.data = &str->data[captures[n]];
+            value.len = captures[n + 1] - captures[n];
+
+            key = ngx_hash_strlow(name.data, name.data, name.len);
+
+            vv = ngx_http_ssi_get_variable(r, &name, key);
+
+            if (vv) {
+                *vv = value;
+                continue;
+            }
+
+            var = ngx_list_push(ctx->variables);
+            if (var == NULL) {
+                return NGX_ERROR;
+            }
+
+            var->name = name;
+            var->key = key;
+            var->value = value;
+        }
+    }
+
+    return NGX_OK;
+
+#else
+
+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                  "the using of the regex \"%V\" in SSI requires PCRE library",
+                  pattern);
+    return NGX_HTTP_SSI_ERROR;
+
+#endif
+}
+
+
+static ngx_int_t
 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
@@ -2451,39 +2586,17 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
         }
 
     } else {
-#if (NGX_PCRE)
-        ngx_regex_compile_t  rgc;
-        u_char               errstr[NGX_MAX_CONF_ERRSTR];
-
         right.data[right.len] = '\0';
 
-        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_http_ssi_regex_match(r, &right, &left);
+
+        if (rc == NGX_OK) {
+            rc = 0;
+        } else if (rc == NGX_DECLINED) {
+            rc = -1;
+        } else {
+            return rc;
         }
-
-        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: %i on \"%V\" using \"%V\"",
-                          rc, &left, &right);
-            return NGX_HTTP_SSI_ERROR;
-        }
-#else
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      "the using of the regex \"%V\" in SSI "
-                      "requires PCRE library", &right);
-
-        return NGX_HTTP_SSI_ERROR;
-#endif
     }
 
     if ((rc == 0 && !negative) || (rc != 0 && negative)) {
--- a/src/http/modules/ngx_http_ssi_filter_module.h
+++ b/src/http/modules/ngx_http_ssi_filter_module.h
@@ -64,6 +64,12 @@ typedef struct {
     ngx_list_t               *variables;
     ngx_array_t              *blocks;
 
+#if (NGX_PCRE)
+    ngx_uint_t                ncaptures;
+    int                      *captures;
+    u_char                   *captures_data;
+#endif
+
     unsigned                  conditional:2;
     unsigned                  encoding:2;
     unsigned                  block:1;
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -274,6 +274,20 @@ static ngx_command_t ngx_http_uwsgi_comm
       offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_methods),
       &ngx_http_upstream_cache_method_mask },
 
+    { ngx_string("uwsgi_cache_lock"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock),
+      NULL },
+
+    { ngx_string("uwsgi_cache_lock_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout),
+      NULL },
+
 #endif
 
     { ngx_string("uwsgi_temp_path"),
@@ -1114,6 +1128,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_lock = NGX_CONF_UNSET;
+    conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
 #endif
 
     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1341,6 +1357,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
         conf->cache_key = prev->cache_key;
     }
 
+    ngx_conf_merge_value(conf->upstream.cache_lock,
+                              prev->upstream.cache_lock, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+                              prev->upstream.cache_lock_timeout, 5000);
+
 #endif
 
     ngx_conf_merge_value(conf->upstream.pass_request_headers,
--- 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.11';
+our $VERSION = '1.1.12';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -79,6 +79,14 @@ struct ngx_http_cache_s {
     ngx_http_file_cache_t           *file_cache;
     ngx_http_file_cache_node_t      *node;
 
+    ngx_msec_t                       lock_timeout;
+    ngx_msec_t                       wait_time;
+
+    ngx_event_t                      wait_event;
+
+    unsigned                         lock:1;
+    unsigned                         waiting:1;
+
     unsigned                         updated:1;
     unsigned                         updating:1;
     unsigned                         exists:1;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2506,6 +2506,7 @@ ngx_http_internal_redirect(ngx_http_requ
 #endif
 
     r->internal = 1;
+    r->valid_unparsed_uri = 0;
     r->add_uri_to_alias = 0;
     r->main->count++;
 
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -10,6 +10,9 @@
 #include <ngx_md5.h>
 
 
+static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r,
+    ngx_http_cache_t *c);
+static void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev);
 static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
     ngx_http_cache_t *c);
 static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r,
@@ -181,13 +184,13 @@ ngx_http_file_cache_create(ngx_http_requ
         return NGX_ERROR;
     }
 
+    cln->handler = ngx_http_file_cache_cleanup;
+    cln->data = c;
+
     if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
         return NGX_ERROR;
     }
 
-    cln->handler = ngx_http_file_cache_cleanup;
-    cln->data = c;
-
     if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
         return NGX_ERROR;
     }
@@ -244,15 +247,24 @@ ngx_http_file_cache_open(ngx_http_reques
 
     c = r->cache;
 
+    if (c->waiting) {
+        return NGX_AGAIN;
+    }
+
     if (c->buf) {
         return ngx_http_file_cache_read(r, c);
     }
 
     cache = c->file_cache;
 
-    cln = ngx_pool_cleanup_add(r->pool, 0);
-    if (cln == NULL) {
-        return NGX_ERROR;
+    if (c->node == NULL) {
+        cln = ngx_pool_cleanup_add(r->pool, 0);
+        if (cln == NULL) {
+            return NGX_ERROR;
+        }
+
+        cln->handler = ngx_http_file_cache_cleanup;
+        cln->data = c;
     }
 
     rc = ngx_http_file_cache_exists(cache, c);
@@ -264,9 +276,6 @@ ngx_http_file_cache_open(ngx_http_reques
         return rc;
     }
 
-    cln->handler = ngx_http_file_cache_cleanup;
-    cln->data = c;
-
     if (rc == NGX_AGAIN) {
         return NGX_HTTP_CACHE_SCARCE;
     }
@@ -306,7 +315,7 @@ ngx_http_file_cache_open(ngx_http_reques
     }
 
     if (!test) {
-        return NGX_DECLINED;
+        goto done;
     }
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -330,7 +339,7 @@ ngx_http_file_cache_open(ngx_http_reques
 
         case NGX_ENOENT:
         case NGX_ENOTDIR:
-            return rv;
+            goto done;
 
         default:
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
@@ -354,6 +363,114 @@ ngx_http_file_cache_open(ngx_http_reques
     }
 
     return ngx_http_file_cache_read(r, c);
+
+done:
+
+    if (rv == NGX_DECLINED) {
+        return ngx_http_file_cache_lock(r, c);
+    }
+
+    return rv;
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
+    ngx_msec_t                 now, timer;
+    ngx_http_file_cache_t     *cache;
+
+    if (!c->lock) {
+        return NGX_DECLINED;
+    }
+
+    cache = c->file_cache;
+
+    ngx_shmtx_lock(&cache->shpool->mutex);
+
+    if (!c->node->updating) {
+        c->node->updating = 1;
+        c->updating = 1;
+    }
+
+    ngx_shmtx_unlock(&cache->shpool->mutex);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http file cache lock u:%d wt:%M",
+                   c->updating, c->wait_time);
+
+    if (c->updating) {
+        return NGX_DECLINED;
+    }
+
+    c->waiting = 1;
+
+    now = ngx_current_msec;
+
+    if (c->wait_time == 0) {
+        c->wait_time = now + c->lock_timeout;
+
+        c->wait_event.handler = ngx_http_file_cache_lock_wait_handler;
+        c->wait_event.data = r;
+        c->wait_event.log = r->connection->log;
+    }
+
+    timer = c->wait_time - now;
+
+    ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer);
+
+    r->main->blocked++;
+
+    return NGX_AGAIN;
+}
+
+
+static void
+ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev)
+{
+    ngx_uint_t                 wait;
+    ngx_msec_t                 timer;
+    ngx_http_cache_t          *c;
+    ngx_http_request_t        *r;
+    ngx_http_file_cache_t     *cache;
+
+    r = ev->data;
+    c = r->cache;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                   "http file cache wait handler wt:%M cur:%M",
+                   c->wait_time, ngx_current_msec);
+
+    timer = c->wait_time - ngx_current_msec;
+
+    if ((ngx_msec_int_t) timer <= 0) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                       "http file cache lock timeout");
+        c->lock = 0;
+        goto wakeup;
+    }
+
+    cache = c->file_cache;
+    wait = 0;
+
+    ngx_shmtx_lock(&cache->shpool->mutex);
+
+    if (c->node->updating) {
+        wait = 1;
+    }
+
+    ngx_shmtx_unlock(&cache->shpool->mutex);
+
+    if (wait) {
+        ngx_add_timer(ev, (timer > 500) ? 500 : timer);
+        return;
+    }
+
+wakeup:
+
+    c->waiting = 0;
+    r->main->blocked--;
+    r->connection->write->handler(r->connection->write);
 }
 
 
@@ -518,13 +635,19 @@ ngx_http_file_cache_exists(ngx_http_file
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
-    fcn = ngx_http_file_cache_lookup(cache, c->key);
+    fcn = c->node;
+
+    if (fcn == NULL) {
+        fcn = ngx_http_file_cache_lookup(cache, c->key);
+    }
 
     if (fcn) {
         ngx_queue_remove(&fcn->queue);
 
-        fcn->uses++;
-        fcn->count++;
+        if (c->node == NULL) {
+            fcn->uses++;
+            fcn->count++;
+        }
 
         if (fcn->error) {
 
@@ -621,6 +744,10 @@ ngx_http_file_cache_name(ngx_http_reques
 
     c = r->cache;
 
+    if (c->file.name.len) {
+        return NGX_OK;
+    }
+
     c->file.name.len = path->name.len + 1 + path->len
                        + 2 * NGX_HTTP_CACHE_KEY_LEN;
 
@@ -957,6 +1084,10 @@ ngx_http_file_cache_free(ngx_http_cache_
             }
         }
     }
+
+    if (c->wait_event.timer_set) {
+        ngx_del_timer(&c->wait_event);
+    }
 }
 
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -707,6 +707,9 @@ ngx_http_upstream_cache(ngx_http_request
         c->body_start = u->conf->buffer_size;
         c->file_cache = u->conf->cache->data;
 
+        c->lock = u->conf->cache_lock;
+        c->lock_timeout = u->conf->cache_lock_timeout;
+
         u->cache_status = NGX_HTTP_CACHE_MISS;
     }
 
@@ -1895,8 +1898,6 @@ ngx_http_upstream_process_headers(ngx_ht
             r->method = NGX_HTTP_GET;
         }
 
-        r->valid_unparsed_uri = 0;
-
         ngx_http_internal_redirect(r, uri, &args);
         ngx_http_finalize_request(r, NGX_DONE);
         return NGX_DONE;
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -165,6 +165,9 @@ typedef struct {
     ngx_uint_t                       cache_use_stale;
     ngx_uint_t                       cache_methods;
 
+    ngx_flag_t                       cache_lock;
+    ngx_msec_t                       cache_lock_timeout;
+
     ngx_array_t                     *cache_valid;
     ngx_array_t                     *cache_bypass;
     ngx_array_t                     *no_cache;
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -223,11 +223,14 @@ ngx_http_write_filter(ngx_http_request_t
             return NGX_AGAIN;
         }
 
-    } else if (clcf->sendfile_max_chunk) {
-        limit = clcf->sendfile_max_chunk;
+        if (clcf->sendfile_max_chunk
+            && (off_t) clcf->sendfile_max_chunk < limit)
+        {
+            limit = clcf->sendfile_max_chunk;
+        }
 
     } else {
-        limit = 0;
+        limit = clcf->sendfile_max_chunk;
     }
 
     sent = c->sent;
@@ -262,17 +265,18 @@ ngx_http_write_filter(ngx_http_request_t
             }
         }
 
-        delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1);
+        delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate);
 
         if (delay > 0) {
+            limit = 0;
             c->write->delayed = 1;
             ngx_add_timer(c->write, delay);
         }
+    }
 
-    } else if (c->write->ready
-               && clcf->sendfile_max_chunk
-               && (size_t) (c->sent - sent)
-                      >= clcf->sendfile_max_chunk - 2 * ngx_pagesize)
+    if (limit
+        && c->write->ready
+        && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))
     {
         c->write->delayed = 1;
         ngx_add_timer(c->write, 1);