changeset 502:89dc5654117c NGINX_0_7_63

nginx 0.7.63 *) Security: now "/../" are disabled in "Destination" request header line. *) Change: minimum supported OpenSSL version is 0.9.7. *) Change: the "ask" parameter of the "ssl_verify_client" directive was changed to the "optional" parameter and now it checks a client certificate if it was offered. Thanks to Brice Figureau. *) Feature: now the "-V" switch shows TLS SNI support. *) Feature: the $ssl_client_verify variable. Thanks to Brice Figureau. *) Feature: the "ssl_crl" directive. Thanks to Brice Figureau. *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the bug had appeared in 0.7.7. Thanks to Sergey Zhuravlev. *) Feature: now the start cache loader runs in a separate process; this should improve large caches handling. *) Feature: now temporary files and permanent storage area may reside at different file systems. *) Bugfix: nginx counted incorrectly disk cache size. *) Change: now directive "gzip_disable msie6" does not disable gzipping for MSIE 6.0 SV1. *) Bugfix: nginx always added "Vary: Accept-Encoding" response header line, if both "gzip_static" and "gzip_vary" were on. *) Feature: the "proxy" parameter of the "geo" directive. *) Feature: the ngx_http_geoip_module. *) Feature: the "limit_rate_after" directive. Thanks to Ivan Debnar. *) Feature: the "limit_req_log_level" and "limit_conn_log_level" directives. *) Bugfix: now "limit_req" directive conforms to the leaky bucket algorithm. Thanks to Maxim Dounin. *) Bugfix: in ngx_http_limit_req_module. Thanks to Maxim Dounin. *) Bugfix: now nginx allows underscores in a request method. *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", "X-Accel-Buffering", and "X-Accel-Charset" lines from backend response header. Thanks to Maxim Dounin. *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend response header lines; the bug had appeared in 0.7.44. Thanks to Maxim Dounin. *) Feature: the "image_filter_transparency" directive. *) Feature: the "image_filter" directive supports variables for setting size. *) Bugfix: in PNG alpha-channel support in the ngx_http_image_filter_module. *) Bugfix: in transparency support in the ngx_http_image_filter_module. *) Feature: now several "perl_modules" directives may be used. *) Bugfix: ngx_http_perl_module responses did not work in subrequests. *) Bugfix: nginx sent '\0' in a "Location" response header line on MKCOL request. Thanks to Xie Zhenye. *) Bugfix: an "error_page" directive did not redirect a 413 error; the bug had appeared in 0.6.10. *) Bugfix: in memory allocation error handling. Thanks to Maxim Dounin and Kirill A. Korinskiy.
author Igor Sysoev <http://sysoev.ru>
date Mon, 26 Oct 2009 00:00:00 +0300
parents dc87c92181c7
children bedade69b1a4
files CHANGES CHANGES.ru auto/lib/conf auto/lib/geoip/conf auto/modules auto/options auto/sources src/core/nginx.c src/core/nginx.h src/core/ngx_cycle.c src/core/ngx_file.c src/core/ngx_file.h src/core/ngx_hash.c src/core/ngx_output_chain.c src/core/ngx_string.c src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_epoll_module.c src/event/modules/ngx_eventport_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_rtsig_module.c src/event/ngx_event.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_access_module.c src/http/modules/ngx_http_addition_filter_module.c src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_browser_module.c src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_geo_module.c src/http/modules/ngx_http_geoip_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_headers_filter_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_limit_req_module.c src/http/modules/ngx_http_limit_zone_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_map_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_random_index_module.c src/http/modules/ngx_http_realip_module.c src/http/modules/ngx_http_referer_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_secure_link_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_ssl_module.h src/http/modules/ngx_http_sub_filter_module.c src/http/modules/ngx_http_userid_filter_module.c src/http/modules/ngx_http_xslt_filter_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c 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_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_script.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_write_filter_module.c src/mail/ngx_mail_auth_http_module.c src/mail/ngx_mail_core_module.c src/mail/ngx_mail_proxy_module.c src/mail/ngx_mail_ssl_module.c src/os/unix/ngx_errno.h src/os/unix/ngx_files.h src/os/unix/ngx_process.c src/os/unix/ngx_process.h src/os/unix/ngx_process_cycle.c src/os/unix/ngx_process_cycle.h
diffstat 78 files changed, 2189 insertions(+), 871 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,96 @@
 
+Changes with nginx 0.7.63                                        26 Oct 2009
+
+    *) Security: now "/../" are disabled in "Destination" request header 
+       line.
+
+    *) Change: minimum supported OpenSSL version is 0.9.7.
+
+    *) Change: the "ask" parameter of the "ssl_verify_client" directive was 
+       changed to the "optional" parameter and now it checks a client 
+       certificate if it was offered.
+       Thanks to Brice Figureau.
+
+    *) Feature: now the "-V" switch shows TLS SNI support.
+
+    *) Feature: the $ssl_client_verify variable.
+       Thanks to Brice Figureau.
+
+    *) Feature: the "ssl_crl" directive.
+       Thanks to Brice Figureau.
+
+    *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the 
+       bug had appeared in 0.7.7.
+       Thanks to Sergey Zhuravlev.
+
+    *) Feature: now the start cache loader runs in a separate process; this 
+       should improve large caches handling.
+
+    *) Feature: now temporary files and permanent storage area may reside 
+       at different file systems.
+
+    *) Bugfix: nginx counted incorrectly disk cache size.
+
+    *) Change: now directive "gzip_disable msie6" does not disable gzipping 
+       for MSIE 6.0 SV1.
+
+    *) Bugfix: nginx always added "Vary: Accept-Encoding" response header 
+       line, if both "gzip_static" and "gzip_vary" were on.
+
+    *) Feature: the "proxy" parameter of the "geo" directive.
+
+    *) Feature: the ngx_http_geoip_module.
+
+    *) Feature: the "limit_rate_after" directive.
+       Thanks to Ivan Debnar.
+
+    *) Feature: the "limit_req_log_level" and "limit_conn_log_level" 
+       directives.
+
+    *) Bugfix: now "limit_req" directive conforms to the leaky bucket 
+       algorithm.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: in ngx_http_limit_req_module.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: now nginx allows underscores in a request method.
+
+    *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did 
+       not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", 
+       "X-Accel-Buffering", and "X-Accel-Charset" lines from backend 
+       response header.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend 
+       response header lines; the bug had appeared in 0.7.44.
+       Thanks to Maxim Dounin.
+
+    *) Feature: the "image_filter_transparency" directive.
+
+    *) Feature: the "image_filter" directive supports variables for setting 
+       size.
+
+    *) Bugfix: in PNG alpha-channel support in the 
+       ngx_http_image_filter_module.
+
+    *) Bugfix: in transparency support in the ngx_http_image_filter_module.
+
+    *) Feature: now several "perl_modules" directives may be used.
+
+    *) Bugfix: ngx_http_perl_module responses did not work in subrequests.
+
+    *) Bugfix: nginx sent '\0' in a "Location" response header line on 
+       MKCOL request.
+       Thanks to Xie Zhenye.
+
+    *) Bugfix: an "error_page" directive did not redirect a 413 error; the 
+       bug had appeared in 0.6.10.
+
+    *) Bugfix: in memory allocation error handling.
+       Thanks to Maxim Dounin and Kirill A. Korinskiy.
+
+
 Changes with nginx 0.7.62                                        14 Sep 2009
 
     *) Security: a segmentation fault might occur in worker process while 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,99 @@
 
+Изменения в nginx 0.7.63                                          26.10.2009
+
+    *) Безопасность: теперь символы "/../" запрещены в строке "Destination" 
+       в заголовке запроса.
+
+    *) Изменение: минимальная поддерживаемая версия OpenSSL - 0.9.7.
+
+    *) Изменение: параметр ask директивы ssl_verify_client изменён на 
+       параметр optional и теперь он проверяет клиентский сертификат, если 
+       он был предложен.
+       Спасибо Brice Figureau.
+
+    *) Добавление: теперь ключ -V показывает статус поддержки TLS SNI.
+
+    *) Добавление: переменная $ssl_client_verify.
+       Спасибо Brice Figureau.
+
+    *) Добавление: директива ssl_crl.
+       Спасибо Brice Figureau.
+
+    *) Исправление: использование переменной $ssl_client_cert портило 
+       память; ошибка появилась в 0.7.7.
+       Спасибо Сергею Журавлёву.
+
+    *) Добавление: теперь стартовый загрузчик кэша работает в отдельном 
+       процесс; это должно улучшить обработку больших кэшей.
+
+    *) Добавление: теперь временные файлы и постоянное место хранения могут 
+       располагаться на разных файловых системах.
+
+    *) Исправление: nginx неверно считал размер кэша на диске.
+
+    *) Изменение: теперь директива "gzip_disable msie6" не запрещает сжатие 
+       для MSIE 6.0 SV1.
+
+    *) Исправление: nginx всегда добавлял строку "Vary: Accept-Encoding" в 
+       заголовок ответа, если обе директивы gzip_static и gzip_vary были 
+       включены.
+
+    *) Добавление: параметр proxy директивы geo.
+
+    *) Добавление: модуль ngx_http_geoip_module.
+
+    *) Добавление: директива limit_rate_after.
+       Спасибо Ivan Debnar.
+
+    *) Добавление: директивы limit_req_log_level и limit_conn_log_level.
+
+    *) Исправление: Теперь директива limit_req соответствует алгоритму 
+       leaky bucket.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: в модуле ngx_http_limit_req_module.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: теперь nginx разрешает подчёркивания в методе запроса.
+
+    *) Исправление: директивы proxy_pass_header и fastcgi_pass_header" не 
+       передавали клиенту строки "X-Accel-Redirect", "X-Accel-Limit-Rate", 
+       "X-Accel-Buffering" и "X-Accel-Charset" из заголовка ответа 
+       бэкенда.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: в обработке строк "Last-Modified" и "Accept-Ranges" в 
+       заголовке ответа бэкенда; ошибка появилась в 0.7.44
+       Спасибо Максиму Дунину.
+
+    *) Добавление: директива image_filter_transparency.
+
+    *) Добавление: директива image_filter поддерживает переменные для 
+       задания размеров.
+
+    *) Исправление: в поддержке альфа-канала PNG в модуле 
+       ngx_http_image_filter_module.
+
+    *) Исправление: в поддержке прозрачности в модуле 
+       ngx_http_image_filter_module.
+
+    *) Добавление: теперь можно использовать несколько директив 
+       perl_modules.
+
+    *) Исправление: ответы модуля ngx_http_perl_module не работали в 
+       подзапросах.
+
+    *) Исправление: nginx слал символ '\0' в строке "Location" в заголовке 
+       в ответе на запрос MKCOL.
+       Спасибо Xie Zhenye.
+
+    *) Исправление: директива error_page не перенаправляла ошибку 413; 
+       ошибка появилась в 0.6.10.
+
+    *) Исправление: в обработке ошибок выделения памяти.
+       Спасибо Максиму Дунину и Кириллу Коринскому.
+
+
 Изменения в nginx 0.7.62                                          14.09.2009
 
     *) Безопасность: при обработке специально созданного запроса в рабочем 
--- a/auto/lib/conf
+++ b/auto/lib/conf
@@ -67,6 +67,9 @@ if [ $USE_PERL = YES ]; then
     . auto/lib/perl/conf
 fi
 
+if [ $HTTP_GEOIP = YES ]; then
+    . auto/lib/geoip/conf
+fi
 if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then
     . auto/lib/google-perftools/conf
 fi
new file mode 100644
--- /dev/null
+++ b/auto/lib/geoip/conf
@@ -0,0 +1,78 @@
+
+# Copyright (C) Igor Sysoev
+
+
+    ngx_feature="GeoIP library"
+    ngx_feature_name=
+    ngx_feature_run=no
+    ngx_feature_incs=
+    ngx_feature_path=
+    ngx_feature_libs="-lGeoIP"
+    ngx_feature_test="GeoIP_open(NULL, 0)"
+    . auto/feature
+
+
+if [ $ngx_found = no ]; then
+
+    # FreeBSD port
+
+    ngx_feature="GeoIP library in /usr/local/"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lGeoIP"
+    else
+        ngx_feature_libs="-L/usr/local/lib -lGeoIP"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+    # NetBSD port
+
+    ngx_feature="GeoIP library in /usr/pkg/"
+    ngx_feature_path="/usr/pkg/include/"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lGeoIP"
+    else
+        ngx_feature_libs="-L/usr/pkg/lib -lGeoIP"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+    # MacPorts
+
+    ngx_feature="GeoIP library in /opt/local/"
+    ngx_feature_path="/opt/local/include"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lGeoIP"
+    else
+        ngx_feature_libs="-L/opt/local/lib -lGeoIP"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = yes ]; then
+    CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+else
+
+cat << END
+
+$0: error: the GeoIP module requires the GeoIP library.
+You can either do not enable the module or install the library.
+
+END
+
+    exit 1
+fi
--- a/auto/modules
+++ b/auto/modules
@@ -240,6 +240,12 @@ if [ $HTTP_GEO = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_GEO_SRCS"
 fi
 
+if [ $HTTP_GEOIP = YES ]; then
+    have=NGX_HTTP_GEOIP . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_GEOIP_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_GEOIP_SRCS"
+fi
+
 if [ $HTTP_MAP = YES ]; then
     have=NGX_HTTP_MAP . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_MAP_MODULE"
--- a/auto/options
+++ b/auto/options
@@ -71,6 +71,7 @@ HTTP_AUTOINDEX=YES
 HTTP_RANDOM_INDEX=NO
 HTTP_STATUS=NO
 HTTP_GEO=YES
+HTTP_GEOIP=NO
 HTTP_MAP=YES
 HTTP_REFERER=YES
 HTTP_REWRITE=YES
@@ -184,6 +185,7 @@ do
         --with-http_addition_module)     HTTP_ADDITION=YES          ;;
         --with-http_xslt_module)         HTTP_XSLT=YES              ;;
         --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES      ;;
+        --with-http_geoip_module)        HTTP_GEOIP=YES             ;;
         --with-http_sub_module)          HTTP_SUB=YES               ;;
         --with-http_dav_module)          HTTP_DAV=YES               ;;
         --with-http_flv_module)          HTTP_FLV=YES               ;;
@@ -310,6 +312,7 @@ cat << END
   --with-http_addition_module        enable ngx_http_addition_module
   --with-http_xslt_module            enable ngx_http_xslt_module
   --with-http_image_filter_module    enable ngx_http_image_filter_module
+  --with-http_geoip_module           enable ngx_http_geoip_module
   --with-http_sub_module             enable ngx_http_sub_module
   --with-http_dav_module             enable ngx_http_dav_module
   --with-http_flv_module             enable ngx_http_flv_module
--- a/auto/sources
+++ b/auto/sources
@@ -377,6 +377,10 @@ HTTP_GEO_MODULE=ngx_http_geo_module
 HTTP_GEO_SRCS=src/http/modules/ngx_http_geo_module.c
 
 
+HTTP_GEOIP_MODULE=ngx_http_geoip_module
+HTTP_GEOIP_SRCS=src/http/modules/ngx_http_geoip_module.c
+
+
 HTTP_MAP_MODULE=ngx_http_map_module
 HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c
 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -239,6 +239,13 @@ main(int argc, char *const *argv)
 #ifdef NGX_COMPILER
             ngx_log_stderr(0, "built by " NGX_COMPILER);
 #endif
+#if (NGX_SSL)
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+            ngx_log_stderr(0, "TLS SNI support enabled");
+#else
+            ngx_log_stderr(0, "TLS SNI support disabled");
+#endif
+#endif
             ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE);
         }
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         7062
-#define NGINX_VERSION      "0.7.62"
+#define nginx_version         7063
+#define NGINX_VERSION      "0.7.63"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -216,7 +216,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 
         if (module->create_conf) {
             rv = module->create_conf(cycle);
-            if (rv == NGX_CONF_ERROR) {
+            if (rv == NULL) {
                 ngx_destroy_pool(pool);
                 return NULL;
             }
@@ -255,11 +255,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 #endif
 
     if (ngx_conf_param(&conf) != NGX_CONF_OK) {
+        environ = senv;
         ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
 
     if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
+        environ = senv;
         ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
@@ -280,6 +282,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                 == NGX_CONF_ERROR)
             {
+                environ = senv;
                 ngx_destroy_cycle_pools(&conf);
                 return NULL;
             }
@@ -698,8 +701,8 @@ old_shm_zone_done:
     if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
 
         /*
-         * perl_destruct() frees environ if it is not the same as it was at
-         * perl_construct() time.  So we have saved an previous cycle
+         * perl_destruct() frees environ, if it is not the same as it was at
+         * perl_construct() time, therefore we save the previous cycle
          * environment before ngx_conf_parse() where it will be changed.
          */
 
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -8,8 +8,9 @@
 #include <ngx_core.h>
 
 
-static ngx_atomic_uint_t  ngx_temp_number;
-static ngx_atomic_uint_t  ngx_random_number;
+static ngx_atomic_t   temp_number = 0;
+ngx_atomic_t         *ngx_temp_number = &temp_number;
+ngx_atomic_int_t      ngx_random_number = 123456;
 
 
 ssize_t
@@ -99,13 +100,7 @@ ngx_create_temp_file(ngx_file_t *file, n
             continue;
         }
 
-        if ((path->level[0] == 0)
-            || (err != NGX_ENOENT
-#if (NGX_WIN32)
-                && err != NGX_ENOTDIR
-#endif
-            ))
-        {
+        if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
             ngx_log_error(NGX_LOG_CRIT, file->log, err,
                           ngx_open_tempfile_n " \"%s\" failed",
                           file->name.data);
@@ -211,22 +206,16 @@ ngx_create_full_path(u_char *dir, ngx_ui
 }
 
 
-void
-ngx_init_temp_number(void)
-{
-    ngx_temp_number = 0;
-    ngx_random_number = 123456;
-}
-
-
 ngx_atomic_uint_t
 ngx_next_temp_number(ngx_uint_t collision)
 {
-    if (collision) {
-        ngx_temp_number += ngx_random_number;
-    }
+    ngx_atomic_uint_t  n, add;
+
+    add = collision ? ngx_random_number : 1;
 
-    return ngx_temp_number++;
+    n = ngx_atomic_fetch_add(ngx_temp_number, add);
+
+    return n + add;
 }
 
 
@@ -264,7 +253,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n
     }
 
     path->len = 0;
-    path->manager = (ngx_path_manager_pt) cmd->post;
+    path->manager = NULL;
+    path->loader = NULL;
     path->conf_file = cf->conf_file->file.name.data;
     path->line = cf->conf_file->line;
 
@@ -325,6 +315,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf
                    + init->level[2] + (init->level[2] ? 1 : 0);
 
     (*path)->manager = NULL;
+    (*path)->loader = NULL;
     (*path)->conf_file = NULL;
 
     if (ngx_add_path(cf, path) != NGX_OK) {
@@ -528,7 +519,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng
 ngx_int_t
 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
 {
-    ngx_err_t  err;
+    u_char           *name;
+    ngx_err_t         err;
+    ngx_copy_file_t   cf;
 
 #if !(NGX_WIN32)
 
@@ -558,14 +551,8 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 
     err = ngx_errno;
 
-    if (err
-#if (NGX_WIN32)
-            == ERROR_PATH_NOT_FOUND
-#else
-            == NGX_ENOENT
-#endif
-       )
-    {
+    if (err == NGX_ENOPATH) {
+
         if (!ext->create_path) {
             goto failed;
         }
@@ -584,7 +571,6 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
         }
 
         err = ngx_errno;
-        goto failed;
     }
 
 #if (NGX_WIN32)
@@ -605,6 +591,53 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 
 #endif
 
+    if (err == NGX_EXDEV) {
+
+        cf.size = -1;
+        cf.buf_size = 0;
+        cf.access = ext->access;
+        cf.time = ext->time;
+        cf.log = ext->log;
+
+        name = ngx_alloc(to->len + 1 + 10 + 1, ext->log);
+        if (name == NULL) {
+            return NGX_ERROR;
+        }
+
+        (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data,
+                           (uint32_t) ngx_next_temp_number(0));
+
+        if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {
+
+            if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) {
+                ngx_free(name);
+
+                if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
+                    ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
+                                  ngx_delete_file_n " \"%s\" failed",
+                                  src->data);
+                    return NGX_ERROR;
+                }
+
+                return NGX_OK;
+            }
+
+            ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
+                          ngx_rename_file_n " \"%s\" to \"%s\" failed",
+                          name, to->data);
+
+            if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
+                              ngx_delete_file_n " \"%s\" failed", name);
+
+            }
+        }
+
+        ngx_free(name);
+
+        err = 0;
+    }
+
 failed:
 
     if (ext->delete_file) {
@@ -614,15 +647,141 @@ failed:
         }
     }
 
-    if (err && ext->log_rename_error) {
+    if (err) {
         ngx_log_error(NGX_LOG_CRIT, ext->log, err,
                       ngx_rename_file_n " \"%s\" to \"%s\" failed",
                       src->data, to->data);
     }
 
-    ext->rename_error = err;
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
+{
+    char             *buf;
+    off_t             size;
+    size_t            len;
+    ssize_t           n;
+    ngx_fd_t          fd, nfd;
+    ngx_int_t         rc;
+    ngx_file_info_t   fi;
+
+    rc = NGX_ERROR;
+    buf = NULL;
+    nfd = NGX_INVALID_FILE;
+
+    fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+
+    if (fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", from);
+        goto failed;
+    }
+
+    if (cf->size != -1) {
+        size = cf->size;
+
+    } else {
+        if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_fd_info_n " \"%s\" failed", from);
+
+            goto failed;
+        }
+
+        size = ngx_file_size(&fi);
+    }
+
+    len = cf->buf_size ? cf->buf_size : 65536;
+
+    if ((off_t) len > size) {
+        len = (size_t) size;
+    }
+
+    buf = ngx_alloc(len, cf->log);
+    if (buf == NULL) {
+        goto failed;
+    }
+
+    nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
+                        cf->access);
+
+    if (nfd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", to);
+        goto failed;
+    }
+
+    while (size > 0) {
 
-    return NGX_ERROR;
+        if ((off_t) len > size) {
+            len = (size_t) size;
+        }
+
+        n = ngx_read_fd(fd, buf, len);
+
+        if (n == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_read_fd_n " \"%s\" failed", from);
+            goto failed;
+        }
+
+        if ((size_t) n != len) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_read_fd_n " has read only %z of %uz from %s",
+                          n, size, from);
+            goto failed;
+        }
+
+        n = ngx_write_fd(nfd, buf, len);
+
+        if (n == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_write_fd_n " \"%s\" failed", to);
+            goto failed;
+        }
+
+        if ((size_t) n != len) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_write_fd_n " has written only %z of %uz to %s",
+                          n, size, to);
+            goto failed;
+        }
+
+        size -= n;
+    }
+
+    if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
+        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                      ngx_set_file_time_n " \"%s\" failed", to);
+        goto failed;
+    }
+
+    rc = NGX_OK;
+
+failed:
+
+    if (nfd != NGX_INVALID_FILE) {
+        if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", to);
+        }
+    }
+
+    if (fd != NGX_INVALID_FILE) {
+        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", from);
+        }
+    }
+
+    if (buf) {
+        ngx_free(buf);
+    }
+
+    return rc;
 }
 
 
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -30,6 +30,7 @@ struct ngx_file_s {
 
 
 typedef time_t (*ngx_path_manager_pt) (void *data);
+typedef void (*ngx_path_loader_pt) (void *data);
 
 
 typedef struct {
@@ -38,6 +39,7 @@ typedef struct {
     size_t                     level[3];
 
     ngx_path_manager_pt        manager;
+    ngx_path_loader_pt         loader;
     void                      *data;
 
     u_char                    *conf_file;
@@ -71,16 +73,25 @@ typedef struct {
     ngx_uint_t                 path_access;
     time_t                     time;
     ngx_fd_t                   fd;
-    ngx_err_t                  rename_error;
 
     unsigned                   create_path:1;
     unsigned                   delete_file:1;
-    unsigned                   log_rename_error:1;
 
     ngx_log_t                 *log;
 } ngx_ext_rename_file_t;
 
 
+typedef struct {
+    off_t                      size;
+    size_t                     buf_size;
+
+    ngx_uint_t                 access;
+    time_t                     time;
+
+    ngx_log_t                 *log;
+} ngx_copy_file_t;
+
+
 typedef struct ngx_tree_ctx_s  ngx_tree_ctx_t;
 
 typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev);
@@ -115,9 +126,9 @@ ngx_int_t ngx_add_path(ngx_conf_t *cf, n
 ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user);
 ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to,
     ngx_ext_rename_file_t *ext);
+ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf);
 ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree);
 
-void ngx_init_temp_number(void);
 ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
 
 char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -126,4 +137,8 @@ char *ngx_conf_merge_path_value(ngx_conf
 char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
+extern ngx_atomic_t      *ngx_temp_number;
+extern ngx_atomic_int_t   ngx_random_number;
+
+
 #endif /* _NGX_FILE_H_INCLUDED_ */
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -534,7 +534,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t *
 
             next_name->key.len = names[n].key.len - len;
             next_name->key.data = names[n].key.data + len;
-            next_name->key_hash= 0;
+            next_name->key_hash = 0;
             next_name->value = names[n].value;
 
 #if 0
@@ -562,7 +562,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t *
 
             next_name->key.len = names[i].key.len - dot_len;
             next_name->key.data = names[i].key.data + dot_len;
-            next_name->key_hash= 0;
+            next_name->key_hash = 0;
             next_name->value = names[i].value;
 
 #if 0
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -314,12 +314,11 @@ ngx_output_chain_add_copy(ngx_pool_t *po
 
 #endif
 
+        cl->next = NULL;
         *ll = cl;
         ll = &cl->next;
     }
 
-    *ll = NULL;
-
     return NGX_OK;
 }
 
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -30,12 +30,15 @@ ngx_cpystrn(u_char *dst, u_char *src, si
         return dst;
     }
 
-    for ( /* void */ ; --n; dst++, src++) {
+    while (--n) {
         *dst = *src;
 
         if (*dst == '\0') {
             return dst;
         }
+
+        dst++;
+        src++;
     }
 
     *dst = '\0';
@@ -565,8 +568,8 @@ ngx_strcasecmp(u_char *s1, u_char *s2)
         c1 = (ngx_uint_t) *s1++;
         c2 = (ngx_uint_t) *s2++;
 
-        c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
-        c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
 
         if (c1 == c2) {
 
@@ -591,8 +594,8 @@ ngx_strncasecmp(u_char *s1, u_char *s2, 
         c1 = (ngx_uint_t) *s1++;
         c2 = (ngx_uint_t) *s2++;
 
-        c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
-        c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
 
         if (c1 == c2) {
 
@@ -680,7 +683,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si
     ngx_uint_t  c1, c2;
 
     c2 = (ngx_uint_t) *s2++;
-    c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+    c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
 
     do {
         do {
@@ -690,7 +693,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si
                 return NULL;
             }
 
-            c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+            c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
 
         } while (c1 != c2);
 
@@ -712,7 +715,7 @@ ngx_strlcasestrn(u_char *s1, u_char *las
     ngx_uint_t  c1, c2;
 
     c2 = (ngx_uint_t) *s2++;
-    c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+    c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
     last -= n;
 
     do {
@@ -723,7 +726,7 @@ ngx_strlcasestrn(u_char *s1, u_char *las
 
             c1 = (ngx_uint_t) *s1++;
 
-            c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+            c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
 
         } while (c1 != c2);
 
@@ -1337,7 +1340,7 @@ ngx_escape_uri(u_char *dst, u_char *src,
 
         /* find the number of the characters to be escaped */
 
-        n  = 0;
+        n = 0;
 
         for (i = 0; i < size; i++) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -550,7 +550,7 @@ ngx_devpoll_create_conf(ngx_cycle_t *cyc
 
     dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
     if (dpcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     dpcf->changes = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -552,7 +552,7 @@ ngx_epoll_create_conf(ngx_cycle_t *cycle
 
     epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t));
     if (epcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     epcf->events = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -581,7 +581,7 @@ ngx_eventport_create_conf(ngx_cycle_t *c
 
     epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
     if (epcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     epcf->events = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -768,7 +768,7 @@ ngx_kqueue_create_conf(ngx_cycle_t *cycl
 
     kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
     if (kcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     kcf->changes = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -691,7 +691,7 @@ ngx_rtsig_create_conf(ngx_cycle_t *cycle
 
     rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t));
     if (rtscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     rtscf->signo = NGX_CONF_UNSET;
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -43,7 +43,7 @@ ngx_uint_t            ngx_event_flags;
 ngx_event_actions_t   ngx_event_actions;
 
 
-ngx_atomic_t          connection_counter = 1;
+static ngx_atomic_t   connection_counter = 1;
 ngx_atomic_t         *ngx_connection_counter = &connection_counter;
 
 
@@ -429,6 +429,7 @@ ngx_event_module_init(ngx_cycle_t *cycle
     u_char              *shared;
     size_t               size, cl;
     ngx_shm_t            shm;
+    ngx_time_t          *tp;
     ngx_core_conf_t     *ccf;
     ngx_event_conf_t    *ecf;
 
@@ -492,7 +493,8 @@ ngx_event_module_init(ngx_cycle_t *cycle
     cl = 128;
 
     size = cl            /* ngx_accept_mutex */
-           + cl;         /* ngx_connection_counter */
+           + cl          /* ngx_connection_counter */
+           + cl;         /* ngx_temp_number */
 
 #if (NGX_STAT_STUB)
 
@@ -526,23 +528,29 @@ ngx_event_module_init(ngx_cycle_t *cycle
 
     ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl);
 
-#if (NGX_STAT_STUB)
-
-    ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * cl);
-    ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * cl);
-    ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * cl);
-    ngx_stat_active = (ngx_atomic_t *) (shared + 5 * cl);
-    ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * cl);
-    ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * cl);
-
-#endif
-
     (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    "counter: %p, %d",
                    ngx_connection_counter, *ngx_connection_counter);
 
+    ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl);
+
+    tp = ngx_timeofday();
+
+    ngx_random_number = (tp->msec << 16) + ngx_pid;
+
+#if (NGX_STAT_STUB)
+
+    ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl);
+    ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl);
+    ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl);
+    ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl);
+    ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl);
+    ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl);
+
+#endif
+
     return NGX_OK;
 }
 
@@ -1113,7 +1121,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle
 
     ecf = ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t));
     if (ecf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     ecf->connections = NGX_CONF_UNSET_UINT;
@@ -1128,7 +1136,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle
     if (ngx_array_init(&ecf->debug_connection, cycle->pool, 4,
                        sizeof(ngx_event_debug_t)) == NGX_ERROR)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
 #endif
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -97,16 +97,12 @@ int  ngx_ssl_session_cache_index;
 ngx_int_t
 ngx_ssl_init(ngx_log_t *log)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x00907000
     OPENSSL_config(NULL);
-#endif
 
     SSL_library_init();
     SSL_load_error_strings();
 
-#if (NGX_SSL_ENGINE)
     ENGINE_load_builtin_engines();
-#endif
 
     ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
 
@@ -169,9 +165,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
 
-#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
     SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
-#endif
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
 
@@ -267,6 +261,51 @@ ngx_ssl_client_certificate(ngx_conf_t *c
 }
 
 
+ngx_int_t
+ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
+{
+    X509_STORE   *store;
+    X509_LOOKUP  *lookup;
+
+    if (crl->len == 0) {
+        return NGX_OK;
+    }
+
+    if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    store = SSL_CTX_get_cert_store(ssl->ctx);
+
+    if (store == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "SSL_CTX_get_cert_store() failed");
+        return NGX_ERROR;
+    }
+
+    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+
+    if (lookup == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "X509_STORE_add_lookup() failed");
+        return NGX_ERROR;
+    }
+
+    if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM)
+        == 0)
+    {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "X509_LOOKUP_load_file(\"%s\") failed", crl->data);
+        return NGX_ERROR;
+    }
+
+    X509_STORE_set_flags(store,
+                         X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+
+    return NGX_OK;
+}
+
+
 static int
 ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
 {
@@ -1201,9 +1240,7 @@ ngx_ssl_connection_error(ngx_connection_
         if (err == NGX_ECONNRESET
             || err == NGX_EPIPE
             || err == NGX_ENOTCONN
-#if !(NGX_CRIT_ETIMEDOUT)
             || err == NGX_ETIMEDOUT
-#endif
             || err == NGX_ECONNREFUSED
             || err == NGX_ENETDOWN
             || err == NGX_ENETUNREACH
@@ -1974,7 +2011,7 @@ ngx_ssl_get_certificate(ngx_connection_t
 
     p = s->data;
 
-    for (i = 0; i < len; i++) {
+    for (i = 0; i < cert.len - 1; i++) {
         *p++ = cert.data[i];
         if (cert.data[i] == LF) {
             *p++ = '\t';
@@ -2108,6 +2145,35 @@ ngx_ssl_get_serial_number(ngx_connection
 }
 
 
+ngx_int_t
+ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    X509  *cert;
+
+    if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
+        s->len = sizeof("FAILED") - 1;
+        s->data = (u_char *) "FAILED";
+
+        return NGX_OK;
+    }
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+
+    if (cert) {
+        s->len = sizeof("SUCCESS") - 1;
+        s->data = (u_char *) "SUCCESS";
+
+    } else {
+        s->len = sizeof("NONE") - 1;
+        s->data = (u_char *) "NONE";
+    }
+
+    X509_free(cert);
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_openssl_create_conf(ngx_cycle_t *cycle)
 {
@@ -2115,7 +2181,7 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc
 
     oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
     if (oscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -2131,7 +2197,6 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc
 static char *
 ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-#if (NGX_SSL_ENGINE)
     ngx_openssl_conf_t *oscf = conf;
 
     ENGINE     *engine;
@@ -2166,23 +2231,11 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c
     ENGINE_free(engine);
 
     return NGX_CONF_OK;
-
-#else
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"ssl_engine\" directive is available only in "
-                       "OpenSSL 0.9.7 and higher,");
-
-    return NGX_CONF_ERROR;
-
-#endif
 }
 
 
 static void
 ngx_openssl_exit(ngx_cycle_t *cycle)
 {
-#if (NGX_SSL_ENGINE)
     ENGINE_cleanup();
-#endif
 }
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -13,12 +13,8 @@
 
 #include <openssl/ssl.h>
 #include <openssl/err.h>
-
-#if OPENSSL_VERSION_NUMBER >= 0x00907000
 #include <openssl/conf.h>
 #include <openssl/engine.h>
-#define NGX_SSL_ENGINE   1
-#endif
 
 #define NGX_SSL_NAME     "OpenSSL"
 
@@ -100,6 +96,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t
     ngx_str_t *cert, ngx_str_t *key);
 ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
     ngx_str_t *cert, ngx_int_t depth);
+ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);
 ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl);
 ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
 ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
@@ -131,6 +128,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_conn
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 
 
 ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -201,7 +201,7 @@ ngx_http_access_create_loc_conf(ngx_conf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return conf;
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -212,7 +212,7 @@ ngx_http_addition_create_conf(ngx_conf_t
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -372,7 +372,7 @@ ngx_http_auth_basic_create_loc_conf(ngx_
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return conf;
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -145,7 +145,7 @@ ngx_http_autoindex_handler(ngx_http_requ
     ngx_int_t                       rc, size;
     ngx_str_t                       path;
     ngx_dir_t                       dir;
-    ngx_uint_t                      i, level;
+    ngx_uint_t                      i, level, utf8;
     ngx_pool_t                     *pool;
     ngx_time_t                     *tp;
     ngx_chain_t                     out;
@@ -252,6 +252,16 @@ ngx_http_autoindex_handler(ngx_http_requ
     filename = path.data;
     filename[path.len] = '/';
 
+    if (r->headers_out.charset.len == 5
+        && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
+           == 0)
+    {
+        utf8 = 1;
+
+    } else {
+        utf8 = 0;
+    }
+
     for ( ;; ) {
         ngx_set_errno(0);
 
@@ -335,7 +345,7 @@ ngx_http_autoindex_handler(ngx_http_requ
         entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
                                            NGX_ESCAPE_HTML);
 
-        if (r->utf8) {
+        if (utf8) {
             entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
         } else {
             entry->utf_len = len;
@@ -622,7 +632,7 @@ ngx_http_autoindex_create_loc_conf(ngx_c
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_browser_module.c
+++ b/src/http/modules/ngx_http_browser_module.c
@@ -423,7 +423,7 @@ ngx_http_browser_create_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_browser_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -9,8 +9,9 @@
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_NO_CHARSET    -2
-#define NGX_HTTP_CHARSET_VAR   0x10000
+#define NGX_HTTP_CHARSET_OFF    -2
+#define NGX_HTTP_NO_CHARSET     -3
+#define NGX_HTTP_CHARSET_VAR    0x10000
 
 /* 1 byte length and up to 3 bytes for the UTF-8 encoding of the UCS-2 */
 #define NGX_UTF_LEN             4
@@ -61,6 +62,7 @@ typedef struct {
 typedef struct {
     u_char                     *table;
     ngx_int_t                   charset;
+    ngx_str_t                   charset_name;
 
     ngx_chain_t                *busy;
     ngx_chain_t                *free_bufs;
@@ -82,9 +84,16 @@ typedef struct {
 } ngx_http_charset_conf_ctx_t;
 
 
-static ngx_int_t ngx_http_charset_get_charset(ngx_http_charset_t *charsets,
-    ngx_uint_t n, ngx_str_t *charset);
-static ngx_int_t ngx_http_charset_set_charset(ngx_http_request_t *r,
+static ngx_int_t ngx_http_destination_charset(ngx_http_request_t *r,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_main_request_charset(ngx_http_request_t *r,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_source_charset(ngx_http_request_t *r,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name);
+static ngx_inline void ngx_http_set_charset(ngx_http_request_t *r,
+    ngx_str_t *charset);
+static ngx_int_t ngx_http_charset_ctx(ngx_http_request_t *r,
     ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset);
 static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table);
 static ngx_chain_t *ngx_http_charset_recode_from_utf8(ngx_pool_t *pool,
@@ -207,207 +216,264 @@ static ngx_int_t
 ngx_http_charset_header_filter(ngx_http_request_t *r)
 {
     ngx_int_t                      charset, source_charset;
-    ngx_str_t                     *mc, *from, *to, s;
-    ngx_uint_t                     n;
+    ngx_str_t                      dst, src;
     ngx_http_charset_t            *charsets;
-    ngx_http_charset_ctx_t        *ctx;
-    ngx_http_variable_value_t     *vv;
-    ngx_http_charset_loc_conf_t   *lcf, *mlcf;
     ngx_http_charset_main_conf_t  *mcf;
 
-    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
-
-    charsets = mcf->charsets.elts;
-    n = mcf->charsets.nelts;
-
-    /* destination charset */
-
     if (r == r->main) {
-
-        if (!r->ignore_content_encoding
-            && r->headers_out.content_encoding
-            && r->headers_out.content_encoding->value.len)
-        {
-            return ngx_http_next_header_filter(r);
-        }
-
-        if (r->headers_out.content_type.len == 0) {
-            return ngx_http_next_header_filter(r);
-        }
-
-        if (r->headers_out.override_charset
-            && r->headers_out.override_charset->len)
-        {
-            charset = ngx_http_charset_get_charset(charsets, n,
-                                              r->headers_out.override_charset);
-
-            if (charset == NGX_HTTP_NO_CHARSET) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "unknown charset \"%V\" to override",
-                              r->headers_out.override_charset);
-
-                return ngx_http_next_header_filter(r);
-            }
-
-        } else {
-            mlcf = ngx_http_get_module_loc_conf(r,
-                                                ngx_http_charset_filter_module);
-            charset = mlcf->charset;
-
-            if (charset == NGX_HTTP_NO_CHARSET) {
-                return ngx_http_next_header_filter(r);
-            }
-
-            if (r->headers_out.charset.len) {
-                if (mlcf->override_charset == 0) {
-                    return ngx_http_next_header_filter(r);
-                }
-
-            } else {
-                if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
-                    return ngx_http_next_header_filter(r);
-                }
-            }
-
-            if (charset >= NGX_HTTP_CHARSET_VAR) {
-                vv = ngx_http_get_indexed_variable(r,
-                                               charset - NGX_HTTP_CHARSET_VAR);
-
-                if (vv == NULL || vv->not_found) {
-                    return NGX_ERROR;
-                }
-
-                s.len = vv->len;
-                s.data = vv->data;
-
-                charset = ngx_http_charset_get_charset(charsets, n, &s);
-            }
-        }
+        charset = ngx_http_destination_charset(r, &dst);
 
     } else {
-        ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);
-
-        if (ctx == NULL) {
-
-            mc = &r->main->headers_out.charset;
-
-            if (mc->len == 0) {
-                return ngx_http_next_header_filter(r);
-            }
+        charset = ngx_http_main_request_charset(r, &dst);
+    }
 
-            ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
-            if (ctx == NULL) {
-                return NGX_ERROR;
-            }
-
-            ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module);
+    if (charset == NGX_ERROR) {
+        return NGX_ERROR;
+    }
 
-            charset = ngx_http_charset_get_charset(charsets, n, mc);
-
-            ctx->charset = charset;
-
-        } else {
-            charset = ctx->charset;
-        }
+    if (charset == NGX_DECLINED) {
+        return ngx_http_next_header_filter(r);
     }
 
-    /* source charset */
-
-    if (r->headers_out.charset.len == 0) {
-        lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
-
-        source_charset = lcf->source_charset;
-
-        if (source_charset >= NGX_HTTP_CHARSET_VAR) {
-            vv = ngx_http_get_indexed_variable(r,
-                                        source_charset - NGX_HTTP_CHARSET_VAR);
-
-            if (vv == NULL || vv->not_found) {
-                return NGX_ERROR;
-            }
+    /* charset: charset index or NGX_HTTP_NO_CHARSET */
 
-            s.len = vv->len;
-            s.data = vv->data;
-
-            source_charset = ngx_http_charset_get_charset(charsets, n, &s);
-        }
+    source_charset = ngx_http_source_charset(r, &src);
 
-        if (charset != NGX_HTTP_NO_CHARSET) {
-            return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
-                                                source_charset);
-        }
-
-        if (source_charset == NGX_CONF_UNSET) {
-            return ngx_http_next_header_filter(r);
-        }
-
-        from = &charsets[source_charset].name;
-        to = &r->main->headers_out.charset;
-
-        goto no_charset_map;
+    if (source_charset == NGX_ERROR) {
+        return NGX_ERROR;
     }
 
-    source_charset = ngx_http_charset_get_charset(charsets, n,
-                                                  &r->headers_out.charset);
+    /*
+     * source_charset: charset index, NGX_HTTP_NO_CHARSET,
+     *                 or NGX_HTTP_CHARSET_OFF
+     */
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "charset: \"%V\" > \"%V\"", &src, &dst);
+
+    if (source_charset == NGX_HTTP_CHARSET_OFF) {
+        ngx_http_set_charset(r, &dst);
+
+        return ngx_http_next_header_filter(r);
+    }
 
     if (charset == NGX_HTTP_NO_CHARSET
         || source_charset == NGX_HTTP_NO_CHARSET)
     {
-        if (charset != source_charset
-            || ngx_strcasecmp(r->main->headers_out.charset.data,
-                              r->headers_out.charset.data)
-                != 0)
+        if (source_charset != charset
+            || ngx_strncasecmp(dst.data, src.data, dst.len) != 0)
         {
-            from = &r->headers_out.charset;
-            to = (charset == NGX_HTTP_NO_CHARSET) ?
-                                           &r->main->headers_out.charset:
-                                           &charsets[charset].name;
-
             goto no_charset_map;
         }
 
+        ngx_http_set_charset(r, &dst);
+
         return ngx_http_next_header_filter(r);
     }
 
+    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+    charsets = mcf->charsets.elts;
+
     if (source_charset != charset
         && (charsets[source_charset].tables == NULL
             || charsets[source_charset].tables[charset] == NULL))
     {
-        from = &charsets[source_charset].name;
-        to = &charsets[charset].name;
-
         goto no_charset_map;
     }
 
     r->headers_out.content_type.len = r->headers_out.content_type_len;
 
-    return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
-                                        source_charset);
+    ngx_http_set_charset(r, &dst);
+
+    if (source_charset != charset) {
+        return ngx_http_charset_ctx(r, charsets, charset, source_charset);
+    }
+
+    return ngx_http_next_header_filter(r);
 
 no_charset_map:
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
-                  from, to);
+                  &src, &dst);
 
     return ngx_http_next_header_filter(r);
 }
 
 
 static ngx_int_t
-ngx_http_charset_get_charset(ngx_http_charset_t *charsets, ngx_uint_t n,
-    ngx_str_t *charset)
+ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_int_t                      charset;
+    ngx_http_charset_t            *charsets;
+    ngx_http_variable_value_t     *vv;
+    ngx_http_charset_loc_conf_t   *mlcf;
+    ngx_http_charset_main_conf_t  *mcf;
+
+    if (!r->ignore_content_encoding
+        && r->headers_out.content_encoding
+        && r->headers_out.content_encoding->value.len)
+    {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_out.content_type.len == 0) {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_out.override_charset
+        && r->headers_out.override_charset->len)
+    {
+        *name = *r->headers_out.override_charset;
+
+        charset = ngx_http_get_charset(r, name);
+
+        if (charset != NGX_HTTP_NO_CHARSET) {
+            return charset;
+        }
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "unknown charset \"%V\" to override", name);
+
+        return NGX_DECLINED;
+    }
+
+    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+    charset = mlcf->charset;
+
+    if (charset == NGX_HTTP_CHARSET_OFF) {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_out.charset.len) {
+        if (mlcf->override_charset == 0) {
+            return NGX_DECLINED;
+        }
+
+    } else {
+        if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
+            return NGX_DECLINED;
+        }
+    }
+
+    if (charset < NGX_HTTP_CHARSET_VAR) {
+        mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+        charsets = mcf->charsets.elts;
+        *name = charsets[charset].name;
+        return charset;
+    }
+
+    vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR);
+
+    if (vv == NULL || vv->not_found) {
+        return NGX_ERROR;
+    }
+
+    name->len = vv->len;
+    name->data = vv->data;
+
+    return ngx_http_get_charset(r, name);
+}
+
+
+static ngx_int_t
+ngx_http_main_request_charset(ngx_http_request_t *r, ngx_str_t *src)
 {
-    ngx_uint_t  i;
+    ngx_int_t                charset;
+    ngx_str_t               *main_charset;
+    ngx_http_charset_ctx_t  *ctx;
+
+    ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);
+
+    if (ctx) {
+        *src = ctx->charset_name;
+        return ctx->charset;
+    }
+
+    main_charset = &r->main->headers_out.charset;
+
+    if (main_charset->len == 0) {
+        return NGX_DECLINED;
+    }
+
+    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
+    if (ctx == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module);
+
+    charset = ngx_http_get_charset(r, main_charset);
+
+    ctx->charset = charset;
+    ctx->charset_name = *main_charset;
+    *src = *main_charset;
+
+    return charset;
+}
+
+
+static ngx_int_t
+ngx_http_source_charset(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_int_t                      charset;
+    ngx_http_charset_t            *charsets;
+    ngx_http_variable_value_t     *vv;
+    ngx_http_charset_loc_conf_t   *lcf;
+    ngx_http_charset_main_conf_t  *mcf;
+
+    if (r->headers_out.charset.len) {
+        *name = r->headers_out.charset;
+        return ngx_http_get_charset(r, name);
+    }
+
+    lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+
+    charset = lcf->source_charset;
+
+    if (charset == NGX_HTTP_CHARSET_OFF) {
+        name->len = 0;
+        return charset;
+    }
+
+    if (charset < NGX_HTTP_CHARSET_VAR) {
+        mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+        charsets = mcf->charsets.elts;
+        *name = charsets[charset].name;
+        return charset;
+    }
+
+    vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR);
+
+    if (vv == NULL || vv->not_found) {
+        return NGX_ERROR;
+    }
+
+    name->len = vv->len;
+    name->data = vv->data;
+
+    return ngx_http_get_charset(r, name);
+}
+
+
+static ngx_int_t
+ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_uint_t                     i, n;
+    ngx_http_charset_t            *charset;
+    ngx_http_charset_main_conf_t  *mcf;
+
+    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+
+    charset = mcf->charsets.elts;
+    n = mcf->charsets.nelts;
 
     for (i = 0; i < n; i++) {
-        if (charsets[i].name.len != charset->len) {
+        if (charset[i].name.len != name->len) {
             continue;
         }
 
-        if (ngx_strncasecmp(charsets[i].name.data, charset->data, charset->len)
-            == 0)
-        {
+        if (ngx_strncasecmp(charset[i].name.data, name->data, name->len) == 0) {
             return i;
         }
     }
@@ -416,11 +482,12 @@ ngx_http_charset_get_charset(ngx_http_ch
 }
 
 
-static ngx_int_t
-ngx_http_charset_set_charset(ngx_http_request_t *r,
-    ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset)
+static ngx_inline void
+ngx_http_set_charset(ngx_http_request_t *r, ngx_str_t *charset)
 {
-    ngx_http_charset_ctx_t  *ctx;
+    if (r != r->main) {
+        return;
+    }
 
     if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY
         || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY)
@@ -431,16 +498,18 @@ ngx_http_charset_set_charset(ngx_http_re
          */
 
         r->headers_out.charset.len = 0;
-
-        return ngx_http_next_header_filter(r);
+        return;
     }
 
-    r->headers_out.charset = charsets[charset].name;
-    r->utf8 = charsets[charset].utf8;
+    r->headers_out.charset = *charset;
+}
+
 
-    if (source_charset == NGX_CONF_UNSET || source_charset == charset) {
-        return ngx_http_next_header_filter(r);
-    }
+static ngx_int_t
+ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets,
+    ngx_int_t charset, ngx_int_t source_charset)
+{
+    ngx_http_charset_ctx_t  *ctx;
 
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
     if (ctx == NULL) {
@@ -451,6 +520,7 @@ ngx_http_charset_set_charset(ngx_http_re
 
     ctx->table = charsets[source_charset].tables[charset];
     ctx->charset = charset;
+    ctx->charset_name = charsets[charset].name;
     ctx->length = charsets[charset].length;
     ctx->from_utf8 = charsets[source_charset].utf8;
     ctx->to_utf8 = charsets[charset].utf8;
@@ -1338,7 +1408,7 @@ ngx_http_set_charset_slot(ngx_conf_t *cf
     if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, charset)
         && ngx_strcmp(value[1].data, "off") == 0)
     {
-        *cp = NGX_HTTP_NO_CHARSET;
+        *cp = NGX_HTTP_CHARSET_OFF;
         return NGX_CONF_OK;
     }
 
@@ -1418,27 +1488,27 @@ ngx_http_charset_create_main_conf(ngx_co
 
     mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t));
     if (mcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&mcf->tables, cf->pool, 1,
                        sizeof(ngx_http_charset_tables_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&mcf->recodes, cf->pool, 2,
                        sizeof(ngx_http_charset_recode_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return mcf;
@@ -1452,7 +1522,7 @@ ngx_http_charset_create_loc_conf(ngx_con
 
     lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t));
     if (lcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -1489,14 +1559,12 @@ ngx_http_charset_merge_loc_conf(ngx_conf
     }
 
     ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0);
-    ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET);
+    ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_CHARSET_OFF);
+    ngx_conf_merge_value(conf->source_charset, prev->source_charset,
+                         NGX_HTTP_CHARSET_OFF);
 
-    if (conf->source_charset == NGX_CONF_UNSET) {
-        conf->source_charset = prev->source_charset;
-    }
-
-    if (conf->charset == NGX_HTTP_NO_CHARSET
-        || conf->source_charset == NGX_CONF_UNSET
+    if (conf->charset == NGX_HTTP_CHARSET_OFF
+        || conf->source_charset == NGX_HTTP_CHARSET_OFF
         || conf->charset == conf->source_charset)
     {
         return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -53,8 +53,6 @@ static ngx_int_t ngx_http_dav_copy_dir_t
     ngx_str_t *path);
 static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
     ngx_str_t *path);
-static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from,
-    u_char *to);
 
 static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt);
 static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
@@ -216,6 +214,8 @@ ngx_http_dav_put_handler(ngx_http_reques
 
     ngx_http_map_uri_to_path(r, &path, &root, 0);
 
+    path.len--;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http put filename: \"%s\"", path.data);
 
@@ -249,7 +249,6 @@ ngx_http_dav_put_handler(ngx_http_reques
     ext.time = -1;
     ext.create_path = dlcf->create_full_put_path;
     ext.delete_file = 1;
-    ext.log_rename_error = 1;
     ext.log = r->connection->log;
 
     if (r->headers_in.date) {
@@ -491,6 +490,7 @@ ngx_http_dav_mkcol_handler(ngx_http_requ
     p = ngx_http_map_uri_to_path(r, &path, &root, 0);
 
     *(p - 1) = '\0';
+    r->uri.len--;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http mkcol path: \"%s\"", path.data);
@@ -517,9 +517,10 @@ ngx_http_dav_copy_move_handler(ngx_http_
     size_t                    len, root;
     ngx_err_t                 err;
     ngx_int_t                 rc, depth;
-    ngx_uint_t                overwrite, slash, dir;
-    ngx_str_t                 path, uri;
+    ngx_uint_t                overwrite, slash, dir, flags;
+    ngx_str_t                 path, uri, duri, args;
     ngx_tree_ctx_t            tree;
+    ngx_copy_file_t           cf;
     ngx_file_info_t           fi;
     ngx_table_elt_t          *dest, *over;
     ngx_ext_rename_file_t     ext;
@@ -594,6 +595,14 @@ invalid_destination:
 
 destination_done:
 
+    duri.len = last - p;
+    duri.data = p;
+    flags = 0;
+
+    if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
+        goto invalid_destination;
+    }
+
     if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
         || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
     {
@@ -656,9 +665,7 @@ overwrite_done:
                    "http copy from: \"%s\"", path.data);
 
     uri = r->uri;
-
-    r->uri.len = last - p;
-    r->uri.data = p;
+    r->uri = duri;
 
     ngx_http_map_uri_to_path(r, &copy.path, &root, 0);
 
@@ -791,43 +798,24 @@ overwrite_done:
             ext.time = -1;
             ext.create_path = 1;
             ext.delete_file = 0;
-            ext.log_rename_error = 0;
             ext.log = r->connection->log;
 
             if (ngx_ext_rename_file(&path, &copy.path, &ext) == NGX_OK) {
                 return NGX_HTTP_NO_CONTENT;
             }
 
-            if (ext.rename_error != NGX_EXDEV) {
-
-                if (ext.rename_error) {
-                    ngx_log_error(NGX_LOG_CRIT, r->connection->log,
-                                  ext.rename_error,
-                                  ngx_rename_file_n " \"%s\" to \"%s\" failed",
-                                  path.data, copy.path.data);
-                }
-
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
         dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
 
-        tree.size = ngx_file_size(&fi);
-        tree.mtime = ngx_file_mtime(&fi);
-        tree.access = dlcf->access;
-        tree.log = r->connection->log;
+        cf.size = ngx_file_size(&fi);
+        cf.buf_size = 0;
+        cf.access = dlcf->access;
+        cf.time = ngx_file_mtime(&fi);
+        cf.log = r->connection->log;
 
-        if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK)
-        {
-            if (r->method == NGX_HTTP_MOVE) {
-                rc = ngx_http_dav_delete_path(r, &path, 0);
-
-                if (rc != NGX_OK) {
-                    return rc;
-                }
-            }
-
+        if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) {
             return NGX_HTTP_NO_CONTENT;
         }
     }
@@ -941,6 +929,7 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
 {
     u_char                   *p, *file;
     size_t                    len;
+    ngx_copy_file_t           cf;
     ngx_http_dav_copy_ctx_t  *copy;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
@@ -961,7 +950,13 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
                    "http copy file to: \"%s\"", file);
 
-    (void) ngx_http_dav_copy_file(ctx, path->data, file);
+    cf.size = ctx->size;
+    cf.buf_size = 0;
+    cf.access = ctx->access;
+    cf.time = ctx->mtime;
+    cf.log = ctx->log;
+
+    (void) ngx_copy_file(path->data, file, &cf);
 
     ngx_free(file);
 
@@ -970,75 +965,6 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
 
 
 static ngx_int_t
-ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to)
-{
-    off_t       size;
-    ssize_t     n;
-    ngx_fd_t    fd, cfd;
-    ngx_int_t   rc;
-    u_char      buf[NGX_HTTP_DAV_COPY_BLOCK];
-
-    fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
-
-    if (fd == NGX_INVALID_FILE) {
-        (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n,
-                                  from);
-        return NGX_ERROR;
-    }
-
-    cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
-                        ctx->access);
-
-    rc = NGX_ERROR;
-
-    if (cfd == NGX_INVALID_FILE) {
-        (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to);
-        goto failed;
-    }
-
-    for (size = ctx->size; size > 0; size -= n) {
-
-        n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK);
-
-        if (n == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                          ngx_read_fd_n " \"%s\" failed", from);
-            goto failed;
-        }
-
-        if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                          ngx_write_fd_n " \"%s\" failed", to);
-            goto failed;
-        }
-    }
-
-    if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                      ngx_set_file_time_n " \"%s\" failed", to);
-        goto failed;
-    }
-
-    if (ngx_close_file(cfd) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                      ngx_close_file_n " \"%s\" failed", to);
-        goto failed;
-    }
-
-    rc = NGX_OK;
-
-failed:
-
-    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                      ngx_close_file_n " \"%s\" failed", from);
-    }
-
-    return rc;
-}
-
-
-static ngx_int_t
 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt)
 {
     ngx_table_elt_t  *depth;
@@ -1154,7 +1080,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -543,20 +543,17 @@ ngx_http_fastcgi_handler(ngx_http_reques
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    if (ngx_http_upstream_create(r) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
     if (f == NULL) {
-        return NGX_ERROR;
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
 
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
-    if (u == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->upstream = u;
-
     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
     if (flcf->fastcgi_lengths) {
@@ -565,15 +562,11 @@ ngx_http_fastcgi_handler(ngx_http_reques
         }
     }
 
+    u = r->upstream;
+
     u->schema.len = sizeof("fastcgi://") - 1;
     u->schema.data = (u_char *) "fastcgi://";
 
-    u->peer.log = r->connection->log;
-    u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
-
     u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
 
     u->conf = &flcf->upstream;
@@ -1836,7 +1829,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -35,6 +35,7 @@ typedef struct {
     ngx_radix_tree_t                *tree;
     ngx_rbtree_t                     rbtree;
     ngx_rbtree_node_t                sentinel;
+    ngx_array_t                     *proxies;
     ngx_pool_t                      *pool;
     ngx_pool_t                      *temp_pool;
 } ngx_http_geo_conf_ctx_t;
@@ -46,12 +47,16 @@ typedef struct {
         ngx_http_geo_high_ranges_t  *high;
     } u;
 
+    ngx_array_t                     *proxies;
+
     ngx_int_t                        index;
 } ngx_http_geo_ctx_t;
 
 
 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r,
     ngx_http_geo_ctx_t *ctx);
+static in_addr_t ngx_http_geo_real_addr(ngx_http_request_t *r,
+    ngx_http_geo_ctx_t *ctx);
 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
@@ -64,6 +69,10 @@ static char *ngx_http_geo_cidr(ngx_conf_
     ngx_str_t *value);
 static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf,
     ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value);
+static char *ngx_http_geo_add_proxy(ngx_conf_t *cf,
+    ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr);
+static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
+    ngx_cidr_t *cidr);
 
 
 static ngx_command_t  ngx_http_geo_commands[] = {
@@ -168,6 +177,50 @@ ngx_http_geo_range_variable(ngx_http_req
 static in_addr_t
 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
 {
+    u_char           *p, *ip;
+    size_t            len;
+    in_addr_t         addr;
+    ngx_uint_t        i, n;
+    ngx_in_cidr_t    *proxies;
+    ngx_table_elt_t  *xfwd;
+
+    addr = ngx_http_geo_real_addr(r, ctx);
+
+    xfwd = r->headers_in.x_forwarded_for;
+
+    if (xfwd == NULL || ctx->proxies == NULL) {
+        return addr;
+    }
+
+    proxies = ctx->proxies->elts;
+    n = ctx->proxies->nelts;
+
+    for (i = 0; i < n; i++) {
+        if ((addr & proxies[i].mask) == proxies[i].addr) {
+
+            len = xfwd->value.len;
+            ip = xfwd->value.data;
+
+            for (p = ip + len - 1; p > ip; p--) {
+                if (*p == ' ' || *p == ',') {
+                    p++;
+                    len -= p - ip;
+                    ip = p;
+                    break;
+                }
+            }
+
+            return ntohl(ngx_inet_addr(ip, len));
+        }
+    }
+
+    return addr;
+}
+
+
+static in_addr_t
+ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
+{
     struct sockaddr_in         *sin;
     ngx_http_variable_value_t  *v;
 
@@ -259,6 +312,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
 
     ctx.high = NULL;
     ctx.tree = NULL;
+    ctx.proxies = NULL;
     ctx.pool = cf->pool;
 
     save = *cf;
@@ -271,6 +325,8 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
 
     *cf = save;
 
+    geo->proxies = ctx.proxies;
+
     if (ctx.high) {
 
         for (i = 0; i < 0x10000; i++) {
@@ -341,6 +397,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
 {
     char                     *rv;
     ngx_str_t                *value, file;
+    ngx_cidr_t                cidr;
     ngx_http_geo_conf_ctx_t  *ctx;
 
     ctx = cf->ctx;
@@ -394,6 +451,16 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
         rv = ngx_conf_parse(cf, &file);
 
         goto done;
+
+    } else if (ngx_strcmp(value[0].data, "proxy") == 0) {
+
+        if (ngx_http_geo_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
+            goto failed;
+        }
+
+        rv = ngx_http_geo_add_proxy(cf, ctx, &cidr);
+
+        goto done;
     }
 
     if (ctx->high) {
@@ -803,33 +870,8 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht
             del = 0;
         }
 
-        if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
-            cidr.u.in.addr = 0xffffffff;
-            cidr.u.in.mask = 0xffffffff;
-
-        } else {
-            rc = ngx_ptocidr(net, &cidr);
-
-            if (rc == NGX_ERROR) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "invalid network \"%V\"", net);
-                return NGX_CONF_ERROR;
-            }
-
-            if (cidr.family != AF_INET) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "\"geo\" supports IPv4 only");
-                return NGX_CONF_ERROR;
-            }
-
-            if (rc == NGX_DONE) {
-                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                                   "low address bits of %V are meaningless",
-                                   net);
-            }
-
-            cidr.u.in.addr = ntohl(cidr.u.in.addr);
-            cidr.u.in.mask = ntohl(cidr.u.in.mask);
+        if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) {
+            return NGX_CONF_ERROR;
         }
 
         if (del) {
@@ -864,7 +906,7 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht
 
         /* rc == NGX_BUSY */
 
-        old  = (ngx_http_variable_value_t *)
+        old = (ngx_http_variable_value_t *)
               ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask);
 
         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
@@ -927,3 +969,64 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_h
 
     return val;
 }
+
+
+static char *
+ngx_http_geo_add_proxy(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
+    ngx_cidr_t *cidr)
+{
+    ngx_in_cidr_t  *c;
+
+    if (ctx->proxies == NULL) {
+        ctx->proxies = ngx_array_create(ctx->pool, 4, sizeof(ngx_in_cidr_t));
+        if (ctx->proxies == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    c = ngx_array_push(ctx->proxies);
+    if (c == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    c->addr = cidr->u.in.addr;
+    c->mask = cidr->u.in.mask;
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
+{
+    ngx_int_t  rc;
+
+    if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
+        cidr->u.in.addr = 0xffffffff;
+        cidr->u.in.mask = 0xffffffff;
+
+        return NGX_OK;
+    }
+
+    rc = ngx_ptocidr(net, cidr);
+
+    if (rc == NGX_ERROR) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
+        return NGX_ERROR;
+    }
+
+    if (cidr->family != AF_INET) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"geo\" supports IPv4 only");
+        return NGX_ERROR;
+    }
+
+    if (rc == NGX_DONE) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "low address bits of %V are meaningless", net);
+    }
+
+    cidr->u.in.addr = ntohl(cidr->u.in.addr);
+    cidr->u.in.mask = ntohl(cidr->u.in.mask);
+
+    return NGX_OK;
+}
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_geoip_module.c
@@ -0,0 +1,376 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include <GeoIP.h>
+#include <GeoIPCity.h>
+
+
+typedef struct {
+    GeoIP      *country;
+    GeoIP      *city;
+} ngx_http_geoip_conf_t;
+
+
+typedef struct {
+    ngx_str_t  *name;
+    uintptr_t   data;
+} ngx_http_geoip_var_t;
+
+
+typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
+
+static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+
+static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
+static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
+static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static void ngx_http_geoip_cleanup(void *data);
+
+
+static ngx_command_t  ngx_http_geoip_commands[] = {
+
+    { ngx_string("geoip_country"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_http_geoip_country,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("geoip_city"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_http_geoip_city,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_geoip_module_ctx = {
+    ngx_http_geoip_add_variables,          /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    ngx_http_geoip_create_conf,            /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_geoip_module = {
+    NGX_MODULE_V1,
+    &ngx_http_geoip_module_ctx,            /* module context */
+    ngx_http_geoip_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_http_variable_t  ngx_http_geoip_vars[] = {
+
+    { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable,
+      (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 },
+
+    { ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable,
+      (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
+
+    { ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable,
+      (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
+
+    { ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, country_code), 0, 0 },
+
+    { ngx_string("geoip_city_country_code3"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, country_code3), 0, 0 },
+
+    { ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, country_name), 0, 0 },
+
+    { ngx_string("geoip_region"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, region), 0, 0 },
+
+    { ngx_string("geoip_city"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, city), 0, 0 },
+
+    { ngx_string("geoip_postal_code"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, postal_code), 0, 0 },
+
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
+};
+
+
+static ngx_int_t
+ngx_http_geoip_country_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_http_geoip_variable_handler_pt  handler =
+        (ngx_http_geoip_variable_handler_pt) data;
+
+    u_long                  addr;
+    const char             *val;
+    struct sockaddr_in     *sin;
+    ngx_http_geoip_conf_t  *gcf;
+
+    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
+
+    if (gcf->country == NULL) {
+        goto not_found;
+    }
+
+    if (r->connection->sockaddr->sa_family != AF_INET) {
+        goto not_found;
+    }
+
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
+    addr = ntohl(sin->sin_addr.s_addr);
+
+    val = handler(gcf->country, addr);
+
+    if (val == NULL) {
+        goto not_found;
+    }
+
+    v->len = ngx_strlen(val);
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = (u_char *) val;
+
+    return NGX_OK;
+
+not_found:
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geoip_city_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_long                  addr;
+    char                   *val;
+    size_t                  len;
+    GeoIPRecord            *gr;
+    struct sockaddr_in     *sin;
+    ngx_http_geoip_conf_t  *gcf;
+
+    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
+
+    if (gcf->city == NULL) {
+        goto not_found;
+    }
+
+    if (r->connection->sockaddr->sa_family != AF_INET) {
+        goto not_found;
+    }
+
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
+    addr = ntohl(sin->sin_addr.s_addr);
+
+    gr = GeoIP_record_by_ipnum(gcf->city, addr);
+
+    if (gr == NULL) {
+        goto not_found;
+    }
+
+    val = *(char **) ((char *) gr + data);
+
+    if (val == NULL) {
+        goto no_value;
+    }
+
+    len = ngx_strlen(val);
+    v->data = ngx_pnalloc(r->pool, len);
+
+    if (v->data == NULL) {
+        GeoIPRecord_delete(gr);
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(v->data, val, len);
+
+    v->len = len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    GeoIPRecord_delete(gr);
+
+    return NGX_OK;
+
+no_value:
+
+    GeoIPRecord_delete(gr);
+
+not_found:
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geoip_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_geoip_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->get_handler = v->get_handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK;
+}
+
+
+static void *
+ngx_http_geoip_create_conf(ngx_conf_t *cf)
+{
+    ngx_pool_cleanup_t     *cln;
+    ngx_http_geoip_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    cln = ngx_pool_cleanup_add(cf->pool, 0);
+    if (cln == NULL) {
+        return NULL;
+    }
+
+    cln->handler = ngx_http_geoip_cleanup;
+    cln->data = conf;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_geoip_conf_t  *gcf = conf;
+
+    ngx_str_t  *value;
+
+    if (gcf->country) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
+
+    if (gcf->country == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "GeoIO_open(\"%V\") failed", &value[1]);
+
+        return NGX_CONF_ERROR;
+    }
+
+    switch (gcf->country->databaseType) {
+
+    case GEOIP_COUNTRY_EDITION:
+    case GEOIP_PROXY_EDITION:
+    case GEOIP_NETSPEED_EDITION:
+
+        return NGX_CONF_OK;
+
+    default:
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid GeoIP database \"%V\" type:%d",
+                           &value[1], gcf->country->databaseType);
+        return NGX_CONF_ERROR;
+    }
+}
+
+
+static char *
+ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_geoip_conf_t  *gcf = conf;
+
+    ngx_str_t  *value;
+
+    if (gcf->city) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
+
+    if (gcf->city == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "GeoIO_open(\"%V\") failed", &value[1]);
+
+        return NGX_CONF_ERROR;
+    }
+
+    switch (gcf->city->databaseType) {
+
+    case GEOIP_CITY_EDITION_REV0:
+    case GEOIP_CITY_EDITION_REV1:
+
+        return NGX_CONF_OK;
+
+    default:
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid GeoIP City database \"%V\" type:%d",
+                           &value[1], gcf->city->databaseType);
+        return NGX_CONF_ERROR;
+    }
+}
+
+
+static void
+ngx_http_geoip_cleanup(void *data)
+{
+    ngx_http_geoip_conf_t  *gcf = data;
+
+    if (gcf->country) {
+        GeoIP_delete(gcf->country);
+    }
+
+    if (gcf->city) {
+        GeoIP_delete(gcf->city);
+    }
+}
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -1069,7 +1069,7 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -95,7 +95,13 @@ ngx_http_gzip_static_handler(ngx_http_re
 
     gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
 
-    if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) {
+    if (!gzcf->enable) {
+        return NGX_DECLINED;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) {
         return NGX_DECLINED;
     }
 
@@ -116,8 +122,6 @@ ngx_http_gzip_static_handler(ngx_http_re
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", path.data);
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
     of.directio = clcf->directio;
@@ -138,6 +142,7 @@ ngx_http_gzip_static_handler(ngx_http_re
         case NGX_ENOTDIR:
         case NGX_ENAMETOOLONG:
 
+            r->gzip = 0;
             return NGX_DECLINED;
 
         case NGX_EACCES:
@@ -251,7 +256,7 @@ ngx_http_gzip_static_create_conf(ngx_con
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -421,7 +421,7 @@ ngx_http_headers_create_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -40,6 +40,11 @@ typedef struct {
     ngx_uint_t                   height;
     ngx_int_t                    jpeg_quality;
 
+    ngx_flag_t                   transparency;
+
+    ngx_http_complex_value_t    *wcv;
+    ngx_http_complex_value_t    *hcv;
+
     size_t                       buffer_size;
 } ngx_http_image_filter_conf_t;
 
@@ -53,6 +58,9 @@ typedef struct {
     ngx_uint_t                   width;
     ngx_uint_t                   height;
 
+    ngx_uint_t                   max_width;
+    ngx_uint_t                   max_height;
+
     ngx_uint_t                   phase;
     ngx_uint_t                   type;
 } ngx_http_image_filter_ctx_t;
@@ -80,6 +88,9 @@ static gdImagePtr ngx_http_image_new(ngx
 static u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type,
     gdImagePtr img, int *size);
 static void ngx_http_image_cleanup(void *data);
+static ngx_uint_t ngx_http_image_filter_get_value(ngx_http_request_t *r,
+    ngx_http_complex_value_t *cv, ngx_uint_t v);
+static ngx_uint_t ngx_http_image_filter_value(ngx_str_t *value);
 
 
 static void *ngx_http_image_filter_create_conf(ngx_conf_t *cf);
@@ -106,6 +117,13 @@ static ngx_command_t  ngx_http_image_fil
       offsetof(ngx_http_image_filter_conf_t, jpeg_quality),
       NULL },
 
+    { ngx_string("image_filter_transparency"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_image_filter_conf_t, transparency),
+      NULL },
+
     { ngx_string("image_filter_buffer"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
@@ -454,7 +472,6 @@ ngx_http_image_read(ngx_http_request_t *
 static ngx_buf_t *
 ngx_http_image_process(ngx_http_request_t *r)
 {
-    ngx_buf_t                     *b;
     ngx_int_t                      rc;
     ngx_http_image_filter_ctx_t   *ctx;
     ngx_http_image_filter_conf_t  *conf;
@@ -468,20 +485,28 @@ ngx_http_image_process(ngx_http_request_
     conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
 
     if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
-
-        b = ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
+        return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
+    }
 
-    } else if (rc == NGX_OK
-               && ctx->width <= conf->width
-               && ctx->height <= conf->height)
-    {
-        b = ngx_http_image_asis(r, ctx);
-
-    } else {
-        b = ngx_http_image_resize(r, ctx);
+    ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
+    if (ctx->max_width == 0) {
+        return NULL;
     }
 
-    return b;
+    ctx->max_height = ngx_http_image_filter_get_value(r, conf->hcv,
+                                                      conf->height);
+    if (ctx->max_height == 0) {
+        return NULL;
+    }
+
+    if (rc == NGX_OK
+        && ctx->width <= ctx->max_width
+        && ctx->height <= ctx->max_height)
+    {
+        return ngx_http_image_asis(r, ctx);
+    }
+
+    return ngx_http_image_resize(r, ctx);
 }
 
 
@@ -662,8 +687,9 @@ ngx_http_image_size(ngx_http_request_t *
 static ngx_buf_t *
 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
 {
-    int                            sx, sy, dx, dy, ox, oy,
-                                   colors, transparent, size;
+    int                            sx, sy, dx, dy, ox, oy, size,
+                                   colors, palette, transparent,
+                                   red, green, blue;
     u_char                        *out;
     ngx_buf_t                     *b;
     ngx_uint_t                     resize;
@@ -682,29 +708,53 @@ ngx_http_image_resize(ngx_http_request_t
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
 
-    if ((ngx_uint_t) sx <= conf->width && (ngx_uint_t) sy <= conf->height) {
+    if ((ngx_uint_t) sx <= ctx->max_width
+        && (ngx_uint_t) sy <= ctx->max_height)
+    {
         gdImageDestroy(src);
         return ngx_http_image_asis(r, ctx);
     }
 
     colors = gdImageColorsTotal(src);
-    transparent = gdImageGetTransparent(src);
+
+    if (colors && conf->transparency) {
+        transparent = gdImageGetTransparent(src);
+
+        if (transparent != -1) {
+            palette = colors;
+            red = gdImageRed(src, transparent);
+            green = gdImageGreen(src, transparent);
+            blue = gdImageBlue(src, transparent);
+
+            goto transparent;
+        }
+    }
+
+    palette = 0;
+    transparent = -1;
+    red = 0;
+    green = 0;
+    blue = 0;
+
+transparent:
+
+    gdImageColorTransparent(src, -1);
 
     dx = sx;
     dy = sy;
 
     if (conf->filter == NGX_HTTP_IMAGE_RESIZE) {
 
-        if ((ngx_uint_t) dx > conf->width) {
-            dy = dy * conf->width / dx;
+        if ((ngx_uint_t) dx > ctx->max_width) {
+            dy = dy * ctx->max_width / dx;
             dy = dy ? dy : 1;
-            dx = conf->width;
+            dx = ctx->max_width;
         }
 
-        if ((ngx_uint_t) dy > conf->height) {
-            dx = dx * conf->height / dy;
+        if ((ngx_uint_t) dy > ctx->max_height) {
+            dx = dx * ctx->max_height / dy;
             dx = dx ? dx : 1;
-            dy = conf->height;
+            dy = ctx->max_height;
         }
 
         resize = 1;
@@ -713,34 +763,44 @@ ngx_http_image_resize(ngx_http_request_t
 
         resize = 0;
 
-        if ((ngx_uint_t) (dx * 100 / dy) < conf->width * 100 / conf->height) {
-
-            if ((ngx_uint_t) dx > conf->width) {
-                dy = dy * conf->width / dx;
+        if ((ngx_uint_t) (dx * 100 / dy)
+            < ctx->max_width * 100 / ctx->max_height)
+        {
+            if ((ngx_uint_t) dx > ctx->max_width) {
+                dy = dy * ctx->max_width / dx;
                 dy = dy ? dy : 1;
-                dx = conf->width;
+                dx = ctx->max_width;
                 resize = 1;
             }
 
         } else {
-            if ((ngx_uint_t) dy > conf->height) {
-                dx = dx * conf->height / dy;
+            if ((ngx_uint_t) dy > ctx->max_height) {
+                dx = dx * ctx->max_height / dy;
                 dx = dx ? dx : 1;
-                dy = conf->height;
+                dy = ctx->max_height;
                 resize = 1;
             }
         }
     }
 
     if (resize) {
-        dst = ngx_http_image_new(r, dx, dy, colors);
+        dst = ngx_http_image_new(r, dx, dy, palette);
         if (dst == NULL) {
             gdImageDestroy(src);
             return NULL;
         }
 
+        if (colors == 0) {
+            gdImageSaveAlpha(dst, 1);
+            gdImageAlphaBlending(dst, 0);
+        }
+
         gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);
 
+        if (colors) {
+            gdImageTrueColorToPalette(dst, 1, 256);
+        }
+
         gdImageDestroy(src);
 
     } else {
@@ -751,15 +811,15 @@ ngx_http_image_resize(ngx_http_request_t
 
         src = dst;
 
-        if ((ngx_uint_t) dx > conf->width) {
-            ox = dx - conf->width;
+        if ((ngx_uint_t) dx > ctx->max_width) {
+            ox = dx - ctx->max_width;
 
         } else {
             ox = 0;
         }
 
-        if ((ngx_uint_t) dy > conf->height) {
-            oy = dy - conf->height;
+        if ((ngx_uint_t) dy > ctx->max_height) {
+            oy = dy - ctx->max_height;
 
         } else {
             oy = 0;
@@ -781,13 +841,24 @@ ngx_http_image_resize(ngx_http_request_t
                            "image crop: %d x %d @ %d x %d",
                            dx, dy, ox, oy);
 
+            if (colors == 0) {
+                gdImageSaveAlpha(dst, 1);
+                gdImageAlphaBlending(dst, 0);
+            }
+
             gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);
 
+            if (colors) {
+                gdImageTrueColorToPalette(dst, 1, 256);
+            }
+
             gdImageDestroy(src);
         }
     }
 
-    gdImageColorTransparent(dst, transparent);
+    if (transparent != -1 && colors) {
+        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
+    }
 
     out = ngx_http_image_out(r, ctx->type, dst, &size);
 
@@ -941,6 +1012,43 @@ ngx_http_image_cleanup(void *data)
 }
 
 
+static ngx_uint_t
+ngx_http_image_filter_get_value(ngx_http_request_t *r,
+    ngx_http_complex_value_t *cv, ngx_uint_t v)
+{
+    ngx_str_t  val;
+
+    if (cv == NULL) {
+        return v;
+    }
+
+    if (ngx_http_complex_value(r, cv, &val) != NGX_OK) {
+        return 0;
+    }
+
+    return ngx_http_image_filter_value(&val);
+}
+
+
+static ngx_uint_t
+ngx_http_image_filter_value(ngx_str_t *value)
+{
+    ngx_int_t  n;
+
+    if (value->len == 1 && value->data[0] == '-') {
+        return (ngx_uint_t) -1;
+    }
+
+    n = ngx_atoi(value->data, value->len);
+
+    if (n > 0) {
+        return (ngx_uint_t) n;
+    }
+
+    return 0;
+}
+
+
 static void *
 ngx_http_image_filter_create_conf(ngx_conf_t *cf)
 {
@@ -948,11 +1056,12 @@ ngx_http_image_filter_create_conf(ngx_co
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_image_filter_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->filter = NGX_CONF_UNSET_UINT;
     conf->jpeg_quality = NGX_CONF_UNSET;
+    conf->transparency = NGX_CONF_UNSET;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
 
     return conf;
@@ -974,12 +1083,16 @@ ngx_http_image_filter_merge_conf(ngx_con
             conf->filter = prev->filter;
             conf->width = prev->width;
             conf->height = prev->height;
+            conf->wcv = prev->wcv;
+            conf->hcv = prev->hcv;
         }
     }
 
     /* 75 is libjpeg default quality */
     ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75);
 
+    ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
+
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
                               1 * 1024 * 1024);
 
@@ -992,9 +1105,11 @@ ngx_http_image_filter(ngx_conf_t *cf, ng
 {
     ngx_http_image_filter_conf_t *imcf = conf;
 
-    ngx_str_t   *value;
-    ngx_int_t    n;
-    ngx_uint_t   i;
+    ngx_str_t                         *value;
+    ngx_int_t                          n;
+    ngx_uint_t                         i;
+    ngx_http_complex_value_t           cv;
+    ngx_http_compile_complex_value_t   ccv;
 
     value = cf->args->elts;
 
@@ -1027,32 +1142,60 @@ ngx_http_image_filter(ngx_conf_t *cf, ng
         goto failed;
     }
 
-    i++;
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[++i];
+    ccv.complex_value = &cv;
 
-    if (value[i].len == 1 && value[i].data[0] == '-') {
-        imcf->width = (ngx_uint_t) -1;
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
 
-    } else {
-        n = ngx_atoi(value[i].data, value[i].len);
-        if (n == NGX_ERROR) {
+    if (cv.lengths == NULL) {
+        n = ngx_http_image_filter_value(&value[i]);
+
+        if (n == 0) {
             goto failed;
         }
 
         imcf->width = (ngx_uint_t) n;
+
+    } else {
+        imcf->wcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->wcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->wcv = cv;
     }
 
-    i++;
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[++i];
+    ccv.complex_value = &cv;
 
-    if (value[i].len == 1 && value[i].data[0] == '-') {
-        imcf->height = (ngx_uint_t) -1;
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
 
-    } else {
-        n = ngx_atoi(value[i].data, value[i].len);
-        if (n == NGX_ERROR) {
+    if (cv.lengths == NULL) {
+        n = ngx_http_image_filter_value(&value[i]);
+
+        if (n == 0) {
             goto failed;
         }
 
         imcf->height = (ngx_uint_t) n;
+
+    } else {
+        imcf->hcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->hcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->hcv = cv;
     }
 
     return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -366,7 +366,7 @@ ngx_http_index_create_loc_conf(ngx_conf_
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->indices = NULL;
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -42,7 +42,10 @@ typedef struct {
     ngx_shm_zone_t              *shm_zone;
     /* integer value, 1 corresponds to 0.001 r/s */
     ngx_uint_t                   burst;
-    ngx_uint_t                   nodelay;/* unsigned  nodelay:1 */
+    ngx_uint_t                   limit_log_level;
+    ngx_uint_t                   delay_log_level;
+
+    ngx_uint_t                   nodelay; /* unsigned  nodelay:1 */
 } ngx_http_limit_req_conf_t;
 
 
@@ -62,6 +65,15 @@ static char *ngx_http_limit_req(ngx_conf
 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf);
 
 
+static ngx_conf_enum_t  ngx_http_limit_req_log_levels[] = {
+    { ngx_string("info"), NGX_LOG_INFO },
+    { ngx_string("notice"), NGX_LOG_NOTICE },
+    { ngx_string("warn"), NGX_LOG_WARN },
+    { ngx_string("error"), NGX_LOG_ERR },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_limit_req_commands[] = {
 
     { ngx_string("limit_req_zone"),
@@ -78,6 +90,13 @@ static ngx_command_t  ngx_http_limit_req
       0,
       NULL },
 
+    { ngx_string("limit_req_log_level"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_limit_req_conf_t, limit_log_level),
+      &ngx_http_limit_req_log_levels },
+
       ngx_null_command
 };
 
@@ -181,12 +200,12 @@ ngx_http_limit_req_handler(ngx_http_requ
     }
 
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                  "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
+                   "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
 
     if (rc == NGX_BUSY) {
         ngx_shmtx_unlock(&ctx->shpool->mutex);
 
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+        ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                       "limiting requests, excess: %ui.%03ui by zone \"%V\"",
                       excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
 
@@ -200,7 +219,7 @@ ngx_http_limit_req_handler(ngx_http_requ
             return NGX_DECLINED;
         }
 
-        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+        ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
                       "delaying request, excess: %ui.%03ui, by zone \"%V\"",
                       excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
 
@@ -263,8 +282,23 @@ done:
 static void
 ngx_http_limit_req_delay(ngx_http_request_t *r)
 {
+    ngx_event_t  *wev;
+
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                  "limit_req delay");
+                   "limit_req delay");
+
+    wev = r->connection->write;
+
+    if (!wev->timedout) {
+
+        if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        }
+
+        return;
+    }
+
+    wev->timedout = 0;
 
     if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -368,15 +402,16 @@ ngx_http_limit_req_lookup(ngx_http_limit
                     excess = 0;
                 }
 
+                if ((ngx_uint_t) excess > lrcf->burst) {
+                    *lrp = lr;
+                    return NGX_BUSY;
+                }
+
                 lr->excess = excess;
                 lr->last = now;
 
                 *lrp = lr;
 
-                if ((ngx_uint_t) excess > lrcf->burst) {
-                    return NGX_BUSY;
-                }
-
                 if (excess) {
                     return NGX_AGAIN;
                 }
@@ -522,7 +557,7 @@ ngx_http_limit_req_create_conf(ngx_conf_
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -533,6 +568,8 @@ ngx_http_limit_req_create_conf(ngx_conf_
      *     conf->nodelay = 0;
      */
 
+    conf->limit_log_level = NGX_CONF_UNSET_UINT;
+
     return conf;
 }
 
@@ -547,6 +584,12 @@ ngx_http_limit_req_merge_conf(ngx_conf_t
         *conf = *prev;
     }
 
+    ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level,
+                              NGX_LOG_ERR);
+
+    conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ?
+                                NGX_LOG_INFO : conf->limit_log_level + 1;
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -33,6 +33,7 @@ typedef struct {
 typedef struct {
     ngx_shm_zone_t     *shm_zone;
     ngx_uint_t          conn;
+    ngx_uint_t          log_level;
 } ngx_http_limit_zone_conf_t;
 
 
@@ -48,6 +49,15 @@ static char *ngx_http_limit_conn(ngx_con
 static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf);
 
 
+static ngx_conf_enum_t  ngx_http_limit_conn_log_levels[] = {
+    { ngx_string("info"), NGX_LOG_INFO },
+    { ngx_string("notice"), NGX_LOG_NOTICE },
+    { ngx_string("warn"), NGX_LOG_WARN },
+    { ngx_string("error"), NGX_LOG_ERR },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_limit_zone_commands[] = {
 
     { ngx_string("limit_zone"),
@@ -64,6 +74,13 @@ static ngx_command_t  ngx_http_limit_zon
       0,
       NULL },
 
+    { ngx_string("limit_conn_log_level"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_limit_zone_conf_t, log_level),
+      &ngx_http_limit_conn_log_levels },
+
       ngx_null_command
 };
 
@@ -189,7 +206,7 @@ ngx_http_limit_zone_handler(ngx_http_req
 
                 ngx_shmtx_unlock(&shpool->mutex);
 
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                ngx_log_error(lzcf->log_level, r->connection->log, 0,
                               "limiting connections by zone \"%V\"",
                               &lzcf->shm_zone->shm.name);
 
@@ -381,7 +398,7 @@ ngx_http_limit_zone_create_conf(ngx_conf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -391,6 +408,8 @@ ngx_http_limit_zone_create_conf(ngx_conf
      *     conf->conn = 0;
      */
 
+    conf->log_level = NGX_CONF_UNSET_UINT;
+
     return conf;
 }
 
@@ -405,6 +424,8 @@ ngx_http_limit_zone_merge_conf(ngx_conf_
         *conf = *prev;
     }
 
+    ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -676,7 +676,7 @@ ngx_http_log_escape(u_char *dst, u_char 
 
         /* find the number of the characters to be escaped */
 
-        n  = 0;
+        n = 0;
 
         for (i = 0; i < size; i++) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
@@ -714,18 +714,18 @@ ngx_http_log_create_main_conf(ngx_conf_t
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     fmt = ngx_array_push(&conf->formats);
     if (fmt == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     fmt->name.len = sizeof("combined") - 1;
@@ -735,7 +735,7 @@ ngx_http_log_create_main_conf(ngx_conf_t
 
     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
     if (fmt->ops == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return conf;
@@ -749,7 +749,7 @@ ngx_http_log_create_loc_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->open_file_cache = NGX_CONF_UNSET_PTR;
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -160,7 +160,7 @@ ngx_http_map_create_conf(ngx_conf_t *cf)
 
     mcf = ngx_palloc(cf->pool, sizeof(ngx_http_map_conf_t));
     if (mcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     mcf->hash_max_size = NGX_CONF_UNSET_UINT;
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -176,23 +176,18 @@ ngx_http_memcached_handler(ngx_http_requ
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
-
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
-    if (u == NULL) {
+    if (ngx_http_upstream_create(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    u = r->upstream;
+
     u->schema.len = sizeof("memcached://") - 1;
     u->schema.data = (u_char *) "memcached://";
 
-    u->peer.log = r->connection->log;
-    u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
+    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
 
-    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
+    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
 
     u->conf = &mlcf->upstream;
 
@@ -202,8 +197,6 @@ ngx_http_memcached_handler(ngx_http_requ
     u->abort_request = ngx_http_memcached_abort_request;
     u->finalize_request = ngx_http_memcached_finalize_request;
 
-    r->upstream = u;
-
     ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
     if (ctx == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -513,7 +506,7 @@ ngx_http_memcached_create_loc_conf(ngx_c
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -590,13 +590,10 @@ ngx_http_proxy_handler(ngx_http_request_
     ngx_http_proxy_ctx_t       *ctx;
     ngx_http_proxy_loc_conf_t  *plcf;
 
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
-    if (u == NULL) {
+    if (ngx_http_upstream_create(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->upstream = u;
-
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
@@ -606,6 +603,8 @@ ngx_http_proxy_handler(ngx_http_request_
 
     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
 
+    u = r->upstream;
+
     if (plcf->proxy_lengths == 0) {
         ctx->vars = plcf->vars;
         u->schema = plcf->vars.schema;
@@ -619,12 +618,6 @@ ngx_http_proxy_handler(ngx_http_request_
         }
     }
 
-    u->peer.log = r->connection->log;
-    u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
-
     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
 
     u->conf = &plcf->upstream;
@@ -1884,7 +1877,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_random_index_module.c
+++ b/src/http/modules/ngx_http_random_index_module.c
@@ -280,7 +280,7 @@ ngx_http_random_index_create_loc_conf(ng
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -360,7 +360,7 @@ ngx_http_realip_create_loc_conf(ngx_conf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -221,7 +221,7 @@ ngx_http_referer_create_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
 #if (NGX_PCRE)
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -220,7 +220,7 @@ ngx_http_rewrite_create_loc_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->stack_size = NGX_CONF_UNSET_UINT;
@@ -446,7 +446,7 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
             return NGX_CONF_ERROR;
         }
 
-        *code = (uintptr_t) NULL;
+        *code = NULL;
     }
 
     regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
@@ -568,7 +568,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
 
     if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
     if (if_code == NULL) {
-        return NULL;
+        return NGX_CONF_ERROR;
     }
 
     if_code->code = ngx_http_script_if_code;
--- a/src/http/modules/ngx_http_secure_link_module.c
+++ b/src/http/modules/ngx_http_secure_link_module.c
@@ -152,7 +152,7 @@ ngx_http_secure_link_create_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -360,6 +360,7 @@ ngx_http_ssi_header_filter(ngx_http_requ
     if (r == r->main) {
         ngx_http_clear_content_length(r);
         ngx_http_clear_last_modified(r);
+        ngx_http_clear_accept_ranges(r);
     }
 
     return ngx_http_next_header_filter(r);
@@ -1907,7 +1908,7 @@ ngx_http_ssi_include(ngx_http_request_t 
 
     args.len = 0;
     args.data = NULL;
-    flags = 0;
+    flags = NGX_HTTP_LOG_UNSAFE;
 
     if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
         return NGX_HTTP_SSI_ERROR;
@@ -2689,14 +2690,14 @@ ngx_http_ssi_create_main_conf(ngx_conf_t
 
     smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_main_conf_t));
     if (smcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     smcf->commands.pool = cf->pool;
     smcf->commands.temp_pool = cf->temp_pool;
 
     if (ngx_hash_keys_array_init(&smcf->commands, NGX_HASH_SMALL) != NGX_OK) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return smcf;
@@ -2736,7 +2737,7 @@ ngx_http_ssi_create_loc_conf(ngx_conf_t 
 
     slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_loc_conf_t));
     if (slcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -31,15 +31,6 @@ static char *ngx_http_ssl_enable(ngx_con
 static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-
-static char  ngx_http_ssl_openssl097[] = "OpenSSL 0.9.7 and higher";
-
-#endif
-
 
 static ngx_conf_bitmask_t  ngx_http_ssl_protocols[] = {
     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
@@ -52,7 +43,7 @@ static ngx_conf_bitmask_t  ngx_http_ssl_
 static ngx_conf_enum_t  ngx_http_ssl_verify[] = {
     { ngx_string("off"), 0 },
     { ngx_string("on"), 1 },
-    { ngx_string("ask"), 2 },
+    { ngx_string("optional"), 2 },
     { ngx_null_string, 0 }
 };
 
@@ -124,14 +115,10 @@ static ngx_command_t  ngx_http_ssl_comma
 
     { ngx_string("ssl_prefer_server_ciphers"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
       ngx_conf_set_flag_slot,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers),
       NULL },
-#else
-      ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 },
-#endif
 
     { ngx_string("ssl_session_cache"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
@@ -147,6 +134,13 @@ static ngx_command_t  ngx_http_ssl_comma
       offsetof(ngx_http_ssl_srv_conf_t, session_timeout),
       NULL },
 
+    { ngx_string("ssl_crl"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_ssl_srv_conf_t, crl),
+      NULL },
+
       ngx_null_command
 };
 
@@ -206,6 +200,9 @@ static ngx_http_variable_t  ngx_http_ssl
     { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
@@ -302,7 +299,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
 
     sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
     if (sscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -313,6 +310,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
      *     sscf->certificate_key = { 0, NULL };
      *     sscf->dhparam = { 0, NULL };
      *     sscf->client_certificate = { 0, NULL };
+     *     sscf->crl = { 0, NULL };
      *     sscf->ciphers.len = 0;
      *     sscf->ciphers.data = NULL;
      *     sscf->shm_zone = NULL;
@@ -359,6 +357,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 
     ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
                          "");
+    ngx_conf_merge_str_value(conf->crl, prev->crl, "");
 
     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
 
@@ -407,9 +406,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
                                                ngx_http_ssl_servername)
         == 0)
     {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_set_tlsext_servername_callback() failed");
-        return NGX_CONF_ERROR;
+        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+            "nginx was built with SNI support, however, now it is linked "
+            "dynamically to an OpenSSL library which has no tlsext support, "
+            "therefore SNI is not available");
     }
 
 #endif
@@ -453,16 +453,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         {
             return NGX_CONF_ERROR;
         }
+
+        if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
     }
 
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
-
     if (conf->prefer_server_ciphers) {
         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
     }
 
-#endif
-
     /* a temporary 512-bit RSA key is required for export versions of MSIE */
     if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
         return NGX_CONF_ERROR;
@@ -620,18 +620,3 @@ invalid:
 
     return NGX_CONF_ERROR;
 }
-
-
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *
-ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"%V\" directive is available only in %s,",
-                       &cmd->name, cmd->post);
-
-    return NGX_CONF_ERROR;
-}
-
-#endif
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -33,6 +33,7 @@ typedef struct {
     ngx_str_t                       certificate_key;
     ngx_str_t                       dhparam;
     ngx_str_t                       client_certificate;
+    ngx_str_t                       crl;
 
     ngx_str_t                       ciphers;
 
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -638,7 +638,7 @@ ngx_http_sub_create_conf(ngx_conf_t *cf)
 
     slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t));
     if (slcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -570,7 +570,7 @@ ngx_http_userid_create_conf(ngx_conf_t *
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -404,7 +404,7 @@ ngx_http_xslt_add_chunk(ngx_http_request
         sax->endElementNs = ngx_http_xslt_sax_end_element;
 
         sax->characters = ngx_http_xslt_sax_characters;
-        sax->ignorableWhitespace  = ngx_http_xslt_sax_characters;
+        sax->ignorableWhitespace = ngx_http_xslt_sax_characters;
         sax->cdataBlock = ngx_http_xslt_sax_cdata_block;
         sax->getEntity = ngx_http_xslt_sax_get_entity;
         sax->resolveEntity = ngx_http_xslt_sax_resolve_entity;
@@ -1172,7 +1172,7 @@ ngx_http_xslt_filter_create_main_conf(ng
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&conf->dtd_files, cf->pool, 1,
@@ -1200,7 +1200,7 @@ ngx_http_xslt_filter_create_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- 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.62';
+our $VERSION = '0.7.63';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -13,8 +13,8 @@
 typedef struct {
     PerlInterpreter   *perl;
     HV                *nginx;
-    ngx_str_t          modules;
-    ngx_array_t        requires;
+    ngx_array_t       *modules;
+    ngx_array_t       *requires;
 } ngx_http_perl_main_conf_t;
 
 
@@ -57,8 +57,6 @@ static char *ngx_http_perl_init_main_con
 static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent,
     void *child);
-static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
 static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
@@ -74,16 +72,16 @@ static ngx_command_t  ngx_http_perl_comm
 
     { ngx_string("perl_modules"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+      ngx_conf_set_str_array_slot,
       NGX_HTTP_MAIN_CONF_OFFSET,
       offsetof(ngx_http_perl_main_conf_t, modules),
       NULL },
 
     { ngx_string("perl_require"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
-      ngx_http_perl_require,
+      ngx_conf_set_str_array_slot,
       NGX_HTTP_MAIN_CONF_OFFSET,
-      0,
+      offsetof(ngx_http_perl_main_conf_t, requires),
       NULL },
 
     { ngx_string("perl"),
@@ -458,8 +456,10 @@ ngx_http_perl_ssi(ngx_http_request_t *r,
 static char *
 ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
 {
+    ngx_str_t               *m;
+    ngx_uint_t               i;
 #if (NGX_HAVE_PERL_MULTIPLICITY)
-    ngx_pool_cleanup_t       *cln;
+    ngx_pool_cleanup_t      *cln;
 
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
@@ -471,14 +471,29 @@ ngx_http_perl_init_interpreter(ngx_conf_
 #endif
 
 #ifdef NGX_PERL_MODULES
-    if (pmcf->modules.data == NULL) {
-        pmcf->modules.data = NGX_PERL_MODULES;
+    if (pmcf->modules == NGX_CONF_UNSET_PTR) {
+
+        pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
+        if (pmcf->modules == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        m = ngx_array_push(pmcf->modules);
+        if (m == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        m->len = sizeof(NGX_PERL_MODULES) - 1;
+        m->data = NGX_PERL_MODULES;
     }
 #endif
 
-    if (pmcf->modules.data) {
-        if (ngx_conf_full_name(cf->cycle, &pmcf->modules, 0) != NGX_OK) {
-            return NGX_CONF_ERROR;
+    if (pmcf->modules != NGX_CONF_UNSET_PTR) {
+        m = pmcf->modules->elts;
+        for (i = 0; i < pmcf->modules->nelts; i++) {
+            if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
         }
     }
 
@@ -490,7 +505,7 @@ ngx_http_perl_init_interpreter(ngx_conf_
             return NGX_CONF_ERROR;
         }
 
-        if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log)
+        if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log)
             != NGX_OK)
         {
             return NGX_CONF_ERROR;
@@ -538,7 +553,9 @@ ngx_http_perl_create_interpreter(ngx_con
     int                n;
     STRLEN             len;
     SV                *sv;
-    char              *ver, *embedding[6];
+    char              *ver, **embedding;
+    ngx_str_t         *m;
+    ngx_uint_t         i;
     PerlInterpreter   *perl;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
@@ -564,15 +581,21 @@ ngx_http_perl_create_interpreter(ngx_con
     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
 #endif
 
+    n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0;
+
+    embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *));
+    if (embedding == NULL) {
+        goto fail;
+    }
+
     embedding[0] = "";
 
-    if (pmcf->modules.data) {
-        embedding[1] = "-I";
-        embedding[2] = (char *) pmcf->modules.data;
-        n = 3;
-
-    } else {
-        n = 1;
+    if (n++) {
+        m = pmcf->modules->elts;
+        for (i = 0; i < pmcf->modules->nelts; i++) {
+            embedding[2 * i + 1] = "-I";
+            embedding[2 * i + 2] = (char *) m[i].data;
+        }
     }
 
     embedding[n++] = "-Mnginx";
@@ -596,7 +619,7 @@ ngx_http_perl_create_interpreter(ngx_con
         goto fail;
     }
 
-    if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) {
+    if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) {
         goto fail;
     }
 
@@ -617,26 +640,28 @@ fail:
 static ngx_int_t
 ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
 {
-    char       **script;
+    u_char      *err;
     STRLEN       len;
-    ngx_str_t    err;
+    ngx_str_t   *script;
     ngx_uint_t   i;
 
+    if (requires == NGX_CONF_UNSET_PTR) {
+        return NGX_OK;
+    }
+
     script = requires->elts;
     for (i = 0; i < requires->nelts; i++) {
 
-        require_pv(script[i]);
+        require_pv((char *) script[i].data);
 
         if (SvTRUE(ERRSV)) {
 
-            err.data = (u_char *) SvPV(ERRSV, len);
-            for (len--; err.data[len] == LF || err.data[len] == CR; len--) {
-                /* void */
-            }
-            err.len = len + 1;
+            err = (u_char *) SvPV(ERRSV, len);
+            while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }
 
             ngx_log_error(NGX_LOG_EMERG, log, 0,
-                          "require_pv(\"%s\") failed: \"%V\"", script[i], &err);
+                          "require_pv(\"%s\") failed: \"%*s\"",
+                          script[i].data, len + 1, err);
 
             return NGX_ERROR;
         }
@@ -653,8 +678,8 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
     SV                *sv;
     int                n, status;
     char              *line;
+    u_char            *err;
     STRLEN             len, n_a;
-    ngx_str_t          err;
     ngx_uint_t         i;
     ngx_connection_t  *c;
 
@@ -724,14 +749,11 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
 
     if (SvTRUE(ERRSV)) {
 
-        err.data = (u_char *) SvPV(ERRSV, len);
-        for (len--; err.data[len] == LF || err.data[len] == CR; len--) {
-            /* void */
-        }
-        err.len = len + 1;
+        err = (u_char *) SvPV(ERRSV, len);
+        while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }
 
         ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                      "call_sv(\"%V\") failed: \"%V\"", handler, &err);
+                      "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err);
 
         if (rv) {
             return NGX_ERROR;
@@ -765,7 +787,10 @@ ngx_http_perl_eval_anon_sub(pTHX_ ngx_st
         }
     }
 
-    if (ngx_strncmp(p, "sub ", 4) == 0 || ngx_strncmp(p, "use ", 4) == 0) {
+    if (ngx_strncmp(p, "sub ", 4) == 0
+        || ngx_strncmp(p, "sub{", 4) == 0
+        || ngx_strncmp(p, "use ", 4) == 0)
+    {
         *sv = eval_pv((char *) p, FALSE);
 
         /* eval_pv() does not set ERRSV on failure */
@@ -784,14 +809,11 @@ ngx_http_perl_create_main_conf(ngx_conf_
 
     pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t));
     if (pmcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
-    if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *))
-        != NGX_OK)
-    {
-        return NULL;
-    }
+    pmcf->modules = NGX_CONF_UNSET_PTR;
+    pmcf->requires = NGX_CONF_UNSET_PTR;
 
     return pmcf;
 }
@@ -869,7 +891,7 @@ ngx_http_perl_create_loc_conf(ngx_conf_t
 
     plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t));
     if (plcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -898,28 +920,6 @@ ngx_http_perl_merge_loc_conf(ngx_conf_t 
 
 
 static char *
-ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_http_perl_main_conf_t *pmcf = conf;
-
-    u_char     **p;
-    ngx_str_t   *value;
-
-    value = cf->args->elts;
-
-    p = ngx_array_push(&pmcf->requires);
-
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    *p = value[1].data;
-
-    return NGX_CONF_OK;
-}
-
-
-static char *
 ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_perl_loc_conf_t *plcf = conf;
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -97,6 +97,7 @@ typedef struct {
     ngx_rbtree_node_t                sentinel;
     ngx_queue_t                      queue;
     ngx_atomic_t                     cold;
+    ngx_atomic_t                     loading;
     off_t                            size;
 } ngx_http_file_cache_sh_t;
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -433,6 +433,14 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, limit_rate),
       NULL },
 
+    { ngx_string("limit_rate_after"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, limit_rate_after),
+      NULL },
+
     { ngx_string("keepalive_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
       ngx_http_core_keepalive,
@@ -877,6 +885,7 @@ ngx_http_core_find_config_phase(ngx_http
                       "client intended to send too large body: %O bytes",
                       r->headers_in.content_length_n);
 
+        (void) ngx_http_discard_request_body(r);
         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
         return NGX_OK;
     }
@@ -2691,14 +2700,14 @@ ngx_http_core_create_main_conf(ngx_conf_
 
     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t));
     if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
                        sizeof(ngx_http_core_srv_conf_t *))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
@@ -2750,7 +2759,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t
 
     cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t));
     if (cscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -2763,14 +2772,14 @@ ngx_http_core_create_srv_conf(ngx_conf_t
                        sizeof(ngx_http_listen_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
                        sizeof(ngx_http_server_name_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     cscf->connection_pool_size = NGX_CONF_UNSET_SIZE;
@@ -2881,7 +2890,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
 
     lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
     if (lcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -2920,6 +2929,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     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;
@@ -3119,6 +3129,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
                               1460);
     ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
+    ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after,
+                              0);
     ngx_conf_merge_msec_value(conf->keepalive_timeout,
                               prev->keepalive_timeout, 75000);
     ngx_conf_merge_sec_value(conf->keepalive_header,
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -324,6 +324,7 @@ struct ngx_http_core_loc_conf_s {
     size_t        send_lowat;              /* send_lowat */
     size_t        postpone_output;         /* postpone_output */
     size_t        limit_rate;              /* limit_rate */
+    size_t        limit_rate_after;        /* limit_rate_after */
     size_t        sendfile_max_chunk;      /* sendfile_max_chunk */
 
     ngx_msec_t    client_body_timeout;     /* client_body_timeout */
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -53,6 +53,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
     ngx_http_file_cache_t  *ocache = data;
 
     size_t                  len;
+    ngx_uint_t              n;
     ngx_http_file_cache_t  *cache;
 
     cache = shm_zone->data;
@@ -68,6 +69,15 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
             return NGX_ERROR;
         }
 
+        for (n = 0; n < 3; n++) {
+            if (cache->path->level[n] != ocache->path->level[n]) {
+                ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
+                              "cache \"%V\" had previously different levels",
+                              &shm_zone->shm.name);
+                return NGX_ERROR;
+            }
+        }
+
         cache->sh = ocache->sh;
 
         cache->shpool = ocache->shpool;
@@ -75,6 +85,10 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
 
         cache->max_size /= cache->bsize;
 
+        if (!cache->sh->cold || cache->sh->loading) {
+            cache->path->loader = NULL;
+        }
+
         return NGX_OK;
     }
 
@@ -100,6 +114,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
     ngx_queue_init(&cache->sh->queue);
 
     cache->sh->cold = 1;
+    cache->sh->loading = 0;
     cache->sh->size = 0;
 
     cache->bsize = ngx_fs_bsize(cache->path->name.data);
@@ -603,7 +618,7 @@ ngx_http_file_cache_set_header(ngx_http_
 void
 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
 {
-    off_t                   size;
+    off_t                   size, length;
     ngx_int_t               rc;
     ngx_file_uniq_t         uniq;
     ngx_file_info_t         fi;
@@ -625,6 +640,7 @@ ngx_http_file_cache_update(ngx_http_requ
     cache = c->file_cache;
 
     uniq = 0;
+    length = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http file cache rename: \"%s\" to \"%s\"",
@@ -635,7 +651,6 @@ ngx_http_file_cache_update(ngx_http_requ
     ext.time = -1;
     ext.create_path = 1;
     ext.delete_file = 1;
-    ext.log_rename_error = 1;
     ext.log = r->connection->log;
 
     rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
@@ -650,10 +665,11 @@ ngx_http_file_cache_update(ngx_http_requ
 
         } else {
             uniq = ngx_file_uniq(&fi);
+            length = ngx_file_size(&fi);
         }
     }
 
-    size = (c->length + cache->bsize - 1) / cache->bsize;
+    size = (length + cache->bsize - 1) / cache->bsize;
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -663,7 +679,7 @@ ngx_http_file_cache_update(ngx_http_requ
 
     size = size - (c->node->length + cache->bsize - 1) / cache->bsize;
 
-    c->node->length = c->length;
+    c->node->length = length;
 
     cache->sh->size += size;
 
@@ -1026,39 +1042,8 @@ ngx_http_file_cache_manager(void *data)
 {
     ngx_http_file_cache_t  *cache = data;
 
-    off_t           size;
-    time_t          next;
-    ngx_tree_ctx_t  tree;
-
-    if (cache->sh->cold) {
-
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
-                       "http file cache manager update");
-
-        tree.init_handler = NULL;
-        tree.file_handler = ngx_http_file_cache_manage_file;
-        tree.pre_tree_handler = ngx_http_file_cache_noop;
-        tree.post_tree_handler = ngx_http_file_cache_noop;
-        tree.spec_handler = ngx_http_file_cache_delete_file;
-        tree.data = cache;
-        tree.alloc = 0;
-        tree.log = ngx_cycle->log;
-
-        cache->last = ngx_current_msec;
-        cache->files = 0;
-
-        if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
-            return 10;
-        }
-
-        cache->sh->cold = 0;
-
-        ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
-                      "http file cache: %V %.3fM, bsize: %uz",
-                      &cache->path->name,
-                      ((double) cache->sh->size * cache->bsize) / (1024 * 1024),
-                      cache->bsize);
-    }
+    off_t   size;
+    time_t  next;
 
     next = ngx_http_file_cache_expire(cache);
 
@@ -1088,6 +1073,52 @@ ngx_http_file_cache_manager(void *data)
 }
 
 
+static void
+ngx_http_file_cache_loader(void *data)
+{
+    ngx_http_file_cache_t  *cache = data;
+
+    ngx_tree_ctx_t  tree;
+
+    if (!cache->sh->cold || cache->sh->loading) {
+        return;
+    }
+
+    if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) {
+        return;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+                   "http file cache loader");
+
+    tree.init_handler = NULL;
+    tree.file_handler = ngx_http_file_cache_manage_file;
+    tree.pre_tree_handler = ngx_http_file_cache_noop;
+    tree.post_tree_handler = ngx_http_file_cache_noop;
+    tree.spec_handler = ngx_http_file_cache_delete_file;
+    tree.data = cache;
+    tree.alloc = 0;
+    tree.log = ngx_cycle->log;
+
+    cache->last = ngx_current_msec;
+    cache->files = 0;
+
+    if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
+        cache->sh->loading = 0;
+        return;
+    }
+
+    cache->sh->cold = 0;
+    cache->sh->loading = 0;
+
+    ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+                  "http file cache: %V %.3fM, bsize: %uz",
+                  &cache->path->name,
+                  ((double) cache->sh->size * cache->bsize) / (1024 * 1024),
+                  cache->bsize);
+}
+
+
 static ngx_int_t
 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache)
 {
@@ -1468,6 +1499,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
     }
 
     cache->path->manager = ngx_http_file_cache_manager;
+    cache->path->loader = ngx_http_file_cache_loader;
     cache->path->data = cache;
 
     if (ngx_add_path(cf, &cache->path) != NGX_OK) {
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -143,7 +143,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             }
 
-            if (ch < 'A' || ch > 'Z') {
+            if ((ch < 'A' || ch > 'Z') && ch != '_') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
 
@@ -257,7 +257,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             }
 
-            if (ch < 'A' || ch > 'Z') {
+            if ((ch < 'A' || ch > 'Z') && ch != '_') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
 
@@ -1322,8 +1322,10 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
 
 unsafe:
 
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "unsafe URI \"%V\" was detected", uri);
+    if (*flags & NGX_HTTP_LOG_UNSAFE) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "unsafe URI \"%V\" was detected", uri);
+    }
 
     return NGX_ERROR;
 }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -129,7 +129,7 @@ ngx_http_header_t  ngx_http_headers_in[]
     { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive),
                  ngx_http_process_header_line },
 
-#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
+#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)
     { ngx_string("X-Forwarded-For"),
                  offsetof(ngx_http_headers_in_t, x_forwarded_for),
                  ngx_http_process_header_line },
@@ -384,6 +384,7 @@ ngx_http_init_request(ngx_event_t *rev)
     r->loc_conf = cscf->ctx->loc_conf;
 
     rev->handler = ngx_http_process_request_line;
+    r->read_event_handler = ngx_http_block_reading;
 
 #if (NGX_HTTP_SSL)
 
@@ -451,13 +452,15 @@ ngx_http_init_request(ngx_event_t *rev)
                       sizeof(ngx_table_elt_t))
         != NGX_OK)
     {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_destroy_pool(r->pool);
+        ngx_http_close_connection(c);
         return;
     }
 
     r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
     if (r->ctx == NULL) {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_destroy_pool(r->pool);
+        ngx_http_close_connection(c);
         return;
     }
 
@@ -466,7 +469,8 @@ ngx_http_init_request(ngx_event_t *rev)
     r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
                                         * sizeof(ngx_http_variable_value_t));
     if (r->variables == NULL) {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_destroy_pool(r->pool);
+        ngx_http_close_connection(c);
         return;
     }
 
@@ -1374,8 +1378,13 @@ ngx_http_process_user_agent(ngx_http_req
                 r->headers_in.msie4 = 1;
                 /* fall through */
             case '5':
+                r->headers_in.msie6 = 1;
+                break;
             case '6':
-                r->headers_in.msie6 = 1;
+                if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) {
+                    r->headers_in.msie6 = 1;
+                }
+                break;
             }
         }
 
@@ -1517,7 +1526,7 @@ ngx_http_process_request(ngx_http_reques
 
         sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
 
-        if (sscf->verify == 1) {
+        if (sscf->verify) {
             rc = SSL_get_verify_result(c->ssl->connection);
 
             if (rc != X509_V_OK) {
@@ -1532,20 +1541,22 @@ ngx_http_process_request(ngx_http_reques
                 return;
             }
 
-            cert = SSL_get_peer_certificate(c->ssl->connection);
-
-            if (cert == NULL) {
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client sent no required SSL certificate");
-
-                ngx_ssl_remove_cached_session(sscf->ssl.ctx,
+            if (sscf->verify == 1) {
+                cert = SSL_get_peer_certificate(c->ssl->connection);
+
+                if (cert == NULL) {
+                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                                  "client sent no required SSL certificate");
+
+                    ngx_ssl_remove_cached_session(sscf->ssl.ctx,
                                        (SSL_get0_session(c->ssl->connection)));
 
-                ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
-                return;
+                    ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
+                    return;
+                }
+
+                X509_free(cert);
             }
-
-            X509_free(cert);
         }
     }
 
@@ -2703,7 +2714,14 @@ ngx_http_send_special(ngx_http_request_t
     }
 
     if (flags & NGX_HTTP_LAST) {
-        b->last_buf = 1;
+
+        if (r == r->main && !r->post_action) {
+            b->last_buf = 1;
+
+        } else {
+            b->sync = 1;
+            b->last_in_chain = 1;
+        }
     }
 
     if (flags & NGX_HTTP_FLUSH) {
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -60,6 +60,7 @@
 #define NGX_HTTP_ZERO_IN_URI               1
 #define NGX_HTTP_SUBREQUEST_IN_MEMORY      2
 #define NGX_HTTP_SUBREQUEST_WAITED         4
+#define NGX_HTTP_LOG_UNSAFE                8
 
 
 #define NGX_HTTP_OK                        200
@@ -184,7 +185,7 @@ typedef struct {
 
     ngx_table_elt_t                  *keep_alive;
 
-#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
+#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)
     ngx_table_elt_t                  *x_forwarded_for;
 #endif
 
@@ -488,7 +489,6 @@ struct ngx_http_request_s {
     unsigned                          root_tested:1;
     unsigned                          done:1;
     unsigned                          logged:1;
-    unsigned                          utf8:1;
 
     unsigned                          buffered:4;
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -561,7 +561,7 @@ ngx_http_script_add_code(ngx_array_t *co
 
     new = ngx_array_push_n(codes, size);
     if (new == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (code) {
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -230,19 +230,19 @@ ngx_http_upstream_header_t  ngx_http_ups
     { ngx_string("X-Accel-Redirect"),
                  ngx_http_upstream_process_header_line,
                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Limit-Rate"),
                  ngx_http_upstream_process_limit_rate, 0,
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Buffering"),
                  ngx_http_upstream_process_buffering, 0,
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Charset"),
                  ngx_http_upstream_process_charset, 0,
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
 #if (NGX_HTTP_GZIP)
     { ngx_string("Content-Encoding"),
@@ -354,6 +354,35 @@ ngx_conf_bitmask_t  ngx_http_upstream_ca
 };
 
 
+ngx_int_t
+ngx_http_upstream_create(ngx_http_request_t *r)
+{
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+
+    if (u && u->cleanup) {
+        ngx_http_upstream_cleanup(r);
+        *u->cleanup = NULL;
+    }
+
+    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
+    if (u == NULL) {
+        return NGX_ERROR;
+    }
+
+    r->upstream = u;
+
+    u->peer.log = r->connection->log;
+    u->peer.log_error = NGX_ERROR_ERR;
+#if (NGX_THREADS)
+    u->peer.lock = &r->connection->lock;
+#endif
+
+    return NGX_OK;
+}
+
+
 void
 ngx_http_upstream_init(ngx_http_request_t *r)
 {
@@ -1733,7 +1762,7 @@ ngx_http_upstream_process_headers(ngx_ht
         uri = &u->headers_in.x_accel_redirect->value;
         args.len = 0;
         args.data = NULL;
-        flags = 0;
+        flags = NGX_HTTP_LOG_UNSAFE;
 
         if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
@@ -2034,11 +2063,6 @@ ngx_http_upstream_send_response(ngx_http
             r->cache->date = now;
             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
 
-            if (r->headers_out.content_length_n != -1) {
-                r->cache->length = r->cache->body_start
-                                   + r->headers_out.content_length_n;
-            }
-
             ngx_http_file_cache_set_header(r, u->buffer.start);
 
         } else {
@@ -2616,7 +2640,6 @@ ngx_http_upstream_store(ngx_http_request
     ext.time = -1;
     ext.create_path = 1;
     ext.delete_file = 1;
-    ext.log_rename_error = 1;
     ext.log = r->connection->log;
 
     if (u->headers_in.last_modified) {
@@ -2643,6 +2666,8 @@ ngx_http_upstream_store(ngx_http_request
         }
     }
 
+    path.len--;
+
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "upstream stores \"%s\" to \"%s\"",
                    tf->file.name.data, path.data);
@@ -2864,7 +2889,7 @@ ngx_http_upstream_finalize_request(ngx_h
 
 #if (NGX_HTTP_CACHE)
 
-    if (u->cacheable) {
+    if (u->cacheable && r->cache) {
         time_t  valid;
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -2898,7 +2923,7 @@ ngx_http_upstream_finalize_request(ngx_h
 
     r->connection->log->action = "sending to client";
 
-    if (rc == 0 && r == r->main && !r->post_action) {
+    if (rc == 0) {
         rc = ngx_http_send_special(r, NGX_HTTP_LAST);
     }
 
@@ -3311,10 +3336,11 @@ ngx_http_upstream_copy_last_modified(ngx
 
     *ho = *h;
 
+    r->headers_out.last_modified = ho;
+
 #if (NGX_HTTP_CACHE)
 
     if (r->upstream->cacheable) {
-        r->headers_out.last_modified = ho;
         r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data,
                                                                 h->value.len);
     }
@@ -3438,6 +3464,8 @@ ngx_http_upstream_copy_allow_ranges(ngx_
 
     *ho = *h;
 
+    r->headers_out.accept_ranges = ho;
+
     return NGX_OK;
 }
 
@@ -4274,7 +4302,7 @@ ngx_http_upstream_create_main_conf(ngx_c
                        sizeof(ngx_http_upstream_srv_conf_t *))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return umcf;
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -317,6 +317,7 @@ typedef struct {
 ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 
+ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r);
 void ngx_http_upstream_init(ngx_http_request_t *r);
 ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
     ngx_url_t *u, ngx_uint_t flags);
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -46,7 +46,7 @@ ngx_module_t  ngx_http_write_filter_modu
 ngx_int_t
 ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
-    off_t                      size, sent, limit;
+    off_t                      size, sent, nsent, limit;
     ngx_uint_t                 last, flush;
     ngx_msec_t                 delay;
     ngx_chain_t               *cl, *ln, **ll, *chain;
@@ -210,7 +210,8 @@ ngx_http_write_filter(ngx_http_request_t
     }
 
     if (r->limit_rate) {
-        limit = r->limit_rate * (ngx_time() - r->start_sec + 1) - c->sent;
+        limit = r->limit_rate * (ngx_time() - r->start_sec + 1)
+                - (c->sent - clcf->limit_rate_after);
 
         if (limit <= 0) {
             c->write->delayed = 1;
@@ -245,7 +246,23 @@ ngx_http_write_filter(ngx_http_request_t
     }
 
     if (r->limit_rate) {
-        delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1);
+
+        nsent = c->sent;
+
+        if (clcf->limit_rate_after) {
+
+            sent -= clcf->limit_rate_after;
+            if (sent < 0) {
+                sent = 0;
+            }
+
+            nsent -= clcf->limit_rate_after;
+            if (nsent < 0) {
+                nsent = 0;
+            }
+        }
+
+        delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1);
 
         if (delay > 0) {
             c->write->delayed = 1;
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1302,7 +1302,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_
 
     ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t));
     if (ahcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     ahcf->timeout = NGX_CONF_UNSET_MSEC;
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -120,20 +120,20 @@ ngx_mail_core_create_main_conf(ngx_conf_
 
     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
     if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
                        sizeof(ngx_mail_core_srv_conf_t *))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return cmcf;
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -1061,7 +1061,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *c
 
     pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t));
     if (pcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     pcf->enable = NGX_CONF_UNSET;
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -22,15 +22,6 @@ static char *ngx_mail_ssl_starttls(ngx_c
 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-
-static char  ngx_mail_ssl_openssl097[] = "OpenSSL 0.9.7 and higher";
-
-#endif
-
 
 static ngx_conf_enum_t  ngx_http_starttls_state[] = {
     { ngx_string("off"), NGX_MAIL_STARTTLS_OFF },
@@ -102,14 +93,10 @@ static ngx_command_t  ngx_mail_ssl_comma
 
     { ngx_string("ssl_prefer_server_ciphers"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
       ngx_conf_set_flag_slot,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers),
       NULL },
-#else
-      ngx_mail_ssl_nosupported, 0, 0, ngx_mail_ssl_openssl097 },
-#endif
 
     { ngx_string("ssl_session_cache"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
@@ -166,7 +153,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
 
     scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t));
     if (scf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -297,14 +284,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
         }
     }
 
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
-
     if (conf->prefer_server_ciphers) {
         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
     }
 
-#endif
-
     if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
@@ -492,18 +475,3 @@ invalid:
 
     return NGX_CONF_ERROR;
 }
-
-
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *
-ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"%V\" directive is available only in %s,",
-                       &cmd->name, cmd->post);
-
-    return NGX_CONF_ERROR;
-}
-
-#endif
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -16,6 +16,7 @@ typedef int               ngx_err_t;
 
 #define NGX_EPERM         EPERM
 #define NGX_ENOENT        ENOENT
+#define NGX_ENOPATH       ENOENT
 #define NGX_ESRCH         ESRCH
 #define NGX_EINTR         EINTR
 #define NGX_ECHILD        ECHILD
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -18,13 +18,13 @@ typedef ino_t                    ngx_fil
 
 
 typedef struct {
-    DIR                        *dir;
-    struct dirent              *de;
-    struct stat                 info;
+    DIR                         *dir;
+    struct dirent               *de;
+    struct stat                  info;
 
-    unsigned                    type:8;
-    unsigned                    valid_info:1;
-    unsigned                    valid_type:1;
+    unsigned                     type:8;
+    unsigned                     valid_info:1;
+    unsigned                     valid_type:1;
 } ngx_dir_t;
 
 
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -214,21 +214,33 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
 
     switch (respawn) {
 
+    case NGX_PROCESS_NORESPAWN:
+        ngx_processes[s].respawn = 0;
+        ngx_processes[s].just_spawn = 0;
+        ngx_processes[s].detached = 0;
+        break;
+
+    case NGX_PROCESS_JUST_SPAWN:
+        ngx_processes[s].respawn = 0;
+        ngx_processes[s].just_spawn = 1;
+        ngx_processes[s].detached = 0;
+        break;
+
     case NGX_PROCESS_RESPAWN:
         ngx_processes[s].respawn = 1;
-        ngx_processes[s].just_respawn = 0;
+        ngx_processes[s].just_spawn = 0;
         ngx_processes[s].detached = 0;
         break;
 
     case NGX_PROCESS_JUST_RESPAWN:
         ngx_processes[s].respawn = 1;
-        ngx_processes[s].just_respawn = 1;
+        ngx_processes[s].just_spawn = 1;
         ngx_processes[s].detached = 0;
         break;
 
     case NGX_PROCESS_DETACHED:
         ngx_processes[s].respawn = 0;
-        ngx_processes[s].just_respawn = 0;
+        ngx_processes[s].just_spawn = 0;
         ngx_processes[s].detached = 1;
         break;
     }
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -27,7 +27,7 @@ typedef struct {
     char               *name;
 
     unsigned            respawn:1;
-    unsigned            just_respawn:1;
+    unsigned            just_spawn:1;
     unsigned            detached:1;
     unsigned            exiting:1;
     unsigned            exited:1;
@@ -45,9 +45,10 @@ typedef struct {
 #define NGX_MAX_PROCESSES         1024
 
 #define NGX_PROCESS_NORESPAWN     -1
-#define NGX_PROCESS_RESPAWN       -2
-#define NGX_PROCESS_JUST_RESPAWN  -3
-#define NGX_PROCESS_DETACHED      -4
+#define NGX_PROCESS_JUST_SPAWN    -2
+#define NGX_PROCESS_RESPAWN       -3
+#define NGX_PROCESS_JUST_RESPAWN  -4
+#define NGX_PROCESS_DETACHED      -5
 
 
 #define ngx_getpid   getpid
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -12,7 +12,9 @@
 
 static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n,
     ngx_int_t type);
-static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type);
+static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle,
+    ngx_uint_t respawn);
+static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch);
 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
 static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle);
 static void ngx_master_process_exit(ngx_cycle_t *cycle);
@@ -26,6 +28,7 @@ static ngx_thread_value_t ngx_worker_thr
 #endif
 static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data);
 static void ngx_cache_manager_process_handler(ngx_event_t *ev);
+static void ngx_cache_loader_process_handler(ngx_event_t *ev);
 
 
 ngx_uint_t    ngx_process;
@@ -62,6 +65,15 @@ u_long         cpu_affinity;
 static u_char  master_process[] = "master process";
 
 
+static ngx_cache_manager_ctx_t  ngx_cache_manager_ctx = {
+    ngx_cache_manager_process_handler, "cache manager process", 0
+};
+
+static ngx_cache_manager_ctx_t  ngx_cache_loader_ctx = {
+    ngx_cache_loader_process_handler, "cache loader process", 60000
+};
+
+
 static ngx_cycle_t      ngx_exit_cycle;
 static ngx_log_t        ngx_exit_log;
 static ngx_open_file_t  ngx_exit_log_file;
@@ -123,7 +135,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
     ngx_start_worker_processes(cycle, ccf->worker_processes,
                                NGX_PROCESS_RESPAWN);
-    ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
+    ngx_start_cache_manager_processes(cycle, 0);
 
     ngx_new_binary = 0;
     delay = 0;
@@ -207,7 +219,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
             if (ngx_new_binary) {
                 ngx_start_worker_processes(cycle, ccf->worker_processes,
                                            NGX_PROCESS_RESPAWN);
-                ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
+                ngx_start_cache_manager_processes(cycle, 0);
                 ngx_noaccepting = 0;
 
                 continue;
@@ -226,7 +238,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
                                                    ngx_core_module);
             ngx_start_worker_processes(cycle, ccf->worker_processes,
                                        NGX_PROCESS_JUST_RESPAWN);
-            ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN);
+            ngx_start_cache_manager_processes(cycle, 1);
             live = 1;
             ngx_signal_worker_processes(cycle,
                                         ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
@@ -236,7 +248,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
             ngx_restart = 0;
             ngx_start_worker_processes(cycle, ccf->worker_processes,
                                        NGX_PROCESS_RESPAWN);
-            ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
+            ngx_start_cache_manager_processes(cycle, 0);
             live = 1;
         }
 
@@ -269,8 +281,6 @@ ngx_single_process_cycle(ngx_cycle_t *cy
 {
     ngx_uint_t  i;
 
-    ngx_init_temp_number();
-
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->init_process) {
             if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
@@ -321,7 +331,7 @@ ngx_single_process_cycle(ngx_cycle_t *cy
 static void
 ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
 {
-    ngx_int_t      i, s;
+    ngx_int_t      i;
     ngx_channel_t  ch;
 
     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
@@ -339,58 +349,70 @@ ngx_start_worker_processes(ngx_cycle_t *
         ch.slot = ngx_process_slot;
         ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
-        for (s = 0; s < ngx_last_process; s++) {
-
-            if (s == ngx_process_slot
-                || ngx_processes[s].pid == -1
-                || ngx_processes[s].channel[0] == -1)
-            {
-                continue;
-            }
-
-            ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
-                          "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
-                          ch.slot, ch.pid, ch.fd,
-                          s, ngx_processes[s].pid,
-                          ngx_processes[s].channel[0]);
-
-            /* TODO: NGX_AGAIN */
-
-            ngx_write_channel(ngx_processes[s].channel[0],
-                              &ch, sizeof(ngx_channel_t), cycle->log);
-        }
+        ngx_pass_open_channel(cycle, &ch);
     }
 }
 
 
 static void
-ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type)
+ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn)
 {
-    ngx_int_t        i;
-    ngx_uint_t       n;
+    ngx_uint_t       i, manager, loader;
     ngx_path_t     **path;
     ngx_channel_t    ch;
 
+    manager = 0;
+    loader = 0;
+
     path = ngx_cycle->pathes.elts;
-    for (n = 0; n < ngx_cycle->pathes.nelts; n++) {
-        if (path[n]->manager) {
-            goto start;
+    for (i = 0; i < ngx_cycle->pathes.nelts; i++) {
+
+        if (path[i]->manager) {
+            manager = 1;
+        }
+
+        if (path[i]->loader) {
+            loader = 1;
         }
     }
 
-    return;
+    if (manager == 0) {
+        return;
+    }
 
-start:
+    ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
+                      &ngx_cache_manager_ctx, "cache manager process",
+                      respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);
 
     ch.command = NGX_CMD_OPEN_CHANNEL;
-
-    ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, NULL,
-                      "cache manager process", type);
-
     ch.pid = ngx_processes[ngx_process_slot].pid;
     ch.slot = ngx_process_slot;
     ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
+    ngx_pass_open_channel(cycle, &ch);
+
+    if (loader == 0) {
+        return;
+    }
+
+    ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
+                      &ngx_cache_loader_ctx, "cache loader process",
+                      respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);
+
+    ch.command = NGX_CMD_OPEN_CHANNEL;
+    ch.pid = ngx_processes[ngx_process_slot].pid;
+    ch.slot = ngx_process_slot;
+    ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+    ngx_pass_open_channel(cycle, &ch);
+}
+
+
+static void
+ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch)
+{
+    ngx_int_t  i;
+
     for (i = 0; i < ngx_last_process; i++) {
 
         if (i == ngx_process_slot
@@ -402,14 +424,14 @@ start:
 
         ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                       "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
-                      ch.slot, ch.pid, ch.fd,
+                      ch->slot, ch->pid, ch->fd,
                       i, ngx_processes[i].pid,
                       ngx_processes[i].channel[0]);
 
         /* TODO: NGX_AGAIN */
 
         ngx_write_channel(ngx_processes[i].channel[0],
-                          &ch, sizeof(ngx_channel_t), cycle->log);
+                          ch, sizeof(ngx_channel_t), cycle->log);
     }
 }
 
@@ -460,14 +482,14 @@ ngx_signal_worker_processes(ngx_cycle_t 
                        ngx_processes[i].exited,
                        ngx_processes[i].detached,
                        ngx_processes[i].respawn,
-                       ngx_processes[i].just_respawn);
+                       ngx_processes[i].just_spawn);
 
         if (ngx_processes[i].detached || ngx_processes[i].pid == -1) {
             continue;
         }
 
-        if (ngx_processes[i].just_respawn) {
-            ngx_processes[i].just_respawn = 0;
+        if (ngx_processes[i].just_spawn) {
+            ngx_processes[i].just_spawn = 0;
             continue;
         }
 
@@ -536,7 +558,7 @@ ngx_reap_children(ngx_cycle_t *cycle)
                        ngx_processes[i].exited,
                        ngx_processes[i].detached,
                        ngx_processes[i].respawn,
-                       ngx_processes[i].just_respawn);
+                       ngx_processes[i].just_spawn);
 
         if (ngx_processes[i].pid == -1) {
             continue;
@@ -593,26 +615,7 @@ ngx_reap_children(ngx_cycle_t *cycle)
                 ch.slot = ngx_process_slot;
                 ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
-                for (n = 0; n < ngx_last_process; n++) {
-
-                    if (n == ngx_process_slot
-                        || ngx_processes[n].pid == -1
-                        || ngx_processes[n].channel[0] == -1)
-                    {
-                        continue;
-                    }
-
-                    ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
-                          "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
-                          ch.slot, ch.pid, ch.fd,
-                          n, ngx_processes[n].pid,
-                          ngx_processes[n].channel[0]);
-
-                    /* TODO: NGX_AGAIN */
-
-                    ngx_write_channel(ngx_processes[n].channel[0],
-                                      &ch, sizeof(ngx_channel_t), cycle->log);
-                }
+                ngx_pass_open_channel(cycle, &ch);
 
                 live = 1;
 
@@ -928,8 +931,6 @@ ngx_worker_process_init(ngx_cycle_t *cyc
                       "sigprocmask() failed");
     }
 
-    ngx_init_temp_number();
-
     /*
      * disable deleting previous events for the listening sockets because
      * in the worker processes there are no events at all at this point
@@ -1268,6 +1269,8 @@ ngx_worker_thread_cycle(void *data)
 static void
 ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
 {
+    ngx_cache_manager_ctx_t *ctx = data;
+
     void         *ident[4];
     ngx_event_t   ev;
 
@@ -1278,16 +1281,16 @@ ngx_cache_manager_process_cycle(ngx_cycl
     ngx_close_listening_sockets(cycle);
 
     ngx_memzero(&ev, sizeof(ngx_event_t));
-    ev.handler = ngx_cache_manager_process_handler;
+    ev.handler = ctx->handler;
     ev.data = ident;
     ev.log = cycle->log;
     ident[3] = (void *) -1;
 
     ngx_use_accept_mutex = 0;
 
-    ngx_setproctitle("cache manager process");
+    ngx_setproctitle(ctx->name);
 
-    ngx_add_timer(&ev, 0);
+    ngx_add_timer(&ev, ctx->delay);
 
     for ( ;; ) {
 
@@ -1334,3 +1337,29 @@ ngx_cache_manager_process_handler(ngx_ev
 
     ngx_add_timer(ev, next * 1000);
 }
+
+
+static void
+ngx_cache_loader_process_handler(ngx_event_t *ev)
+{
+    ngx_uint_t     i;
+    ngx_path_t   **path;
+    ngx_cycle_t   *cycle;
+
+    cycle = (ngx_cycle_t *) ngx_cycle;
+
+    path = cycle->pathes.elts;
+    for (i = 0; i < cycle->pathes.nelts; i++) {
+
+        if (ngx_terminate || ngx_quit) {
+            break;
+        }
+
+        if (path[i]->loader) {
+            path[i]->loader(path[i]->data);
+            ngx_time_update(0, 0);
+        }
+    }
+
+    exit(0);
+}
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -25,6 +25,13 @@
 #define NGX_PROCESS_SIGNALLER  3
 
 
+typedef struct {
+    ngx_event_handler_pt       handler;
+    char                      *name;
+    ngx_msec_t                 delay;
+} ngx_cache_manager_ctx_t;
+
+
 void ngx_master_process_cycle(ngx_cycle_t *cycle);
 void ngx_single_process_cycle(ngx_cycle_t *cycle);