changeset 358:9121a0a91f47 NGINX_0_6_23

nginx 0.6.23 *) Change: the "off" parameter in the "ssl_session_cache" directive; now this is default parameter. *) Change: the "open_file_cache_retest" directive was renamed to the "open_file_cache_valid". *) Feature: the "open_file_cache_min_uses" directive. *) Feature: the ngx_http_gzip_static_module. *) Feature: the "gzip_disable" directive. *) Feature: the "memcached_pass" directive may be used inside the "if" block. *) Bugfix: a segmentation fault occurred in worker process, if the "memcached_pass" and "if" directives were used in the same location. *) Bugfix: if a "satisfy_any on" directive was used and not all access and auth modules directives were set, then other given access and auth directives were not tested; *) Bugfix: regex parameters in a "valid_referers" directive were not inherited from previous level. *) Bugfix: a "post_action" directive did run if a request was completed with 499 status code. *) Bugfix: optimization of 16K buffer usage in a SSL connection. Thanks to Ben Maurer. *) Bugfix: the STARTTLS in SMTP mode did not work. Thanks to Oleg Motienko. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error; bug appeared in 0.5.13.
author Igor Sysoev <http://sysoev.ru>
date Thu, 27 Dec 2007 00:00:00 +0300
parents 16d557a75356
children 580da4bad456
files CHANGES CHANGES.ru auto/modules auto/options auto/sources src/core/nginx.h src/core/ngx_open_file_cache.c src/core/ngx_open_file_cache.h src/core/ngx_queue.h src/core/ngx_rbtree.c src/core/ngx_regex.c src/core/ngx_regex.h src/core/ngx_resolver.c src/core/ngx_slab.c src/core/ngx_string.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_auth_basic_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_flv_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_index_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_referer_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/nginx.xs src/http/ngx_http_copy_filter_module.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_script.c src/http/ngx_http_upstream.c src/mail/ngx_mail_smtp_handler.c src/mail/ngx_mail_ssl_module.c src/os/unix/ngx_freebsd.h src/os/unix/ngx_freebsd_init.c
diffstat 43 files changed, 1425 insertions(+), 702 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,44 @@
 
+Changes with nginx 0.6.23                                        27 Dec 2007
+
+    *) Change: the "off" parameter in the "ssl_session_cache" directive; 
+       now this is default parameter.
+
+    *) Change: the "open_file_cache_retest" directive was renamed to the 
+       "open_file_cache_valid".
+
+    *) Feature: the "open_file_cache_min_uses" directive.
+
+    *) Feature: the ngx_http_gzip_static_module.
+
+    *) Feature: the "gzip_disable" directive.
+
+    *) Feature: the "memcached_pass" directive may be used inside the "if" 
+       block.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if the 
+       "memcached_pass" and "if" directives were used in the same location.
+
+    *) Bugfix: if a "satisfy_any on" directive was used and not all access 
+       and auth modules directives were set, then other given access and 
+       auth directives were not tested;
+
+    *) Bugfix: regex parameters in a "valid_referers" directive were not 
+       inherited from previous level.
+
+    *) Bugfix: a "post_action" directive did run if a request was completed 
+       with 499 status code.
+
+    *) Bugfix: optimization of 16K buffer usage in a SSL connection.
+       Thanks to Ben Maurer.
+
+    *) Bugfix: the STARTTLS in SMTP mode did not work.
+       Thanks to Oleg Motienko.
+
+    *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" 
+       error; bug appeared in 0.5.13.
+
+
 Changes with nginx 0.6.22                                        19 Dec 2007
 
     *) Change: now all ngx_http_perl_module methods return values copied to 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,46 @@
 
+Изменения в nginx 0.6.23                                          27.12.2007
+
+    *) Изменение: параметр "off" в директиве ssl_session_cache; теперь этот 
+       параметр используется по умолчанию.
+
+    *) Изменение: директива open_file_cache_retest переименована в 
+       open_file_cache_valid.
+
+    *) Добавление: директива open_file_cache_min_uses.
+
+    *) Добавление: модуль ngx_http_gzip_static_module.
+
+    *) Добавление: директива gzip_disable.
+
+    *) Добавление: директиву memcached_pass можно использовать внутри блока 
+       if.
+
+    *) Исправление: если внутри одного location'а использовались директивы 
+       "memcached_pass" и "if", то в рабочем процессе происходил 
+       segmentation fault.
+
+    *) Исправление: если при использовании директивы satisfy_any on" были 
+       заданы директивы не всех модулей доступа, то заданные директивы не 
+       проверялись.
+
+    *) Исправление: параметры, заданные регулярным выражением в директиве 
+       valid_referers, не наследовалась с предыдущего уровня.
+
+    *) Исправление: директива post_action не работала, если запрос 
+       завершался с кодом 499.
+
+    *) Исправление: оптимизация использования 16K буфера для 
+       SSL-соединения.
+       Спасибо Ben Maurer.
+
+    *) Исправление: STARTTLS в режиме SMTP не работал.
+       Спасибо Олегу Мотиенко.
+
+    *) Исправление: при использовании HTTPS запросы могли завершаться с 
+       ошибкой "bad write retry"; ошибка появилась в 0.5.13.
+
+
 Изменения в nginx 0.6.22                                          19.12.2007
 
     *) Изменение: теперь все методы модуля ngx_http_perl_module возвращают 
@@ -79,7 +121,7 @@
 
     *) Добавление: директива proxy_pass поддерживает переменные.
 
-    *) Добавление: директива resolver и resolver_timeout.
+    *) Добавление: директивы resolver и resolver_timeout.
 
     *) Добавление: теперь директива "add_header last-modified ''" удаляет в 
        заголовке ответа строку "Last-Modified".
--- a/auto/modules
+++ b/auto/modules
@@ -265,6 +265,12 @@ if [ $HTTP_FLV = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS"
 fi
 
+if [ $HTTP_GZIP_STATIC = YES ]; then
+    have=NGX_HTTP_GZIP . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_GZIP_STATIC_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_STATIC_SRCS"
+fi
+
 if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then
     HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_IP_HASH_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS"
--- a/auto/options
+++ b/auto/options
@@ -76,6 +76,7 @@ HTTP_LIMIT_ZONE=YES
 HTTP_EMPTY_GIF=YES
 HTTP_BROWSER=YES
 HTTP_FLV=NO
+HTTP_GZIP_STATIC=NO
 HTTP_UPSTREAM_IP_HASH=YES
 
 # STUB
@@ -162,6 +163,7 @@ do
         --with-http_sub_module)          HTTP_SUB=YES               ;;
         --with-http_dav_module)          HTTP_DAV=YES               ;;
         --with-http_flv_module)          HTTP_FLV=YES               ;;
+        --with-http_gzip_static_module)  HTTP_GZIP_STATIC=YES       ;;
 
         --without-http_charset_module)   HTTP_CHARSET=NO            ;;
         --without-http_gzip_module)      HTTP_GZIP=NO               ;;
@@ -273,6 +275,7 @@ cat << END
   --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
+  --with-http_gzip_static_module     enable ngx_http_gzip_static_module
   --with-http_stub_status_module     enable ngx_http_stub_status_module
 
   --without-http_charset_module      disable ngx_http_charset_module
--- a/auto/sources
+++ b/auto/sources
@@ -178,7 +178,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \
 
 POSIX_DEPS=src/os/unix/ngx_posix_config.h
 
-FREEBSD_DEPS=src/os/unix/ngx_freebsd_config.h
+FREEBSD_DEPS="src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd.h"
 FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c
 FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c
 FREEBSD_RFORK_DEPS="src/os/unix/ngx_freebsd_rfork_thread.h"
@@ -187,12 +187,12 @@ FREEBSD_RFORK_THREAD_SRCS="src/os/unix/r
 
 PTHREAD_SRCS="src/os/unix/ngx_pthread_thread.c"
 
-LINUX_DEPS=src/os/unix/ngx_linux_config.h
+LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h"
 LINUX_SRCS=src/os/unix/ngx_linux_init.c
 LINUX_SENDFILE_SRCS=src/os/unix/ngx_linux_sendfile_chain.c
 
 
-SOLARIS_DEPS=src/os/unix/ngx_solaris_config.h
+SOLARIS_DEPS="src/os/unix/ngx_solaris_config.h src/os/unix/ngx_solaris.h"
 SOLARIS_SRCS=src/os/unix/ngx_solaris_init.c
 SOLARIS_SENDFILEV_SRCS=src/os/unix/ngx_solaris_sendfilev_chain.c
 
@@ -417,6 +417,10 @@ HTTP_FLV_MODULE=ngx_http_flv_module
 HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c
 
 
+HTTP_GZIP_STATIC_MODULE=ngx_http_gzip_static_module
+HTTP_GZIP_STATIC_SRCS=src/http/modules/ngx_http_gzip_static_module.c
+
+
 HTTP_UPSTREAM_IP_HASH_MODULE=ngx_http_upstream_ip_hash_module
 HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.22"
+#define NGINX_VERSION      "0.6.23"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -18,22 +18,27 @@
 
 
 static void ngx_open_file_cache_cleanup(void *data);
+static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
+    ngx_log_t *log);
+static void ngx_open_file_add_event(ngx_open_file_cache_t *cache,
+    ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log);
 static void ngx_open_file_cleanup(void *data);
 static void ngx_close_cached_file(ngx_open_file_cache_t *cache,
-    ngx_cached_open_file_t *file, ngx_log_t *log);
-static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
-    ngx_log_t *log);
+    ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log);
+static void ngx_open_file_del_event(ngx_cached_open_file_t *file);
 static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache,
     ngx_uint_t n, ngx_log_t *log);
 static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static ngx_cached_open_file_t *
+    ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,
+    uint32_t hash);
 static void ngx_open_file_cache_remove(ngx_event_t *ev);
 
 
 ngx_open_file_cache_t *
 ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive)
 {
-    ngx_rbtree_node_t      *sentinel;
     ngx_pool_cleanup_t     *cln;
     ngx_open_file_cache_t  *cache;
 
@@ -42,19 +47,10 @@ ngx_open_file_cache_init(ngx_pool_t *poo
         return NULL;
     }
 
-    cache->list_head.prev = NULL;
-    cache->list_head.next = &cache->list_tail;
-
-    cache->list_tail.prev = &cache->list_head;
-    cache->list_tail.next = NULL;
+    ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
+                    ngx_open_file_cache_rbtree_insert_value);
 
-    sentinel = ngx_palloc(pool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NULL;
-    }
-
-    ngx_rbtree_init(&cache->rbtree, sentinel,
-                    ngx_open_file_cache_rbtree_insert_value);
+    ngx_queue_init(&cache->expire_queue);
 
     cache->current = 0;
     cache->max = max;
@@ -77,6 +73,7 @@ ngx_open_file_cache_cleanup(void *data)
 {
     ngx_open_file_cache_t  *cache = data;
 
+    ngx_queue_t             *q;
     ngx_cached_open_file_t  *file;
 
     ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
@@ -84,14 +81,15 @@ ngx_open_file_cache_cleanup(void *data)
 
     for ( ;; ) {
 
-        file = cache->list_tail.prev;
-
-        if (file == &cache->list_head) {
+        if (ngx_queue_empty(&cache->expire_queue)) {
             break;
         }
 
-        file->next->prev = file->prev;
-        file->prev->next = file->next;
+        q = ngx_queue_last(&cache->expire_queue);
+
+        file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
+
+        ngx_queue_remove(q);
 
         ngx_rbtree_delete(&cache->rbtree, &file->node);
 
@@ -103,7 +101,7 @@ ngx_open_file_cache_cleanup(void *data)
         if (!file->err && !file->is_dir) {
             file->close = 1;
             file->count = 0;
-            ngx_close_cached_file(cache, file, ngx_cycle->log);
+            ngx_close_cached_file(cache, file, 0, ngx_cycle->log);
 
         } else {
             ngx_free(file->name);
@@ -132,11 +130,9 @@ ngx_open_cached_file(ngx_open_file_cache
     time_t                          now;
     uint32_t                        hash;
     ngx_int_t                       rc;
-    ngx_rbtree_node_t              *node, *sentinel;
     ngx_pool_cleanup_t             *cln;
     ngx_cached_open_file_t         *file;
     ngx_pool_cleanup_file_t        *clnf;
-    ngx_open_file_cache_event_t    *fev;
     ngx_open_file_cache_cleanup_t  *ofcln;
 
     of->err = 0;
@@ -167,145 +163,147 @@ ngx_open_cached_file(ngx_open_file_cache
         return NGX_ERROR;
     }
 
-    hash = ngx_crc32_long(name->data, name->len);
-
-    node = cache->rbtree.root;
-    sentinel = cache->rbtree.sentinel;
-
     now = ngx_time();
 
-    while (node != sentinel) {
+    hash = ngx_crc32_long(name->data, name->len);
+
+    file = ngx_open_file_lookup(cache, name, hash);
+
+    if (file) {
+
+        file->uses++;
+
+        ngx_queue_remove(&file->queue);
 
-        if (hash < node->key) {
-            node = node->left;
-            continue;
-        }
+        if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) {
+
+            /* file was not used often enough to keep open */
+
+            rc = ngx_open_and_stat_file(name->data, of, pool->log);
 
-        if (hash > node->key) {
-            node = node->right;
-            continue;
+            if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
+                goto failed;
+            }
+
+            goto add_event;
         }
 
-        /* hash == node->key */
-
-        do {
-            file = (ngx_cached_open_file_t *) node;
-
-            rc = ngx_strcmp(name->data, file->name);
-
-            if (rc == 0) {
-
-                file->next->prev = file->prev;
-                file->prev->next = file->next;
-
-                if (file->event || now - file->created < of->retest) {
-                    if (file->err == 0) {
-                        of->fd = file->fd;
-                        of->uniq = file->uniq;
-                        of->mtime = file->mtime;
-                        of->size = file->size;
-
-                        of->is_dir = file->is_dir;
-                        of->is_file = file->is_file;
-                        of->is_link = file->is_link;
-                        of->is_exec = file->is_exec;
+        if ((file->event && file->use_event)
+            || (file->event == NULL && now - file->created < of->valid))
+        {
+            if (file->err == 0) {
 
-                        if (!file->is_dir) {
-                            file->count++;
-                        }
-
-                    } else {
-                        of->err = file->err;
-                    }
-
-                    goto found;
-                }
+                of->fd = file->fd;
+                of->uniq = file->uniq;
+                of->mtime = file->mtime;
+                of->size = file->size;
 
-                ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
-                               "retest open file: %s, fd:%d, c:%d, e:%d",
-                               file->name, file->fd, file->count, file->err);
-
-                if (file->is_dir) {
+                of->is_dir = file->is_dir;
+                of->is_file = file->is_file;
+                of->is_link = file->is_link;
+                of->is_exec = file->is_exec;
 
-                    /*
-                     * chances that directory became file are very small
-                     * so test_dir flag allows to use a single ngx_file_info()
-                     * syscall instead of three syscalls
-                     */
-
-                    of->test_dir = 1;
+                if (!file->is_dir) {
+                    file->count++;
+                    ngx_open_file_add_event(cache, file, of, pool->log);
                 }
 
-                rc = ngx_open_and_stat_file(name->data, of, pool->log);
+            } else {
+                of->err = file->err;
+            }
+
+            goto found;
+        }
+
+        ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
+                       "retest open file: %s, fd:%d, c:%d, e:%d",
+                       file->name, file->fd, file->count, file->err);
+
+        if (file->is_dir) {
+
+            /*
+             * chances that directory became file are very small
+             * so test_dir flag allows to use a single syscall
+             * in ngx_file_info() instead of three syscalls
+             */
+
+            of->test_dir = 1;
+        }
+
+        rc = ngx_open_and_stat_file(name->data, of, pool->log);
 
-                if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
-                    goto failed;
+        if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
+            goto failed;
+        }
+
+        if (of->is_dir) {
+
+            if (file->is_dir || file->err) {
+                goto update;
+            }
+
+            /* file became directory */
+
+        } else if (of->err == 0) {  /* file */
+
+            if (file->is_dir || file->err) {
+                goto add_event;
+            }
+
+            if (of->uniq == file->uniq
+                && of->mtime == file->mtime
+                && of->size == file->size)
+            {
+                if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
+                    ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
+                                  ngx_close_file_n " \"%s\" failed",
+                                  name->data);
                 }
 
-                if (of->is_dir) {
-                    if (file->is_dir || file->err) {
-                        goto update;
-                    }
-
-                    /* file became directory */
-
-                } else if (of->err == 0) {  /* file */
-
-                    if (file->is_dir || file->err) {
-                        goto update;
-                    }
+                of->fd = file->fd;
+                file->count++;
 
-                    if (of->uniq == file->uniq
-                        && of->mtime == file->mtime
-                        && of->size == file->size)
-                    {
-                        if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
-                            ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
-                                          ngx_close_file_n " \"%s\" failed",
-                                          name->data);
-                        }
-
-                        of->fd = file->fd;
-                        file->count++;
-
-                        goto renew;
-                    }
-
-                    /* file was changed */
-
-                } else { /* error to cache */
-
-                    if (file->err || file->is_dir) {
-                        goto update;
-                    }
-
-                    /* file was removed, etc. */
+                if (file->event) {
+                    file->use_event = 1;
+                    goto renew;
                 }
 
-                if (file->count == 0) {
-                    if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
-                        ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
-                                      ngx_close_file_n " \"%s\" failed",
-                                      name->data);
-                    }
+                ngx_open_file_add_event(cache, file, of, pool->log);
+
+                goto renew;
+            }
 
-                    goto update;
-                }
-
-                ngx_rbtree_delete(&cache->rbtree, &file->node);
+            /* file was changed */
 
-                cache->current--;
+        } else { /* error to cache */
 
-                file->close = 1;
-
-                goto create;
+            if (file->err || file->is_dir) {
+                goto update;
             }
 
-            node = (rc < 0) ? node->left : node->right;
+            /* file was removed, etc. */
+        }
+
+        if (file->count == 0) {
+
+            ngx_open_file_del_event(file);
 
-        } while (node != sentinel && hash == node->key);
+            if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
+                              ngx_close_file_n " \"%s\" failed",
+                              name->data);
+            }
 
-        break;
+            goto add_event;
+        }
+
+        ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+        cache->current--;
+
+        file->close = 1;
+
+        goto create;
     }
 
     /* not found */
@@ -346,51 +344,17 @@ create:
 
     cache->current++;
 
+    file->uses = 1;
     file->count = 0;
+    file->use_event = 0;
+    file->event = NULL;
+
+add_event:
+
+    ngx_open_file_add_event(cache, file, of, pool->log);
 
 update:
 
-    if (of->events
-        && (ngx_event_flags & NGX_USE_VNODE_EVENT)
-        && of->fd != NGX_INVALID_FILE)
-    {
-        file->event = ngx_calloc(sizeof(ngx_event_t), pool->log);
-        if (file->event== NULL) {
-            goto failed;
-        }
-
-        fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), pool->log);
-        if (fev == NULL) {
-            goto failed;
-        }
-
-        fev->fd = of->fd;
-        fev->file = file;
-        fev->cache = cache;
-
-        file->event->handler = ngx_open_file_cache_remove;
-        file->event->data = fev;
-
-        /*
-         * although vnode event may be called while ngx_cycle->poll
-         * destruction; however, cleanup procedures are run before any
-         * memory freeing and events will be canceled.
-         */
-
-        file->event->log = ngx_cycle->log;
-
-        if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT)
-            != NGX_OK)
-        {
-            ngx_free(file->event->data);
-            ngx_free(file->event);
-            goto failed;
-        }
-
-    } else {
-        file->event = NULL;
-    }
-
     file->fd = of->fd;
     file->err = of->err;
 
@@ -419,16 +383,11 @@ found:
 
     file->accessed = now;
 
-    /* add to the inactive list head */
+    ngx_queue_insert_head(&cache->expire_queue, &file->queue);
 
-    file->next = cache->list_head.next;
-    file->next->prev = file;
-    file->prev = &cache->list_head;
-    cache->list_head.next = file;
-
-    ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
-                   "cached open file: %s, fd:%d, c:%d, e:%d",
-                   file->name, file->fd, file->count, file->err);
+    ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0,
+                   "cached open file: %s, fd:%d, c:%d, e:%d, u:%d",
+                   file->name, file->fd, file->count, file->err, file->uses);
 
     if (of->err == 0) {
 
@@ -438,6 +397,7 @@ found:
 
             ofcln->cache = cache;
             ofcln->file = file;
+            ofcln->min_uses = of->min_uses;
             ofcln->log = pool->log;
         }
 
@@ -543,6 +503,72 @@ ngx_open_and_stat_file(u_char *name, ngx
 }
 
 
+/*
+ * we ignore any possible event setting error and
+ * fallback to usual periodic file retests
+ */
+
+static void
+ngx_open_file_add_event(ngx_open_file_cache_t *cache,
+    ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log)
+{
+    ngx_open_file_cache_event_t  *fev;
+
+    if (!(ngx_event_flags & NGX_USE_VNODE_EVENT)
+        || !of->events
+        || file->event
+        || of->fd == NGX_INVALID_FILE
+        || file->uses < of->min_uses)
+    {
+        return;
+    }
+
+    file->event = ngx_calloc(sizeof(ngx_event_t), log);
+    if (file->event== NULL) {
+        return;
+    }
+
+    fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log);
+    if (fev == NULL) {
+        ngx_free(file->event);
+        file->event = NULL;
+        return;
+    }
+
+    fev->fd = of->fd;
+    fev->file = file;
+    fev->cache = cache;
+
+    file->event->handler = ngx_open_file_cache_remove;
+    file->event->data = fev;
+
+    /*
+     * although vnode event may be called while ngx_cycle->poll
+     * destruction, however, cleanup procedures are run before any
+     * memory freeing and events will be canceled.
+     */
+
+    file->event->log = ngx_cycle->log;
+
+    if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT)
+        != NGX_OK)
+    {
+        ngx_free(file->event->data);
+        ngx_free(file->event);
+        file->event = NULL;
+        return;
+    }
+
+    /*
+     * we do not file->use_event here because there may be a race
+     * condition between opening file and adding event, so we rely
+     * upon event notification only after first file revalidation
+     */
+
+    return;
+}
+
+
 static void
 ngx_open_file_cleanup(void *data)
 {
@@ -550,7 +576,7 @@ ngx_open_file_cleanup(void *data)
 
     c->file->count--;
 
-    ngx_close_cached_file(c->cache, c->file, c->log);
+    ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log);
 
     /* drop one or two expired open files */
     ngx_expire_old_cached_files(c->cache, 1, c->log);
@@ -559,50 +585,43 @@ ngx_open_file_cleanup(void *data)
 
 static void
 ngx_close_cached_file(ngx_open_file_cache_t *cache,
-    ngx_cached_open_file_t *file, ngx_log_t *log)
+    ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log)
 {
-    ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0,
-                   "close cached open file: %s, fd:%d, c:%d, %d",
-                   file->name, file->fd, file->count, file->close);
+    ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0,
+                   "close cached open file: %s, fd:%d, c:%d, u:%d, %d",
+                   file->name, file->fd, file->count, file->uses, file->close);
 
     if (!file->close) {
 
         file->accessed = ngx_time();
 
-        if (cache->list_head.next != file) {
+        ngx_queue_remove(&file->queue);
 
-            /* delete from inactive list */
-
-            file->next->prev = file->prev;
-            file->prev->next = file->next;
+        ngx_queue_insert_head(&cache->expire_queue, &file->queue);
 
-            /* add to the inactive list head */
-
-            file->next = cache->list_head.next;
-            file->next->prev = file;
-            file->prev = &cache->list_head;
-            cache->list_head.next = file;
+        if (file->uses >= min_uses || file->count) {
+            return;
         }
-
-        return;
     }
 
-    if (file->event) {
-        (void) ngx_del_event(file->event, NGX_VNODE_EVENT,
-                             file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT);
-
-        ngx_free(file->event->data);
-        ngx_free(file->event);
-        file->event = NULL;
-    }
+    ngx_open_file_del_event(file);
 
     if (file->count) {
         return;
     }
 
-    if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      ngx_close_file_n " \"%s\" failed", file->name);
+    if (file->fd != NGX_INVALID_FILE) {
+
+        if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", file->name);
+        }
+
+        file->fd = NGX_INVALID_FILE;
+    }
+
+    if (!file->close) {
+        return;
     }
 
     ngx_free(file->name);
@@ -611,10 +630,28 @@ ngx_close_cached_file(ngx_open_file_cach
 
 
 static void
+ngx_open_file_del_event(ngx_cached_open_file_t *file)
+{
+    if (file->event == NULL) {
+        return;
+    }
+
+    (void) ngx_del_event(file->event, NGX_VNODE_EVENT,
+                         file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT);
+
+    ngx_free(file->event->data);
+    ngx_free(file->event);
+    file->event = NULL;
+    file->use_event = 0;
+}
+
+
+static void
 ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n,
     ngx_log_t *log)
 {
     time_t                   now;
+    ngx_queue_t             *q;
     ngx_cached_open_file_t  *file;
 
     now = ngx_time();
@@ -627,18 +664,19 @@ ngx_expire_old_cached_files(ngx_open_fil
 
     while (n < 3) {
 
-        file = cache->list_tail.prev;
-
-        if (file == &cache->list_head) {
+        if (ngx_queue_empty(&cache->expire_queue)) {
             return;
         }
 
+        q = ngx_queue_last(&cache->expire_queue);
+
+        file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
+
         if (n++ != 0 && now - file->accessed <= cache->inactive) {
             return;
         }
 
-        file->next->prev = file->prev;
-        file->prev->next = file->next;
+        ngx_queue_remove(q);
 
         ngx_rbtree_delete(&cache->rbtree, &file->node);
 
@@ -649,7 +687,7 @@ ngx_expire_old_cached_files(ngx_open_fil
 
         if (!file->err && !file->is_dir) {
             file->close = 1;
-            ngx_close_cached_file(cache, file, log);
+            ngx_close_cached_file(cache, file, 0, log);
 
         } else {
             ngx_free(file->name);
@@ -700,6 +738,51 @@ ngx_open_file_cache_rbtree_insert_value(
 }
 
 
+static ngx_cached_open_file_t *
+ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,
+    uint32_t hash)
+{
+    ngx_int_t                rc;
+    ngx_rbtree_node_t       *node, *sentinel;
+    ngx_cached_open_file_t  *file;
+
+    node = cache->rbtree.root;
+    sentinel = cache->rbtree.sentinel;
+
+    while (node != sentinel) {
+
+        if (hash < node->key) {
+            node = node->left;
+            continue;
+        }
+
+        if (hash > node->key) {
+            node = node->right;
+            continue;
+        }
+
+        /* hash == node->key */
+
+        do {
+            file = (ngx_cached_open_file_t *) node;
+
+            rc = ngx_strcmp(name->data, file->name);
+
+            if (rc == 0) {
+                return file;
+            }
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
+    }
+
+    return NULL;
+}
+
+
 static void
 ngx_open_file_cache_remove(ngx_event_t *ev)
 {
@@ -709,8 +792,7 @@ ngx_open_file_cache_remove(ngx_event_t *
     fev = ev->data;
     file = fev->file;
 
-    file->next->prev = file->prev;
-    file->prev->next = file->next;
+    ngx_queue_remove(&file->queue);
 
     ngx_rbtree_delete(&fev->cache->rbtree, &file->node);
 
@@ -721,7 +803,7 @@ ngx_open_file_cache_remove(ngx_event_t *
 
     file->close = 1;
 
-    ngx_close_cached_file(fev->cache, file, ev->log);
+    ngx_close_cached_file(fev->cache, file, 0, ev->log);
 
     /* free memory only when fev->cache and fev->file are already not needed */
 
--- a/src/core/ngx_open_file_cache.h
+++ b/src/core/ngx_open_file_cache.h
@@ -19,7 +19,9 @@ typedef struct {
     off_t                    size;
     ngx_err_t                err;
 
-    time_t                   retest;
+    time_t                   valid;
+
+    ngx_uint_t               min_uses;
 
     unsigned                 test_dir:1;
     unsigned                 errors:1;
@@ -36,8 +38,7 @@ typedef struct ngx_cached_open_file_s  n
 
 struct ngx_cached_open_file_s {
     ngx_rbtree_node_t        node;
-    ngx_cached_open_file_t  *prev;
-    ngx_cached_open_file_t  *next;
+    ngx_queue_t              queue;
 
     u_char                  *name;
     time_t                   created;
@@ -49,8 +50,11 @@ struct ngx_cached_open_file_s {
     off_t                    size;
     ngx_err_t                err;
 
+    uint32_t                 uses;
+
     unsigned                 count:24;
     unsigned                 close:1;
+    unsigned                 use_event:1;
 
     unsigned                 is_dir:1;
     unsigned                 is_file:1;
@@ -63,8 +67,8 @@ struct ngx_cached_open_file_s {
 
 typedef struct {
     ngx_rbtree_t             rbtree;
-    ngx_cached_open_file_t   list_head;
-    ngx_cached_open_file_t   list_tail;
+    ngx_rbtree_node_t        sentinel;
+    ngx_queue_t              expire_queue;
 
     ngx_uint_t               current;
     ngx_uint_t               max;
@@ -75,6 +79,7 @@ typedef struct {
 typedef struct {
     ngx_open_file_cache_t   *cache;
     ngx_cached_open_file_t  *file;
+    ngx_uint_t               min_uses;
     ngx_log_t               *log;
 } ngx_open_file_cache_cleanup_t;
 
--- a/src/core/ngx_queue.h
+++ b/src/core/ngx_queue.h
@@ -22,7 +22,7 @@ struct ngx_queue_s {
 
 #define ngx_queue_init(q)                                                     \
     (q)->prev = q;                                                            \
-    (q)->next = q;
+    (q)->next = q
 
 
 #define ngx_queue_empty(h)                                                    \
--- a/src/core/ngx_rbtree.c
+++ b/src/core/ngx_rbtree.c
@@ -242,13 +242,13 @@ ngx_rbtree_delete(ngx_thread_volatile ng
         if (subst->right != sentinel) {
             subst->right->parent = subst;
         }
+    }
 
-        /* DEBUG stuff */
-        node->left = NULL;
-        node->right = NULL;
-        node->parent = NULL;
-        node->key = 0;
-    }
+    /* DEBUG stuff */
+    node->left = NULL;
+    node->right = NULL;
+    node->parent = NULL;
+    node->key = 0;
 
     if (red) {
         return;
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -114,6 +114,39 @@ ngx_regex_exec(ngx_regex_t *re, ngx_str_
 }
 
 
+ngx_int_t
+ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
+{
+    ngx_int_t         n;
+    ngx_uint_t        i;
+    ngx_regex_elt_t  *re;
+
+    re = a->elts;
+
+    for (i = 0; i < a->nelts; i++) {
+
+        n = ngx_regex_exec(re[i].regex, s, NULL, 0);
+
+        if (n == NGX_REGEX_NO_MATCHED) {
+            continue;
+        }
+
+        if (n < 0) {
+            ngx_log_error(NGX_LOG_ALERT, log, 0,
+                          ngx_regex_exec_n " failed: %d on \"%V\" using \"%s\"",
+                          n, s, re[i].name);
+            return NGX_ERROR;
+        }
+
+        /* match */
+
+        return NGX_OK;
+    }
+
+    return NGX_DECLINED;
+}
+
+
 static void * ngx_libc_cdecl
 ngx_regex_malloc(size_t size)
 {
--- a/src/core/ngx_regex.h
+++ b/src/core/ngx_regex.h
@@ -20,12 +20,20 @@
 
 typedef pcre  ngx_regex_t;
 
+typedef struct {
+    ngx_regex_t   *regex;
+    u_char        *name;
+} ngx_regex_elt_t;
+
+
 void ngx_regex_init(void);
 ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options,
     ngx_pool_t *pool, ngx_str_t *err);
 ngx_int_t ngx_regex_capture_count(ngx_regex_t *re);
 ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures,
     ngx_int_t size);
+ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
+
 
 #define ngx_regex_exec_n           "pcre_exec()"
 #define ngx_regex_capture_count_n  "pcre_fullinfo()"
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -669,17 +669,8 @@ ngx_resolver_expire(ngx_resolver_t *r, n
             return;
         }
 
-#if (NGX_DEBUG)
-        {
-        ngx_str_t  s;
-
-        s.len = rn->nlen;
-        s.data = rn->name;
-
-        ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
-                       "resolver expire \"%V\"", &s);
-        }
-#endif
+        ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+                       "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
 
         ngx_queue_remove(q);
 
@@ -783,17 +774,9 @@ ngx_resolver_resend(ngx_resolver_t *r, n
             return rn->expire - now;
         }
 
-#if (NGX_DEBUG)
-        {
-        ngx_str_t  s;
-
-        s.len = rn->nlen;
-        s.data = rn->name;
-
-        ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
-                   "resolver resend \"%V\" %p", &s, rn->waiting);
-        }
-#endif
+        ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+                       "resolver resend \"%*s\" %p",
+                       (size_t) rn->nlen, rn->name, rn->waiting);
 
         ngx_queue_remove(q);
 
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -58,9 +58,22 @@
 
 
 #if (NGX_DEBUG_MALLOC)
-#define ngx_slab_junk(p, size)  ngx_memset(p, 0xD0, size)
+
+#define ngx_slab_junk(p, size)     ngx_memset(p, 0xD0, size)
+
 #else
+
+#if (NGX_FREEBSD)
+
+#define ngx_slab_junk(p, size)                                                \
+    if (ngx_freebsd_debug_malloc)  ngx_memset(p, 0xD0, size)
+
+#else
+
 #define ngx_slab_junk(p, size)
+
+#endif
+
 #endif
 
 static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -63,6 +63,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t 
  *    %V                        ngx_str_t *
  *    %v                        ngx_variable_value_t *
  *    %s                        null-terminated string
+ *    %*s                       length and string
  *    %Z                        '\0'
  *    %N                        '\n'
  *    %c                        char
@@ -112,7 +113,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c
                                      * but icc issues the warning
                                      */
     int                    d;
-    size_t                 len;
+    size_t                 len, slen;
     uint32_t               ui32;
     int64_t                i64;
     uint64_t               ui64;
@@ -146,6 +147,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c
             sign = 1;
             hexadecimal = 0;
             max_width = 0;
+            slen = 0;
 
             p = temp + NGX_INT64_LEN;
 
@@ -179,6 +181,11 @@ ngx_vsnprintf(u_char *buf, size_t max, c
                     fmt++;
                     continue;
 
+                case '*':
+                    slen = va_arg(args, u_int);
+                    fmt++;
+                    continue;
+
                 default:
                     break;
                 }
@@ -214,9 +221,15 @@ ngx_vsnprintf(u_char *buf, size_t max, c
             case 's':
                 p = va_arg(args, u_char *);
 
-                while (*p && buf < last) {
-                    *buf++ = *p++;
+                if (slen == 0) {
+                    while (*p && buf < last) {
+                        *buf++ = *p++;
+                    }
+
+                } else {
+                    buf = ngx_cpymem(buf, p, slen);
                 }
+
                 fmt++;
 
                 continue;
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -22,6 +22,7 @@ static void ngx_ssl_read_handler(ngx_eve
 static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
     ngx_err_t err, char *text);
+static void ngx_ssl_clear_error(ngx_log_t *log);
 
 static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone,
     void *data);
@@ -186,8 +187,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
         SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]);
     }
 
-    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
     SSL_CTX_set_read_ahead(ssl->ctx, 1);
 
     return NGX_OK;
@@ -345,14 +344,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl
         return NGX_ERROR;
     }
 
-    if (flags & NGX_SSL_BUFFER) {
-        sc->buffer = 1;
-
-        sc->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
-        if (sc->buf == NULL) {
-            return NGX_ERROR;
-        }
-    }
+    sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
 
     sc->connection = SSL_new(ssl->ctx);
 
@@ -404,6 +396,8 @@ ngx_ssl_handshake(ngx_connection_t *c)
     int        n, sslerr;
     ngx_err_t  err;
 
+    ngx_ssl_clear_error(c->log);
+
     n = SSL_do_handshake(c->ssl->connection);
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
@@ -605,6 +599,8 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 
     bytes = 0;
 
+    ngx_ssl_clear_error(c->log);
+
     /*
      * SSL_read() may return data in parts, so try to read
      * until SSL_read() would return no data
@@ -801,8 +797,28 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
         limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
     }
 
-
     buf = c->ssl->buf;
+
+    if (buf == NULL) {
+        buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
+        if (buf == NULL) {
+            return NGX_CHAIN_ERROR;
+        }
+
+        c->ssl->buf = buf;
+    }
+
+    if (buf->start == NULL) {
+        buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE);
+        if (buf->start == NULL) {
+            return NGX_CHAIN_ERROR;
+        }
+
+        buf->pos = buf->start;
+        buf->last = buf->start;
+        buf->end = buf->start + NGX_SSL_BUFSIZE;
+    }
+
     send = 0;
     flush = (in == NULL) ? 1 : 0;
 
@@ -895,6 +911,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
     int        n, sslerr;
     ngx_err_t  err;
 
+    ngx_ssl_clear_error(c->log);
+
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size);
 
     n = SSL_write(c->ssl->connection, data, size);
@@ -975,12 +993,20 @@ ngx_ssl_read_handler(ngx_event_t *rev)
 }
 
 
+void
+ngx_ssl_free_buffer(ngx_connection_t *c)
+{
+    if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) {
+        c->ssl->buf->start = NULL;
+    }
+}
+
+
 ngx_int_t
 ngx_ssl_shutdown(ngx_connection_t *c)
 {
-    int         n, sslerr, mode;
-    ngx_err_t   err;
-    ngx_uint_t  again;
+    int        n, sslerr, mode;
+    ngx_err_t  err;
 
     if (c->timedout) {
         mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
@@ -999,40 +1025,34 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
     SSL_set_shutdown(c->ssl->connection, mode);
 
-    again = 0;
+    ngx_ssl_clear_error(c->log);
+
+    n = SSL_shutdown(c->ssl->connection);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
+
     sslerr = 0;
 
-    for ( ;; ) {
-        n = SSL_shutdown(c->ssl->connection);
-
-        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
-
-        if (n == 1 || (n == 0 && c->timedout)) {
-            SSL_free(c->ssl->connection);
-            c->ssl = NULL;
-
-            return NGX_OK;
-        }
-
-        if (n == 0) {
-            again = 1;
-            break;
-        }
-
-        break;
-    }
-
-    if (!again) {
+    /* SSL_shutdown() never return -1, on error it return 0 */
+
+    if (n != 1) {
         sslerr = SSL_get_error(c->ssl->connection, n);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "SSL_get_error: %d", sslerr);
     }
 
-    if (again
-        || sslerr == SSL_ERROR_WANT_READ
-        || sslerr == SSL_ERROR_WANT_WRITE)
+    if (n == 1
+        || sslerr == SSL_ERROR_ZERO_RETURN
+        || (sslerr == 0 && c->timedout))
     {
+        SSL_free(c->ssl->connection);
+        c->ssl = NULL;
+
+        return NGX_OK;
+    }
+
+    if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
         c->read->handler = ngx_ssl_shutdown_handler;
         c->write->handler = ngx_ssl_shutdown_handler;
 
@@ -1044,7 +1064,7 @@ ngx_ssl_shutdown(ngx_connection_t *c)
             return NGX_ERROR;
         }
 
-        if (again || sslerr == SSL_ERROR_WANT_READ) {
+        if (sslerr == SSL_ERROR_WANT_READ) {
             ngx_add_timer(c->read, 30000);
         }
 
@@ -1125,6 +1145,15 @@ ngx_ssl_connection_error(ngx_connection_
 }
 
 
+static void
+ngx_ssl_clear_error(ngx_log_t *log)
+{
+    if (ERR_peek_error()) {
+        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error");
+    }
+}
+
+
 void ngx_cdecl
 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
 {
@@ -1167,6 +1196,11 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
 {
     long  cache_mode;
 
+    if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
+        SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
+        return NGX_OK;
+    }
+
     cache_mode = SSL_SESS_CACHE_SERVER;
 
     if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
@@ -1210,7 +1244,6 @@ static ngx_int_t
 ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
 {
     ngx_slab_pool_t          *shpool;
-    ngx_rbtree_node_t        *sentinel;
     ngx_ssl_session_cache_t  *cache;
 
     if (data) {
@@ -1225,25 +1258,11 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
         return NGX_ERROR;
     }
 
-    cache->session_cache_head.prev = NULL;
-    cache->session_cache_head.next = &cache->session_cache_tail;
-
-    cache->session_cache_tail.prev = &cache->session_cache_head;
-    cache->session_cache_tail.next = NULL;
-
-    cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
-    if (cache->session_rbtree == NULL) {
-        return NGX_ERROR;
-    }
-
-    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_rbtree_init(cache->session_rbtree, sentinel,
+    ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,
                     ngx_ssl_session_rbtree_insert_value);
 
+    ngx_queue_init(&cache->expire_queue);
+
     shm_zone->data = cache;
 
     return NGX_OK;
@@ -1274,7 +1293,6 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     u_char                   *p, *id, *cached_sess;
     uint32_t                  hash;
     SSL_CTX                  *ssl_ctx;
-    ngx_time_t               *tp;
     ngx_shm_zone_t           *shm_zone;
     ngx_connection_t         *c;
     ngx_slab_pool_t          *shpool;
@@ -1350,22 +1368,17 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
                    "http ssl new session: %08XD:%d:%d",
                    hash, sess->session_id_length, len);
 
-    tp = ngx_timeofday();
-
     sess_id->node.key = hash;
     sess_id->node.data = (u_char) sess->session_id_length;
     sess_id->id = id;
     sess_id->len = len;
     sess_id->session = cached_sess;
 
-    sess_id->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
-
-    sess_id->next = cache->session_cache_head.next;
-    sess_id->next->prev = sess_id;
-    sess_id->prev = &cache->session_cache_head;
-    cache->session_cache_head.next = sess_id;
-
-    ngx_rbtree_insert(cache->session_rbtree, &sess_id->node);
+    sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx);
+
+    ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue);
+
+    ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node);
 
     ngx_shmtx_unlock(&shpool->mutex);
 
@@ -1400,7 +1413,6 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
     u_char                   *p;
     uint32_t                  hash;
     ngx_int_t                 rc;
-    ngx_time_t               *tp;
     ngx_shm_zone_t           *shm_zone;
     ngx_slab_pool_t          *shpool;
     ngx_connection_t         *c;
@@ -1423,18 +1435,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
 
     cache = shm_zone->data;
 
-    if (cache->session_rbtree == NULL) {
-        return NULL;
-    }
-
     sess = NULL;
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
     ngx_shmtx_lock(&shpool->mutex);
 
-    node = cache->session_rbtree->root;
-    sentinel = cache->session_rbtree->sentinel;
+    node = cache->session_rbtree.root;
+    sentinel = cache->session_rbtree.sentinel;
 
     while (node != sentinel) {
 
@@ -1457,9 +1465,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
                               (size_t) len, (size_t) node->data);
             if (rc == 0) {
 
-                tp = ngx_timeofday();
-
-                if (sess_id->expire > tp->sec) {
+                if (sess_id->expire > ngx_time()) {
                     ngx_memcpy(buf, sess_id->session, sess_id->len);
 
                     ngx_shmtx_unlock(&shpool->mutex);
@@ -1470,10 +1476,9 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
                     return sess;
                 }
 
-                sess_id->next->prev = sess_id->prev;
-                sess_id->prev->next = sess_id->next;
-
-                ngx_rbtree_delete(cache->session_rbtree, node);
+                ngx_queue_remove(&sess_id->queue);
+
+                ngx_rbtree_delete(&cache->session_rbtree, node);
 
                 ngx_slab_free_locked(shpool, sess_id->session);
 #if (NGX_PTR_SIZE == 4)
@@ -1530,8 +1535,8 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
 
     ngx_shmtx_lock(&shpool->mutex);
 
-    node = cache->session_rbtree->root;
-    sentinel = cache->session_rbtree->sentinel;
+    node = cache->session_rbtree.root;
+    sentinel = cache->session_rbtree.sentinel;
 
     while (node != sentinel) {
 
@@ -1553,10 +1558,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
             rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data);
 
             if (rc == 0) {
-                sess_id->next->prev = sess_id->prev;
-                sess_id->prev->next = sess_id->next;
-
-                ngx_rbtree_delete(cache->session_rbtree, node);
+
+                ngx_queue_remove(&sess_id->queue);
+
+                ngx_rbtree_delete(&cache->session_rbtree, node);
 
                 ngx_slab_free_locked(shpool, sess_id->session);
 #if (NGX_PTR_SIZE == 4)
@@ -1584,31 +1589,33 @@ static void
 ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
     ngx_slab_pool_t *shpool, ngx_uint_t n)
 {
-    ngx_time_t         *tp;
+    time_t              now;
+    ngx_queue_t        *q;
     ngx_ssl_sess_id_t  *sess_id;
 
-    tp = ngx_timeofday();
+    now = ngx_time();
 
     while (n < 3) {
 
-        sess_id = cache->session_cache_tail.prev;
-
-        if (sess_id == &cache->session_cache_head) {
+        if (ngx_queue_empty(&cache->expire_queue)) {
             return;
         }
 
-        if (n++ != 0 && sess_id->expire > tp->sec) {
+        q = ngx_queue_last(&cache->expire_queue);
+
+        sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue);
+
+        if (n++ != 0 && sess_id->expire > now) {
             return;
         }
 
-        sess_id->next->prev = sess_id->prev;
-        sess_id->prev->next = sess_id->next;
-
-        ngx_rbtree_delete(cache->session_rbtree, &sess_id->node);
+        ngx_queue_remove(q);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
                        "expire session: %08Xi", sess_id->node.key);
 
+        ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node);
+
         ngx_slab_free_locked(shpool, sess_id->session);
 #if (NGX_PTR_SIZE == 4)
         ngx_slab_free_locked(shpool, sess_id->id);
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -53,9 +53,10 @@ typedef struct {
 
 #define NGX_SSL_DFLT_BUILTIN_SCACHE  -2
 #define NGX_SSL_NO_BUILTIN_SCACHE    -3
+#define NGX_SSL_NO_SCACHE            -4
 
 
-#define NGX_SSL_MAX_SESSION_SIZE (4096)
+#define NGX_SSL_MAX_SESSION_SIZE  4096
 
 typedef struct ngx_ssl_sess_id_s  ngx_ssl_sess_id_t;
 
@@ -64,8 +65,7 @@ struct ngx_ssl_sess_id_s {
     u_char                     *id;
     size_t                      len;
     u_char                     *session;
-    ngx_ssl_sess_id_t          *prev;
-    ngx_ssl_sess_id_t          *next;
+    ngx_queue_t                 queue;
     time_t                      expire;
 #if (NGX_PTR_SIZE == 8)
     void                       *stub;
@@ -75,9 +75,9 @@ struct ngx_ssl_sess_id_s {
 
 
 typedef struct {
-    ngx_rbtree_t               *session_rbtree;
-    ngx_ssl_sess_id_t           session_cache_head;
-    ngx_ssl_sess_id_t           session_cache_tail;
+    ngx_rbtree_t                session_rbtree;
+    ngx_rbtree_node_t           sentinel;
+    ngx_queue_t                 expire_queue;
 } ngx_ssl_session_cache_t;
 
 
@@ -132,6 +132,7 @@ ssize_t ngx_ssl_write(ngx_connection_t *
 ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl);
 ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in,
     off_t limit);
+void ngx_ssl_free_buffer(ngx_connection_t *c);
 ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c);
 void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
     char *fmt, ...);
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -98,7 +98,7 @@ ngx_http_access_handler(ngx_http_request
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
 
     if (alcf->rules == NULL) {
-        return NGX_OK;
+        return NGX_DECLINED;
     }
 
     /* AF_INET only */
@@ -128,7 +128,7 @@ ngx_http_access_handler(ngx_http_request
         }
     }
 
-    return NGX_OK;
+    return NGX_DECLINED;
 }
 
 
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -113,7 +113,7 @@ ngx_http_auth_basic_handler(ngx_http_req
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);
 
     if (alcf->realm.len == 0 || alcf->user_file.len == 0) {
-        return NGX_OK;
+        return NGX_DECLINED;
     }
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module);
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -37,7 +37,6 @@ static ngx_int_t ngx_http_dav_handler(ng
 static void ngx_http_dav_put_handler(ngx_http_request_t *r);
 
 static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r);
-static ngx_int_t ngx_http_dav_no_init(void *ctx, void *prev);
 static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
 static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
 static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path);
@@ -409,13 +408,6 @@ ngx_http_dav_delete_handler(ngx_http_req
 
 
 static ngx_int_t
-ngx_http_dav_no_init(void *ctx, void *prev)
-{
-    return NGX_OK;
-}
-
-
-static ngx_int_t
 ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
 {
     return NGX_OK;
@@ -710,7 +702,7 @@ overwrite_done:
 
         copy.len = path.len;
 
-        tree.init_handler = ngx_http_dav_no_init;
+        tree.init_handler = NULL;
         tree.file_handler = ngx_http_dav_copy_file;
         tree.pre_tree_handler = ngx_http_dav_copy_dir;
         tree.post_tree_handler = ngx_http_dav_copy_dir_time;
@@ -960,7 +952,7 @@ ngx_http_dav_delete_path(ngx_http_reques
 
     if (dir) {
 
-        tree.init_handler = ngx_http_dav_no_init;
+        tree.init_handler = NULL;
         tree.file_handler = ngx_http_dav_delete_file;
         tree.pre_tree_handler = ngx_http_dav_noop;
         tree.post_tree_handler = ngx_http_dav_delete_dir;
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -106,7 +106,8 @@ ngx_http_flv_handler(ngx_http_request_t 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     of.test_dir = 0;
-    of.retest = clcf->open_file_cache_retest;
+    of.valid = clcf->open_file_cache_valid;
+    of.min_uses = clcf->open_file_cache_min_uses;
     of.errors = clcf->open_file_cache_errors;
     of.events = clcf->open_file_cache_events;
 
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -14,15 +14,11 @@
 typedef struct {
     ngx_flag_t           enable;
     ngx_flag_t           no_buffer;
-    ngx_flag_t           vary;
 
     ngx_array_t         *types;     /* array of ngx_str_t */
 
     ngx_bufs_t           bufs;
 
-    ngx_uint_t           http_version;
-    ngx_uint_t           proxied;
-
     ngx_int_t            level;
     size_t               wbits;
     size_t               memlevel;
@@ -30,17 +26,6 @@ typedef struct {
 } ngx_http_gzip_conf_t;
 
 
-#define NGX_HTTP_GZIP_PROXIED_OFF       0x0002
-#define NGX_HTTP_GZIP_PROXIED_EXPIRED   0x0004
-#define NGX_HTTP_GZIP_PROXIED_NO_CACHE  0x0008
-#define NGX_HTTP_GZIP_PROXIED_NO_STORE  0x0010
-#define NGX_HTTP_GZIP_PROXIED_PRIVATE   0x0020
-#define NGX_HTTP_GZIP_PROXIED_NO_LM     0x0040
-#define NGX_HTTP_GZIP_PROXIED_NO_ETAG   0x0080
-#define NGX_HTTP_GZIP_PROXIED_AUTH      0x0100
-#define NGX_HTTP_GZIP_PROXIED_ANY       0x0200
-
-
 typedef struct {
     ngx_chain_t         *in;
     ngx_chain_t         *free;
@@ -70,8 +55,6 @@ typedef struct {
 } ngx_http_gzip_ctx_t;
 
 
-static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r,
-    ngx_http_gzip_conf_t *conf);
 static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
     u_int size);
 static void ngx_http_gzip_filter_free(void *opaque, void *address);
@@ -99,27 +82,6 @@ static ngx_conf_post_handler_pt  ngx_htt
 static ngx_conf_post_handler_pt  ngx_http_gzip_hash_p = ngx_http_gzip_hash;
 
 
-static ngx_conf_enum_t  ngx_http_gzip_http_version[] = {
-    { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
-    { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_conf_bitmask_t  ngx_http_gzip_proxied_mask[] = {
-    { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF },
-    { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED },
-    { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE },
-    { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE },
-    { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE },
-    { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM },
-    { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG },
-    { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH },
-    { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY },
-    { ngx_null_string, 0 }
-};
-
-
 static ngx_command_t  ngx_http_gzip_filter_commands[] = {
 
     { ngx_string("gzip"),
@@ -172,20 +134,6 @@ static ngx_command_t  ngx_http_gzip_filt
       offsetof(ngx_http_gzip_conf_t, no_buffer),
       NULL },
 
-    { ngx_string("gzip_http_version"),
-      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_gzip_conf_t, http_version),
-      &ngx_http_gzip_http_version },
-
-    { ngx_string("gzip_proxied"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
-      ngx_conf_set_bitmask_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_gzip_conf_t, proxied),
-      &ngx_http_gzip_proxied_mask },
-
     { ngx_string("gzip_min_length"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
@@ -193,13 +141,6 @@ static ngx_command_t  ngx_http_gzip_filt
       offsetof(ngx_http_gzip_conf_t, min_length),
       NULL },
 
-    { ngx_string("gzip_vary"),
-      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_gzip_conf_t, vary),
-      NULL },
-
       ngx_null_command
 };
 
@@ -255,10 +196,6 @@ struct gztrailer {
 
 
 static ngx_str_t  ngx_http_gzip_ratio = ngx_string("gzip_ratio");
-static ngx_str_t  ngx_http_gzip_no_cache = ngx_string("no-cache");
-static ngx_str_t  ngx_http_gzip_no_store = ngx_string("no-store");
-static ngx_str_t  ngx_http_gzip_private = ngx_string("private");
-
 
 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
@@ -267,11 +204,12 @@ static ngx_http_output_body_filter_pt   
 static ngx_int_t
 ngx_http_gzip_header_filter(ngx_http_request_t *r)
 {
-    ngx_str_t             *type;
-    ngx_uint_t             i;
-    ngx_table_elt_t       *header;
-    ngx_http_gzip_ctx_t   *ctx;
-    ngx_http_gzip_conf_t  *conf;
+    ngx_str_t                 *type;
+    ngx_uint_t                 i;
+    ngx_table_elt_t           *h;
+    ngx_http_gzip_ctx_t       *ctx;
+    ngx_http_gzip_conf_t      *conf;
+    ngx_http_core_loc_conf_t  *clcf;
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
@@ -280,23 +218,16 @@ ngx_http_gzip_header_filter(ngx_http_req
             && r->headers_out.status != NGX_HTTP_FORBIDDEN
             && r->headers_out.status != NGX_HTTP_NOT_FOUND)
         || r->header_only
-        || r != r->main
-        || r->http_version < conf->http_version
         || r->headers_out.content_type.len == 0
         || (r->headers_out.content_encoding
             && r->headers_out.content_encoding->value.len)
-        || r->headers_in.accept_encoding == NULL
         || (r->headers_out.content_length_n != -1
             && r->headers_out.content_length_n < conf->min_length)
-        || ngx_strcasestrn(r->headers_in.accept_encoding->value.data,
-                           "gzip", 4 - 1)
-           == NULL
-       )
+        || ngx_http_gzip_ok(r) != NGX_OK)
     {
         return ngx_http_next_header_filter(r);
     }
 
-
     type = conf->types->elts;
     for (i = 0; i < conf->types->nelts; i++) {
         if (r->headers_out.content_type.len >= type[i].len
@@ -309,32 +240,8 @@ ngx_http_gzip_header_filter(ngx_http_req
 
     return ngx_http_next_header_filter(r);
 
-
 found:
 
-    if (r->headers_in.via) {
-        if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) {
-            return ngx_http_next_header_filter(r);
-        }
-
-        if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_ANY)
-            && ngx_http_gzip_proxied(r, conf) == NGX_DECLINED)
-        {
-            return ngx_http_next_header_filter(r);
-        }
-    }
-
-
-    /*
-     * if the URL (without the "http://" prefix) is longer than 253 bytes
-     * then MSIE 4.x can not handle the compressed stream - it waits too long,
-     * hangs up or crashes
-     */
-
-    if (r->headers_in.msie4 && r->unparsed_uri.len > 200) {
-        return ngx_http_next_header_filter(r);
-    }
-
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
@@ -342,33 +249,34 @@ found:
 
     ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
 
-
     ctx->request = r;
 
-    header = ngx_list_push(&r->headers_out.headers);
-    if (header == NULL) {
+    h = ngx_list_push(&r->headers_out.headers);
+    if (h == NULL) {
         return NGX_ERROR;
     }
 
-    header->hash = 1;
-    header->key.len = sizeof("Content-Encoding") - 1;
-    header->key.data = (u_char *) "Content-Encoding";
-    header->value.len = sizeof("gzip") - 1;
-    header->value.data = (u_char *) "gzip";
+    h->hash = 1;
+    h->key.len = sizeof("Content-Encoding") - 1;
+    h->key.data = (u_char *) "Content-Encoding";
+    h->value.len = sizeof("gzip") - 1;
+    h->value.data = (u_char *) "gzip";
 
-    r->headers_out.content_encoding = header;
+    r->headers_out.content_encoding = h;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (conf->vary) {
-        header = ngx_list_push(&r->headers_out.headers);
-        if (header == NULL) {
+    if (clcf->gzip_vary) {
+        h = ngx_list_push(&r->headers_out.headers);
+        if (h == NULL) {
             return NGX_ERROR;
         }
 
-        header->hash = 1;
-        header->key.len = sizeof("Vary") - 1;
-        header->key.data = (u_char *) "Vary";
-        header->value.len = sizeof("Accept-Encoding") - 1;
-        header->value.data = (u_char *) "Accept-Encoding";
+        h->hash = 1;
+        h->key.len = sizeof("Vary") - 1;
+        h->key.data = (u_char *) "Vary";
+        h->value.len = sizeof("Accept-Encoding") - 1;
+        h->value.data = (u_char *) "Accept-Encoding";
     }
 
     ctx->length = r->headers_out.content_length_n;
@@ -383,89 +291,6 @@ found:
 
 
 static ngx_int_t
-ngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf)
-{
-    time_t  date, expires;
-
-    if (r->headers_in.authorization
-        && (conf->proxied & NGX_HTTP_GZIP_PROXIED_AUTH))
-    {
-        return NGX_OK;
-    }
-
-    if (r->headers_out.expires) {
-
-        if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_EXPIRED)) {
-            return NGX_DECLINED;
-        }
-
-        expires = ngx_http_parse_time(r->headers_out.expires->value.data,
-                                      r->headers_out.expires->value.len);
-        if (expires == NGX_ERROR) {
-            return NGX_DECLINED;
-        }
-
-        if (r->headers_out.date) {
-            date = ngx_http_parse_time(r->headers_out.date->value.data,
-                                       r->headers_out.date->value.len);
-            if (date == NGX_ERROR) {
-                return NGX_DECLINED;
-            }
-
-        } else {
-            date = ngx_time();
-        }
-
-        if (expires < date) {
-            return NGX_OK;
-        }
-
-        return NGX_DECLINED;
-    }
-
-    if (r->headers_out.cache_control.elts) {
-
-        if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
-            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
-                   &ngx_http_gzip_no_cache, NULL) >= 0)
-        {
-            return NGX_OK;
-        }
-
-        if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE)
-            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
-                   &ngx_http_gzip_no_store, NULL) >= 0)
-        {
-            return NGX_OK;
-        }
-
-        if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE)
-            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
-                   &ngx_http_gzip_private, NULL) >= 0)
-        {
-            return NGX_OK;
-        }
-
-        return NGX_DECLINED;
-    }
-
-    if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_LM)
-        && r->headers_out.last_modified)
-    {
-        return NGX_DECLINED;
-    }
-
-    if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_ETAG)
-        && r->headers_out.etag)
-    {
-        return NGX_DECLINED;
-    }
-
-    return NGX_OK;
-}
-
-
-static ngx_int_t
 ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
     int                    rc, wbits, memlevel;
@@ -1017,15 +842,11 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf
      * set by ngx_pcalloc():
      *
      *     conf->bufs.num = 0;
-     *     conf->proxied = 0;
      *     conf->types = NULL;
      */
 
     conf->enable = NGX_CONF_UNSET;
     conf->no_buffer = NGX_CONF_UNSET;
-    conf->vary = NGX_CONF_UNSET;
-
-    conf->http_version = NGX_CONF_UNSET_UINT;
 
     conf->level = NGX_CONF_UNSET;
     conf->wbits = (size_t) NGX_CONF_UNSET;
@@ -1048,18 +869,12 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf,
 
     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize);
 
-    ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
-                              NGX_HTTP_VERSION_11);
-    ngx_conf_merge_bitmask_value(conf->proxied, prev->proxied,
-                              (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF));
-
     ngx_conf_merge_value(conf->level, prev->level, 1);
     ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS);
     ngx_conf_merge_size_value(conf->memlevel, prev->memlevel,
                               MAX_MEM_LEVEL - 1);
     ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
     ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
-    ngx_conf_merge_value(conf->vary, prev->vary, 0);
 
     if (conf->types == NULL) {
         if (prev->types == NULL) {
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -0,0 +1,302 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    ngx_flag_t  enable;
+} ngx_http_gzip_static_conf_t;
+
+
+static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r);
+static void *ngx_http_gzip_static_create_conf(ngx_conf_t *cf);
+static char *ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+static ngx_int_t ngx_http_gzip_static_init(ngx_conf_t *cf);
+
+
+static ngx_command_t  ngx_http_gzip_static_commands[] = {
+
+    { ngx_string("gzip_static"),
+      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_gzip_static_conf_t, enable),
+      NULL },
+
+      ngx_null_command
+};
+
+
+ngx_http_module_t  ngx_http_gzip_static_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_gzip_static_init,             /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_gzip_static_create_conf,      /* create location configuration */
+    ngx_http_gzip_static_merge_conf        /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_gzip_static_module = {
+    NGX_MODULE_V1,
+    &ngx_http_gzip_static_module_ctx,      /* module context */
+    ngx_http_gzip_static_commands,         /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_gzip_static_handler(ngx_http_request_t *r)
+{
+    u_char                       *p;
+    size_t                        root;
+    ngx_str_t                     path;
+    ngx_int_t                     rc;
+    ngx_uint_t                    level;
+    ngx_log_t                    *log;
+    ngx_buf_t                    *b;
+    ngx_chain_t                   out;
+    ngx_table_elt_t              *h;
+    ngx_open_file_info_t          of;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_gzip_static_conf_t  *gzcf;
+
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
+        return NGX_HTTP_NOT_ALLOWED;
+    }
+
+    if (r->uri.data[r->uri.len - 1] == '/') {
+        return NGX_DECLINED;
+    }
+
+    /* TODO: Win32 */
+    if (r->zero_in_uri) {
+        return NGX_DECLINED;
+    }
+
+    gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
+
+    if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) {
+        return NGX_DECLINED;
+    }
+
+    log = r->connection->log;
+
+    p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1);
+    if (p == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    *p++ = '.';
+    *p++ = 'g';
+    *p++ = 'z';
+    *p = '\0';
+
+    path.len = p - path.data;
+
+    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);
+
+    of.test_dir = 0;
+    of.valid = clcf->open_file_cache_valid;
+    of.min_uses = clcf->open_file_cache_min_uses;
+    of.errors = clcf->open_file_cache_errors;
+    of.events = clcf->open_file_cache_events;
+
+    rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
+
+    if (rc == NGX_ERROR) {
+
+        switch (of.err) {
+
+        case 0:
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+
+        case NGX_ENOENT:
+        case NGX_ENOTDIR:
+        case NGX_ENAMETOOLONG:
+
+            return NGX_DECLINED;
+
+        case NGX_EACCES:
+
+            level = NGX_LOG_ERR;
+            rc = NGX_DECLINED;
+            break;
+
+        default:
+
+            level = NGX_LOG_CRIT;
+            rc = NGX_DECLINED;
+            break;
+        }
+
+        ngx_log_error(level, log, of.err,
+                      ngx_open_file_n " \"%s\" failed", path.data);
+
+        return rc;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
+
+    if (of.is_dir) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
+        return NGX_DECLINED;
+    }
+
+#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
+
+    if (!of.is_file) {
+        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+                      "\"%s\" is not a regular file", path.data);
+
+        return NGX_HTTP_NOT_FOUND;
+    }
+
+#endif
+
+    rc = ngx_http_discard_request_body(r);
+
+    if (rc != NGX_OK) {
+        return rc;
+    }
+
+    log->action = "sending response to client";
+
+    r->headers_out.status = NGX_HTTP_OK;
+    r->headers_out.content_length_n = of.size;
+    r->headers_out.last_modified_time = of.mtime;
+
+    if (ngx_http_set_content_type(r) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    h = ngx_list_push(&r->headers_out.headers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    h->hash = 1;
+    h->key.len = sizeof("Content-Encoding") - 1;
+    h->key.data = (u_char *) "Content-Encoding";
+    h->value.len = sizeof("gzip") - 1;
+    h->value.data = (u_char *) "gzip";
+
+    r->headers_out.content_encoding = h;
+
+    if (clcf->gzip_vary) {
+        h = ngx_list_push(&r->headers_out.headers);
+        if (h == NULL) {
+            return NGX_ERROR;
+        }
+
+        h->hash = 1;
+        h->key.len = sizeof("Vary") - 1;
+        h->key.data = (u_char *) "Vary";
+        h->value.len = sizeof("Accept-Encoding") - 1;
+        h->value.data = (u_char *) "Accept-Encoding";
+    }
+
+    /* we need to allocate all before the header would be sent */
+
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    if (b == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
+    if (b->file == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    rc = ngx_http_send_header(r);
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
+    }
+
+    b->file_pos = 0;
+    b->file_last = of.size;
+
+    b->in_file = b->file_last ? 1 : 0;
+    b->last_buf = 1;
+    b->last_in_chain = 1;
+
+    b->file->fd = of.fd;
+    b->file->name = path;
+    b->file->log = log;
+
+    out.buf = b;
+    out.next = NULL;
+
+    return ngx_http_output_filter(r, &out);
+}
+
+
+static void *
+ngx_http_gzip_static_create_conf(ngx_conf_t *cf)
+{
+    ngx_http_gzip_static_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->enable = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_gzip_static_conf_t *prev = parent;
+    ngx_http_gzip_static_conf_t *conf = child;
+
+    ngx_conf_merge_value(conf->enable, prev->enable, 0);
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_gzip_static_init(ngx_conf_t *cf)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_gzip_static_handler;
+
+    return NGX_OK;
+}
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -209,7 +209,8 @@ ngx_http_index_handler(ngx_http_request_
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%V\"", &path);
 
         of.test_dir = 0;
-        of.retest = clcf->open_file_cache_retest;
+        of.valid = clcf->open_file_cache_valid;
+        of.min_uses = clcf->open_file_cache_min_uses;
         of.errors = clcf->open_file_cache_errors;
         of.events = clcf->open_file_cache_events;
 
@@ -292,7 +293,8 @@ ngx_http_index_test_dir(ngx_http_request
                    "http index check dir: \"%V\"", &dir);
 
     of.test_dir = 1;
-    of.retest = clcf->open_file_cache_retest;
+    of.valid = clcf->open_file_cache_valid;
+    of.min_uses = 0;
     of.errors = clcf->open_file_cache_errors;
 
     if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool)
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -58,7 +58,7 @@ static ngx_conf_bitmask_t  ngx_http_memc
 static ngx_command_t  ngx_http_memcached_commands[] = {
 
     { ngx_string("memcached_pass"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
       ngx_http_memcached_pass,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -524,8 +524,6 @@ ngx_http_memcached_create_loc_conf(ngx_c
      *     conf->upstream.schema = { 0, NULL };
      *     conf->upstream.uri = { 0, NULL };
      *     conf->upstream.location = NULL;
-     *
-     *     conf->index = 0;
      */
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
@@ -548,6 +546,8 @@ ngx_http_memcached_create_loc_conf(ngx_c
     conf->upstream.pass_request_headers = 0;
     conf->upstream.pass_request_body = 0;
 
+    conf->index = NGX_CONF_UNSET;
+
     return conf;
 }
 
@@ -582,6 +582,15 @@ ngx_http_memcached_merge_loc_conf(ngx_co
                                        |NGX_HTTP_UPSTREAM_FT_OFF;
     }
 
+    if (conf->upstream.upstream == NULL) {
+        conf->upstream.upstream = prev->upstream.upstream;
+        conf->upstream.schema = prev->upstream.schema;
+    }
+
+    if (conf->index == NGX_CONF_UNSET) {
+        conf->index = prev->index;
+    }
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -880,16 +880,9 @@ ngx_http_proxy_create_request(ngx_http_r
         b->last = e.pos;
     }
 
-#if (NGX_DEBUG)
-    {
-    ngx_str_t  s;
-
-    s.len = b->last - b->pos;
-    s.data = b->pos;
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http proxy header:\n\"%V\"", &s);
-    }
-#endif
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http proxy header:\n\"%*s\"",
+                   (size_t) (b->last - b->pos), b->pos);
 
     if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
 
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -11,14 +11,7 @@
 
 #define NGX_HTTP_REFERER_NO_URI_PART  ((void *) 4)
 
-#if (NGX_PCRE)
-
-typedef struct {
-    ngx_regex_t             *regex;
-    ngx_str_t                name;
-} ngx_http_referer_regex_t;
-
-#else
+#if !(NGX_PCRE)
 
 #define ngx_regex_t          void
 
@@ -168,34 +161,23 @@ ngx_http_referer_variable(ngx_http_reque
 #if (NGX_PCRE)
 
     if (rlcf->regex) {
-        ngx_int_t                  n;
-        ngx_str_t                  referer;
-        ngx_http_referer_regex_t  *regex;
+        ngx_int_t  rc;
+        ngx_str_t  referer;
 
         referer.len = len - 7;
         referer.data = ref;
 
-        regex = rlcf->regex->elts;
-
-        for (i = 0; i < rlcf->regex->nelts; i++) {
-            n = ngx_regex_exec(regex[i].regex, &referer, NULL, 0);
-
-            if (n == NGX_REGEX_NO_MATCHED) {
-                continue;
-            }
+        rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log);
 
-            if (n < 0) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                              ngx_regex_exec_n
-                              " failed: %d on \"%V\" using \"%V\"",
-                              n, &referer, &regex[i].name);
-                return NGX_ERROR;
-            }
-
-            /* match */
-
+        if (rc == NGX_OK) {
             goto valid;
         }
+
+        if (rc == NGX_ERROR) {
+            return rc;
+        }
+
+        /* NGX_DECLINED */
     }
 
 #endif
@@ -242,6 +224,10 @@ ngx_http_referer_create_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
+#if (NGX_PCRE)
+    conf->regex = NGX_CONF_UNSET_PTR;
+#endif
+
     conf->no_referer = NGX_CONF_UNSET;
     conf->blocked_referer = NGX_CONF_UNSET;
 
@@ -260,6 +246,7 @@ ngx_http_referer_merge_conf(ngx_conf_t *
     if (conf->keys == NULL) {
         conf->hash = prev->hash;
 
+        ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
         ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
         ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0);
 
@@ -335,6 +322,8 @@ ngx_http_referer_merge_conf(ngx_conf_t *
         conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
     }
 
+    ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
+
     if (conf->no_referer == NGX_CONF_UNSET) {
         conf->no_referer = 0;
     }
@@ -509,26 +498,25 @@ ngx_http_add_regex_referer(ngx_conf_t *c
     ngx_str_t *name, ngx_regex_t *regex)
 {
 #if (NGX_PCRE)
-    ngx_str_t                  err;
-    ngx_http_referer_regex_t  *rr;
-    u_char                     errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t         err;
+    ngx_regex_elt_t  *re;
+    u_char            errstr[NGX_MAX_CONF_ERRSTR];
 
-    if (rlcf->regex == NULL) {
-        rlcf->regex = ngx_array_create(cf->pool, 2,
-                                       sizeof(ngx_http_referer_regex_t));
+    if (rlcf->regex == NGX_CONF_UNSET_PTR) {
+        rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t));
         if (rlcf->regex == NULL) {
             return NGX_CONF_ERROR;
         }
     }
 
-    rr = ngx_array_push(rlcf->regex);
-    if (rr == NULL) {
+    re = ngx_array_push(rlcf->regex);
+    if (re == NULL) {
         return NGX_CONF_ERROR;
     }
 
     if (regex) {
-        rr->regex = regex;
-        rr->name = *name;
+        re->regex = regex;
+        re->name = name->data;
 
         return NGX_CONF_OK;
     }
@@ -539,14 +527,14 @@ ngx_http_add_regex_referer(ngx_conf_t *c
     name->len--;
     name->data++;
 
-    rr->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err);
+    re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err);
 
-    if (rr->regex == NULL) {
+    if (re->regex == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
         return NGX_CONF_ERROR;
     }
 
-    rr->name = *name;
+    re->name = name->data;
 
     return NGX_CONF_OK;
 
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -415,8 +415,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     }
 
     ngx_conf_merge_value(conf->builtin_session_cache,
-                         prev->builtin_session_cache,
-                         NGX_SSL_DFLT_BUILTIN_SCACHE);
+                         prev->builtin_session_cache, NGX_SSL_NO_SCACHE);
 
     if (conf->shm_zone == NULL) {
         conf->shm_zone = prev->shm_zone;
@@ -448,6 +447,11 @@ ngx_http_ssl_session_cache(ngx_conf_t *c
 
     for (i = 1; i < cf->args->nelts; i++) {
 
+        if (ngx_strcmp(value[i].data, "off") == 0) {
+            sscf->builtin_session_cache = NGX_SSL_NO_SCACHE;
+            continue;
+        }
+
         if (ngx_strcmp(value[i].data, "builtin") == 0) {
             sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
             continue;
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -97,7 +97,8 @@ ngx_http_static_handler(ngx_http_request
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     of.test_dir = 0;
-    of.retest = clcf->open_file_cache_retest;
+    of.valid = clcf->open_file_cache_valid;
+    of.min_uses = clcf->open_file_cache_min_uses;
     of.errors = clcf->open_file_cache_errors;
     of.events = clcf->open_file_cache_events;
 
--- 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.6.22';
+our $VERSION = '0.6.23';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -643,7 +643,8 @@ sendfile(r, filename, offset = -1, bytes
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     of.test_dir = 0;
-    of.retest = clcf->open_file_cache_retest;
+    of.valid = clcf->open_file_cache_valid;
+    of.min_uses = clcf->open_file_cache_min_uses;
     of.errors = clcf->open_file_cache_errors;
     of.events = clcf->open_file_cache_events;
 
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -121,11 +121,8 @@ ngx_http_copy_filter(ngx_http_request_t 
             r->out = ctx->in;
         }
 
-#if (NGX_DEBUG)
         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
-#endif
-
     }
 
     return rc;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -71,6 +71,10 @@ static char *ngx_http_core_internal(ngx_
     void *conf);
 static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+#if (NGX_HTTP_GZIP)
+static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+#endif
 
 static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data);
 static char *ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data);
@@ -85,6 +89,10 @@ static ngx_conf_deprecated_t  ngx_conf_d
     ngx_conf_deprecated, "optimize_host_names", "optimize_server_names"
 };
 
+static ngx_conf_deprecated_t  ngx_conf_deprecated_open_file_cache_retest = {
+    ngx_conf_deprecated, "open_file_cache_retest", "open_file_cache_valid"
+};
+
 
 static ngx_conf_enum_t  ngx_http_core_request_body_in_file[] = {
     { ngx_string("off"), NGX_HTTP_REQUEST_BODY_FILE_OFF },
@@ -94,6 +102,36 @@ static ngx_conf_enum_t  ngx_http_core_re
 };
 
 
+#if (NGX_HTTP_GZIP)
+
+static ngx_conf_enum_t  ngx_http_gzip_http_version[] = {
+    { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
+    { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_conf_bitmask_t  ngx_http_gzip_proxied_mask[] = {
+    { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF },
+    { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED },
+    { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE },
+    { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE },
+    { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE },
+    { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM },
+    { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG },
+    { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH },
+    { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_str_t  ngx_http_gzip_no_cache = ngx_string("no-cache");
+static ngx_str_t  ngx_http_gzip_no_store = ngx_string("no-store");
+static ngx_str_t  ngx_http_gzip_private = ngx_string("private");
+
+#endif
+
+
 static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("variables_hash_max_size"),
@@ -473,11 +511,25 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, open_file_cache),
       NULL },
 
+    { ngx_string("open_file_cache_valid"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_sec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid),
+      NULL },
+
     { ngx_string("open_file_cache_retest"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_sec_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_core_loc_conf_t, open_file_cache_retest),
+      offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid),
+      &ngx_conf_deprecated_open_file_cache_retest },
+
+    { ngx_string("open_file_cache_min_uses"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, open_file_cache_min_uses),
       NULL },
 
     { ngx_string("open_file_cache_errors"),
@@ -508,6 +560,38 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, resolver_timeout),
       NULL },
 
+#if (NGX_HTTP_GZIP)
+
+    { ngx_string("gzip_vary"),
+      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_core_loc_conf_t, gzip_vary),
+      NULL },
+
+    { ngx_string("gzip_http_version"),
+      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_core_loc_conf_t, gzip_http_version),
+      &ngx_http_gzip_http_version },
+
+    { ngx_string("gzip_proxied"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, gzip_proxied),
+      &ngx_http_gzip_proxied_mask },
+
+    { ngx_string("gzip_disable"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_gzip_disable,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+#endif
+
       ngx_null_command
 };
 
@@ -600,6 +684,7 @@ ngx_http_handler(ngx_http_request_t *r)
     }
 
     r->valid_location = 1;
+    r->gzip = 0;
 
     r->write_event_handler = ngx_http_core_run_phases;
     ngx_http_core_run_phases(r);
@@ -1386,6 +1471,164 @@ ngx_http_auth_basic_user(ngx_http_reques
 }
 
 
+#if (NGX_HTTP_GZIP)
+
+ngx_int_t
+ngx_http_gzip_ok(ngx_http_request_t *r)
+{
+    time_t                     date, expires;
+    ngx_uint_t                 p;
+    ngx_array_t               *cc;
+    ngx_table_elt_t           *e, *d;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (r->gzip == 1) {
+        return NGX_OK;
+    }
+
+    if (r->gzip == 2) {
+        return NGX_DECLINED;
+    }
+
+    r->gzip = 2;
+
+    if (r != r->main
+        || r->headers_in.accept_encoding == NULL
+        || ngx_strcasestrn(r->headers_in.accept_encoding->value.data,
+                           "gzip", 4 - 1)
+           == NULL
+
+        /*
+         * if the URL (without the "http://" prefix) is longer than 253 bytes,
+         * then MSIE 4.x can not handle the compressed stream - it waits
+         * too long, hangs up or crashes
+         */
+
+        || (r->headers_in.msie4 && r->unparsed_uri.len > 200))
+    {
+        return NGX_DECLINED;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (r->http_version < clcf->gzip_http_version) {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_in.via == NULL) {
+        goto ok;
+    }
+
+    p = clcf->gzip_proxied;
+
+    if (p & NGX_HTTP_GZIP_PROXIED_OFF) {
+        return NGX_DECLINED;
+    }
+
+    if (p & NGX_HTTP_GZIP_PROXIED_ANY) {
+        goto ok;
+    }
+
+    if (r->headers_in.authorization && (p & NGX_HTTP_GZIP_PROXIED_AUTH)) {
+        goto ok;
+    }
+
+    e = r->headers_out.expires;
+
+    if (e) {
+
+        if (!(p & NGX_HTTP_GZIP_PROXIED_EXPIRED)) {
+            return NGX_DECLINED;
+        }
+
+        expires = ngx_http_parse_time(e->value.data, e->value.len);
+        if (expires == NGX_ERROR) {
+            return NGX_DECLINED;
+        }
+
+        d = r->headers_out.date;
+
+        if (d) {
+            date = ngx_http_parse_time(d->value.data, d->value.len);
+            if (date == NGX_ERROR) {
+                return NGX_DECLINED;
+            }
+
+        } else {
+            date = ngx_time();
+        }
+
+        if (expires < date) {
+            goto ok;
+        }
+
+        return NGX_DECLINED;
+    }
+
+    cc = &r->headers_out.cache_control;
+
+    if (cc->elts) {
+
+        if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
+            && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache,
+                                                 NULL)
+               >= 0)
+        {
+            goto ok;
+        }
+
+        if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE)
+            && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store,
+                                                 NULL)
+               >= 0)
+        {
+            goto ok;
+        }
+
+        if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE)
+            && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private,
+                                                 NULL)
+               >= 0)
+        {
+            goto ok;
+        }
+
+        return NGX_DECLINED;
+    }
+
+    if ((p & NGX_HTTP_GZIP_PROXIED_NO_LM) && r->headers_out.last_modified) {
+        return NGX_DECLINED;
+    }
+
+    if ((p & NGX_HTTP_GZIP_PROXIED_NO_ETAG) && r->headers_out.etag) {
+        return NGX_DECLINED;
+    }
+
+ok:
+
+#if (NGX_PCRE)
+
+    if (clcf->gzip_disable && r->headers_in.user_agent) {
+
+        if (ngx_regex_exec_array(clcf->gzip_disable, 
+                                 &r->headers_in.user_agent->value,
+                                 r->connection->log)
+            != NGX_DECLINED)
+        {
+            return NGX_DECLINED;
+        }
+    }
+
+#endif
+
+    r->gzip = 1;
+
+    return NGX_OK;
+}
+
+#endif
+
+
 ngx_int_t
 ngx_http_subrequest(ngx_http_request_t *r,
     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
@@ -2386,6 +2629,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
      *     lcf->exact_match = 0;
      *     lcf->auto_redirect = 0;
      *     lcf->alias = 0;
+     *     lcf->gzip_proxied = 0;
      */
 
     lcf->client_max_body_size = NGX_CONF_UNSET;
@@ -2416,11 +2660,19 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->server_tokens = NGX_CONF_UNSET;
     lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
     lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
+
     lcf->open_file_cache = NGX_CONF_UNSET_PTR;
-    lcf->open_file_cache_retest = NGX_CONF_UNSET;
+    lcf->open_file_cache_valid = NGX_CONF_UNSET;
+    lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
     lcf->open_file_cache_errors = NGX_CONF_UNSET;
     lcf->open_file_cache_events = NGX_CONF_UNSET;
 
+#if (NGX_HTTP_GZIP)
+    lcf->gzip_vary = NGX_CONF_UNSET;
+    lcf->gzip_http_version = NGX_CONF_UNSET_UINT;
+    lcf->gzip_disable = NGX_CONF_UNSET_PTR;
+#endif
+
     return lcf;
 }
 
@@ -2618,16 +2870,30 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1);
 
     ngx_conf_merge_ptr_value(conf->open_file_cache,
-                             prev->open_file_cache, NULL);
-
-    ngx_conf_merge_sec_value(conf->open_file_cache_retest,
-                             prev->open_file_cache_retest, 60);
+                              prev->open_file_cache, NULL);
+
+    ngx_conf_merge_sec_value(conf->open_file_cache_valid,
+                              prev->open_file_cache_valid, 60);
+
+    ngx_conf_merge_uint_value(conf->open_file_cache_min_uses,
+                              prev->open_file_cache_min_uses, 1);
 
     ngx_conf_merge_sec_value(conf->open_file_cache_errors,
-                             prev->open_file_cache_errors, 0);
+                              prev->open_file_cache_errors, 0);
 
     ngx_conf_merge_sec_value(conf->open_file_cache_events,
-                             prev->open_file_cache_events, 0);
+                              prev->open_file_cache_events, 0);
+#if (NGX_HTTP_GZIP)
+
+    ngx_conf_merge_value(conf->gzip_vary, prev->gzip_vary, 0);
+    ngx_conf_merge_uint_value(conf->gzip_http_version, prev->gzip_http_version,
+                              NGX_HTTP_VERSION_11);
+    ngx_conf_merge_bitmask_value(conf->gzip_proxied, prev->gzip_proxied,
+                              (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF));
+
+    ngx_conf_merge_ptr_value(conf->gzip_disable, prev->gzip_disable, NULL);
+
+#endif
 
     return NGX_CONF_OK;
 }
@@ -2869,8 +3135,7 @@ ngx_http_core_server_name(ngx_conf_t *cf
         sn->regex = NULL;
 #endif
         sn->core_srv_conf = cscf;
-        sn->name.len = value[i].len;
-        sn->name.data = value[i].data;
+        sn->name = value[i];
 
         if (value[i].data[0] != '~') {
             continue;
@@ -2895,8 +3160,7 @@ ngx_http_core_server_name(ngx_conf_t *cf
             return NGX_CONF_ERROR;
         }
 
-        sn->name.len = value[i].len;
-        sn->name.data = value[i].data;
+        sn->name = value[i];
         }
 #else
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3418,6 +3682,63 @@ ngx_http_core_resolver(ngx_conf_t *cf, n
 }
 
 
+#if (NGX_HTTP_GZIP)
+
+static char *
+ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+#if (NGX_PCRE)
+    ngx_http_core_loc_conf_t  *clcf = conf;
+
+    ngx_str_t         err, *value;
+    ngx_uint_t        i;
+    ngx_regex_elt_t  *re;
+    u_char            errstr[NGX_MAX_CONF_ERRSTR];
+
+    if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) {
+        clcf->gzip_disable = ngx_array_create(cf->pool, 2,
+                                              sizeof(ngx_regex_elt_t));
+        if (clcf->gzip_disable == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+
+    err.len = NGX_MAX_CONF_ERRSTR;
+    err.data = errstr;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+
+        re = ngx_array_push(clcf->gzip_disable);
+        if (re == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool,
+                                      &err);
+
+        if (re->regex == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+            return NGX_CONF_ERROR;
+        }
+
+        re->name = value[i].data;
+    }
+
+    return NGX_CONF_OK;
+
+#else
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "\"gzip_disable\" requires PCRE library");
+
+    return NGX_CONF_ERROR;
+#endif
+}
+
+#endif
+
+
 static char *
 ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data)
 {
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -13,6 +13,17 @@
 #include <ngx_http.h>
 
 
+#define NGX_HTTP_GZIP_PROXIED_OFF       0x0002
+#define NGX_HTTP_GZIP_PROXIED_EXPIRED   0x0004
+#define NGX_HTTP_GZIP_PROXIED_NO_CACHE  0x0008
+#define NGX_HTTP_GZIP_PROXIED_NO_STORE  0x0010
+#define NGX_HTTP_GZIP_PROXIED_PRIVATE   0x0020
+#define NGX_HTTP_GZIP_PROXIED_NO_LM     0x0040
+#define NGX_HTTP_GZIP_PROXIED_NO_ETAG   0x0080
+#define NGX_HTTP_GZIP_PROXIED_AUTH      0x0100
+#define NGX_HTTP_GZIP_PROXIED_ANY       0x0200
+
+
 typedef struct {
     unsigned                   default_server:1;
     unsigned                   bind:1;
@@ -290,12 +301,24 @@ struct ngx_http_core_loc_conf_s {
     ngx_flag_t    recursive_error_pages;   /* recursive_error_pages */
     ngx_flag_t    server_tokens;           /* server_tokens */
 
+#if (NGX_HTTP_GZIP)
+    ngx_flag_t    gzip_vary;               /* gzip_vary */
+
+    ngx_uint_t    gzip_http_version;       /* gzip_http_version */
+    ngx_uint_t    gzip_proxied;            /* gzip_proxied */
+
+#if (NGX_PCRE)
+    ngx_array_t  *gzip_disable;            /* gzip_disable */
+#endif
+#endif
+
     ngx_array_t  *error_pages;             /* error_page */
 
     ngx_path_t   *client_body_temp_path;   /* client_body_temp_path */
 
     ngx_open_file_cache_t  *open_file_cache;
-    time_t        open_file_cache_retest;
+    time_t        open_file_cache_valid;
+    ngx_uint_t    open_file_cache_min_uses;
     ngx_flag_t    open_file_cache_errors;
     ngx_flag_t    open_file_cache_events;
 
@@ -329,6 +352,10 @@ ngx_int_t ngx_http_set_exten(ngx_http_re
 u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name,
     size_t *root_length, size_t reserved);
 ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r);
+#if (NGX_HTTP_GZIP)
+ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r);
+#endif
+
 
 ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,
     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr,
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -521,10 +521,8 @@ ngx_http_header_filter(ngx_http_request_
         *b->last++ = CR; *b->last++ = LF;
     }
 
-#if (NGX_DEBUG)
-    *b->last = '\0';
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%s\n", b->pos);
-#endif
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "%*s\n", (size_t) (b->last - b->pos), b->pos);
 
     /* the end of HTTP header */
     *b->last++ = CR; *b->last++ = LF;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1595,7 +1595,11 @@ ngx_http_finalize_request(ngx_http_reque
         rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc);
     }
 
-    if (rc == NGX_ERROR || rc == NGX_HTTP_REQUEST_TIME_OUT || c->error) {
+    if (rc == NGX_ERROR
+        || rc == NGX_HTTP_REQUEST_TIME_OUT
+        || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
+        || c->error)
+    {
         if (rc > 0 && r->headers_out.status == 0) {
             r->headers_out.status = rc;
         }
@@ -1677,8 +1681,8 @@ ngx_http_finalize_request(ngx_http_reque
                 }
 
                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                           "http fast subrequest: \"%V?%V\" done",
-                           &r->uri, &r->args);
+                               "http fast subrequest: \"%V?%V\" done",
+                               &r->uri, &r->args);
                 return;
             }
 
@@ -2112,6 +2116,12 @@ ngx_http_set_keepalive(ngx_http_request_
         hc->nbusy = 0;
     }
 
+#if (NGX_HTTP_SSL)
+    if (c->ssl) {
+        ngx_ssl_free_buffer(c);
+    }
+#endif
+
     rev->handler = ngx_http_keepalive_handler;
 
     if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -430,6 +430,8 @@ struct ngx_http_request_s {
 
     unsigned                          header_timeout_set:1;
 
+    unsigned                          gzip:2;
+
     unsigned                          proxy:1;
     unsigned                          bypass_cache:1;
     unsigned                          no_cache:1;
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -976,7 +976,8 @@ ngx_http_script_file_code(ngx_http_scrip
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     of.test_dir = 0;
-    of.retest = clcf->open_file_cache_retest;
+    of.valid = clcf->open_file_cache_valid;
+    of.min_uses = clcf->open_file_cache_min_uses;
     of.errors = clcf->open_file_cache_errors;
     of.events = clcf->open_file_cache_events;
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2123,7 +2123,9 @@ ngx_http_upstream_store(ngx_http_request
     ngx_str_t        *temp, path, *last_modified;
     ngx_temp_file_t  *tf;
 
-    if (u->pipe->temp_file->file.fd == NGX_INVALID_FILE) {
+    tf = u->pipe->temp_file;
+
+    if (tf->file.fd == NGX_INVALID_FILE) {
 
         /* create file for empty 200 response */
 
@@ -2148,7 +2150,7 @@ ngx_http_upstream_store(ngx_http_request
         u->pipe->temp_file = tf;
     }
 
-    temp = &u->pipe->temp_file->file.name;
+    temp = &tf->file.name;
 
 #if !(NGX_WIN32)
 
@@ -2171,9 +2173,7 @@ ngx_http_upstream_store(ngx_http_request
         lm = ngx_http_parse_time(last_modified->data, last_modified->len);
 
         if (lm != NGX_ERROR) {
-            if (ngx_set_file_time(temp->data, u->pipe->temp_file->file.fd, lm)
-                != NGX_OK)
-            {
+            if (ngx_set_file_time(temp->data, tf->file.fd, lm) != NGX_OK) {
                 err = ngx_errno;
                 failed = ngx_set_file_time_n;
                 name = temp->data;
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -29,6 +29,7 @@ static void ngx_mail_smtp_log_rejected_c
 
 static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
 static u_char  smtp_bye[] = "221 2.0.0 Bye" CRLF;
+static u_char  smtp_starttls[] = "220 2.0.0 Start TLS" CRLF;
 static u_char  smtp_next[] = "334 " CRLF;
 static u_char  smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
 static u_char  smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
@@ -250,6 +251,8 @@ ngx_mail_smtp_auth_state(ngx_event_t *re
 
             case NGX_SMTP_STARTTLS:
                 rc = ngx_mail_smtp_starttls(s, c);
+                s->out.len = sizeof(smtp_starttls) - 1;
+                s->out.data = smtp_starttls;
                 break;
 
             default:
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -208,10 +208,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
                           |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
 
     ngx_conf_merge_str_value(conf->certificate, prev->certificate,
-                             NGX_DEFLAUT_CERTIFICATE);
+                         NGX_DEFLAUT_CERTIFICATE);
 
     ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
-                             NGX_DEFLAUT_CERTIFICATE_KEY);
+                         NGX_DEFLAUT_CERTIFICATE_KEY);
 
     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS);
 
@@ -261,8 +261,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
     }
 
     ngx_conf_merge_value(conf->builtin_session_cache,
-                         prev->builtin_session_cache,
-                         NGX_SSL_DFLT_BUILTIN_SCACHE);
+                         prev->builtin_session_cache, NGX_SSL_NO_SCACHE);
 
     if (conf->shm_zone == NULL) {
         conf->shm_zone = prev->shm_zone;
@@ -294,6 +293,11 @@ ngx_mail_ssl_session_cache(ngx_conf_t *c
 
     for (i = 1; i < cf->args->nelts; i++) {
 
+        if (ngx_strcmp(value[i].data, "off") == 0) {
+            scf->builtin_session_cache = NGX_SSL_NO_SCACHE;
+            continue;
+        }
+
         if (ngx_strcmp(value[i].data, "builtin") == 0) {
             scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
             continue;
--- a/src/os/unix/ngx_freebsd.h
+++ b/src/os/unix/ngx_freebsd.h
@@ -11,13 +11,14 @@
 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
     off_t limit);
 
-extern int     ngx_freebsd_kern_osreldate;
-extern int     ngx_freebsd_hw_ncpu;
-extern u_long  ngx_freebsd_net_inet_tcp_sendspace;
-extern int     ngx_freebsd_kern_ipc_zero_copy_send;
+extern int         ngx_freebsd_kern_osreldate;
+extern int         ngx_freebsd_hw_ncpu;
+extern u_long      ngx_freebsd_net_inet_tcp_sendspace;
+extern int         ngx_freebsd_kern_ipc_zero_copy_send;
 
-extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug;
-extern ngx_uint_t ngx_freebsd_use_tcp_nopush;
+extern ngx_uint_t  ngx_freebsd_sendfile_nbytes_bug;
+extern ngx_uint_t  ngx_freebsd_use_tcp_nopush;
+extern ngx_uint_t  ngx_freebsd_debug_malloc;
 
 
 #endif /* _NGX_FREEBSD_H_INCLUDED_ */
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -23,8 +23,9 @@ int     ngx_freebsd_machdep_hlt_logical_
 int     ngx_freebsd_kern_ipc_zero_copy_send;
 
 
-ngx_uint_t ngx_freebsd_sendfile_nbytes_bug;
-ngx_uint_t ngx_freebsd_use_tcp_nopush;
+ngx_uint_t  ngx_freebsd_sendfile_nbytes_bug;
+ngx_uint_t  ngx_freebsd_use_tcp_nopush;
+ngx_uint_t  ngx_freebsd_debug_malloc;
 
 
 static ngx_os_io_t ngx_freebsd_io = {
@@ -86,6 +87,16 @@ ngx_debug_init()
     malloc_options = "J";
 #endif
 
+    ngx_freebsd_debug_malloc = 1;
+
+#else
+    char  *mo;
+
+    mo = getenv("MALLOC_OPTIONS");
+
+    if (mo && ngx_strchr(mo, 'J')) {
+        ngx_freebsd_debug_malloc = 1;
+    }
 #endif
 }