changeset 496:116d5de7cbb6 NGINX_0_7_60

nginx 0.7.60 *) Feature: the "updating" parameter in "proxy_cache_use_stale" and "fastcgi_cache_use_stale" directives. *) Feature: the "keepalive_requests" directive. *) Bugfix: in open_file_cache and proxy/fastcgi cache interaction on start up. *) Bugfix: open_file_cache might cache open file descriptors too long. *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request header lines were passed to backend while caching if no "proxy_set_header" directive was used with any parameters. *) Bugfix: the "Set-Cookie" and "P3P" response header lines were not hidden while caching if no "proxy_hide_header/fastcgi_hide_header" directives were used with any parameters. *) Bugfix: the ngx_http_image_filter_module did not support GIF87a format. Thanks to Denis Ilyinyh. *) Bugfix: nginx could not be built modules on Solaris 10 and early; the bug had appeared in 0.7.56. *) Bugfix: XLST filter did not work in subrequests. *) Bugfix: in relative paths handling in nginx/Windows. *) Bugfix: in proxy_store, fastcgi_store, proxy_cache, and fastcgi_cache in nginx/Windows.
author Igor Sysoev <http://sysoev.ru>
date Mon, 15 Jun 2009 00:00:00 +0400
parents 6d9fb4461113
children b0914e65af8e
files CHANGES CHANGES.ru auto/cc/msvc auto/lib/conf auto/lib/google-perftools/conf auto/lib/md5/conf auto/lib/openssl/conf auto/lib/openssl/make auto/lib/pcre/conf auto/lib/zlib/conf auto/os/features auto/summary auto/unix src/core/nginx.c src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_connection.c src/core/ngx_connection.h src/core/ngx_cycle.c src/core/ngx_file.c src/core/ngx_open_file_cache.c src/core/ngx_output_chain.c src/core/ngx_palloc.c src/core/ngx_palloc.h src/core/ngx_slab.h src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_xslt_filter_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_core_module.h src/http/ngx_http_file_cache.c src/http/ngx_http_request.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h
diffstat 37 files changed, 433 insertions(+), 195 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,39 @@
 
+Changes with nginx 0.7.60                                        15 Jun 2009
+
+    *) Feature: the "updating" parameter in "proxy_cache_use_stale" and 
+       "fastcgi_cache_use_stale" directives.
+
+    *) Feature: the "keepalive_requests" directive.
+
+    *) Bugfix: in open_file_cache and proxy/fastcgi cache interaction on 
+       start up.
+
+    *) Bugfix: open_file_cache might cache open file descriptors too long.
+
+    *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request 
+       header lines were passed to backend while caching if no 
+       "proxy_set_header" directive was used with any parameters.
+
+    *) Bugfix: the "Set-Cookie" and "P3P" response header lines were not 
+       hidden while caching if no "proxy_hide_header/fastcgi_hide_header" 
+       directives were used with any parameters.
+
+    *) Bugfix: the ngx_http_image_filter_module did not support GIF87a 
+       format.
+       Thanks to Denis Ilyinyh.
+
+    *) Bugfix: nginx could not be built modules on Solaris 10 and early; 
+       the bug had appeared in 0.7.56.
+
+    *) Bugfix: XLST filter did not work in subrequests.
+
+    *) Bugfix: in relative paths handling in nginx/Windows.
+
+    *) Bugfix: in proxy_store, fastcgi_store, proxy_cache, and 
+       fastcgi_cache in nginx/Windows.
+
+
 Changes with nginx 0.7.59                                        25 May 2009
 
     *) Feature: the "proxy_cache_methods" and "fastcgi_cache_methods" 
@@ -12,7 +47,7 @@ Changes with nginx 0.7.59               
        the bug had appeared in 0.7.58.
 
     *) Bugfix: the SSL modules might not built on Solaris and Linux;
-       the bug had appeared in 0.7.58.
+       the bug had appeared in 0.7.56.
 
     *) Bugfix: ngx_http_xslt_filter_module responses were not handled by 
        SSI, charset, and gzip filters.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,40 @@
 
+Изменения в nginx 0.7.60                                          15.06.2009
+
+    *) Добавление: параметр updating в директивах proxy_cache_use_stale и 
+       fastcgi_cache_use_stale.
+
+    *) Добавление: директива keepalive_requests.
+
+    *) Исправление: во взаимодействии open_file_cache и proxy/fastcgi кэша 
+       на старте.
+
+    *) Исправление: open_file_cache мог кэшировать открытые файлы очень 
+       долго.
+
+    *) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в 
+       заголовке запроса клиента передавались бэкенду при кэшировании, если 
+       не использовалась директива proxy_set_header с любыми параметрами.
+
+    *) Исправление: строки "Set-Cookie" и "P3P" в заголовке ответа бэкенда 
+       не скрывались при кэшировании, если не использовались директивы 
+       proxy_hide_header/fastcgi_hide_header с любыми параметрами.
+
+    *) Исправление: модуль ngx_http_image_filter_module не понимал формат 
+       GIF87a.
+       Спасибо Денису Ильиных.
+
+    *) Исправление: nginx не собирался на Solaris 10 и более ранних; ошибка 
+       появилась в 0.7.56.
+
+    *) Исправление: XSLT-фильтр не работал в подзапросах.
+
+    *) Исправление: обработке относительных путей в nginx/Windows.
+
+    *) Исправление: в proxy_store, fastcgi_store, proxy_cache и 
+       fastcgi_cache в nginx/Windows.
+
+
 Изменения в nginx 0.7.59                                          25.05.2009
 
     *) Добавление: директивы proxy_cache_methods и fastcgi_cache_methods.
@@ -56,7 +92,7 @@
 
 Изменения в nginx 0.7.55                                          06.05.2009
 
-    *) Исправление: параметры http_XXX в директиве proxy_cache_use_stale и 
+    *) Исправление: параметры http_XXX в директивах proxy_cache_use_stale и 
        fastcgi_cache_use_stale не работали.
 
     *) Исправление: fastcgi кэш не кэшировал ответы, состоящие только из 
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -125,7 +125,7 @@ ngx_objext="obj"
 ngx_binext=".exe"
 
 ngx_long_start='@<<
-        '
+	'
 ngx_long_end='<<'
 ngx_long_regex_cont=' \
 	'
--- a/auto/lib/conf
+++ b/auto/lib/conf
@@ -4,15 +4,29 @@
 
 if [ $USE_PCRE = YES -o $PCRE != NONE ]; then
     . auto/lib/pcre/conf
+
+else
+    if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then
+
+cat << END
+
+$0: error: the HTTP rewrite module requires the PCRE library.
+You can either disable the module by using --without-http_rewrite_module
+option or you have to enable the PCRE support.
+
+END
+        exit 1
+    fi
 fi
 
+
 if [ $USE_OPENSSL = YES ]; then
     . auto/lib/openssl/conf
 fi
 
 if [ $USE_MD5 = YES ]; then
 
-    if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then
+    if [ $USE_OPENSSL = YES ]; then
         have=NGX_HAVE_OPENSSL_MD5_H . auto/have
         have=NGX_OPENSSL_MD5 . auto/have
         MD5=YES
@@ -26,7 +40,7 @@ fi
 
 if [ $USE_SHA1 = YES ]; then
 
-    if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then
+    if [ $USE_OPENSSL = YES ]; then
         have=NGX_HAVE_OPENSSL_SHA1_H . auto/have
         SHA1=YES
         SHA1_LIB=OpenSSL
--- a/auto/lib/google-perftools/conf
+++ b/auto/lib/google-perftools/conf
@@ -30,4 +30,15 @@ fi
 
 if [ $ngx_found = yes ]; then
     CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+else
+
+cat << END
+
+$0: error: the Google perftool module requires the Google perftools
+library. You can either do not enable the module or install the library.
+
+END
+
+    exit 1
 fi
--- a/auto/lib/md5/conf
+++ b/auto/lib/md5/conf
@@ -94,6 +94,18 @@ else
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             MD5=YES
             MD5_LIB=$ngx_md5_lib
+        else
+
+cat << END
+
+$0: error: the HTTP cache module requires md5 functions
+from OpenSSL library.  You can either disable the module by using
+--without-http_cache option, or install the OpenSSL library into the system,
+or build the OpenSSL library statically from the source with nginx by using
+--with-openssl=<path> option.
+
+END
+            exit 1
         fi
 
     fi
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -66,6 +66,17 @@ else
                 have=NGX_SSL . auto/have
                 CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL"
                 OPENSSL=YES
+            else
+
+cat << END
+
+$0: error: SSL modules require the OpenSSL library.
+You can either do not enable the modules, or install the OpenSSL library
+into the system, or build the OpenSSL library statically from the source
+with nginx by using --with-openssl=<path> option.
+
+END
+                exit 1
             fi
         ;;
 
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -2,11 +2,6 @@
 # Copyright (C) Igor Sysoev
 
 
-case $USE_THREADS in
-    NO) OPENSSL_OPT="$OPENSSL_OPT no-threads" ;;
-    *)  OPENSSL_OPT="$OPENSSL_OPT threads" ;;
-esac
-
 case "$CC" in
 
     cl)
@@ -21,7 +16,7 @@ END
 
     ;;
 
-    cl | bcc32)
+    bcc32)
 
         ngx_opt=`echo "-DOPENSSL=\"$OPENSSL\" -DOPENSSL_OPT=\"$OPENSSL_OPT\"" \
             | sed -e "s/\//$ngx_regex_dirsep/g"`
@@ -45,16 +40,14 @@ END
     ;;
 
     *)
-        case $OPENSSL in
+        case $USE_THREADS in
+            NO) OPENSSL_OPT="$OPENSSL_OPT no-threads" ;;
+            *)  OPENSSL_OPT="$OPENSSL_OPT threads" ;;
+        esac
 
-        /*)
-            ngx_prefix="$OPENSSL/openssl"
-        ;;
-
-        *)
-            ngx_prefix="$PWD/$OPENSSL/openssl"
-        ;;
-
+        case $OPENSSL in
+            /*) ngx_prefix="$OPENSSL/openssl" ;;
+            *)  ngx_prefix="$PWD/$OPENSSL/openssl" ;;
         esac
 
         cat << END                                            >> $NGX_MAKEFILE
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -161,6 +161,18 @@ else
             CORE_INCS="$CORE_INCS $ngx_feature_path"
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             PCRE=YES
+        else
+
+cat << END
+
+$0: error: the HTTP rewrite module requires the PCRE library.
+You can either disable the module by using --without-http_rewrite_module
+option, or install the PCRE library into the system, or build the PCRE library
+statically from the source with nginx by using --with-pcre=<path> option.
+
+END
+            exit 1
+
         fi
 
     fi
--- a/auto/lib/zlib/conf
+++ b/auto/lib/zlib/conf
@@ -57,6 +57,17 @@ else
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             ZLIB=YES
             ngx_found=no
+        else
+
+cat << END
+
+$0: error: the HTTP gzip module requires the zlib library.
+You can either disable the module by using --without-http_gzip_module
+option, or install the zlib library into the system, or build the zlib library
+statically from the source with nginx by using --with-zlib=<path> option.
+
+END
+            exit 1
         fi
     fi
 
--- a/auto/os/features
+++ b/auto/os/features
@@ -252,3 +252,25 @@ if [ $ngx_found != yes ]; then
         NGX_LIBDL="-ldl"
     fi
 fi
+
+
+ngx_feature="sched_yield()"
+ngx_feature_name="NGX_HAVE_SCHED_YIELD"
+ngx_feature_run=no
+ngx_feature_incs="#include <sched.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="sched_yield()"
+. auto/feature
+
+
+if [ $ngx_found != yes ]; then
+
+    ngx_feature="sched_yield() in librt"
+    ngx_feature_libs="-lrt"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        CORE_LIBS="$CORE_LIBS -lrt"
+    fi
+fi
--- a/auto/summary
+++ b/auto/summary
@@ -74,65 +74,6 @@ esac
 echo
 
 
-if [ $HTTP_REWRITE = YES ]; then
-    if [ $USE_PCRE = DISABLED ]; then
-
-cat << END
-$0: error: the HTTP rewrite module requires the PCRE library.
-You can either disable the module by using --without-http_rewrite_module
-option or you have to enable the PCRE support.
-
-END
-        exit 1
-    fi
-
-    if [ $PCRE = NONE -o $PCRE = NO ]; then
-
-cat << END
-$0: error: the HTTP rewrite module requires the PCRE library.
-You can either disable the module by using --without-http_rewrite_module
-option, or install the PCRE library into the system, or build the PCRE library
-statically from the source with nginx by using --with-pcre=<path> option.
-
-END
-
-        exit 1
-    fi
-fi
-
-
-if [ $HTTP_GZIP = YES ]; then
-    if [ $ZLIB = NONE -o $ZLIB = NO ]; then
-
-cat << END
-$0: error: the HTTP gzip module requires the zlib library.
-You can either disable the module by using --without-http_gzip_module
-option, or install the zlib library into the system, or build the zlib library
-statically from the source with nginx by using --with-zlib=<path> option.
-
-END
-
-        exit 1
-    fi
-fi
-
-
-if [ $HTTP_SSL = YES ]; then
-    if [ $OPENSSL = NONE -o $OPENSSL = NO ]; then
-
-cat << END
-$0: error: the HTTP SSL module requires the OpenSSL library.
-You can either do not enable the module, or install the OpenSSL library
-into the system, or build the OpenSSL library statically from the source
-with nginx by using --with-openssl=<path> option.
-
-END
-
-        exit 1
-    fi
-fi
-
-
 cat << END
   nginx path prefix: "$NGX_PREFIX"
   nginx binary file: "$NGX_SBIN_PATH"
--- a/auto/unix
+++ b/auto/unix
@@ -163,28 +163,6 @@ ngx_feature_test="void *p; p = memalign(
 . auto/feature
 
 
-ngx_feature="sched_yield()"
-ngx_feature_name="NGX_HAVE_SCHED_YIELD"
-ngx_feature_run=no
-ngx_feature_incs="#include <sched.h>"
-ngx_feature_path=
-ngx_feature_libs=
-ngx_feature_test="sched_yield()"
-. auto/feature
-
-
-if [ $ngx_found != yes ]; then
-
-    ngx_feature="sched_yield() in librt"
-    ngx_feature_libs="-lrt"
-    . auto/feature
-
-    if [ $ngx_found = yes ]; then
-        CORE_LIBS="$CORE_LIBS -lrt"
-    fi
-fi
-
-
 ngx_feature="mmap(MAP_ANON|MAP_SHARED)"
 ngx_feature_name="NGX_HAVE_MAP_ANON"
 ngx_feature_run=yes
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -330,6 +330,10 @@ main(int argc, char *const *argv)
         return 0;
     }
 
+    if (ngx_signal) {
+        return ngx_signal_process(cycle, ngx_signal);
+    }
+
     ngx_os_status(cycle->log);
 
     ngx_cycle = cycle;
@@ -340,10 +344,6 @@ main(int argc, char *const *argv)
         ngx_process = NGX_PROCESS_MASTER;
     }
 
-    if (ngx_signal) {
-        return ngx_signal_process(cycle, ngx_signal);
-    }
-
 #if !(NGX_WIN32)
 
     if (ngx_init_signals(cycle->log) != NGX_OK) {
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         7059
-#define NGINX_VERSION      "0.7.59"
+#define nginx_version         7060
+#define NGINX_VERSION      "0.7.60"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -12,6 +12,7 @@
 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
 static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name);
 static void ngx_conf_flush_files(ngx_cycle_t *cycle);
 
 
@@ -802,29 +803,15 @@ ngx_int_t
 ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
 {
     size_t      len;
-    u_char     *p, *prefix;
-    ngx_str_t   old;
-
-#if (NGX_WIN32)
+    u_char     *p, *n, *prefix;
+    ngx_int_t   rc;
 
-    if (name->len > 2
-        && name->data[1] == ':'
-        && ((name->data[0] >= 'a' && name->data[0] <= 'z')
-             || (name->data[0] >= 'A' && name->data[0] <= 'Z')))
-    {
-        return NGX_OK;
-    }
+    rc = ngx_conf_test_full_name(name);
 
-#else
-
-    if (name->data[0] == '/') {
-        return NGX_OK;
+    if (rc == NGX_OK) {
+        return rc;
     }
 
-#endif
-
-    old = *name;
-
     if (conf_prefix) {
         len = cycle->conf_prefix.len;
         prefix = cycle->conf_prefix.data;
@@ -834,19 +821,79 @@ ngx_conf_full_name(ngx_cycle_t *cycle, n
         prefix = cycle->prefix.data;
     }
 
-    name->len = len + old.len;
-    name->data = ngx_pnalloc(cycle->pool, name->len + 1);
-    if (name->data == NULL) {
+#if (NGX_WIN32)
+
+    if (rc == 2) {
+        len = rc;
+    }
+
+#endif
+
+    n = ngx_pnalloc(cycle->pool, len + name->len + 1);
+    if (n == NULL) {
         return NGX_ERROR;
     }
 
-    p = ngx_cpymem(name->data, prefix, len);
-    ngx_cpystrn(p, old.data, old.len + 1);
+    p = ngx_cpymem(n, prefix, len);
+    ngx_cpystrn(p, name->data, name->len + 1);
+
+    name->len += len;
+    name->data = n;
 
     return NGX_OK;
 }
 
 
+static ngx_int_t
+ngx_conf_test_full_name(ngx_str_t *name)
+{
+#if (NGX_WIN32)
+    u_char  c0, c1;
+
+    c0 = name->data[0];
+
+    if (name->len < 2) {
+        if (c0 == '/') {
+            return 2;
+        }
+
+        return NGX_DECLINED;
+    }
+
+    c1 = name->data[1];
+
+    if (c1 == ':') {
+        c0 |= 0x20;
+
+        if ((c0 >= 'a' && c0 <= 'z')) {
+            return NGX_OK;
+        }
+
+        return NGX_DECLINED;
+    }
+
+    if (c1 == '/') {
+        return NGX_OK;
+    }
+
+    if (c0 == '/') {
+        return 2;
+    }
+
+    return NGX_DECLINED;
+
+#else
+
+    if (name->data[0] == '/') {
+        return NGX_OK;
+    }
+
+    return NGX_DECLINED;
+
+#endif
+}
+
+
 ngx_open_file_t *
 ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name)
 {
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -603,6 +603,8 @@ ngx_close_listening_sockets(ngx_cycle_t 
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                           ngx_close_socket_n " %V failed", &ls[i].addr_text);
         }
+
+        ls[i].fd = (ngx_socket_t) -1;
     }
 }
 
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -135,6 +135,8 @@ struct ngx_connection_s {
 
     ngx_atomic_uint_t   number;
 
+    ngx_uint_t          requests;
+
     unsigned            buffered:8;
 
     unsigned            log_error:3;     /* ngx_connection_log_error_e */
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -269,7 +269,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
                        cycle->conf_file.data);
     }
 
-
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->type != NGX_CORE_MODULE) {
             continue;
@@ -287,6 +286,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
     }
 
+    if (ngx_process == NGX_PROCESS_SIGNALLER) {
+        return cycle;
+    }
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
@@ -463,11 +465,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             goto failed;
         }
 
-        if (!shm_zone[i].shm.exists) {
-
-            if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
-                goto failed;
-            }
+        if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
+            goto failed;
         }
 
         if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
@@ -567,14 +566,12 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
     }
 
-    if (ngx_process != NGX_PROCESS_SIGNALLER) {
-        if (ngx_open_listening_sockets(cycle) != NGX_OK) {
-            goto failed;
-        }
+    if (ngx_open_listening_sockets(cycle) != NGX_OK) {
+        goto failed;
+    }
 
-        if (!ngx_test_config) {
-            ngx_configure_listening_sockets(cycle);
-        }
+    if (!ngx_test_config) {
+        ngx_configure_listening_sockets(cycle);
     }
 
 
@@ -656,7 +653,8 @@ old_shm_zone_done:
 
     ls = old_cycle->listening.elts;
     for (i = 0; i < old_cycle->listening.nelts; i++) {
-        if (ls[i].remain) {
+
+        if (ls[i].remain || ls[i].fd == -1) {
             continue;
         }
 
@@ -885,8 +883,21 @@ ngx_init_zone_pool(ngx_cycle_t *cycle, n
 
     sp = (ngx_slab_pool_t *) zn->shm.addr;
 
+    if (zn->shm.exists) {
+
+        if (sp == sp->addr) {
+            return NGX_OK;
+        }
+
+        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                      "shared zone \"%V\" has no equal addresses: %p vs %p",
+                      &zn->shm.name, sp->addr, sp);
+        return NGX_ERROR;
+    }
+
     sp->end = zn->shm.addr + zn->shm.size;
     sp->min_shift = 3;
+    sp->addr = zn->shm.addr;
 
 #if (NGX_HAVE_ATOMIC_OPS)
 
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -558,8 +558,14 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 
     err = ngx_errno;
 
-    if (err == NGX_ENOENT) {
-
+    if (err
+#if (NGX_WIN32)
+            == ERROR_PATH_NOT_FOUND
+#else
+            == NGX_ENOENT
+#endif
+       )
+    {
         if (!ext->create_path) {
             goto failed;
         }
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -360,6 +360,7 @@ create:
 
     file->uses = 1;
     file->count = 0;
+    file->use_event = 0;
     file->event = NULL;
 
 add_event:
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -503,6 +503,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
         if (src->pos == src->last) {
             dst->flush = src->flush;
             dst->last_buf = src->last_buf;
+            dst->last_in_chain = src->last_in_chain;
         }
 
     } else {
@@ -577,6 +578,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
         if (src->file_pos == src->file_last) {
             dst->flush = src->flush;
             dst->last_buf = src->last_buf;
+            dst->last_in_chain = src->last_in_chain;
         }
     }
 
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -25,6 +25,7 @@ ngx_create_pool(size_t size, ngx_log_t *
     p->d.last = (u_char *) p + sizeof(ngx_pool_t);
     p->d.end = (u_char *) p + size;
     p->d.next = NULL;
+    p->d.failed = 0;
 
     size = size - sizeof(ngx_pool_t);
     p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
@@ -189,6 +190,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_
 
     new->d.end = m + psize;
     new->d.next = NULL;
+    new->d.failed = 0;
 
     m += sizeof(ngx_pool_data_t);
     m = ngx_align_ptr(m, NGX_ALIGNMENT);
@@ -197,7 +199,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_
     current = pool->current;
 
     for (p = current; p->d.next; p = p->d.next) {
-        if ((size_t) (p->d.end - p->d.last) < NGX_ALIGNMENT) {
+        if (p->d.failed++ > 4) {
             current = p->d.next;
         }
     }
@@ -214,6 +216,7 @@ static void *
 ngx_palloc_large(ngx_pool_t *pool, size_t size)
 {
     void              *p;
+    ngx_uint_t         n;
     ngx_pool_large_t  *large;
 
     p = ngx_alloc(size, pool->log);
@@ -221,6 +224,19 @@ ngx_palloc_large(ngx_pool_t *pool, size_
         return NULL;
     }
 
+    n = 0;
+
+    for (large = pool->large; large; large = large->next) {
+        if (large->alloc == NULL) {
+            large->alloc = p;
+            return p;
+        }
+
+        if (n++ > 3) {
+            break;
+        }
+    }
+
     large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
     if (large == NULL) {
         ngx_free(p);
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -46,6 +46,7 @@ typedef struct {
     u_char               *last;
     u_char               *end;
     ngx_pool_t           *next;
+    ngx_uint_t            failed;
 } ngx_pool_data_t;
 
 
--- a/src/core/ngx_slab.h
+++ b/src/core/ngx_slab.h
@@ -39,6 +39,7 @@ typedef struct {
     u_char            zero;
 
     void             *data;
+    void             *addr;
 } ngx_slab_pool_t;
 
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -178,6 +178,7 @@ static ngx_conf_bitmask_t  ngx_http_fast
     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+    { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
     { ngx_null_string, 0 }
 };
@@ -1911,7 +1912,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store,
-                                  prev->upstream.store, 0);
+                              prev->upstream.store, 0);
 
         if (conf->upstream.store_lengths == NULL) {
             conf->upstream.store_lengths = prev->upstream.store_lengths;
@@ -2541,20 +2542,31 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, n
     ngx_str_t                  *value;
     ngx_http_script_compile_t   sc;
 
-    if (flcf->upstream.store != NGX_CONF_UNSET || flcf->upstream.store_lengths)
+    if (flcf->upstream.store != NGX_CONF_UNSET
+        || flcf->upstream.store_lengths)
     {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    if (ngx_strcmp(value[1].data, "on") == 0) {
-        flcf->upstream.store = 1;
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        flcf->upstream.store = 0;
         return NGX_CONF_OK;
     }
 
-    if (ngx_strcmp(value[1].data, "off") == 0) {
-        flcf->upstream.store = 0;
+#if (NGX_HTTP_CACHE)
+
+    if (flcf->upstream.cache != NGX_CONF_UNSET_PTR
+        && flcf->upstream.cache != NULL)
+    {
+        return "is incompatible with \"fastcgi_cache\"";
+    }
+
+#endif
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        flcf->upstream.store = 1;
         return NGX_CONF_OK;
     }
 
@@ -2599,6 +2611,10 @@ ngx_http_fastcgi_cache(ngx_conf_t *cf, n
         return NGX_CONF_OK;
     }
 
+    if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) {
+        return "is incompatible with \"fastcgi_store\"";
+    }
+
     flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
                                                  &ngx_http_fastcgi_module);
     if (flcf->upstream.cache == NULL) {
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -383,11 +383,12 @@ ngx_http_image_test(ngx_http_request_t *
         return NGX_HTTP_IMAGE_JPEG;
 
     } else if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F' && p[3] == '8'
-               && p[4] == '9' && p[5] == 'a')
+               && p[5] == 'a')
     {
-        /* GIF */
-
-        return NGX_HTTP_IMAGE_GIF;
+        if (p[4] == '9' || p[4] == '7') {
+            /* GIF */
+            return NGX_HTTP_IMAGE_GIF;
+        }
 
     } else if (p[0] == 0x89 && p[1] == 'P' && p[2] == 'N' && p[3] == 'G'
                && p[4] == 0x0d && p[5] == 0x0a && p[6] == 0x1a && p[7] == 0x0a)
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -167,6 +167,7 @@ static ngx_conf_bitmask_t  ngx_http_prox
     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+    { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
     { ngx_null_string, 0 }
 };
@@ -1973,7 +1974,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store,
-                                  prev->upstream.store, 0);
+                              prev->upstream.store, 0);
 
         if (conf->upstream.store_lengths == NULL) {
             conf->upstream.store_lengths = prev->upstream.store_lengths;
@@ -2341,7 +2342,9 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
         conf->headers_source = prev->headers_source;
     }
 
-    if (conf->headers_set_hash.buckets) {
+    if (conf->headers_set_hash.buckets
+        && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)))
+    {
         return NGX_OK;
     }
 
@@ -2809,20 +2812,31 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx
     ngx_str_t                  *value;
     ngx_http_script_compile_t   sc;
 
-    if (plcf->upstream.store != NGX_CONF_UNSET || plcf->upstream.store_lengths)
+    if (plcf->upstream.store != NGX_CONF_UNSET
+        || plcf->upstream.store_lengths)
     {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    if (ngx_strcmp(value[1].data, "on") == 0) {
-        plcf->upstream.store = 1;
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        plcf->upstream.store = 0;
         return NGX_CONF_OK;
     }
 
-    if (ngx_strcmp(value[1].data, "off") == 0) {
-        plcf->upstream.store = 0;
+#if (NGX_HTTP_CACHE)
+
+    if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
+        && plcf->upstream.cache != NULL)
+    {
+        return "is incompatible with \"proxy_cache\"";
+    }
+
+#endif
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        plcf->upstream.store = 1;
         return NGX_CONF_OK;
     }
 
@@ -2867,6 +2881,10 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx
         return NGX_CONF_OK;
     }
 
+    if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
+        return "is incompatible with \"proxy_store\"";
+    }
+
     plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
                                                  &ngx_http_proxy_module);
     if (plcf->upstream.cache == NULL) {
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -280,7 +280,7 @@ ngx_http_xslt_body_filter(ngx_http_reque
             return ngx_http_xslt_send(r, ctx, NULL);
         }
 
-        if (cl->buf->last_buf) {
+        if (cl->buf->last_buf || cl->buf->last_in_chain) {
 
             ctx->doc = ctx->ctxt->myDoc;
 
@@ -427,8 +427,8 @@ ngx_http_xslt_add_chunk(ngx_http_request
         ctx->request = r;
     }
 
-    err = xmlParseChunk(ctx->ctxt, (char *) b->pos,
-                        (int) (b->last - b->pos), b->last_buf);
+    err = xmlParseChunk(ctx->ctxt, (char *) b->pos, (int) (b->last - b->pos),
+                        (b->last_buf) || (b->last_in_chain));
 
     if (err == 0) {
         b->pos = b->last;
@@ -812,7 +812,6 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
     b->pos = buf;
     b->last = buf + len;
     b->memory = 1;
-    b->last_buf = 1;
 
     if (encoding) {
         r->headers_out.charset.len = ngx_strlen(encoding);
@@ -823,6 +822,8 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
         return b;
     }
 
+    b->last_buf = 1;
+
     if (type) {
         len = ngx_strlen(type);
 
--- 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.7.59';
+our $VERSION = '0.7.60';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -13,11 +13,8 @@
 #include <ngx_http.h>
 
 
-/**/
 #define NGX_HTTP_CACHE_STALE         1
-#define NGX_HTTP_CACHE_AGED          2
-#define NGX_HTTP_CACHE_THE_SAME      3
-/**/
+#define NGX_HTTP_CACHE_UPDATING      2
 
 #define NGX_HTTP_CACHE_KEY_LEN       16
 
@@ -28,8 +25,6 @@ typedef struct {
 } ngx_http_cache_valid_t;
 
 
-/* ngx_http_file_cache_node_t takes exactly 64 bytes on FreeBSD/i386 */
-
 typedef struct {
     ngx_rbtree_node_t                node;
     ngx_queue_t                      queue;
@@ -41,8 +36,9 @@ typedef struct {
     unsigned                         uses:10;
     unsigned                         valid_msec:10;
     unsigned                         error:10;
-                                     /* 7 unused bits */
     unsigned                         exists:1;
+    unsigned                         updating:1;
+                                     /* 12 unused bits */
 
     ngx_file_uniq_t                  uniq;
     time_t                           expire;
@@ -68,7 +64,6 @@ struct ngx_http_cache_s {
     off_t                            length;
 
     ngx_uint_t                       min_uses;
-    ngx_uint_t                       uses;
     ngx_uint_t                       error;
     ngx_uint_t                       valid_msec;
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -440,6 +440,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("keepalive_requests"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, keepalive_requests),
+      NULL },
+
     { ngx_string("satisfy"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_enum_slot,
@@ -1326,8 +1333,13 @@ ngx_http_update_location_config(ngx_http
 
     r->request_body_in_single_buf = clcf->client_body_in_single_buffer;
 
-    if (r->keepalive && clcf->keepalive_timeout == 0) {
-        r->keepalive = 0;
+    if (r->keepalive) {
+        if (clcf->keepalive_timeout == 0) {
+            r->keepalive = 0;
+
+        } else if (r->connection->requests >= clcf->keepalive_requests) {
+            r->keepalive = 0;
+        }
     }
 
     if (!clcf->tcp_nopush) {
@@ -2914,6 +2926,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->limit_rate = 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;
@@ -3114,6 +3127,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
                               prev->keepalive_timeout, 75000);
     ngx_conf_merge_sec_value(conf->keepalive_header,
                               prev->keepalive_header, 0);
+    ngx_conf_merge_uint_value(conf->keepalive_requests,
+                              prev->keepalive_requests, 100);
     ngx_conf_merge_msec_value(conf->lingering_time,
                               prev->lingering_time, 30000);
     ngx_conf_merge_msec_value(conf->lingering_timeout,
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -337,6 +337,7 @@ struct ngx_http_core_loc_conf_s {
 
     time_t        keepalive_header;        /* keepalive_timeout */
 
+    ngx_uint_t    keepalive_requests;      /* keepalive_requests */
     ngx_uint_t    satisfy;                 /* satisfy */
     ngx_uint_t    if_modified_since;       /* if_modified_since */
     ngx_uint_t    client_body_in_file_only; /* client_body_in_file_only */
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -172,9 +172,8 @@ ngx_http_file_cache_open(ngx_http_reques
 
     rc = ngx_http_file_cache_exists(cache, c);
 
-    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http file cache exists: %i u:%ui e:%d",
-                   rc, c->uses, c->exists);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http file cache exists: %i e:%d", rc, c->exists);
 
     if (rc == NGX_ERROR) {
         return rc;
@@ -321,6 +320,7 @@ ngx_http_file_cache_open(ngx_http_reques
             c->node->uses = 1;
             c->node->body_start = c->body_start;
             c->node->exists = 1;
+            c->node->uniq = of.uniq;
 
             cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
         }
@@ -332,16 +332,25 @@ ngx_http_file_cache_open(ngx_http_reques
 
     if (c->valid_sec < now) {
 
-        c->uses = c->min_uses;
+        ngx_shmtx_lock(&cache->shpool->mutex);
 
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http file cache expired: %T %T", c->valid_sec, now);
+        if (c->node->updating) {
+            rc = NGX_HTTP_CACHE_UPDATING;
 
-        return NGX_HTTP_CACHE_STALE;
+        } else {
+            c->node->updating = 1;
+            rc = NGX_HTTP_CACHE_STALE;
+        }
+
+        ngx_shmtx_unlock(&cache->shpool->mutex);
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http file cache expired: %i %T %T",
+                       rc, c->valid_sec, now);
+
+        return rc;
     }
 
-    /* TODO: NGX_HTTP_CACHE_AGED */
-
     return NGX_OK;
 }
 
@@ -442,7 +451,6 @@ done:
     ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
 
     c->uniq = fcn->uniq;
-    c->uses = fcn->uses;
     c->error = fcn->error;
     c->node = fcn;
 
@@ -654,6 +662,8 @@ ngx_http_file_cache_update(ngx_http_requ
         c->node->exists = 1;
     }
 
+    c->node->updating = 0;
+
     ngx_shmtx_unlock(&cache->shpool->mutex);
 }
 
@@ -736,6 +746,8 @@ ngx_http_file_cache_free(ngx_http_reques
         c->node->error = c->error;
     }
 
+    c->node->updating = 0;
+
     ngx_shmtx_unlock(&cache->shpool->mutex);
 
     if (c->temp_file) {
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -259,6 +259,8 @@ ngx_http_init_request(ngx_event_t *rev)
         return;
     }
 
+    c->requests++;
+
     hc = c->data;
 
     if (hc == NULL) {
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -577,8 +577,17 @@ ngx_http_upstream_cache(ngx_http_request
 
     rc = ngx_http_file_cache_open(r);
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http upstream cache: %i u:%ui", rc, c->uses);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http upstream cache: %i", rc);
+
+    if (rc == NGX_HTTP_CACHE_UPDATING) {
+        if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) {
+            rc = NGX_OK;
+
+        } else {
+            rc = NGX_HTTP_CACHE_STALE;
+        }
+    }
 
     if (rc == NGX_OK) {
 
@@ -4076,7 +4085,9 @@ ngx_http_upstream_hide_headers_hash(ngx_
     {
         conf->hide_headers_hash = prev->hide_headers_hash;
 
-        if (conf->hide_headers_hash.buckets) {
+        if (conf->hide_headers_hash.buckets
+            && ((conf->cache == NULL) == (prev->cache == NULL)))
+        {
             return NGX_OK;
         }
 
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -24,8 +24,9 @@
 #define NGX_HTTP_UPSTREAM_FT_HTTP_503        0x00000040
 #define NGX_HTTP_UPSTREAM_FT_HTTP_504        0x00000080
 #define NGX_HTTP_UPSTREAM_FT_HTTP_404        0x00000100
-#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK       0x00000200
-#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING     0x00000400
+#define NGX_HTTP_UPSTREAM_FT_UPDATING        0x00000200
+#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK       0x00000400
+#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING     0x00000800
 #define NGX_HTTP_UPSTREAM_FT_NOLIVE          0x40000000
 #define NGX_HTTP_UPSTREAM_FT_OFF             0x80000000