changeset 418:c65888a079bf

Merge with current.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 18 Sep 2008 15:59:08 +0400
parents 2f3f9dbf84d0 (current diff) b453a4324c60 (diff)
children cdd5890b5538
files auto/modules auto/sources src/http/ngx_http_request.h src/os/unix/ngx_types.h
diffstat 73 files changed, 1666 insertions(+), 670 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -198,3 +198,9 @@ 34fb3a5735483bd22e77f90f305103307a813fc4
 05981f639d211e316c98ff3074a0f268fbde8bed NGINX_0_7_9
 349057ecf4d5d2886b08e6c61656548577243141 NGINX_0_7_10
 9d81578d04bbc73636567e84ed5a48e86826eb1b NGINX_0_7_11
+6ebbca3d5ed73b82e1e0aa14adff133b50bbb4ea NGINX_0_7_12
+df7b79c859c361542f840721db02f2183471c834 NGINX_0_7_13
+a094317ba3074c6d71215c39b02a0e027ae1bd79 NGINX_0_7_14
+79c5df00501e08b14b9457873e691c74059e7519 NGINX_0_7_15
+a2a3905c04abe7ff22d33176682cdba5eb6cf186 NGINX_0_7_16
+a8e3f1441eec1b608b77f39110e16f0b82b983d5 NGINX_0_7_17
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,87 @@
 
+Changes with nginx 0.7.17                                        15 Sep 2008
+
+    *) Feature: now the "directio" directive works on Linux.
+
+    *) Feature: the $pid variable.
+
+    *) Bugfix: the "directio" optimization that had appeared in 0.7.15 did 
+       not work with open_file_cache.
+
+    *) Bugfix: the "access_log" with variables did not work on Linux; the 
+       bug had appeared in 0.7.7.
+
+    *) Bugfix: the ngx_http_charset_module did not understand quoted 
+       charset name received from backend.
+
+
+Changes with nginx 0.7.16                                        08 Sep 2008
+
+    *) Bugfix: nginx could not be built on 64-bit platforms; the bug had 
+       appeared in 0.7.15.
+
+
+Changes with nginx 0.7.15                                        08 Sep 2008
+
+    *) Feature: the ngx_http_random_index_module.
+
+    *) Feature: the "directio" directive has been optimized for file 
+       requests starting from arbitrary position.
+
+    *) Feature: the "directio" directive turns off sendfile if it is 
+       necessary.
+
+    *) Feature: now nginx allows underscores in a client request header 
+       line names.
+
+
+Changes with nginx 0.7.14                                        01 Sep 2008
+
+    *) Change: now the ssl_certificate and ssl_certificate_key directives 
+       have not default values.
+
+    *) Feature: the "listen" directive supports the "ssl" parameter.
+
+    *) Feature: now nginx takes into account a time zone change while 
+       reconfiguration on FreeBSD and Linux.
+
+    *) Bugfix: the "listen" directive parameters such as "backlog", 
+       "rcvbuf", etc. were not set, if a default server was not the first 
+       one.
+
+    *) Bugfix: if URI part captured by a "rewrite" directive was used as a 
+       query string, then the query string was not escaped.
+
+    *) Bugfix: configuration file validity test improvements.
+
+
+Changes with nginx 0.7.13                                        26 Aug 2008
+
+    *) Bugfix: nginx could not be built on Linux and Solaris; the bug had 
+       appeared in 0.7.12.
+
+
+Changes with nginx 0.7.12                                        26 Aug 2008
+
+    *) Feature: the "server_name" directive supports empty name "".
+
+    *) Feature: the "gzip_disable" directive supports special "msie6" mask.
+
+    *) Bugfix: if the "max_fails=0" parameter was used in upstream with 
+       several servers, then a worker process exited on a SIGFPE signal.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a request body was dropped while redirection via an 
+       "error_page" directive.
+
+    *) Bugfix: a full response was returned for request method HEAD while 
+       redirection via an "error_page" directive.
+
+    *) Bugfix: the $r->header_in() method did not return value of the 
+       "Host", "User-Agent", and "Connection" request header lines; the bug 
+       had appeared in 0.7.0.
+
+
 Changes with nginx 0.7.11                                        18 Aug 2008
 
     *) Change: now ngx_http_charset_module does not work by default with 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,90 @@
 
+Изменения в nginx 0.7.17                                          15.09.2008
+
+    *) Добавление: директива directio теперь работает на Linux.
+
+    *) Добавление: переменная $pid.
+
+    *) Исправление: оптимизация directio, появившаяся в 0.7.15, не работала 
+       при использовании open_file_cache.
+
+    *) Исправление: access_log с переменными не работал на Linux; ошибка 
+       появилась в 0.7.7.
+
+    *) Исправление: модуль ngx_http_charset_module не понимал название 
+       кодировки в кавычках, полученное от бэкенда.
+
+
+Изменения в nginx 0.7.16                                          08.09.2008
+
+    *) Исправление: nginx не собирался на 64-битных платформах; ошибка 
+       появилась в 0.7.15.
+
+
+Изменения в nginx 0.7.15                                          08.09.2008
+
+    *) Добавление: модуль ngx_http_random_index_module.
+
+    *) Добавление: директива directio оптимизирована для запросов файлов, 
+       начинающихся с произвольной позиции.
+
+    *) Добавление: директива directio при необходимости запрещает 
+       использование sendfile.
+
+    *) Добавление: теперь nginx разрешает подчёркивания в именах строк в 
+       заголовке запроса клиента.
+
+
+Изменения в nginx 0.7.14                                          01.09.2008
+
+    *) Изменение: теперь директивы ssl_certificate и ssl_certificate_key не 
+       имеют значений по умолчанию.
+
+    *) Добавление: директива listen поддерживает параметр ssl.
+
+    *) Добавление: теперь при переконфигурации nginx учитывает изменение 
+       временной зоны на FreeBSD и Linux.
+
+    *) Исправление: параметры директивы listen, такие как backlog, rcvbuf и 
+       прочие, не устанавливались, если сервером по умолчанию был не первый 
+       сервер.
+
+    *) Исправление: при использовании в качестве аргументов части URI, 
+       выделенного с помощью директивы rewrite, эти аргументы не 
+       экранировались.
+
+    *) Исправление: улучшения тестирования правильности конфигурационного 
+       файла.
+
+
+Изменения в nginx 0.7.13                                          26.08.2008
+
+    *) Исправление: nginx не собирался на Linux и Solaris; ошибка появилась 
+       в 0.7.12.
+
+
+Изменения в nginx 0.7.12                                          26.08.2008
+
+    *) Добавление: директива server_name поддерживает пустое имя "".
+
+    *) Добавление: директива gzip_disable поддерживает специальную маску 
+       msie6.
+
+    *) Исправление: при использовании параметра max_fails=0 в upstream'е с 
+       несколькими серверами рабочий процесс выходил по сигналу SIGFPE.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: при перенаправлении запроса с помощью директивы 
+       error_page терялось тело запроса.
+
+    *) Исправление: при перенаправлении запроса с методом HEAD с помощью 
+       директивы error_page возвращался полный ответ.
+
+    *) Исправление: метод $r->header_in() не возвращал значения строк 
+       "Host", "User-Agent", и "Connection" из заголовка запроса; ошибка 
+       появилась в 0.7.0.
+
+
 Изменения в nginx 0.7.11                                          18.08.2008
 
     *) Изменение: теперь ngx_http_charset_module по умолчанию не работает 
--- a/auto/modules
+++ b/auto/modules
@@ -81,6 +81,7 @@ fi
 #     ngx_http_dav_module
 #     ngx_http_autoindex_module
 #     ngx_http_index_module
+#     ngx_http_random_index_module
 #
 #     ngx_http_access_module
 #     ngx_http_realip_module
@@ -179,6 +180,12 @@ fi
 
 HTTP_MODULES="$HTTP_MODULES $HTTP_INDEX_MODULE"
 
+if [ $HTTP_RANDOM_INDEX = YES ]; then
+    have=NGX_HTTP_RANDOM_INDEX . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_RANDOM_INDEX_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS"
+fi
+
 if [ $HTTP_AUTH_BASIC = YES ]; then
     have=NGX_HTTP_AUTH_BASIC . auto/have
     have=NGX_CRYPT . auto/have
--- a/auto/options
+++ b/auto/options
@@ -64,6 +64,7 @@ HTTP_ACCESS=YES
 HTTP_AUTH_BASIC=YES
 HTTP_USERID=YES
 HTTP_AUTOINDEX=YES
+HTTP_RANDOM_INDEX=NO
 HTTP_STATUS=NO
 HTTP_GEO=YES
 HTTP_MAP=YES
@@ -171,6 +172,7 @@ do
         --with-http_dav_module)          HTTP_DAV=YES               ;;
         --with-http_flv_module)          HTTP_FLV=YES               ;;
         --with-http_gzip_static_module)  HTTP_GZIP_STATIC=YES       ;;
+        --with-http_random_index_module) HTTP_RANDOM_INDEX=YES      ;;
 
         --without-http_charset_module)   HTTP_CHARSET=NO            ;;
         --without-http_gzip_module)      HTTP_GZIP=NO               ;;
@@ -287,6 +289,7 @@ cat << END
   --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_random_index_module    enable ngx_http_random_index_module
   --with-http_stub_status_module     enable ngx_http_stub_status_module
 
   --without-http_charset_module      disable ngx_http_charset_module
--- a/auto/os/features
+++ b/auto/os/features
@@ -182,6 +182,10 @@ ngx_feature_test="fcntl(0, F_SETFL, O_DI
 . auto/feature
 
 
+if [ $ngx_found = yes -a "$NGX_SYSTEM" = "Linux" ]; then
+    have=NGX_HAVE_ALIGNED_DIRECTIO . auto/have
+fi
+
 ngx_feature="F_NOCACHE"
 ngx_feature_name="NGX_HAVE_F_NOCACHE"
 ngx_feature_run=no
--- a/auto/sources
+++ b/auto/sources
@@ -131,7 +131,6 @@ UNIX_INCS="$CORE_INCS $EVENT_INCS src/os
 
 UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/unix/ngx_time.h \
-            src/os/unix/ngx_types.h \
             src/os/unix/ngx_errno.h \
             src/os/unix/ngx_alloc.h \
             src/os/unix/ngx_files.h \
@@ -208,7 +207,6 @@ WIN32_INCS="$CORE_INCS $EVENT_INCS src/o
 WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/win32/ngx_win32_config.h \
             src/os/win32/ngx_time.h \
-            src/os/win32/ngx_types.h \
             src/os/win32/ngx_errno.h \
             src/os/win32/ngx_alloc.h \
             src/os/win32/ngx_files.h \
@@ -369,6 +367,10 @@ HTTP_AUTOINDEX_MODULE=ngx_http_autoindex
 HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c
 
 
+HTTP_RANDOM_INDEX_MODULE=ngx_http_random_index_module
+HTTP_RANDOM_INDEX_SRCS=src/http/modules/ngx_http_random_index_module.c
+
+
 HTTP_STATUS_MODULE=ngx_http_status_module
 HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_module.c
 
--- a/auto/unix
+++ b/auto/unix
@@ -229,3 +229,23 @@ ngx_feature_path=
 ngx_feature_libs=
 ngx_feature_test="struct tm  tm; tm.tm_gmtoff = 0"
 . auto/feature
+
+
+ngx_feature="struct dirent.d_namlen"
+ngx_feature_name="NGX_HAVE_D_NAMLEN"
+ngx_feature_run=no
+ngx_feature_incs="#include <dirent.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="struct dirent  dir; dir.d_namlen = 0"
+. auto/feature
+
+
+ngx_feature="struct dirent.d_type"
+ngx_feature_name="NGX_HAVE_D_TYPE"
+ngx_feature_run=no
+ngx_feature_incs="#include <dirent.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="struct dirent  dir; dir.d_type = DT_REG"
+. auto/feature
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -33,6 +33,8 @@ types {
     application/vnd.ms-powerpoint         ppt;
     application/vnd.wap.wmlc              wmlc;
     application/vnd.wap.xhtml+xml         xhtml;
+    application/vnd.google-earth.kml+xml  kml;
+    application/vnd.google-earth.kmz      kmz;
     application/x-cocoa                   cco;
     application/x-java-archive-diff       jardiff;
     application/x-java-jnlp-file          jnlp;
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <nginx.h>
 
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.7.11"
+#define NGINX_VERSION      "0.7.17"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -78,6 +78,10 @@ typedef struct {
     ngx_chain_t                 *busy;
 
     unsigned                     sendfile;
+    unsigned                     directio;
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+    unsigned                     unaligned;
+#endif
     unsigned                     need_in_memory;
     unsigned                     need_in_temp;
 
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -7,6 +7,7 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 
+#define NGX_CONF_BUFFER  4096
 
 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
@@ -43,9 +44,9 @@ ngx_module_t  ngx_conf_module = {
 };
 
 
-/* The ten fixed arguments */
+/* The eight fixed arguments */
 
-static int argument_number[] = {
+static ngx_uint_t argument_number[] = {
     NGX_CONF_NOARGS,
     NGX_CONF_TAKE1,
     NGX_CONF_TAKE2,
@@ -141,14 +142,14 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
 
         cf->conf_file->buffer = b;
 
-        b->start = ngx_alloc(ngx_pagesize, cf->log);
+        b->start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
         if (b->start == NULL) {
             return NGX_CONF_ERROR;
         }
 
         b->pos = b->start;
         b->last = b->start;
-        b->end = b->last + ngx_pagesize;
+        b->end = b->last + NGX_CONF_BUFFER;
         b->temporary = 1;
 
         cf->conf_file->file.fd = fd;
@@ -433,10 +434,11 @@ static ngx_int_t
 ngx_conf_read_token(ngx_conf_t *cf)
 {
     u_char      *start, ch, *src, *dst;
-    int          len;
-    int          found, need_space, last_space, sharp_comment, variable;
-    int          quoted, s_quoted, d_quoted;
-    ssize_t      n;
+    off_t        file_size;
+    size_t       len;
+    ssize_t      n, size;
+    ngx_uint_t   found, need_space, last_space, sharp_comment, variable;
+    ngx_uint_t   quoted, s_quoted, d_quoted, start_line;
     ngx_str_t   *word;
     ngx_buf_t   *b;
 
@@ -450,14 +452,16 @@ ngx_conf_read_token(ngx_conf_t *cf)
     cf->args->nelts = 0;
     b = cf->conf_file->buffer;
     start = b->pos;
+    start_line = cf->conf_file->line;
+
+    file_size = ngx_file_size(&cf->conf_file->file.info);
 
     for ( ;; ) {
 
         if (b->pos >= b->last) {
 
-            if (cf->conf_file->file.offset
-                                 >= ngx_file_size(&cf->conf_file->file.info))
-            {
+            if (cf->conf_file->file.offset >= file_size) {
+
                 if (cf->args->nelts > 0) {
 
                     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
@@ -476,22 +480,58 @@ ngx_conf_read_token(ngx_conf_t *cf)
                 return NGX_CONF_FILE_DONE;
             }
 
-            if (b->pos - start) {
-                ngx_memcpy(b->start, start, b->pos - start);
+            len = b->pos - start;
+
+            if (len == NGX_CONF_BUFFER) {
+                cf->conf_file->line = start_line;
+
+                if (d_quoted) {
+                    ch = '"';
+
+                } else if (s_quoted) {
+                    ch = '\'';
+
+                } else {
+                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                       "too long parameter \"%*s...\" started",
+                                       10, start);
+                    return NGX_ERROR;
+                }
+
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "too long parameter, probably "
+                                   "missing terminating \"%c\" character", ch);
+                return NGX_ERROR;
             }
 
-            n = ngx_read_file(&cf->conf_file->file,
-                              b->start + (b->pos - start),
-                              b->end - (b->start + (b->pos - start)),
+            if (len) {
+                ngx_memcpy(b->start, start, len);
+            }
+
+            size = (ssize_t) (file_size - cf->conf_file->file.offset);
+
+            if (size > b->end - (b->start + len)) {
+                size = b->end - (b->start + len);
+            }
+
+            n = ngx_read_file(&cf->conf_file->file, b->start + len, size,
                               cf->conf_file->file.offset);
 
             if (n == NGX_ERROR) {
                 return NGX_ERROR;
             }
 
-            b->pos = b->start + (b->pos - start);
+            if (n != size) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   ngx_read_file_n " returned "
+                                   "only %z bytes instead of %z",
+                                   n, size);
+                return NGX_ERROR;
+            }
+
+            b->pos = b->start + len;
+            b->last = b->pos + n;
             start = b->start;
-            b->last = b->pos + n;
         }
 
         ch = *b->pos++;
@@ -545,6 +585,7 @@ ngx_conf_read_token(ngx_conf_t *cf)
             }
 
             start = b->pos - 1;
+            start_line = cf->conf_file->line;
 
             switch (ch) {
 
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -314,9 +314,6 @@ char *ngx_conf_check_num_bounds(ngx_conf
     }
 
 
-#define addressof(addr)  ((int) &addr)
-
-
 char *ngx_conf_param(ngx_conf_t *cf);
 char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename);
 
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -116,10 +116,6 @@ typedef intptr_t        ngx_flag_t;
 #define INADDR_NONE  ((unsigned int) -1)
 #endif
 
-#ifndef INET_ADDRSTRLEN  /* Win32 */
-#define INET_ADDRSTRLEN  16
-#endif
-
 #ifdef MAXHOSTNAMELEN
 #define NGX_MAXHOSTNAMELEN  MAXHOSTNAMELEN
 #else
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -37,23 +37,23 @@ ngx_listening_inet_stream_socket(ngx_con
 
 
     ls->addr_text.data = ngx_pnalloc(cf->pool,
-                                    INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1);
+                                    NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1);
     if (ls->addr_text.data == NULL) {
         return NULL;
     }
 
-    len = ngx_inet_ntop(AF_INET, &addr, ls->addr_text.data, INET_ADDRSTRLEN);
+    len = ngx_inet_ntop(AF_INET, &addr, ls->addr_text.data,
+                        NGX_INET_ADDRSTRLEN);
 
     ls->addr_text.len = ngx_sprintf(ls->addr_text.data + len, ":%d", port)
                         - ls->addr_text.data;
 
     ls->fd = (ngx_socket_t) -1;
-    ls->family = AF_INET;
     ls->type = SOCK_STREAM;
     ls->sockaddr = (struct sockaddr *) sin;
     ls->socklen = sizeof(struct sockaddr_in);
     ls->addr = offsetof(struct sockaddr_in, sin_addr);
-    ls->addr_text_max_len = INET_ADDRSTRLEN;
+    ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
 
     return ls;
 }
@@ -104,17 +104,16 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
             continue;
         }
 
-        ls[i].addr_text_max_len = INET_ADDRSTRLEN;
+        ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
 
         ls[i].addr_text.data = ngx_pnalloc(cycle->pool,
-                                   INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1);
+                                   NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1);
         if (ls[i].addr_text.data == NULL) {
             return NGX_ERROR;
         }
 
-        ls[i].family = sin->sin_family;
-        len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr,
-                            ls[i].addr_text.data, INET_ADDRSTRLEN);
+        len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data,
+                            NGX_INET_ADDRSTRLEN);
         if (len == 0) {
             return NGX_ERROR;
         }
@@ -254,7 +253,7 @@ ngx_open_listening_sockets(ngx_cycle_t *
                 continue;
             }
 
-            s = ngx_socket(ls[i].family, ls[i].type, 0);
+            s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
 
             if (s == -1) {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -23,7 +23,6 @@ struct ngx_listening_s {
     size_t              addr_text_max_len;
     ngx_str_t           addr_text;
 
-    int                 family;
     int                 type;
 
     int                 backlog;
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -40,11 +40,11 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_rbtree.h>
 #include <ngx_time.h>
 #include <ngx_socket.h>
-#include <ngx_types.h>
+#include <ngx_string.h>
+#include <ngx_files.h>
 #include <ngx_shmem.h>
 #include <ngx_process.h>
 #include <ngx_user.h>
-#include <ngx_string.h>
 #include <ngx_parse.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
@@ -55,7 +55,6 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_list.h>
 #include <ngx_hash.h>
 #include <ngx_file.h>
-#include <ngx_files.h>
 #include <ngx_crc.h>
 #include <ngx_crc32.h>
 #if (NGX_PCRE)
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -47,6 +47,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     u_char              *lock_file;
     ngx_uint_t           i, n;
     ngx_log_t           *log;
+    ngx_time_t          *tp;
     ngx_conf_t           conf;
     ngx_pool_t          *pool;
     ngx_cycle_t         *cycle, **old;
@@ -59,6 +60,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     ngx_core_module_t   *module;
     char                 hostname[NGX_MAXHOSTNAMELEN];
 
+    ngx_timezone_update();
+
+    /* force localtime update with a new timezone */
+
+    tp = ngx_timeofday();
+    tp->sec = 0;
+
+    ngx_time_update(0, 0);
+
+
     log = old_cycle->log;
 
     pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -26,7 +26,8 @@ struct ngx_file_s {
 
     ngx_log_t          *log;
 
-    ngx_uint_t          valid_info;  /* unsigned  valid_info:1; */
+    unsigned            valid_info:1;
+    unsigned            directio:1;
 };
 
 #define NGX_MAX_PATH_LEVEL  3
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -220,6 +220,10 @@ ngx_hash_find_combined(ngx_hash_combined
         }
     }
 
+    if (len == 0) {
+        return NULL;
+    }
+
     if (hash->wc_head && hash->wc_head->hash.buckets) {
         value = ngx_hash_find_wc_head(hash->wc_head, name, len);
 
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -8,7 +8,8 @@
 #include <ngx_core.h>
 
 
-static size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len);
+static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
+static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
 
 
 /* AF_INET only */
@@ -56,166 +57,43 @@ ngx_inet_addr(u_char *text, size_t len)
 }
 
 
-/*
- * ngx_sock_ntop() and ngx_inet_ntop() may be implemented as
- * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", however,
- * they had been implemented long before the ngx_sprintf() had appeared
- * and they are faster by 1.5-2.5 times, so it is worth to keep them.
- *
- * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times
- * than using FreeBSD libc's snprintf().
- */
-
 /* AF_INET only */
 
 size_t
-ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len)
+ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len)
 {
     u_char              *p;
-    size_t               n;
-    ngx_uint_t           i;
     struct sockaddr_in  *sin;
 
-    if (len == 0) {
-        return 0;
-    }
+    if (sa->sa_family == AF_INET) {
 
-    if (family != AF_INET) {
-        return 0;
-    }
+        sin = (struct sockaddr_in *) sa;
+        p = (u_char *) &sin->sin_addr;
 
-    sin = (struct sockaddr_in *) sa;
-    p = (u_char *) &sin->sin_addr;
-
-    if (len > INET_ADDRSTRLEN) {
-        len = INET_ADDRSTRLEN;
+        return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
+                            p[0], p[1], p[2], p[3])
+               - text;
     }
 
-    n = ngx_sprint_uchar(text, p[0], len);
-
-    i = 1;
-
-    do {
-        if (len == n) {
-            text[n - 1] = '\0';
-            return n;
-        }
-
-        text[n++] = '.';
-
-        if (len == n) {
-            text[n - 1] = '\0';
-            return n;
-        }
-
-        n += ngx_sprint_uchar(&text[n], p[i++], len - n);
-
-    } while (i < 4);
-
-    if (len == n) {
-        text[n] = '\0';
-        return n;
-    }
-
-    text[n] = '\0';
-
-    return n;
+    return 0;
 }
 
 
 size_t
 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
 {
-    u_char      *p;
-    size_t       n;
-    ngx_uint_t   i;
-
-    if (len == 0) {
-        return 0;
-    }
+    u_char  *p;
 
-    if (family != AF_INET) {
-        return 0;
-    }
-
-    p = (u_char *) addr;
-
-    if (len > INET_ADDRSTRLEN) {
-        len = INET_ADDRSTRLEN;
-    }
-
-    n = ngx_sprint_uchar(text, p[0], len);
+    if (family == AF_INET) {
 
-    i = 1;
-
-    do {
-        if (len == n) {
-            text[n - 1] = '\0';
-            return n;
-        }
-
-        text[n++] = '.';
+        p = (u_char *) addr;
 
-        if (len == n) {
-            text[n - 1] = '\0';
-            return n;
-        }
-
-        n += ngx_sprint_uchar(&text[n], p[i++], len - n);
-
-    } while (i < 4);
-
-    if (len == n) {
-        text[n] = '\0';
-        return n;
+        return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
+                            p[0], p[1], p[2], p[3])
+               - text;
     }
 
-    text[n] = '\0';
-
-    return n;
-}
-
-
-static size_t
-ngx_sprint_uchar(u_char *text, u_char c, size_t len)
-{
-    size_t      n;
-    ngx_uint_t  c1, c2;
-
-    n = 0;
-
-    if (len == n) {
-        return n;
-    }
-
-    c1 = c / 100;
-
-    if (c1) {
-        *text++ = (u_char) (c1 + '0');
-        n++;
-
-        if (len == n) {
-            return n;
-        }
-    }
-
-    c2 = (c % 100) / 10;
-
-    if (c1 || c2) {
-        *text++ = (u_char) (c2 + '0');
-        n++;
-
-        if (len == n) {
-            return n;
-        }
-    }
-
-    c2 = c % 10;
-
-    *text = (u_char) (c2 + '0');
-    n++;
-
-    return n;
+    return 0;
 }
 
 
@@ -224,43 +102,48 @@ ngx_sprint_uchar(u_char *text, u_char c,
 ngx_int_t
 ngx_ptocidr(ngx_str_t *text, void *cidr)
 {
-    ngx_int_t         m;
-    ngx_uint_t        i;
+    u_char           *addr, *mask, *last;
+    ngx_int_t         shift;
     ngx_inet_cidr_t  *in_cidr;
 
     in_cidr = cidr;
-
-    for (i = 0; i < text->len; i++) {
-        if (text->data[i] == '/') {
-            break;
-        }
-    }
+    addr = text->data;
+    last = addr + text->len;
 
-    if (i == text->len) {
-        return NGX_ERROR;
-    }
+    mask = ngx_strlchr(addr, last, '/');
 
-    text->data[i] = '\0';
-    in_cidr->addr = inet_addr((char *) text->data);
-    text->data[i] = '/';
+    in_cidr->addr = ngx_inet_addr(addr, (mask ? mask : last) - addr);
+
     if (in_cidr->addr == INADDR_NONE) {
         return NGX_ERROR;
     }
 
-    m = ngx_atoi(&text->data[i + 1], text->len - (i + 1));
-    if (m == NGX_ERROR) {
+    if (mask == NULL) {
+        in_cidr->mask = 0xffffffff;
+        return NGX_OK;
+    }
+
+    mask++;
+
+    shift = ngx_atoi(mask, last - mask);
+    if (shift == NGX_ERROR) {
         return NGX_ERROR;
     }
 
-    if (m == 0) {
+    if (shift == 0) {
 
         /* the x86 compilers use the shl instruction that shifts by modulo 32 */
 
         in_cidr->mask = 0;
-        return NGX_OK;
+
+        if (in_cidr->addr == 0) {
+            return NGX_OK;
+        }
+
+        return NGX_DONE;
     }
 
-    in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - m))));
+    in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
 
     if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) {
         return NGX_OK;
@@ -275,85 +158,12 @@ ngx_ptocidr(ngx_str_t *text, void *cidr)
 ngx_int_t
 ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
 {
-    u_char              *p, *host, *port_start;
-    size_t               len, port_len;
-    ngx_int_t            port;
-    ngx_uint_t           i;
-    struct hostent      *h;
-#if (NGX_HAVE_UNIX_DOMAIN)
-    struct sockaddr_un  *saun;
-#endif
+    u_char  *p;
 
-    len = u->url.len;
     p = u->url.data;
 
     if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
-
-#if (NGX_HAVE_UNIX_DOMAIN)
-
-        p += 5;
-        len -= 5;
-
-        u->uri.len = len;
-        u->uri.data = p;
-
-        if (u->uri_part) {
-            for (i = 0; i < len; i++) {
-
-                if (p[i] == ':') {
-                    len = i;
-
-                    u->uri.len -= len + 1;
-                    u->uri.data += len + 1;
-
-                    break;
-                }
-            }
-        }
-
-        if (len == 0) {
-            u->err = "no path in the unix domain socket";
-            return NGX_ERROR;
-        }
-
-        if (len + 1 > sizeof(saun->sun_path)) {
-            u->err = "too long path in the unix domain socket";
-            return NGX_ERROR;
-        }
-
-        u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
-        if (u->addrs == NULL) {
-            return NGX_ERROR;
-        }
-
-        saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
-        if (saun == NULL) {
-            return NGX_ERROR;
-        }
-
-        u->naddrs = 1;
-
-        saun->sun_family = AF_UNIX;
-        (void) ngx_cpystrn((u_char *) saun->sun_path, p, len + 1);
-
-        u->addrs[0].sockaddr = (struct sockaddr *) saun;
-        u->addrs[0].socklen = sizeof(struct sockaddr_un);
-        u->addrs[0].name.len = len + 5;
-        u->addrs[0].name.data = u->url.data;
-
-        u->host.len = len;
-        u->host.data = p;
-
-        u->unix_socket = 1;
-
-        return NGX_OK;
-
-#else
-        u->err = "the unix domain sockets are not supported on this platform";
-
-        return NGX_ERROR;
-
-#endif
+        return ngx_parse_unix_domain_url(pool, u);
     }
 
     if ((p[0] == ':' || p[0] == '/') && !u->listen) {
@@ -361,150 +171,219 @@ ngx_parse_url(ngx_pool_t *pool, ngx_url_
         return NGX_ERROR;
     }
 
-    u->host.data = p;
+    return ngx_parse_inet_url(pool, u);
+}
 
-    port_start = NULL;
-    port_len = 0;
-
-    for (i = 0; i < len; i++) {
 
-        if (p[i] == ':') {
-            port_start = &p[i + 1];
-            u->host.len = i;
-
-            if (!u->uri_part) {
-                port_len = len - (i + 1);
-                break;
-            }
-        }
+static ngx_int_t
+ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
+{
+#if (NGX_HAVE_UNIX_DOMAIN)
+    u_char              *path, *uri, *last;
+    size_t               len;
+    struct sockaddr_un  *saun;
 
-        if (p[i] == '/') {
-            u->uri.len = len - i;
-            u->uri.data = &p[i];
+    len = u->url.len;
+    path = u->url.data;
 
-            if (u->host.len == 0) {
-                u->host.len = i;
-            }
+    path += 5;
+    len -= 5;
+
+    if (u->uri_part) {
 
-            if (port_start == NULL) {
-                u->no_port = 1;
-                goto no_port;
-            }
-
-            port_len = &p[i] - port_start;
+        last = path + len;
+        uri = ngx_strlchr(path, last, ':');
 
-            if (port_len == 0) {
-                u->err = "invalid port";
-                return NGX_ERROR;
-            }
-
-            break;
+        if (uri) {
+            len = uri - path;
+            uri++;
+            u->uri.len = last - uri;
+            u->uri.data = uri;
         }
     }
 
-    if (port_start) {
+    if (len == 0) {
+        u->err = "no path in the unix domain socket";
+        return NGX_ERROR;
+    }
+
+    u->host.len = len++;
+    u->host.data = path;
+    u->family = AF_UNIX;
+
+    if (len > sizeof(saun->sun_path)) {
+        u->err = "too long path in the unix domain socket";
+        return NGX_ERROR;
+    }
 
-        if (port_len == 0) {
-            port_len = &p[i] - port_start;
+    u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
+    if (u->addrs == NULL) {
+        return NGX_ERROR;
+    }
+
+    saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
+    if (saun == NULL) {
+        return NGX_ERROR;
+    }
+
+    u->naddrs = 1;
+
+    saun->sun_family = AF_UNIX;
+    (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
+
+    u->addrs[0].sockaddr = (struct sockaddr *) saun;
+    u->addrs[0].socklen = sizeof(struct sockaddr_un);
+    u->addrs[0].name.len = len + 4;
+    u->addrs[0].name.data = u->url.data;
 
-            if (port_len == 0) {
-                u->err = "invalid port";
-                return NGX_ERROR;
-            }
+    return NGX_OK;
+
+#else
+
+    u->err = "the unix domain sockets are not supported on this platform";
+
+    return NGX_ERROR;
+
+#endif
+}
+
+
+static ngx_int_t
+ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
+{
+    u_char          *p, *host, *port, *last, *uri;
+    size_t           len;
+    ngx_int_t        n;
+    struct hostent  *h;
+
+    u->family = AF_INET;
+
+    host = u->url.data;
+
+    last = host + u->url.len;
+
+    port = ngx_strlchr(host, last, ':');
+
+    uri = ngx_strlchr(port ? port : host, last, '/');
+
+    if (uri) {
+        if (u->listen || !u->uri_part) {
+            u->err = "invalid host";
+            return NGX_ERROR;
         }
 
-        port = ngx_atoi(port_start, port_len);
+        u->uri.len = last - uri;
+        u->uri.data = uri;
+
+        last = uri;
+    }
 
-        if (port == NGX_ERROR || port < 1 || port > 65536) {
+    if (port) {
+        port++;
+
+        len = last - port;
+
+        if (len == 0) {
             u->err = "invalid port";
             return NGX_ERROR;
         }
 
-        u->port_text.len = port_len;
-        u->port_text.data = port_start;
-
-    } else {
-        port = ngx_atoi(p, len);
-
-        if (port == NGX_ERROR) {
-            u->host.len = len;
-            u->no_port = 1;
-
-            goto no_port;
-        }
-
-        u->wildcard = 1;
-    }
+        n = ngx_atoi(port, len);
 
-    u->port = (in_port_t) port;
-
-no_port:
-
-    if (u->listen) {
-
-        if (u->port == 0) {
-            if (u->default_port == 0) {
-                u->err = "no port";
-                return NGX_ERROR;
-            }
-
-            u->port = u->default_port;
-        }
-
-        if (u->host.len == 1 && u->host.data[0] == '*') {
-            u->host.len = 0;
+        if (n < 1 || n > 65536) {
+            u->err = "invalid port";
+            return NGX_ERROR;
         }
 
-        /* AF_INET only */
+        u->port = (in_port_t) n;
 
-        if (u->host.len) {
+        u->port_text.len = len;
+        u->port_text.data = port;
+
+        last = port - 1;
 
-            host = ngx_alloc(u->host.len + 1, pool->log);
-            if (host == NULL) {
-                return NGX_ERROR;
-            }
+    } else {
+        if (uri == NULL) {
 
-            (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+            if (u->listen) {
 
-            u->addr.in_addr = inet_addr((const char *) host);
+                /* test value as port only */
+
+                n = ngx_atoi(host, last - host);
 
-            if (u->addr.in_addr == INADDR_NONE) {
-                h = gethostbyname((const char *) host);
+                if (n != NGX_ERROR) {
+
+                    if (n < 1 || n > 65536) {
+                        u->err = "invalid port";
+                        return NGX_ERROR;
+                    }
 
-                if (h == NULL || h->h_addr_list[0] == NULL) {
-                    ngx_free(host);
-                    u->err = "host not found";
-                    return NGX_ERROR;
+                    u->port = (in_port_t) n;
+
+                    u->port_text.len = last - host;
+                    u->port_text.data = host;
+
+                    return NGX_OK;
                 }
-
-                u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
             }
-
-            ngx_free(host);
-
-        } else {
-            u->addr.in_addr = INADDR_ANY;
         }
 
-        return NGX_OK;
+        u->no_port = 1;
     }
 
-    if (u->host.len == 0) {
+    len = last - host;
+
+    if (len == 0) {
         u->err = "no host";
         return NGX_ERROR;
     }
 
+    if (len == 1 && *host == '*') {
+        len = 0;
+    }
+
+    u->host.len = len;
+    u->host.data = host;
+
     if (u->no_resolve) {
         return NGX_OK;
     }
 
+    if (len++) {
+
+        p = ngx_alloc(len, pool->log);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        (void) ngx_cpystrn(p, host, len);
+
+        u->addr.in_addr = inet_addr((const char *) p);
+
+        if (u->addr.in_addr == INADDR_NONE) {
+            h = gethostbyname((const char *) p);
+
+            if (h == NULL || h->h_addr_list[0] == NULL) {
+                ngx_free(p);
+                u->err = "host not found";
+                return NGX_ERROR;
+            }
+
+            u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
+        }
+
+        ngx_free(p);
+
+    } else {
+        u->addr.in_addr = INADDR_ANY;
+    }
+
     if (u->no_port) {
         u->port = u->default_port;
     }
 
-    if (u->port == 0) {
-        u->err = "no port";
-        return NGX_ERROR;
+    if (u->listen) {
+        return NGX_OK;
     }
 
     if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
@@ -576,14 +455,14 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
             u->addrs[i].sockaddr = (struct sockaddr *) sin;
             u->addrs[i].socklen = sizeof(struct sockaddr_in);
 
-            len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1;
+            len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
 
             p = ngx_pnalloc(pool, len);
             if (p == NULL) {
                 return NGX_ERROR;
             }
 
-            len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, p, len);
+            len = ngx_sock_ntop((struct sockaddr *) sin, p, len);
 
             u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p;
             u->addrs[i].name.data = p;
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -12,6 +12,9 @@
 #include <ngx_core.h>
 
 
+#define NGX_INET_ADDRSTRLEN  (sizeof("255.255.255.255") - 1)
+
+
 typedef struct {
     in_addr_t         addr;
     in_addr_t         mask;
@@ -31,8 +34,6 @@ typedef struct {
 
 
 typedef struct {
-    ngx_int_t         type;
-
     ngx_str_t         url;
     ngx_str_t         host;
     ngx_str_t         port_text;
@@ -40,15 +41,14 @@ typedef struct {
 
     in_port_t         port;
     in_port_t         default_port;
+    int               family;
 
     unsigned          listen:1;
     unsigned          uri_part:1;
     unsigned          no_resolve:1;
     unsigned          one_addr:1;
 
-    unsigned          wildcard:1;
     unsigned          no_port:1;
-    unsigned          unix_socket:1;
 
     ngx_url_addr_t    addr;
 
@@ -60,7 +60,7 @@ typedef struct {
 
 
 in_addr_t ngx_inet_addr(u_char *text, size_t len);
-size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len);
+size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len);
 size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
 ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr);
 ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u);
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -205,6 +205,7 @@ ngx_open_cached_file(ngx_open_file_cache
                 of->is_file = file->is_file;
                 of->is_link = file->is_link;
                 of->is_exec = file->is_exec;
+                of->is_directio = file->is_directio;
 
                 if (!file->is_dir) {
                     file->count++;
@@ -360,6 +361,7 @@ update:
         file->is_file = of->is_file;
         file->is_link = of->is_link;
         file->is_exec = of->is_exec;
+        file->is_directio = of->is_directio;
 
         if (!of->is_dir) {
             file->count++;
@@ -499,9 +501,12 @@ ngx_open_and_stat_file(u_char *name, ngx
         of->fd = fd;
 
         if (of->directio <= ngx_file_size(&fi)) {
-            if (ngx_directio(fd) == -1) {
+            if (ngx_directio_on(fd) == -1) {
                 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                              ngx_directio_n " \"%s\" failed", name);
+                              ngx_directio_on_n " \"%s\" failed", name);
+
+            } else {
+                of->is_directio = 1;
             }
         }
     }
--- a/src/core/ngx_open_file_cache.h
+++ b/src/core/ngx_open_file_cache.h
@@ -33,6 +33,7 @@ typedef struct {
     unsigned                 is_file:1;
     unsigned                 is_link:1;
     unsigned                 is_exec:1;
+    unsigned                 is_directio:1;
 } ngx_open_file_info_t;
 
 
@@ -62,6 +63,7 @@ struct ngx_cached_open_file_s {
     unsigned                 is_file:1;
     unsigned                 is_link:1;
     unsigned                 is_exec:1;
+    unsigned                 is_directio:1;
 
     ngx_event_t             *event;
 };
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -18,21 +18,21 @@
 
 
 static ngx_inline ngx_int_t
-    ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
+    ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
 static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
     ngx_chain_t **chain, ngx_chain_t *in);
-static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
-    ngx_uint_t sendfile);
+static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx,
+    off_t bsize);
+static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx,
+    off_t bsize);
+static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx);
 
 
 ngx_int_t
 ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
 {
     off_t         bsize;
-    size_t        size;
     ngx_int_t     rc, last;
-    ngx_uint_t    recycled;
-    ngx_buf_t    *b;
     ngx_chain_t  *cl, *out, **last_out;
 
     if (ctx->in == NULL && ctx->busy == NULL) {
@@ -51,7 +51,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 #if (NGX_SENDFILE_LIMIT)
             && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
 #endif
-            && !ngx_output_chain_need_to_copy(ctx, in->buf))
+            && ngx_output_chain_as_is(ctx, in->buf))
         {
             return ctx->output_filter(ctx->filter_ctx, in);
         }
@@ -75,7 +75,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
             /*
              * cycle while there are the ctx->in bufs
-             * or there are the free output bufs to copy in
+             * and there are the free output bufs to copy in
              */
 
             bsize = ngx_buf_size(ctx->in->buf);
@@ -102,7 +102,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
                 continue;
             }
 
-            if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) {
+            if (ngx_output_chain_as_is(ctx, ctx->in->buf)) {
 
                 /* move the chain link to the output chain */
 
@@ -118,79 +118,35 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
             if (ctx->buf == NULL) {
 
-                /* get the free buf */
+                rc = ngx_output_chain_align_file_buf(ctx, bsize);
 
-                if (ctx->free) {
-                    cl = ctx->free;
-                    ctx->buf = cl->buf;
-                    ctx->free = cl->next;
-                    ngx_free_chain(ctx->pool, cl);
-
-                } else if (out || ctx->allocated == ctx->bufs.num) {
+                if (rc == NGX_ERROR) {
+                    return NGX_ERROR;
+                }
 
-                    break;
-
-                } else {
+                if (rc != NGX_OK) {
 
-                    size = ctx->bufs.size;
-                    recycled = 1;
+                    if (ctx->free) {
 
-                    if (ctx->in->buf->last_in_chain) {
-
-                        if (bsize < (off_t) ctx->bufs.size) {
+                        /* get the free buf */
 
-                           /*
-                            * allocate small temp buf for the small last buf
-                            * or its small last part
-                            */
+                        cl = ctx->free;
+                        ctx->buf = cl->buf;
+                        ctx->free = cl->next;
 
-                            size = (size_t) bsize;
-                            recycled = 0;
+                        ngx_free_chain(ctx->pool, cl);
 
-                        } else if (ctx->bufs.num == 1
-                                   && (bsize < (off_t) (ctx->bufs.size
-                                                     + (ctx->bufs.size >> 2))))
-                        {
-                            /*
-                             * allocate a temp buf that equals
-                             * to the last buf if the last buf size is lesser
-                             * than 1.25 of bufs.size and a temp buf is single
-                             */
+                    } else if (out || ctx->allocated == ctx->bufs.num) {
 
-                            size = (size_t) bsize;
-                            recycled = 0;
-                        }
-                    }
+                        break;
 
-                    b = ngx_calloc_buf(ctx->pool);
-                    if (b == NULL) {
+                    } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
                         return NGX_ERROR;
                     }
-
-                    /*
-                     * allocate block aligned to a disk sector size
-                     * to enable O_DIRECT
-                     */
-
-                    b->start = ngx_pmemalign(ctx->pool, size, 512);
-                    if (b->start == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    b->pos = b->start;
-                    b->last = b->start;
-                    b->end = b->last + size;
-                    b->temporary = 1;
-                    b->tag = ctx->tag;
-                    b->recycled = recycled;
-
-                    ctx->buf = b;
-                    ctx->allocated++;
                 }
             }
 
-            rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf,
-                                           ctx->sendfile);
+            rc = ngx_output_chain_copy_buf(ctx);
 
             if (rc == NGX_ERROR) {
                 return rc;
@@ -244,11 +200,15 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
 
 static ngx_inline ngx_int_t
-ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
+ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
 {
     ngx_uint_t  sendfile;
 
     if (ngx_buf_special(buf)) {
+        return 1;
+    }
+
+    if (buf->in_file && buf->file->directio) {
         return 0;
     }
 
@@ -265,21 +225,21 @@ ngx_output_chain_need_to_copy(ngx_output
     if (!sendfile) {
 
         if (!ngx_buf_in_memory(buf)) {
-            return 1;
+            return 0;
         }
 
         buf->in_file = 0;
     }
 
     if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
-        return 1;
+        return 0;
     }
 
     if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
-        return 1;
+        return 0;
     }
 
-    return 0;
+    return 1;
 }
 
 
@@ -313,6 +273,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po
             && buf->file_pos < NGX_SENDFILE_LIMIT
             && buf->file_last > NGX_SENDFILE_LIMIT)
         {
+            /* split a file buf on two bufs by the sendfile limit */
+
             b = ngx_calloc_buf(pool);
             if (b == NULL) {
                 return NGX_ERROR;
@@ -352,10 +314,141 @@ ngx_output_chain_add_copy(ngx_pool_t *po
 
 
 static ngx_int_t
-ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile)
+ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
+{
+    size_t      size;
+    ngx_buf_t  *in;
+
+    in = ctx->in->buf;
+
+    if (in->file == NULL || !in->file->directio) {
+        return NGX_DECLINED;
+    }
+
+    ctx->directio = 1;
+
+    size = (size_t) (in->file_pos - (in->file_pos & ~511));
+
+    if (size == 0) {
+
+        if (bsize >= (off_t) ctx->bufs.size) {
+            return NGX_DECLINED;
+        }
+
+        size = (size_t) bsize;
+
+    } else {
+        size = 512 - size;
+
+        if ((off_t) size > bsize) {
+            size = (size_t) bsize;
+        }
+    }
+
+    ctx->buf = ngx_create_temp_buf(ctx->pool, size);
+    if (ctx->buf == NULL) {
+        return NGX_ERROR;
+    }
+
+    /*
+     * we do not set ctx->buf->tag, because we do not want
+     * to reuse the buf via ctx->free list
+     */
+
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+    ctx->unaligned = 1;
+#endif
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
 {
-    off_t    size;
-    ssize_t  n;
+    size_t       size;
+    ngx_buf_t   *b, *in;
+    ngx_uint_t   recycled;
+
+    in = ctx->in->buf;
+    size = ctx->bufs.size;
+    recycled = 1;
+
+    if (in->last_in_chain) {
+
+        if (bsize < (off_t) size) {
+
+            /*
+             * allocate a small temp buf for a small last buf
+             * or its small last part
+             */
+
+            size = (size_t) bsize;
+            recycled = 0;
+
+        } else if (!ctx->directio
+                   && ctx->bufs.num == 1
+                   && (bsize < (off_t) (size + size / 4)))
+        {
+            /*
+             * allocate a temp buf that equals to a last buf,
+             * if there is no directio, the last buf size is lesser
+             * than 1.25 of bufs.size and the temp buf is single
+             */
+
+            size = (size_t) bsize;
+            recycled = 0;
+        }
+    }
+
+    b = ngx_calloc_buf(ctx->pool);
+    if (b == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (ctx->directio) {
+
+        /*
+         * allocate block aligned to a disk sector size to enable
+         * userland buffer direct usage conjunctly with directio
+         */
+
+        b->start = ngx_pmemalign(ctx->pool, size, 512);
+        if (b->start == NULL) {
+            return NGX_ERROR;
+        }
+
+    } else {
+        b->start = ngx_palloc(ctx->pool, size);
+        if (b->start == NULL) {
+            return NGX_ERROR;
+        }
+    }
+
+    b->pos = b->start;
+    b->last = b->start;
+    b->end = b->last + size;
+    b->temporary = 1;
+    b->tag = ctx->tag;
+    b->recycled = recycled;
+
+    ctx->buf = b;
+    ctx->allocated++;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
+{
+    off_t        size;
+    ssize_t      n;
+    ngx_buf_t   *src, *dst;
+    ngx_uint_t   sendfile;
+
+    src = ctx->in->buf;
+    dst = ctx->buf;
 
     size = ngx_buf_size(src);
 
@@ -363,6 +456,8 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
         size = dst->end - dst->pos;
     }
 
+    sendfile = ctx->sendfile & !ctx->directio;
+
 #if (NGX_SENDFILE_LIMIT)
 
     if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) {
@@ -400,8 +495,41 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
         }
 
     } else {
+
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+
+        if (ctx->unaligned) {
+            if (ngx_directio_off(src->file->fd) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
+                              ngx_directio_off_n " \"%s\" failed",
+                              src->file->name.data);
+            }
+        }
+
+#endif
+
         n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
 
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+
+        if (ctx->unaligned) {
+            ngx_err_t  err;
+
+            err = ngx_errno;
+
+            if (ngx_directio_on(src->file->fd) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
+                              ngx_directio_on_n " \"%s\" failed",
+                              src->file->name.data);
+            }
+
+            ngx_set_errno(err);
+
+            ctx->unaligned = 0;
+        }
+
+#endif
+
         if (n == NGX_ERROR) {
             return (ngx_int_t) n;
         }
@@ -413,9 +541,9 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
 #endif
 
         if (n != size) {
-            ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
-                          ngx_read_file_n " read only %z of %O from file",
-                          n, size);
+            ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+                          ngx_read_file_n " read only %z of %O from \"%s\"",
+                          n, size, src->file->name.data);
             if (n == 0) {
                 return NGX_ERROR;
             }
--- a/src/core/ngx_radix_tree.c
+++ b/src/core/ngx_radix_tree.c
@@ -274,7 +274,7 @@ ngx_radix_alloc(ngx_radix_tree_t *tree)
     }
 
     if (tree->size < sizeof(ngx_radix_node_t)) {
-        tree->start = ngx_palloc(tree->pool, ngx_pagesize);
+        tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
         if (tree->start == NULL) {
             return NULL;
         }
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -54,8 +54,24 @@ void ngx_strlow(u_char *dst, u_char *src
 
 
 #define ngx_strstr(s1, s2)  strstr((const char *) s1, (const char *) s2)
+#define ngx_strlen(s)       strlen((const char *) s)
+
 #define ngx_strchr(s1, c)   strchr((const char *) s1, (int) c)
-#define ngx_strlen(s)       strlen((const char *) s)
+
+static ngx_inline u_char *
+ngx_strlchr(u_char *p, u_char *last, u_char c)
+{
+    while (p < last) {
+
+        if (*p == c) {
+            return p;
+        }
+
+        p++;
+    }
+
+    return NULL;
+}
 
 
 /*
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -50,10 +50,6 @@ ngx_time_init(void)
 
     ngx_cached_time = &cached_time[0];
 
-#if !(NGX_WIN32)
-    tzset();
-#endif
-
     ngx_time_update(0, 0);
 }
 
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -1051,13 +1051,6 @@ ngx_event_debug_connection(ngx_conf_t *c
         return NGX_CONF_ERROR;
     }
 
-    dc->addr = inet_addr((char *) value[1].data);
-
-    if (dc->addr != INADDR_NONE) {
-        dc->mask = 0xffffffff;
-        return NGX_CONF_OK;
-    }
-
     rc = ngx_ptocidr(&value[1], &in_cidr);
 
     if (rc == NGX_DONE) {
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -207,8 +207,7 @@ ngx_event_accept(ngx_event_t *ev)
                 return;
             }
 
-            c->addr_text.len = ngx_sock_ntop(ls->family, c->sockaddr,
-                                             c->addr_text.data,
+            c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data,
                                              ls->addr_text_max_len);
             if (c->addr_text.len == 0) {
                 ngx_close_accepted_connection(c);
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -166,14 +166,6 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx
         return NGX_CONF_OK;
     }
 
-    rule->addr = inet_addr((char *) value[1].data);
-
-    if (rule->addr != INADDR_NONE) {
-        rule->mask = 0xffffffff;
-
-        return NGX_CONF_OK;
-    }
-
     rc = ngx_ptocidr(&value[1], &in_cidr);
 
     if (rc == NGX_ERROR) {
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_http.h>
-#include <nginx.h>
 
 
 typedef struct {
@@ -1170,7 +1169,7 @@ ngx_http_fastcgi_process_header(ngx_http
                     u->headers_in.status_line.len =
                                            sizeof("302 Moved Temporarily") - 1;
                     u->headers_in.status_line.data =
-                                           (u_char *) "302 Moved Temporarily"; 
+                                           (u_char *) "302 Moved Temporarily";
 
                 } else {
                     u->headers_in.status_n = 200;
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -244,6 +244,7 @@ ngx_http_flv_handler(ngx_http_request_t 
     b->file->fd = of.fd;
     b->file->name = path;
     b->file->log = log;
+    b->file->directio = of.is_directio;
 
     out[1].buf = b;
     out[1].next = NULL;
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -235,6 +235,7 @@ ngx_http_gzip_static_handler(ngx_http_re
     b->file->fd = of.fd;
     b->file->name = path;
     b->file->log = log;
+    b->file->directio = of.is_directio;
 
     out.buf = b;
     out.next = NULL;
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_http.h>
-#include <nginx.h>
 
 
 typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
@@ -431,6 +430,7 @@ ngx_http_log_script_write(ngx_http_reque
     of.log = 1;
     of.valid = llcf->open_file_cache_valid;
     of.min_uses = llcf->open_file_cache_min_uses;
+    of.directio = NGX_MAX_OFF_T_VALUE;
 
     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
         != NGX_OK)
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
@@ -2546,7 +2545,7 @@ static ngx_int_t
 ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
     ngx_http_proxy_vars_t *v)
 {
-    if (!u->unix_socket) {
+    if (u->family != AF_UNIX) {
         if (u->no_port || u->port == u->default_port) {
             v->host_header = u->host;
 
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_random_index_module.c
@@ -0,0 +1,321 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    ngx_flag_t  enable;
+} ngx_http_random_index_loc_conf_t;
+
+
+#define NGX_HTTP_RANDOM_INDEX_PREALLOCATE  50
+
+
+static ngx_int_t ngx_http_random_index_error(ngx_http_request_t *r,
+    ngx_dir_t *dir, ngx_str_t *name);
+static ngx_int_t ngx_http_random_index_init(ngx_conf_t *cf);
+static void *ngx_http_random_index_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf,
+    void *parent, void *child);
+
+
+static ngx_command_t  ngx_http_random_index_commands[] = {
+
+    { ngx_string("random_index"),
+      NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_random_index_loc_conf_t, enable),
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_random_index_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_random_index_init,            /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_random_index_create_loc_conf, /* create location configration */
+    ngx_http_random_index_merge_loc_conf   /* merge location configration */
+};
+
+
+ngx_module_t  ngx_http_random_index_module = {
+    NGX_MODULE_V1,
+    &ngx_http_random_index_module_ctx,     /* module context */
+    ngx_http_random_index_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_random_index_handler(ngx_http_request_t *r)
+{
+    u_char                            *last, *filename;
+    size_t                             len, allocated, root;
+    ngx_err_t                          err;
+    ngx_int_t                          rc;
+    ngx_str_t                          path, uri, *name;
+    ngx_dir_t                          dir;
+    ngx_uint_t                         n, level;
+    ngx_array_t                        names;
+    ngx_http_random_index_loc_conf_t  *rlcf;
+
+    if (r->uri.data[r->uri.len - 1] != '/') {
+        return NGX_DECLINED;
+    }
+
+    /* TODO: Win32 */
+    if (r->zero_in_uri) {
+        return NGX_DECLINED;
+    }
+
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
+        return NGX_DECLINED;
+    }
+
+    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module);
+
+    if (!rlcf->enable) {
+        return NGX_DECLINED;
+    }
+
+#if (NGX_HAVE_D_TYPE)
+    len = NGX_DIR_MASK_LEN;
+#else
+    len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE;
+#endif
+
+    last = ngx_http_map_uri_to_path(r, &path, &root, len);
+    if (last == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    allocated = path.len;
+
+    path.len = last - path.data - 1;
+    path.data[path.len] = '\0';
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http random index: \"%s\"", path.data);
+
+    if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
+        err = ngx_errno;
+
+        if (err == NGX_ENOENT
+            || err == NGX_ENOTDIR
+            || err == NGX_ENAMETOOLONG)
+        {
+            level = NGX_LOG_ERR;
+            rc = NGX_HTTP_NOT_FOUND;
+
+        } else if (err == NGX_EACCES) {
+            level = NGX_LOG_ERR;
+            rc = NGX_HTTP_FORBIDDEN;
+
+        } else {
+            level = NGX_LOG_CRIT;
+            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_log_error(level, r->connection->log, err,
+                      ngx_open_dir_n " \"%s\" failed", path.data);
+
+        return rc;
+    }
+
+    if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) {
+        return ngx_http_random_index_error(r, &dir, &path);
+    }
+
+    filename = path.data;
+    filename[path.len] = '/';
+
+    for ( ;; ) {
+        ngx_set_errno(0);
+
+        if (ngx_read_dir(&dir) == NGX_ERROR) {
+            err = ngx_errno;
+
+            if (err != NGX_ENOMOREFILES) {
+                ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+                              ngx_read_dir_n " \"%V\" failed", &path);
+                return ngx_http_random_index_error(r, &dir, &path);
+            }
+
+            break;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http random index file: \"%s\"", ngx_de_name(&dir));
+
+        if (ngx_de_name(&dir)[0] == '.') {
+            continue;
+        }
+
+        len = ngx_de_namelen(&dir);
+
+        if (!dir.valid_type) {
+
+            /* 1 byte for '/' and 1 byte for terminating '\0' */
+
+            if (path.len + 1 + len + 1 > allocated) {
+                allocated = path.len + 1 + len + 1
+                                     + NGX_HTTP_RANDOM_INDEX_PREALLOCATE;
+
+                filename = ngx_pnalloc(r->pool, allocated);
+                if (filename == NULL) {
+                    return ngx_http_random_index_error(r, &dir, &path);
+                }
+
+                last = ngx_cpystrn(filename, path.data, path.len + 1);
+                *last++ = '/';
+            }
+
+            ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
+
+            if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
+                err = ngx_errno;
+
+                if (err != NGX_ENOENT) {
+                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+                                  ngx_de_info_n " \"%s\" failed", filename);
+                    return ngx_http_random_index_error(r, &dir, &path);
+                }
+
+                if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
+                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                                  ngx_de_link_info_n " \"%s\" failed",
+                                  filename);
+                    return ngx_http_random_index_error(r, &dir, &path);
+                }
+            }
+        }
+
+        if (!ngx_de_is_file(&dir)) {
+            continue;
+        }
+
+        name = ngx_array_push(&names);
+        if (name == NULL) {
+            return ngx_http_random_index_error(r, &dir, &path);
+        }
+
+        name->len = len;
+
+        name->data = ngx_pnalloc(r->pool, len);
+        if (name->data == NULL) {
+            return ngx_http_random_index_error(r, &dir, &path);
+        }
+
+        ngx_memcpy(name->data, ngx_de_name(&dir), len);
+    }
+
+    if (ngx_close_dir(&dir) == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_close_dir_n " \"%s\" failed", &path);
+    }
+
+    n = names.nelts;
+
+    if (n == 0) {
+        return NGX_DECLINED;
+    }
+
+    name = names.elts;
+
+    n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000);
+
+    uri.len = r->uri.len + name[n].len;
+
+    uri.data = ngx_pnalloc(r->pool, uri.len);
+    if (uri.data == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    last = ngx_copy(uri.data, r->uri.data, r->uri.len);
+    ngx_memcpy(last, name[n].data, name[n].len);
+
+    return ngx_http_internal_redirect(r, &uri, &r->args);
+}
+
+
+static ngx_int_t
+ngx_http_random_index_error(ngx_http_request_t *r, ngx_dir_t *dir,
+    ngx_str_t *name)
+{
+    if (ngx_close_dir(dir) == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_close_dir_n " \"%V\" failed", name);
+    }
+
+    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+}
+
+
+static void *
+ngx_http_random_index_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_random_index_loc_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->enable = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_random_index_loc_conf_t *prev = parent;
+    ngx_http_random_index_loc_conf_t *conf = child;
+
+    ngx_conf_merge_value(conf->enable, prev->enable, 0);
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_random_index_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_random_index_handler;
+
+    return NGX_OK;
+}
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -251,14 +251,6 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
 
     value = cf->args->elts;
 
-    from->addr = inet_addr((char *) value[1].data);
-
-    if (from->addr != INADDR_NONE) {
-        from->mask = 0xffffffff;
-
-        return NGX_CONF_OK;
-    }
-
     rc = ngx_ptocidr(&value[1], &in_cidr);
 
     if (rc == NGX_ERROR) {
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -13,8 +13,6 @@ typedef ngx_int_t (*ngx_ssl_variable_han
     ngx_pool_t *pool, ngx_str_t *s);
 
 
-#define NGX_DEFAULT_CERTIFICATE      "cert.pem"
-#define NGX_DEFAULT_CERTIFICATE_KEY  "cert.pem"
 #define NGX_DEFAULT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
@@ -28,6 +26,8 @@ static void *ngx_http_ssl_create_srv_con
 static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
     void *parent, void *child);
 
+static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
@@ -61,7 +61,7 @@ static ngx_command_t  ngx_http_ssl_comma
 
     { ngx_string("ssl"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
+      ngx_http_ssl_enable,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, enable),
       NULL },
@@ -339,10 +339,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
 
-    if (conf->enable == 0) {
-        return NGX_CONF_OK;
-    }
-
     ngx_conf_merge_value(conf->session_timeout,
                          prev->session_timeout, 300);
 
@@ -356,11 +352,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
     ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
 
-    ngx_conf_merge_str_value(conf->certificate, prev->certificate,
-                         NGX_DEFAULT_CERTIFICATE);
-
-    ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
-                         NGX_DEFAULT_CERTIFICATE_KEY);
+    ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
+    ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
 
     ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
 
@@ -372,6 +365,38 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 
     conf->ssl.log = cf->log;
 
+    if (conf->enable) {
+
+        if (conf->certificate.len == 0) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "no \"ssl_certificate\" is defined for "
+                          "the \"ssl\" directive in %s:%ui",
+                          conf->file, conf->line);
+            return NGX_CONF_ERROR;
+        }
+
+        if (conf->certificate_key.len == 0) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "no \"ssl_certificate_key\" is defined for "
+                          "the \"ssl\" directive in %s:%ui",
+                          conf->file, conf->line);
+            return NGX_CONF_ERROR;
+        }
+
+    } else {
+
+        if (conf->certificate.len == 0) {
+            return NGX_CONF_OK;
+        }
+
+        if (conf->certificate_key.len == 0) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "no \"ssl_certificate_key\" is defined "
+                          "for certificate \"%V\"", &conf->certificate);
+            return NGX_CONF_ERROR;
+        }
+    }
+
     if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
@@ -467,6 +492,26 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 
 
 static char *
+ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_ssl_srv_conf_t *sscf = conf;
+
+    char  *rv;
+
+    rv = ngx_conf_set_flag_slot(cf, cmd, conf);
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    sscf->file = cf->conf_file->file.name.data;
+    sscf->line = cf->conf_file->line;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
 ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_ssl_srv_conf_t *sscf = conf;
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -37,6 +37,9 @@ typedef struct {
     ngx_str_t                       ciphers;
 
     ngx_shm_zone_t                 *shm_zone;
+
+    u_char                         *file;
+    ngx_uint_t                      line;
 } ngx_http_ssl_srv_conf_t;
 
 
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -251,6 +251,7 @@ ngx_http_static_handler(ngx_http_request
     b->file->fd = of.fd;
     b->file->name = path;
     b->file->log = log;
+    b->file->directio = of.is_directio;
 
     out.buf = b;
     out.next = NULL;
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -136,6 +136,7 @@ static void *ngx_http_xslt_filter_create
 static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent,
     void *child);
 static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf);
+static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle);
 
 
 ngx_str_t  ngx_http_xslt_default_types[] = {
@@ -196,8 +197,8 @@ ngx_module_t  ngx_http_xslt_filter_modul
     NULL,                                  /* init process */
     NULL,                                  /* init thread */
     NULL,                                  /* exit thread */
-    NULL,                                  /* exit process */
-    NULL,                                  /* exit master */
+    ngx_http_xslt_filter_exit,            /* exit process */
+    ngx_http_xslt_filter_exit,             /* exit master */
     NGX_MODULE_V1_PADDING
 };
 
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.7.11';
+our $VERSION = '0.7.17';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -681,6 +681,7 @@ sendfile(r, filename, offset = -1, bytes
 
     b->file->fd = of.fd;
     b->file->log = r->connection->log;
+    b->file->directio = of.is_directio;
 
     (void) ngx_http_perl_output(r, b);
 
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
@@ -1158,6 +1157,10 @@ ngx_http_init_server_lists(ngx_conf_t *c
 
                         in_addr[a].core_srv_conf = cscfp[s];
                         in_addr[a].default_server = 1;
+#if (NGX_HTTP_SSL)
+                        in_addr[a].ssl = listen[l].conf.ssl;
+#endif
+                        in_addr[a].listen_conf = &listen[l].conf;
                     }
 
                     goto found;
@@ -1241,17 +1244,11 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
     in_addr->core_srv_conf = cscf;
     in_addr->default_server = listen->conf.default_server;
     in_addr->bind = listen->conf.bind;
+#if (NGX_HTTP_SSL)
+    in_addr->ssl = listen->conf.ssl;
+#endif
     in_addr->listen_conf = &listen->conf;
 
-#if (NGX_DEBUG)
-    {
-    u_char text[20];
-    ngx_inet_ntop(AF_INET, &in_addr->addr, text, 20);
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "address: %s:%d",
-                   text, in_port->port);
-    }
-#endif
-
     return ngx_http_add_names(cf, cscf, in_addr);
 }
 
@@ -1656,6 +1653,10 @@ ngx_http_init_listening(ngx_conf_t *cf, 
             hip->addrs[i].addr = in_addr[i].addr;
             hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf;
 
+#if (NGX_HTTP_SSL)
+            hip->addrs[i].ssl = in_addr[i].ssl;
+#endif
+
             if (in_addr[i].hash.buckets == NULL
                 && (in_addr[i].wc_head == NULL
                     || in_addr[i].wc_head->hash.buckets == NULL)
@@ -1787,11 +1788,11 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx
 
         if (prev_keys == NULL) {
 
-	    if (ngx_http_set_default_types(cf, &prev_keys, default_types)
+            if (ngx_http_set_default_types(cf, &prev_keys, default_types)
                 != NGX_OK)
             {
-		return NGX_CONF_ERROR;
-	    }
+                return NGX_CONF_ERROR;
+            }
         }
 
         hash.hash = prev_types_hash;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -6,9 +6,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
-#include <nginx.h>
 
 
 typedef struct {
@@ -1625,8 +1623,8 @@ ngx_http_server_addr(ngx_http_request_t 
         return NGX_OK;
     }
 
-    s->len = ngx_inet_ntop(c->listening->family, &r->in_addr,
-                           s->data, INET_ADDRSTRLEN);
+    s->len = ngx_sock_ntop((struct sockaddr *) &sin, s->data,
+                           NGX_INET_ADDRSTRLEN);
 
     return NGX_OK;
 }
@@ -1672,6 +1670,10 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
+    if (r->headers_in.msie6 && clcf->gzip_disable_msie6) {
+        return NGX_DECLINED;
+    }
+
     if (r->http_version < clcf->gzip_http_version) {
         return NGX_DECLINED;
     }
@@ -2677,6 +2679,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->gzip_http_version = NGX_CONF_UNSET_UINT;
 #if (NGX_PCRE)
     lcf->gzip_disable = NGX_CONF_UNSET_PTR;
+    lcf->gzip_disable_msie6 = 3;
 #endif
 #endif
 
@@ -2914,6 +2917,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_ptr_value(conf->gzip_disable, prev->gzip_disable, NULL);
 #endif
 
+    if (conf->gzip_disable_msie6 == 3) {
+        conf->gzip_disable_msie6 =
+            (prev->gzip_disable_msie6 == 3) ? 0 : prev->gzip_disable_msie6;
+    }
+
 #endif
 
     return NGX_CONF_OK;
@@ -2962,7 +2970,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
     ngx_memzero(ls, sizeof(ngx_http_listen_t));
 
-    ls->family = AF_INET;
+    ls->family = u.family;
     ls->addr = u.addr.in_addr;
     ls->port = u.port;
     ls->file_name = cf->conf_file->file.name.data;
@@ -2971,7 +2979,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
     ls->conf.rcvbuf = -1;
     ls->conf.sndbuf = -1;
 
-    n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, INET_ADDRSTRLEN + 6);
+    n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, NGX_INET_ADDRSTRLEN);
     ngx_sprintf(&ls->conf.addr[n], ":%ui", ls->port);
 
     if (cf->args->nelts == 2) {
@@ -3071,6 +3079,18 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             continue;
         }
 
+        if (ngx_strcmp(value[n].data, "ssl") == 0) {
+#if (NGX_HTTP_SSL)
+            ls->conf.ssl = 1;
+            continue;
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the \"ssl\" parameter requires "
+                               "ngx_http_ssl_module");
+            return NGX_CONF_ERROR;
+#endif
+        }
+
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "the invalid \"%V\" parameter", &value[n]);
         return NGX_CONF_ERROR;
@@ -3094,17 +3114,24 @@ ngx_http_core_server_name(ngx_conf_t *cf
 
     ch = value[1].data[0];
 
-    if (cscf->server_name.data == NULL && value[1].len) {
-        name = value[1];
-
-        if (ch == '.') {
-            name.len--;
-            name.data++;
-        }
-
-        cscf->server_name.len = name.len;
-        cscf->server_name.data = ngx_pstrdup(cf->pool, &name);
-        if (cscf->server_name.data == NULL) {
+    if (cscf->server_name.data == NULL) {
+        if (value[1].len) {
+            name = value[1];
+
+            if (ch == '.') {
+                name.len--;
+                name.data++;
+            }
+
+            cscf->server_name.len = name.len;
+            cscf->server_name.data = ngx_pstrdup(cf->pool, &name);
+            if (cscf->server_name.data == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+        } else {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the first server name must not be empty");
             return NGX_CONF_ERROR;
         }
     }
@@ -3113,8 +3140,7 @@ ngx_http_core_server_name(ngx_conf_t *cf
 
         ch = value[i].data[0];
 
-        if (value[i].len == 0
-            || (ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
+        if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
             || (ch == '.' && value[i].len < 2))
         {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3747,8 +3773,9 @@ ngx_http_core_resolver(ngx_conf_t *cf, n
 static char *
 ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
+    ngx_http_core_loc_conf_t  *clcf = conf;
+
 #if (NGX_PCRE)
-    ngx_http_core_loc_conf_t  *clcf = conf;
 
     ngx_str_t         err, *value;
     ngx_uint_t        i;
@@ -3770,6 +3797,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
 
     for (i = 1; i < cf->args->nelts; i++) {
 
+        if (ngx_strcmp(value[1].data, "msie6") == 0) {
+            clcf->gzip_disable_msie6 = 1;
+            continue;
+        }
+
         re = ngx_array_push(clcf->gzip_disable);
         if (re == NULL) {
             return NGX_CONF_ERROR;
@@ -3789,8 +3821,18 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
     return NGX_CONF_OK;
 
 #else
+    ngx_str_t  *value;
+
+    value = cf->args->elts;
+
+    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "msie6") == 0) {
+        clcf->gzip_disable_msie6 = 1;
+        return NGX_CONF_OK;
+    }
+
     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"gzip_disable\" requires PCRE library");
+                       "without PCRE library \"gzip_disable\" supports "
+                       "builtin \"msie6\" mask only");
 
     return NGX_CONF_ERROR;
 #endif
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -8,8 +8,8 @@
 #define _NGX_HTTP_CORE_H_INCLUDED_
 
 
-#include <ngx_string.h>
-#include <ngx_array.h>
+#include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_http.h>
 
 
@@ -35,6 +35,9 @@ typedef struct ngx_http_core_loc_conf_s 
 typedef struct {
     unsigned                   default_server:1;
     unsigned                   bind:1;
+#if (NGX_HTTP_SSL)
+    unsigned                   ssl:1;
+#endif
 
     int                        backlog;
     int                        rcvbuf;
@@ -47,7 +50,7 @@ typedef struct {
     ngx_uint_t                 deferred_accept;
 #endif
 
-    u_char                     addr[INET_ADDRSTRLEN + 6];
+    u_char                     addr[NGX_INET_ADDRSTRLEN + sizeof(":65535")];
 
 } ngx_http_listen_conf_t;
 
@@ -167,6 +170,10 @@ typedef struct {
     ngx_http_core_srv_conf_t  *core_srv_conf;
 
     ngx_http_virtual_names_t  *virtual_names;
+
+#if (NGX_HTTP_SSL)
+    ngx_uint_t                 ssl;   /* unsigned  ssl:1; */
+#endif
 } ngx_http_in_addr_t;
 
 
@@ -203,6 +210,9 @@ typedef struct {
 
     unsigned                   default_server:1;
     unsigned                   bind:1;
+#if (NGX_HTTP_SSL)
+    unsigned                   ssl:1;
+#endif
 
     ngx_http_listen_conf_t    *listen_conf;
 } ngx_http_conf_in_addr_t;
@@ -242,6 +252,9 @@ struct ngx_http_core_loc_conf_s {
 
     unsigned      auto_redirect:1;
     unsigned      alias:1;
+#if (NGX_HTTP_GZIP)
+    unsigned      gzip_disable_msie6:2;
+#endif
 
     ngx_http_location_tree_node_t   *static_locations;
     ngx_http_core_loc_conf_t       **regex_locations;
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -162,7 +162,7 @@ ngx_http_header_filter(ngx_http_request_
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
     /* AF_INET only */
-    u_char                     addr[INET_ADDRSTRLEN];
+    u_char                     addr[NGX_INET_ADDRSTRLEN];
 
     r->header_sent = 1;
 
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -720,7 +720,7 @@ ngx_http_parse_header_line(ngx_http_requ
     static u_char  lowcase[] =
         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
         "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
-        "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
+        "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_"
         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
--- a/src/http/ngx_http_parse_time.c
+++ b/src/http/ngx_http_parse_time.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_types.h>
 
 
 static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
@@ -74,15 +73,18 @@ static char *ngx_http_client_errors[] = 
 
 
 ngx_http_header_t  ngx_http_headers_in[] = {
-    { ngx_string("Host"), 0, ngx_http_process_host },
-
-    { ngx_string("Connection"), 0, ngx_http_process_connection },
+    { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host),
+                 ngx_http_process_host },
+
+    { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),
+                 ngx_http_process_connection },
 
     { ngx_string("If-Modified-Since"),
                  offsetof(ngx_http_headers_in_t, if_modified_since),
                  ngx_http_process_unique_header_line },
 
-    { ngx_string("User-Agent"), 0, ngx_http_process_user_agent },
+    { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent),
+                 ngx_http_process_user_agent },
 
     { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer),
                  ngx_http_process_header_line },
@@ -354,9 +356,20 @@ ngx_http_init_request(ngx_event_t *rev)
     ngx_http_ssl_srv_conf_t  *sscf;
 
     sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
-    if (sscf->enable) {
+    if (sscf->enable || hia[i].ssl) {
 
         if (c->ssl == NULL) {
+
+            c->log->action = "SSL handshaking";
+
+            if (hia[i].ssl && sscf->ssl.ctx == NULL) {
+                ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                              "no \"ssl_certificate\" is defined "
+                              "in server listening on SSL port");
+                ngx_http_close_connection(c);
+                return;
+            }
+
             if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
                 == NGX_ERROR)
             {
@@ -526,6 +539,8 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
         }
     }
 
+    c->log->action = "reading client request line";
+
     rev->handler = ngx_http_process_request_line;
     ngx_http_process_request_line(rev);
 }
@@ -568,6 +583,7 @@ ngx_http_ssl_handshake_handler(ngx_conne
 int
 ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
 {
+    size_t                    len;
     const char               *servername;
     ngx_connection_t         *c;
     ngx_http_request_t       *r;
@@ -584,12 +600,15 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "SSL server name: \"%s\"", servername);
 
+    len = ngx_strlen(servername);
+
+    if (len == 0) {
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
     r = c->data;
 
-    if (ngx_http_find_virtual_server(r, (u_char *) servername,
-                                     ngx_strlen(servername))
-        != NGX_OK)
-    {
+    if (ngx_http_find_virtual_server(r, (u_char *) servername, len) != NGX_OK) {
         return SSL_TLSEXT_ERR_NOACK;
     }
 
@@ -1283,7 +1302,7 @@ static ngx_int_t
 ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    u_char  *ua, *user_agent;
+    u_char  *user_agent, *msie;
 
     if (r->headers_in.user_agent) {
         return NGX_OK;
@@ -1295,14 +1314,22 @@ ngx_http_process_user_agent(ngx_http_req
 
     user_agent = h->value.data;
 
-    ua = ngx_strstrn(user_agent, "MSIE", 4 - 1);
-
-    if (ua && ua + 8 < user_agent + h->value.len) {
+    msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1);
+
+    if (msie && msie + 7 < user_agent + h->value.len) {
 
         r->headers_in.msie = 1;
 
-        if (ua[4] == ' ' && ua[5] == '4' && ua[6] == '.') {
-            r->headers_in.msie4 = 1;
+        if (msie[6] == '.') {
+
+            switch (msie[5]) {
+            case '4':
+                r->headers_in.msie4 = 1;
+                /* fall through */
+            case '5':
+            case '6':
+                r->headers_in.msie6 = 1;
+            }
         }
 
 #if 0
@@ -1317,6 +1344,7 @@ ngx_http_process_user_agent(ngx_http_req
         r->headers_in.opera = 1;
         r->headers_in.msie = 0;
         r->headers_in.msie4 = 0;
+        r->headers_in.msie6 = 0;
     }
 
     if (!r->headers_in.msie && !r->headers_in.opera) {
@@ -1556,7 +1584,7 @@ ngx_http_find_virtual_server(ngx_http_re
     ngx_http_core_srv_conf_t  *cscf;
     u_char                     buf[32];
 
-    if (len == 0 || r->virtual_names == NULL) {
+    if (r->virtual_names == NULL) {
         return NGX_DECLINED;
     }
 
@@ -1723,6 +1751,9 @@ ngx_http_finalize_request(ngx_http_reque
             }
         }
 
+        c->read->handler = ngx_http_request_handler;
+        c->write->handler = ngx_http_request_handler;
+
         ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
         return;
     }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -214,6 +214,7 @@ typedef struct {
     unsigned                          connection_type:2;
     unsigned                          msie:1;
     unsigned                          msie4:1;
+    unsigned                          msie6:1;
     unsigned                          opera:1;
     unsigned                          gecko:1;
     unsigned                          konqueror:1;
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -574,6 +574,7 @@ ngx_http_script_start_args_code(ngx_http
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
                    "http script args");
 
+    e->is_args = 1;
     e->args = e->pos;
     e->ip += sizeof(uintptr_t);
 }
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -327,7 +327,6 @@ static ngx_str_t  ngx_http_get_name = { 
 ngx_int_t
 ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
 {
-    ngx_int_t                  rc;
     ngx_uint_t                 i, err;
     ngx_http_err_page_t       *err_page;
     ngx_http_core_loc_conf_t  *clcf;
@@ -336,12 +335,6 @@ ngx_http_special_response_handler(ngx_ht
                    "http special response: %d, \"%V?%V\"",
                    error, &r->uri, &r->args);
 
-    rc = ngx_http_discard_request_body(r);
-
-    if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
-        error = NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
     r->err_status = error;
 
     if (r->keepalive) {
@@ -386,6 +379,10 @@ ngx_http_special_response_handler(ngx_ht
         }
     }
 
+    if (ngx_http_discard_request_body(r) != NGX_OK) {
+        error = NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
     if (clcf->msie_refresh
         && r->headers_in.msie
         && (error == NGX_HTTP_MOVED_PERMANENTLY
@@ -493,8 +490,10 @@ ngx_http_send_error_page(ngx_http_reques
 
     if (uri->data[0] == '/') {
 
-        r->method = NGX_HTTP_GET;
-        r->method_name = ngx_http_get_name;
+        if (r->method != NGX_HTTP_HEAD) {
+            r->method = NGX_HTTP_GET;
+            r->method_name = ngx_http_get_name;
+        }
 
         return ngx_http_internal_redirect(r, uri, args);
     }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2632,7 +2632,17 @@ ngx_http_upstream_copy_content_type(ngx_
 
         r->headers_out.content_type_len = last - h->value.data;
 
-        r->headers_out.charset.len = h->value.data + h->value.len - p;
+        if (*p == '"') {
+            p++;
+        }
+
+        last = h->value.data + h->value.len;
+
+        if (*(last - 1) == '"') {
+            last--;
+        }
+
+        r->headers_out.charset.len = last - p;
         r->headers_out.charset.data = p;
 
         return NGX_OK;
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -281,14 +281,14 @@ ngx_http_upstream_create_round_robin_pee
 
     for (i = 0; i < ur->naddrs; i++) {
 
-        len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1;
+        len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
 
         p = ngx_pnalloc(r->pool, len);
         if (p == NULL) {
             return NGX_ERROR;
         }
 
-        len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, INET_ADDRSTRLEN);
+        len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
         len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
 
         sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
@@ -645,7 +645,9 @@ ngx_http_upstream_free_round_robin_peer(
         peer->fails++;
         peer->accessed = now;
 
-        peer->current_weight -= peer->weight / peer->max_fails;
+        if (peer->max_fails) {
+            peer->current_weight -= peer->weight / peer->max_fails;
+        }
 
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                        "free rr peer failed: %ui %i",
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 #include <nginx.h>
 
@@ -79,6 +78,8 @@ static ngx_int_t ngx_http_variable_nginx
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 
 /*
  * TODO:
@@ -228,6 +229,9 @@ static ngx_http_variable_t  ngx_http_cor
     { ngx_string("hostname"), NULL, ngx_http_variable_hostname,
       0, 0, 0 },
 
+    { ngx_string("pid"), NULL, ngx_http_variable_pid,
+      0, 0, 0 },
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
@@ -872,7 +876,7 @@ ngx_http_variable_server_addr(ngx_http_r
 {
     ngx_str_t  s;
 
-    s.data = ngx_pnalloc(r->pool, INET_ADDRSTRLEN);
+    s.data = ngx_pnalloc(r->pool, NGX_INET_ADDRSTRLEN);
     if (s.data == NULL) {
         return NGX_ERROR;
     }
@@ -1354,6 +1358,27 @@ ngx_http_variable_hostname(ngx_http_requ
 }
 
 
+static ngx_int_t
+ngx_http_variable_pid(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_char  *p;
+
+    p = ngx_pnalloc(r->pool, NGX_INT64_LEN);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = p;
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -10,7 +10,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -6,7 +6,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
 #include <ngx_http.h>
 
 
--- a/src/mail/ngx_mail.c
+++ b/src/mail/ngx_mail.c
@@ -261,6 +261,9 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
         in_addr->addr = imls[l].addr;
         in_addr->ctx = imls[l].ctx;
         in_addr->bind = imls[l].bind;
+#if (NGX_MAIL_SSL)
+        in_addr->ssl = imls[l].ssl;
+#endif
     }
 
     /* optimize the lists of ports and addresses */
@@ -358,18 +361,22 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
                 imip->addrs[i].ctx = in_addr[i].ctx;
 
                 text = ngx_pnalloc(cf->pool,
-                                   INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1);
+                                   NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1);
                 if (text == NULL) {
                     return NGX_CONF_ERROR;
                 }
 
                 len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text,
-                                    INET_ADDRSTRLEN);
+                                    NGX_INET_ADDRSTRLEN);
 
                 len = ngx_sprintf(text + len, ":%d", in_port[p].port) - text;
 
                 imip->addrs[i].addr_text.len = len;
                 imip->addrs[i].addr_text.data = text;
+
+#if (NGX_MAIL_SSL)
+                imip->addrs[i].ssl = in_addr[i].ssl;
+#endif
             }
 
             if (done) {
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -34,6 +34,9 @@ typedef struct {
     ngx_mail_conf_ctx_t    *ctx;
 
     unsigned                bind:1;
+#if (NGX_MAIL_SSL)
+    unsigned                ssl:1;
+#endif
 } ngx_mail_listen_t;
 
 
@@ -41,6 +44,9 @@ typedef struct {
     in_addr_t               addr;
     ngx_mail_conf_ctx_t    *ctx;
     ngx_str_t               addr_text;
+#if (NGX_MAIL_SSL)
+    ngx_uint_t              ssl;    /* unsigned   ssl:1; */
+#endif
 } ngx_mail_in_addr_t;
 
 
@@ -60,6 +66,9 @@ typedef struct {
     in_addr_t               addr;
     ngx_mail_conf_ctx_t    *ctx;
     unsigned                bind:1;
+#if (NGX_MAIL_SSL)
+    unsigned                ssl:1;
+#endif
 } ngx_mail_conf_in_addr_t;
 
 
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -329,7 +329,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
 
     imls->addr = u.addr.in_addr;
     imls->port = u.port;
-    imls->family = AF_INET;
+    imls->family = u.family;
     imls->ctx = cf->ctx;
 
     for (m = 0; ngx_modules[m]; m++) {
@@ -351,18 +351,31 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
         }
     }
 
-    if (cf->args->nelts == 2) {
-        return NGX_CONF_OK;
+    for (i = 2; i < cf->args->nelts; i++) {
+
+        if (ngx_strcmp(value[i].data, "bind") == 0) {
+            imls->bind = 1;
+            continue;
+        }
+
+        if (ngx_strcmp(value[i].data, "ssl") == 0) {
+#if (NGX_MAIL_SSL)
+            imls->ssl = 1;
+            continue;
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the \"ssl\" parameter requires "
+                               "ngx_mail_ssl_module");
+            return NGX_CONF_ERROR;
+#endif
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the invalid \"%V\" parameter", &value[i]);
+        return NGX_CONF_ERROR;
     }
 
-    if (ngx_strcmp(value[2].data, "bind") == 0) {
-        imls->bind = 1;
-        return NGX_CONF_OK;
-    }
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "the invalid \"%V\" parameter", &value[2]);
-    return NGX_CONF_ERROR;
+    return NGX_CONF_OK;
 }
 
 
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -118,9 +118,28 @@ ngx_mail_init_connection(ngx_connection_
     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
 
     if (sslcf->enable) {
+        c->log->action = "SSL handshaking";
+
         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
         return;
     }
+
+    if (imia[i].ssl) {
+
+        c->log->action = "SSL handshaking";
+
+        if (sslcf->ssl.ctx == NULL) {
+            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                          "no \"ssl_certificate\" is defined "
+                          "in server listening on SSL port");
+            ngx_mail_close_connection(c);
+            return;
+        }
+
+        ngx_mail_ssl_init_connection(&sslcf->ssl, c);
+        return;
+    }
+
     }
 #endif
 
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -9,13 +9,16 @@
 #include <ngx_mail.h>
 
 
-#define NGX_DEFAULT_CERTIFICATE      "cert.pem"
-#define NGX_DEFAULT_CERTIFICATE_KEY  "cert.pem"
 #define NGX_DEFAULT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf);
 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
+
+static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
@@ -50,14 +53,14 @@ static ngx_command_t  ngx_mail_ssl_comma
 
     { ngx_string("ssl"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
+      ngx_mail_ssl_enable,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_ssl_conf_t, enable),
       NULL },
 
     { ngx_string("starttls"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_enum_slot,
+      ngx_mail_ssl_starttls,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_ssl_conf_t, starttls),
       ngx_http_starttls_state },
@@ -194,14 +197,12 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
     ngx_mail_ssl_conf_t *prev = parent;
     ngx_mail_ssl_conf_t *conf = child;
 
+    char                *mode;
     ngx_pool_cleanup_t  *cln;
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
-    ngx_conf_merge_value(conf->starttls, prev->starttls, NGX_MAIL_STARTTLS_OFF);
-
-    if (conf->enable == 0 && conf->starttls == NGX_MAIL_STARTTLS_OFF) {
-        return NGX_CONF_OK;
-    }
+    ngx_conf_merge_uint_value(conf->starttls, prev->starttls,
+                         NGX_MAIL_STARTTLS_OFF);
 
     ngx_conf_merge_value(conf->session_timeout,
                          prev->session_timeout, 300);
@@ -213,11 +214,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
                          (NGX_CONF_BITMASK_SET
                           |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
 
-    ngx_conf_merge_str_value(conf->certificate, prev->certificate,
-                         NGX_DEFAULT_CERTIFICATE);
-
-    ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
-                         NGX_DEFAULT_CERTIFICATE_KEY);
+    ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
+    ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
 
     ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
 
@@ -226,6 +224,49 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
 
     conf->ssl.log = cf->log;
 
+    if (conf->enable) {
+       mode = "ssl";
+
+    } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) {
+       mode = "starttls";
+
+    } else {
+       mode = "";
+    }
+
+    if (*mode) {
+
+        if (conf->certificate.len == 0) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "no \"ssl_certificate\" is defined for "
+                          "the \"%s\" directive in %s:%ui",
+                          mode, conf->file, conf->line);
+            return NGX_CONF_ERROR;
+        }
+
+        if (conf->certificate_key.len == 0) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "no \"ssl_certificate_key\" is defined for "
+                          "the \"%s\" directive in %s:%ui",
+                          mode, conf->file, conf->line);
+            return NGX_CONF_ERROR;
+        }
+
+    } else {
+
+        if (conf->certificate.len == 0) {
+            return NGX_CONF_OK;
+        }
+
+        if (conf->certificate_key.len == 0) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "no \"ssl_certificate_key\" is defined "
+                          "for certificate \"%V\"",
+                          &conf->certificate);
+            return NGX_CONF_ERROR;
+        }
+    }
+
     if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
@@ -292,6 +333,58 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
 
 
 static char *
+ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_mail_ssl_conf_t  *scf = conf;
+
+    char  *rv;
+
+    rv = ngx_conf_set_flag_slot(cf, cmd, conf);
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "\"starttls\" directive conflicts with \"ssl on\"");
+        return NGX_CONF_ERROR;
+    }
+
+    scf->file = cf->conf_file->file.name.data;
+    scf->line = cf->conf_file->line;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_mail_ssl_conf_t  *scf = conf;
+
+    char  *rv;
+
+    rv = ngx_conf_set_enum_slot(cf, cmd, conf);
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "\"ssl\" directive conflicts with \"starttls\"");
+        return NGX_CONF_ERROR;
+    }
+
+    scf->file = cf->conf_file->file.name.data;
+    scf->line = cf->conf_file->line;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_mail_ssl_conf_t  *scf = conf;
--- a/src/mail/ngx_mail_ssl_module.h
+++ b/src/mail/ngx_mail_ssl_module.h
@@ -20,12 +20,11 @@
 
 typedef struct {
     ngx_flag_t       enable;
+    ngx_flag_t       prefer_server_ciphers;
 
     ngx_ssl_t        ssl;
 
-    ngx_flag_t       prefer_server_ciphers;
-    ngx_flag_t       starttls;
-
+    ngx_uint_t       starttls;
     ngx_uint_t       protocols;
 
     ssize_t          builtin_session_cache;
@@ -39,6 +38,9 @@ typedef struct {
     ngx_str_t        ciphers;
 
     ngx_shm_zone_t  *shm_zone;
+
+    u_char          *file;
+    ngx_uint_t       line;
 } ngx_mail_ssl_conf_t;
 
 
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -249,12 +249,33 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t 
     }
 
     dir->valid_info = 0;
+#if (NGX_HAVE_D_TYPE)
+    dir->valid_type = 1;
+#else
+    dir->valid_type = 0;
+#endif
 
     return NGX_OK;
 }
 
 
 ngx_int_t
+ngx_read_dir(ngx_dir_t *dir)
+{
+    dir->de = readdir(dir->dir);
+
+    if (dir->de) {
+#if (NGX_HAVE_D_TYPE)
+        dir->type = dir->de->d_type;
+#endif
+        return NGX_OK;
+    }
+
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
 ngx_open_glob(ngx_glob_t *gl)
 {
     int  n;
@@ -265,10 +286,14 @@ ngx_open_glob(ngx_glob_t *gl)
         return NGX_OK;
     }
 
+#ifdef GLOB_NOMATCH
+
     if (n == GLOB_NOMATCH && gl->test) {
         return NGX_OK;
     }
 
+#endif
+
     return NGX_ERROR;
 }
 
@@ -276,7 +301,15 @@ ngx_open_glob(ngx_glob_t *gl)
 ngx_int_t
 ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name)
 {
-    if (gl->n < (size_t) gl->pglob.gl_pathc) {
+    size_t  count;
+
+#ifdef GLOB_NOMATCH
+    count = (size_t) gl->pglob.gl_pathc;
+#else
+    count = (size_t) gl->pglob.gl_matchc;
+#endif
+
+    if (gl->n < count) {
 
         name->len = (size_t) ngx_strlen(gl->pglob.gl_pathv[gl->n]);
         name->data = (u_char *) gl->pglob.gl_pathv[gl->n];
@@ -356,7 +389,7 @@ ngx_unlock_fd(ngx_fd_t fd)
 #if (NGX_HAVE_O_DIRECT)
 
 ngx_int_t
-ngx_directio(ngx_fd_t fd)
+ngx_directio_on(ngx_fd_t fd)
 {
     int  flags;
 
@@ -369,4 +402,19 @@ ngx_directio(ngx_fd_t fd)
     return fcntl(fd, F_SETFL, flags | O_DIRECT);
 }
 
+
+ngx_int_t
+ngx_directio_off(ngx_fd_t fd)
+{
+    int  flags;
+
+    flags = fcntl(fd, F_GETFL);
+
+    if (flags == -1) {
+        return -1;
+    }
+
+    return fcntl(fd, F_SETFL, flags & ~O_DIRECT);
+}
+
 #endif
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -12,6 +12,31 @@
 #include <ngx_core.h>
 
 
+typedef int                      ngx_fd_t;
+typedef struct stat              ngx_file_info_t;
+typedef ino_t                    ngx_file_uniq_t;
+
+
+typedef struct {
+    DIR                        *dir;
+    struct dirent              *de;
+    struct stat                 info;
+
+    unsigned                    type:8;
+    unsigned                    valid_info:1;
+    unsigned                    valid_type:1;
+} ngx_dir_t;
+
+
+typedef struct {
+    size_t                       n;
+    glob_t                       pglob;
+    u_char                      *pattern;
+    ngx_log_t                   *log;
+    ngx_uint_t                   test;
+} ngx_glob_t;
+
+
 #define NGX_INVALID_FILE         -1
 #define NGX_FILE_ERROR           -1
 
@@ -135,8 +160,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 #define ngx_close_dir_n          "closedir()"
 
 
-#define ngx_read_dir(d)                                                      \
-    (((d)->de = readdir((d)->dir)) ? NGX_OK : NGX_ERROR)
+ngx_int_t ngx_read_dir(ngx_dir_t *dir);
 #define ngx_read_dir_n           "readdir()"
 
 
@@ -152,7 +176,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 
 
 #define ngx_de_name(dir)         ((u_char *) (dir)->de->d_name)
-#if (NGX_FREEBSD)
+#if (NGX_HAVE_D_NAMLEN)
 #define ngx_de_namelen(dir)      (dir)->de->d_namlen
 #else
 #define ngx_de_namelen(dir)      ngx_strlen((dir)->de->d_name)
@@ -161,23 +185,26 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 #define ngx_de_info_n            "stat()"
 #define ngx_de_link_info(name, dir)  lstat((const char *) name, &(dir)->info)
 #define ngx_de_link_info_n       "lstat()"
+
+#if (NGX_HAVE_D_TYPE)
+
+#define ngx_de_is_dir(dir)       ((dir)->type == DT_DIR)
+#define ngx_de_is_file(dir)      ((dir)->type == DT_REG)
+#define ngx_de_is_link(dir)      ((dir)->type == DT_LINK)
+
+#else
+
 #define ngx_de_is_dir(dir)       (S_ISDIR((dir)->info.st_mode))
 #define ngx_de_is_file(dir)      (S_ISREG((dir)->info.st_mode))
 #define ngx_de_is_link(dir)      (S_ISLNK((dir)->info.st_mode))
+
+#endif
+
 #define ngx_de_access(dir)       (((dir)->info.st_mode) & 0777)
 #define ngx_de_size(dir)         (dir)->info.st_size
 #define ngx_de_mtime(dir)        (dir)->info.st_mtime
 
 
-typedef struct {
-    size_t       n;
-    glob_t       pglob;
-    u_char      *pattern;
-    ngx_log_t   *log;
-    ngx_uint_t   test;
-} ngx_glob_t;
-
-
 ngx_int_t ngx_open_glob(ngx_glob_t *gl);
 #define ngx_open_glob_n          "glob()"
 ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name);
@@ -195,23 +222,26 @@ ngx_err_t ngx_unlock_fd(ngx_fd_t fd);
 
 #if (NGX_HAVE_O_DIRECT)
 
-ngx_int_t ngx_directio(ngx_fd_t fd);
-#define ngx_directio_n           "fcntl(O_DIRECT)"
+ngx_int_t ngx_directio_on(ngx_fd_t fd);
+#define ngx_directio_on_n        "fcntl(O_DIRECT)"
+
+ngx_int_t ngx_directio_off(ngx_fd_t fd);
+#define ngx_directio_off_n       "fcntl(!O_DIRECT)"
 
 #elif (NGX_HAVE_F_NOCACHE)
 
-#define ngx_directio(fd)         fcntl(fd, F_NOCACHE, 1)
-#define ngx_directio_n           "fcntl(F_NOCACHE)"
+#define ngx_directio_on(fd)      fcntl(fd, F_NOCACHE, 1)
+#define ngx_directio_on_n        "fcntl(F_NOCACHE, 1)"
 
 #elif (NGX_HAVE_DIRECTIO)
 
-#define ngx_directio(fd)         directio(fd, DIRECTIO_ON)
-#define ngx_directio_n           "directio(DIRECTIO_ON)"
+#define ngx_directio_on(fd)      directio(fd, DIRECTIO_ON)
+#define ngx_directio_on_n        "directio(DIRECTIO_ON)"
 
 #else
 
-#define ngx_directio(fd)         0
-#define ngx_directio_n           "ngx_directio_n"
+#define ngx_directio_on(fd)      0
+#define ngx_directio_on_n        "ngx_directio_on_n"
 
 #endif
 
--- a/src/os/unix/ngx_time.c
+++ b/src/os/unix/ngx_time.c
@@ -8,6 +8,50 @@
 #include <ngx_core.h>
 
 
+/*
+ * FreeBSD does not test /etc/localtime change, however, we can workaround it
+ * by calling tzset() with TZ and then without TZ to update timezone.
+ * The trick should work since FreeBSD 2.1.0.
+ *
+ * Linux does not test /etc/localtime change in localtime(),
+ * but may stat("/etc/localtime") several times in every strftime(),
+ * therefore we use it to update timezone.
+ *
+ * Solaris does not test /etc/TIMEZONE change too and no workaround available.
+ */
+
+void
+ngx_timezone_update(void)
+{
+#if (NGX_FREEBSD)
+
+    if (getenv("TZ")) {
+        return;
+    }
+
+    putenv("TZ=UTC");
+
+    tzset();
+
+    unsetenv("TZ");
+
+    tzset();
+
+#elif (NGX_LINUX)
+    time_t      s;
+    struct tm  *t;
+    char        buf[4];
+
+    s = time(0);
+
+    t = localtime(&s);
+
+    strftime(buf, 4, "%H", t);
+
+#endif
+}
+
+
 void
 ngx_localtime(time_t s, ngx_tm_t *tm)
 {
--- a/src/os/unix/ngx_time.h
+++ b/src/os/unix/ngx_time.h
@@ -52,6 +52,7 @@ typedef struct tm             ngx_tm_t;
 #endif
 
 
+void ngx_timezone_update(void);
 void ngx_localtime(time_t s, ngx_tm_t *tm);
 void ngx_libc_localtime(time_t s, struct tm *tm);
 void ngx_libc_gmtime(time_t s, struct tm *tm);
deleted file mode 100644
--- a/src/os/unix/ngx_types.h
+++ /dev/null
@@ -1,27 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_TYPES_H_INCLUDED_
-#define _NGX_TYPES_H_INCLUDED_
-
-
-#include <ngx_config.h>
-
-
-typedef int            ngx_fd_t;
-typedef struct stat    ngx_file_info_t;
-typedef ino_t          ngx_file_uniq_t;
-
-typedef struct {
-    DIR              *dir;
-    struct dirent    *de;
-    struct stat       info;
-
-    ngx_uint_t        valid_info:1;  /* unsigned  valid_info:1; */
-} ngx_dir_t;
-
-
-#endif /* _NGX_TYPES_H_INCLUDED_ */