changeset 694:88a1b4797f2e NGINX_1_3_10

nginx 1.3.10 *) Change: domain names specified in configuration file are now resolved to IPv6 addresses as well as IPv4 ones. *) Change: now if the "include" directive with mask is used on Unix systems, included files are sorted in alphabetical order. *) Change: the "add_header" directive adds headers to 201 responses. *) Feature: the "geo" directive now supports IPv6 addresses in CIDR notation. *) Feature: the "flush" and "gzip" parameters of the "access_log" directive. *) Feature: variables support in the "auth_basic" directive. *) Bugfix: nginx could not be built with the ngx_http_perl_module in some cases. *) Bugfix: a segmentation fault might occur in a worker process if the ngx_http_xslt_module was used. *) Bugfix: nginx could not be built on MacOSX in some cases. Thanks to Piotr Sikora. *) Bugfix: the "limit_rate" directive with high rates might result in truncated responses on 32-bit platforms. Thanks to Alexey Antropov. *) Bugfix: a segmentation fault might occur in a worker process if the "if" directive was used. Thanks to Piotr Sikora. *) Bugfix: a "100 Continue" response was issued with "413 Request Entity Too Large" responses. *) Bugfix: the "image_filter", "image_filter_jpeg_quality" and "image_filter_sharpen" directives might be inherited incorrectly. Thanks to Ian Babrou. *) Bugfix: "crypt_r() failed" errors might appear if the "auth_basic" directive was used on Linux. *) Bugfix: in backup servers handling. Thanks to Thomas Chen. *) Bugfix: proxied HEAD requests might return incorrect response if the "gzip" directive was used.
author Igor Sysoev <http://sysoev.ru>
date Tue, 25 Dec 2012 00:00:00 +0400
parents cfd4279acc6e
children 09a8f76a129b
files CHANGES CHANGES.ru auto/lib/pcre/conf auto/lib/perl/make auto/lib/zlib/conf auto/unix src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_cycle.c src/core/ngx_file.c src/core/ngx_inet.c src/core/ngx_inet.h src/core/ngx_radix_tree.c src/core/ngx_radix_tree.h src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_geo_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_map_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_split_clients_module.c src/http/modules/ngx_http_sub_filter_module.c src/http/modules/ngx_http_upstream_least_conn_module.c src/http/modules/ngx_http_uwsgi_module.c src/http/modules/ngx_http_xslt_filter_module.c src/http/modules/perl/Makefile.PL src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_script.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream_round_robin.c src/http/ngx_http_variables.c src/http/ngx_http_write_filter_module.c src/mail/ngx_mail_auth_http_module.c src/os/unix/ngx_files.c src/os/unix/ngx_user.c
diffstat 41 files changed, 1386 insertions(+), 398 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES	Tue Nov 27 00:00:00 2012 +0400
+++ b/CHANGES	Tue Dec 25 00:00:00 2012 +0400
@@ -1,4 +1,56 @@
 
+Changes with nginx 1.3.10                                        25 Dec 2012
+
+    *) Change: domain names specified in configuration file are now resolved
+       to IPv6 addresses as well as IPv4 ones.
+
+    *) Change: now if the "include" directive with mask is used on Unix
+       systems, included files are sorted in alphabetical order.
+
+    *) Change: the "add_header" directive adds headers to 201 responses.
+
+    *) Feature: the "geo" directive now supports IPv6 addresses in CIDR
+       notation.
+
+    *) Feature: the "flush" and "gzip" parameters of the "access_log"
+       directive.
+
+    *) Feature: variables support in the "auth_basic" directive.
+
+    *) Bugfix: nginx could not be built with the ngx_http_perl_module in
+       some cases.
+
+    *) Bugfix: a segmentation fault might occur in a worker process if the
+       ngx_http_xslt_module was used.
+
+    *) Bugfix: nginx could not be built on MacOSX in some cases.
+       Thanks to Piotr Sikora.
+
+    *) Bugfix: the "limit_rate" directive with high rates might result in
+       truncated responses on 32-bit platforms.
+       Thanks to Alexey Antropov.
+
+    *) Bugfix: a segmentation fault might occur in a worker process if the
+       "if" directive was used.
+       Thanks to Piotr Sikora.
+
+    *) Bugfix: a "100 Continue" response was issued with "413 Request Entity
+       Too Large" responses.
+
+    *) Bugfix: the "image_filter", "image_filter_jpeg_quality" and
+       "image_filter_sharpen" directives might be inherited incorrectly.
+       Thanks to Ian Babrou.
+
+    *) Bugfix: "crypt_r() failed" errors might appear if the "auth_basic"
+       directive was used on Linux.
+
+    *) Bugfix: in backup servers handling.
+       Thanks to Thomas Chen.
+
+    *) Bugfix: proxied HEAD requests might return incorrect response if the
+       "gzip" directive was used.
+
+
 Changes with nginx 1.3.9                                         27 Nov 2012
 
     *) Feature: support for chunked transfer encoding while reading client
--- a/CHANGES.ru	Tue Nov 27 00:00:00 2012 +0400
+++ b/CHANGES.ru	Tue Dec 25 00:00:00 2012 +0400
@@ -1,4 +1,57 @@
 
+Изменения в nginx 1.3.10                                          25.12.2012
+
+    *) Изменение: для указанных в конфигурационном файле доменных имён
+       теперь используются не только IPv4, но и IPv6 адреса.
+
+    *) Изменение: теперь при использовании директивы include с маской на
+       Unix-системах включаемые файлы сортируются в алфавитном порядке.
+
+    *) Изменение: директива add_header добавляет строки в ответы с кодом
+       201.
+
+    *) Добавление: директива geo теперь поддерживает IPv6 адреса в формате
+       CIDR.
+
+    *) Добавление: параметры flush и gzip в директиве access_log.
+
+    *) Добавление: директива auth_basic поддерживает переменные.
+
+    *) Исправление: nginx в некоторых случаях не собирался с модулем
+       ngx_http_perl_module.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault,
+       если использовался модуль ngx_http_xslt_module.
+
+    *) Исправление: nginx мог не собираться на MacOSX.
+       Спасибо Piotr Sikora.
+
+    *) Исправление: при использовании директивы limit_rate с большими
+       значениями скорости на 32-битных системах ответ мог возвращаться не
+       целиком.
+       Спасибо Алексею Антропову.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault,
+       если использовалась директива if.
+       Спасибо Piotr Sikora.
+
+    *) Исправление: ответ "100 Continue" выдавался вместе с ответом "413
+       Request Entity Too Large".
+
+    *) Исправление: директивы image_filter, image_filter_jpeg_quality и
+       image_filter_sharpen могли наследоваться некорректно.
+       Спасибо Ивану Боброву.
+
+    *) Исправление: при использовании директивы auth_basic под Linux могли
+       возникать ошибки "crypt_r() failed".
+
+    *) Исправление: в обработке backup-серверов.
+       Спасибо Thomas Chen.
+
+    *) Исправление: при проксировании HEAD-запросов мог возвращаться
+       некорректный ответ, если использовалась директива gzip.
+
+
 Изменения в nginx 1.3.9                                           27.11.2012
 
     *) Добавление: поддержка chunked transfer encoding при получении тела
--- a/auto/lib/pcre/conf	Tue Nov 27 00:00:00 2012 +0400
+++ b/auto/lib/pcre/conf	Tue Dec 25 00:00:00 2012 +0400
@@ -172,6 +172,7 @@
             ngx_feature="PCRE JIT support"
             ngx_feature_name="NGX_HAVE_PCRE_JIT"
             ngx_feature_test="int jit = 0;
+                              pcre_free_study(NULL);
                               pcre_config(PCRE_CONFIG_JIT, &jit);
                               if (jit != 1) return 1;"
             . auto/feature
--- a/auto/lib/perl/make	Tue Nov 27 00:00:00 2012 +0400
+++ b/auto/lib/perl/make	Tue Dec 25 00:00:00 2012 +0400
@@ -26,9 +26,7 @@
 
 	cd $NGX_OBJS/src/http/modules/perl				\
 		&& NGX_PM_CFLAGS="\$(NGX_PM_CFLAGS) -g $NGX_CC_OPT"	\
-			NGX_PCRE=$PCRE					\
-			NGX_OBJS=$NGX_OBJS				\
-			NGX_OPENSSL=$OPENSSL				\
+			NGX_INCS="$CORE_INCS $NGX_OBJS $HTTP_INCS"	\
 		$NGX_PERL Makefile.PL					\
 			LIB=$NGX_PERL_MODULES				\
 			INSTALLSITEMAN3DIR=$NGX_PERL_MODULES_MAN
--- a/auto/lib/zlib/conf	Tue Nov 27 00:00:00 2012 +0400
+++ b/auto/lib/zlib/conf	Tue Dec 25 00:00:00 2012 +0400
@@ -9,11 +9,13 @@
     case "$NGX_CC_NAME" in
 
         msvc* | owc* | bcc)
+            have=NGX_ZLIB . auto/have
             LINK_DEPS="$LINK_DEPS $ZLIB/zlib.lib"
             CORE_LIBS="$CORE_LIBS $ZLIB/zlib.lib"
         ;;
 
         icc*)
+            have=NGX_ZLIB . auto/have
             LINK_DEPS="$LINK_DEPS $ZLIB/libz.a"
 
             # to allow -ipo optimization we link with the *.o but not library
@@ -30,6 +32,7 @@
         ;;
 
         *)
+            have=NGX_ZLIB . auto/have
             LINK_DEPS="$LINK_DEPS $ZLIB/libz.a"
             CORE_LIBS="$CORE_LIBS $ZLIB/libz.a"
             #CORE_LIBS="$CORE_LIBS -L $ZLIB -lz"
@@ -45,7 +48,7 @@
         # FreeBSD, Solaris, Linux
 
         ngx_feature="zlib library"
-        ngx_feature_name=
+        ngx_feature_name="NGX_ZLIB"
         ngx_feature_run=no
         ngx_feature_incs="#include <zlib.h>"
         ngx_feature_path=
--- a/auto/unix	Tue Nov 27 00:00:00 2012 +0400
+++ b/auto/unix	Tue Dec 25 00:00:00 2012 +0400
@@ -778,3 +778,17 @@
                   openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW);
                   fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);"
 . auto/feature
+
+
+ngx_feature="getaddrinfo()"
+ngx_feature_name="NGX_HAVE_GETADDRINFO"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/types.h>
+                  #include <sys/socket.h>
+                  #include <netdb.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test='struct addrinfo *res;
+                  if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1;
+                  freeaddrinfo(res)'
+. auto/feature
--- a/src/core/nginx.h	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/nginx.h	Tue Dec 25 00:00:00 2012 +0400
@@ -9,8 +9,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version      1003009
-#define NGINX_VERSION      "1.3.9"
+#define nginx_version      1003010
+#define NGINX_VERSION      "1.3.10"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_conf_file.c	Tue Dec 25 00:00:00 2012 +0400
@@ -945,7 +945,7 @@
         file->name = *name;
     }
 
-    file->buffer = NULL;
+    file->flush = NULL;
 
     return file;
 }
@@ -954,7 +954,6 @@
 static void
 ngx_conf_flush_files(ngx_cycle_t *cycle)
 {
-    ssize_t           n, len;
     ngx_uint_t        i;
     ngx_list_part_t  *part;
     ngx_open_file_t  *file;
@@ -975,23 +974,8 @@
             i = 0;
         }
 
-        len = file[i].pos - file[i].buffer;
-
-        if (file[i].buffer == NULL || len == 0) {
-            continue;
-        }
-
-        n = ngx_write_fd(file[i].fd, file[i].buffer, len);
-
-        if (n == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
-                          ngx_write_fd_n " to \"%s\" failed",
-                          file[i].name.data);
-
-        } else if (n != len) {
-            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
-                          ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
-                          file[i].name.data, n, len);
+        if (file[i].flush) {
+            file[i].flush(&file[i], cycle->log);
         }
     }
 }
--- a/src/core/ngx_conf_file.h	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_conf_file.h	Tue Dec 25 00:00:00 2012 +0400
@@ -91,17 +91,8 @@
     ngx_fd_t              fd;
     ngx_str_t             name;
 
-    u_char               *buffer;
-    u_char               *pos;
-    u_char               *last;
-
-#if 0
-    /* e.g. append mode, error_log */
-    ngx_uint_t            flags;
-    /* e.g. reopen db file */
-    ngx_uint_t          (*handler)(void *data, ngx_open_file_t *file);
+    void                (*flush)(ngx_open_file_t *file, ngx_log_t *log);
     void                 *data;
-#endif
 };
 
 
--- a/src/core/ngx_cycle.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_cycle.c	Tue Dec 25 00:00:00 2012 +0400
@@ -1115,7 +1115,6 @@
 void
 ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
 {
-    ssize_t           n, len;
     ngx_fd_t          fd;
     ngx_uint_t        i;
     ngx_list_part_t  *part;
@@ -1139,24 +1138,8 @@
             continue;
         }
 
-        len = file[i].pos - file[i].buffer;
-
-        if (file[i].buffer && len != 0) {
-
-            n = ngx_write_fd(file[i].fd, file[i].buffer, len);
-
-            if (n == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
-                              ngx_write_fd_n " to \"%s\" failed",
-                              file[i].name.data);
-
-            } else if (n != len) {
-                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
-                          ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
-                          file[i].name.data, n, len);
-            }
-
-            file[i].pos = file[i].buffer;
+        if (file[i].flush) {
+            file[i].flush(&file[i], cycle->log);
         }
 
         fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND,
--- a/src/core/ngx_file.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_file.c	Tue Dec 25 00:00:00 2012 +0400
@@ -732,14 +732,14 @@
 
         n = ngx_read_fd(fd, buf, len);
 
-        if (n == NGX_FILE_ERROR) {
+        if (n == -1) {
             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                           ngx_read_fd_n " \"%s\" failed", from);
             goto failed;
         }
 
         if ((size_t) n != len) {
-            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                           ngx_read_fd_n " has read only %z of %uz from %s",
                           n, size, from);
             goto failed;
@@ -747,14 +747,14 @@
 
         n = ngx_write_fd(nfd, buf, len);
 
-        if (n == NGX_FILE_ERROR) {
+        if (n == -1) {
             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                           ngx_write_fd_n " \"%s\" failed", to);
             goto failed;
         }
 
         if ((size_t) n != len) {
-            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                           ngx_write_fd_n " has written only %z of %uz to %s",
                           n, size, to);
             goto failed;
--- a/src/core/ngx_inet.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_inet.c	Tue Dec 25 00:00:00 2012 +0400
@@ -465,7 +465,7 @@
      * prevent MSVC8 warning:
      *    potentially uninitialized local variable 'inaddr6' used
      */
-    ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr));
+    ngx_memzero(&inaddr6, sizeof(struct in6_addr));
 #endif
 
     inaddr = ngx_inet_addr(text, len);
@@ -611,11 +611,13 @@
 static ngx_int_t
 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
 {
-    u_char              *p, *host, *port, *last, *uri, *args;
-    size_t               len;
-    ngx_int_t            n;
-    struct hostent      *h;
-    struct sockaddr_in  *sin;
+    u_char               *p, *host, *port, *last, *uri, *args;
+    size_t                len;
+    ngx_int_t             n;
+    struct sockaddr_in   *sin;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6  *sin6;
+#endif
 
     u->socklen = sizeof(struct sockaddr_in);
     sin = (struct sockaddr_in *) &u->sockaddr;
@@ -705,6 +707,11 @@
         }
 
         u->no_port = 1;
+
+        if (!u->no_resolve) {
+            u->port = u->default_port;
+            sin->sin_port = htons(u->default_port);
+        }
     }
 
     len = last - host;
@@ -714,59 +721,88 @@
         return NGX_ERROR;
     }
 
-    if (len == 1 && *host == '*') {
-        len = 0;
+    u->host.len = len;
+    u->host.data = host;
+
+    if (u->listen && len == 1 && *host == '*') {
+        sin->sin_addr.s_addr = INADDR_ANY;
+        u->wildcard = 1;
+        return NGX_OK;
     }
 
-    u->host.len = len;
-    u->host.data = host;
+    sin->sin_addr.s_addr = ngx_inet_addr(host, len);
+
+    if (sin->sin_addr.s_addr != INADDR_NONE) {
+
+        if (sin->sin_addr.s_addr == INADDR_ANY) {
+            u->wildcard = 1;
+        }
+
+        u->naddrs = 1;
+
+        u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+        if (u->addrs == NULL) {
+            return NGX_ERROR;
+        }
+
+        sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+        if (sin == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_memcpy(sin, u->sockaddr, sizeof(struct sockaddr_in));
+
+        u->addrs[0].sockaddr = (struct sockaddr *) sin;
+        u->addrs[0].socklen = sizeof(struct sockaddr_in);
+
+        p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
+                                           &u->host, u->port) - p;
+        u->addrs[0].name.data = p;
+
+        return NGX_OK;
+    }
 
     if (u->no_resolve) {
         return NGX_OK;
     }
 
-    if (len) {
-        sin->sin_addr.s_addr = ngx_inet_addr(host, len);
+    if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
+        return NGX_ERROR;
+    }
 
-        if (sin->sin_addr.s_addr == INADDR_NONE) {
-            p = ngx_alloc(++len, pool->log);
-            if (p == NULL) {
-                return NGX_ERROR;
-            }
+    u->family = u->addrs[0].sockaddr->sa_family;
+    u->socklen = u->addrs[0].socklen;
+    ngx_memcpy(u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);
 
-            (void) ngx_cpystrn(p, host, len);
+    switch (u->family) {
 
-            h = gethostbyname((const char *) p);
-
-            ngx_free(p);
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *) &u->sockaddr;
 
-            if (h == NULL || h->h_addr_list[0] == NULL) {
-                u->err = "host not found";
-                return NGX_ERROR;
-            }
+        if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+            u->wildcard = 1;
+        }
 
-            sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]);
-        }
+        break;
+#endif
+
+    default: /* AF_INET */
+        sin = (struct sockaddr_in *) &u->sockaddr;
 
         if (sin->sin_addr.s_addr == INADDR_ANY) {
             u->wildcard = 1;
         }
 
-    } else {
-        sin->sin_addr.s_addr = INADDR_ANY;
-        u->wildcard = 1;
+        break;
     }
 
-    if (u->no_port) {
-        u->port = u->default_port;
-        sin->sin_port = htons(u->default_port);
-    }
-
-    if (u->listen) {
-        return NGX_OK;
-    }
-
-    return ngx_inet_resolve_host(pool, u);
+    return NGX_OK;
 }
 
 
@@ -832,6 +868,11 @@
 
         } else {
             u->no_port = 1;
+
+            if (!u->no_resolve) {
+                u->port = u->default_port;
+                sin6->sin6_port = htons(u->default_port);
+            }
         }
     }
 
@@ -854,11 +895,6 @@
         u->wildcard = 1;
     }
 
-    if (u->no_port) {
-        u->port = u->default_port;
-        sin6->sin6_port = htons(u->default_port);
-    }
-
     u->family = AF_INET6;
     u->naddrs = 1;
 
@@ -898,6 +934,150 @@
 }
 
 
+#if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
+{
+    u_char               *p, *host;
+    size_t                len;
+    in_port_t             port;
+    ngx_uint_t            i;
+    struct addrinfo       hints, *res, *rp;
+    struct sockaddr_in   *sin;
+    struct sockaddr_in6  *sin6;
+
+    port = htons(u->port);
+
+    host = ngx_alloc(u->host.len + 1, pool->log);
+    if (host == NULL) {
+        return NGX_ERROR;
+    }
+
+    (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
+    ngx_memzero(&hints, sizeof(struct addrinfo));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) {
+        u->err = "host not found";
+        ngx_free(host);
+        return NGX_ERROR;
+    }
+
+    ngx_free(host);
+
+    for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) {
+
+        switch (rp->ai_family) {
+
+        case AF_INET:
+        case AF_INET6:
+            break;
+
+        default:
+            continue;
+        }
+
+        i++;
+    }
+
+    if (i == 0) {
+        u->err = "host not found";
+        goto failed;
+    }
+
+    /* MP: ngx_shared_palloc() */
+
+    u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
+    if (u->addrs == NULL) {
+        goto failed;
+    }
+
+    u->naddrs = i;
+
+    i = 0;
+
+    /* AF_INET addresses first */
+
+    for (rp = res; rp != NULL; rp = rp->ai_next) {
+
+        if (rp->ai_family != AF_INET) {
+            continue;
+        }
+
+        sin = ngx_pcalloc(pool, rp->ai_addrlen);
+        if (sin == NULL) {
+            goto failed;
+        }
+
+        ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen);
+
+        sin->sin_port = port;
+
+        u->addrs[i].sockaddr = (struct sockaddr *) sin;
+        u->addrs[i].socklen = rp->ai_addrlen;
+
+        len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
+
+        p = ngx_pnalloc(pool, len);
+        if (p == NULL) {
+            goto failed;
+        }
+
+        len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
+
+        u->addrs[i].name.len = len;
+        u->addrs[i].name.data = p;
+
+        i++;
+    }
+
+    for (rp = res; rp != NULL; rp = rp->ai_next) {
+
+        if (rp->ai_family != AF_INET6) {
+            continue;
+        }
+
+        sin6 = ngx_pcalloc(pool, rp->ai_addrlen);
+        if (sin6 == NULL) {
+            goto failed;
+        }
+
+        ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen);
+
+        sin6->sin6_port = port;
+
+        u->addrs[i].sockaddr = (struct sockaddr *) sin6;
+        u->addrs[i].socklen = rp->ai_addrlen;
+
+        len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
+
+        p = ngx_pnalloc(pool, len);
+        if (p == NULL) {
+            goto failed;
+        }
+
+        len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1);
+
+        u->addrs[i].name.len = len;
+        u->addrs[i].name.data = p;
+
+        i++;
+    }
+
+    freeaddrinfo(res);
+    return NGX_OK;
+
+failed:
+
+    freeaddrinfo(res);
+    return NGX_ERROR;
+}
+
+#else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */
+
 ngx_int_t
 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
 {
@@ -932,12 +1112,7 @@
             return NGX_ERROR;
         }
 
-        if (u->one_addr == 0) {
-            for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
-
-        } else {
-            i = 1;
-        }
+        for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
 
         /* MP: ngx_shared_palloc() */
 
@@ -1010,3 +1185,5 @@
 
     return NGX_OK;
 }
+
+#endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */
--- a/src/core/ngx_inet.h	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_inet.h	Tue Dec 25 00:00:00 2012 +0400
@@ -30,7 +30,7 @@
 #if (NGX_HAVE_UNIX_DOMAIN)
 #define NGX_SOCKADDR_STRLEN   (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN)
 #else
-#define NGX_SOCKADDR_STRLEN   (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1)
+#define NGX_SOCKADDR_STRLEN   (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1)
 #endif
 
 #if (NGX_HAVE_UNIX_DOMAIN)
@@ -87,7 +87,7 @@
     unsigned                  listen:1;
     unsigned                  uri_part:1;
     unsigned                  no_resolve:1;
-    unsigned                  one_addr:1;
+    unsigned                  one_addr:1;  /* compatibility */
 
     unsigned                  no_port:1;
     unsigned                  wildcard:1;
--- a/src/core/ngx_radix_tree.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_radix_tree.c	Tue Dec 25 00:00:00 2012 +0400
@@ -9,7 +9,7 @@
 #include <ngx_core.h>
 
 
-static void *ngx_radix_alloc(ngx_radix_tree_t *tree);
+static ngx_radix_node_t *ngx_radix_alloc(ngx_radix_tree_t *tree);
 
 
 ngx_radix_tree_t *
@@ -263,13 +263,210 @@
 }
 
 
-static void *
+#if (NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask,
+    uintptr_t value)
+{
+    u_char             bit;
+    ngx_uint_t         i;
+    ngx_radix_node_t  *node, *next;
+
+    i = 0;
+    bit = 0x80;
+
+    node = tree->root;
+    next = tree->root;
+
+    while (bit & mask[i]) {
+        if (key[i] & bit) {
+            next = node->right;
+
+        } else {
+            next = node->left;
+        }
+
+        if (next == NULL) {
+            break;
+        }
+
+        bit >>= 1;
+        node = next;
+
+        if (bit == 0) {
+            if (++i == 16) {
+                break;
+            }
+
+            bit = 0x80;
+        }
+    }
+
+    if (next) {
+        if (node->value != NGX_RADIX_NO_VALUE) {
+            return NGX_BUSY;
+        }
+
+        node->value = value;
+        return NGX_OK;
+    }
+
+    while (bit & mask[i]) {
+        next = ngx_radix_alloc(tree);
+        if (next == NULL) {
+            return NGX_ERROR;
+        }
+
+        next->right = NULL;
+        next->left = NULL;
+        next->parent = node;
+        next->value = NGX_RADIX_NO_VALUE;
+
+        if (key[i] & bit) {
+            node->right = next;
+
+        } else {
+            node->left = next;
+        }
+
+        bit >>= 1;
+        node = next;
+
+        if (bit == 0) {
+            if (++i == 16) {
+                break;
+            }
+
+            bit = 0x80;
+        }
+    }
+
+    node->value = value;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask)
+{
+    u_char             bit;
+    ngx_uint_t         i;
+    ngx_radix_node_t  *node;
+
+    i = 0;
+    bit = 0x80;
+    node = tree->root;
+
+    while (node && (bit & mask[i])) {
+        if (key[i] & bit) {
+            node = node->right;
+
+        } else {
+            node = node->left;
+        }
+
+        bit >>= 1;
+
+        if (bit == 0) {
+            if (++i == 16) {
+                break;
+            }
+
+            bit = 0x80;
+        }
+    }
+
+    if (node == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (node->right || node->left) {
+        if (node->value != NGX_RADIX_NO_VALUE) {
+            node->value = NGX_RADIX_NO_VALUE;
+            return NGX_OK;
+        }
+
+        return NGX_ERROR;
+    }
+
+    for ( ;; ) {
+        if (node->parent->right == node) {
+            node->parent->right = NULL;
+
+        } else {
+            node->parent->left = NULL;
+        }
+
+        node->right = tree->free;
+        tree->free = node;
+
+        node = node->parent;
+
+        if (node->right || node->left) {
+            break;
+        }
+
+        if (node->value != NGX_RADIX_NO_VALUE) {
+            break;
+        }
+
+        if (node->parent == NULL) {
+            break;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+uintptr_t
+ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key)
+{
+    u_char             bit;
+    uintptr_t          value;
+    ngx_uint_t         i;
+    ngx_radix_node_t  *node;
+
+    i = 0;
+    bit = 0x80;
+    value = NGX_RADIX_NO_VALUE;
+    node = tree->root;
+
+    while (node) {
+        if (node->value != NGX_RADIX_NO_VALUE) {
+            value = node->value;
+        }
+
+        if (key[i] & bit) {
+            node = node->right;
+
+        } else {
+            node = node->left;
+        }
+
+        bit >>= 1;
+
+        if (bit == 0) {
+            i++;
+            bit = 0x80;
+        }
+    }
+
+    return value;
+}
+
+#endif
+
+
+static ngx_radix_node_t *
 ngx_radix_alloc(ngx_radix_tree_t *tree)
 {
-    char  *p;
+    ngx_radix_node_t  *p;
 
     if (tree->free) {
-        p = (char *) tree->free;
+        p = tree->free;
         tree->free = tree->free->right;
         return p;
     }
@@ -283,7 +480,7 @@
         tree->size = ngx_pagesize;
     }
 
-    p = tree->start;
+    p = (ngx_radix_node_t *) tree->start;
     tree->start += sizeof(ngx_radix_node_t);
     tree->size -= sizeof(ngx_radix_node_t);
 
--- a/src/core/ngx_radix_tree.h	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/core/ngx_radix_tree.h	Tue Dec 25 00:00:00 2012 +0400
@@ -36,11 +36,20 @@
 
 ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool,
     ngx_int_t preallocate);
+
 ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
     uint32_t key, uint32_t mask, uintptr_t value);
 ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
     uint32_t key, uint32_t mask);
 uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);
 
+#if (NGX_HAVE_INET6)
+ngx_int_t ngx_radix128tree_insert(ngx_radix_tree_t *tree,
+    u_char *key, u_char *mask, uintptr_t value);
+ngx_int_t ngx_radix128tree_delete(ngx_radix_tree_t *tree,
+    u_char *key, u_char *mask);
+uintptr_t ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key);
+#endif
+
 
 #endif /* _NGX_RADIX_TREE_H_INCLUDED_ */
--- a/src/http/modules/ngx_http_auth_basic_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_auth_basic_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -20,8 +20,8 @@
 
 
 typedef struct {
-    ngx_str_t                 realm;
-    ngx_http_complex_value_t  user_file;
+    ngx_http_complex_value_t  *realm;
+    ngx_http_complex_value_t   user_file;
 } ngx_http_auth_basic_loc_conf_t;
 
 
@@ -35,22 +35,19 @@
 static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
 static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf);
-static char *ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data);
 static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
 
-static ngx_conf_post_handler_pt  ngx_http_auth_basic_p = ngx_http_auth_basic;
-
 static ngx_command_t  ngx_http_auth_basic_commands[] = {
 
     { ngx_string("auth_basic"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
                         |NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+      ngx_http_set_complex_value_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_auth_basic_loc_conf_t, realm),
-      &ngx_http_auth_basic_p },
+      NULL },
 
     { ngx_string("auth_basic_user_file"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
@@ -103,7 +100,7 @@
     ngx_fd_t                         fd;
     ngx_int_t                        rc;
     ngx_err_t                        err;
-    ngx_str_t                        pwd, user_file;
+    ngx_str_t                        pwd, realm, user_file;
     ngx_uint_t                       i, level, login, left, passwd;
     ngx_file_t                       file;
     ngx_http_auth_basic_ctx_t       *ctx;
@@ -117,7 +114,15 @@
 
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);
 
-    if (alcf->realm.len == 0 || alcf->user_file.value.len == 0) {
+    if (alcf->realm == NULL || alcf->user_file.value.data == NULL) {
+        return NGX_DECLINED;
+    }
+
+    if (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    if (realm.len == 3 && ngx_strncmp(realm.data, "off", 3) == 0) {
         return NGX_DECLINED;
     }
 
@@ -125,7 +130,7 @@
 
     if (ctx) {
         return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd,
-                                                 &alcf->realm);
+                                                 &realm);
     }
 
     rc = ngx_http_auth_basic_user(r);
@@ -135,7 +140,7 @@
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "no user/password was provided for basic authentication");
 
-        return ngx_http_auth_basic_set_realm(r, &alcf->realm);
+        return ngx_http_auth_basic_set_realm(r, &realm);
     }
 
     if (rc == NGX_ERROR) {
@@ -233,7 +238,7 @@
                     pwd.data = &buf[passwd];
 
                     return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd,
-                                                             &alcf->realm);
+                                                             &realm);
                 }
 
                 break;
@@ -271,14 +276,14 @@
 
         ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);
 
-        return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &alcf->realm);
+        return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm);
     }
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "user \"%V\" was not found in \"%V\"",
                   &r->headers_in.user, &user_file);
 
-    return ngx_http_auth_basic_set_realm(r, &alcf->realm);
+    return ngx_http_auth_basic_set_realm(r, &realm);
 }
 
 
@@ -344,14 +349,29 @@
 static ngx_int_t
 ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
 {
+    size_t   len;
+    u_char  *basic, *p;
+
     r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers);
     if (r->headers_out.www_authenticate == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    len = sizeof("Basic realm=\"\"") - 1 + realm->len;
+
+    basic = ngx_pnalloc(r->pool, len);
+    if (basic == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
+    p = ngx_cpymem(p, realm->data, realm->len);
+    *p = '"';
+
     r->headers_out.www_authenticate->hash = 1;
     ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
-    r->headers_out.www_authenticate->value = *realm;
+    r->headers_out.www_authenticate->value.data = basic;
+    r->headers_out.www_authenticate->value.len = len;
 
     return NGX_HTTP_UNAUTHORIZED;
 }
@@ -386,11 +406,11 @@
     ngx_http_auth_basic_loc_conf_t  *prev = parent;
     ngx_http_auth_basic_loc_conf_t  *conf = child;
 
-    if (conf->realm.data == NULL) {
+    if (conf->realm == NULL) {
         conf->realm = prev->realm;
     }
 
-    if (conf->user_file.value.len == 0) {
+    if (conf->user_file.value.data == NULL) {
         conf->user_file = prev->user_file;
     }
 
@@ -418,37 +438,6 @@
 
 
 static char *
-ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data)
-{
-    ngx_str_t  *realm = data;
-
-    size_t   len;
-    u_char  *basic, *p;
-
-    if (ngx_strcmp(realm->data, "off") == 0) {
-        ngx_str_set(realm, "");
-        return NGX_CONF_OK;
-    }
-
-    len = sizeof("Basic realm=\"") - 1 + realm->len + 1;
-
-    basic = ngx_pnalloc(cf->pool, len);
-    if (basic == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
-    p = ngx_cpymem(p, realm->data, realm->len);
-    *p = '"';
-
-    realm->len = len;
-    realm->data = basic;
-
-    return NGX_CONF_OK;
-}
-
-
-static char *
 ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_auth_basic_loc_conf_t *alcf = conf;
@@ -456,7 +445,7 @@
     ngx_str_t                         *value;
     ngx_http_compile_complex_value_t   ccv;
 
-    if (alcf->user_file.value.len) {
+    if (alcf->user_file.value.data) {
         return "is duplicate";
     }
 
--- a/src/http/modules/ngx_http_fastcgi_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_fastcgi_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -3014,7 +3014,7 @@
 
     value = cf->args->elts;
 
-    if (flcf->cache_key.value.len) {
+    if (flcf->cache_key.value.data) {
         return "is duplicate";
     }
 
--- a/src/http/modules/ngx_http_geo_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_geo_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -18,6 +18,14 @@
 
 
 typedef struct {
+    ngx_radix_tree_t                *tree;
+#if (NGX_HAVE_INET6)
+    ngx_radix_tree_t                *tree6;
+#endif
+} ngx_http_geo_trees_t;
+
+
+typedef struct {
     ngx_http_geo_range_t           **low;
     ngx_http_variable_value_t       *default_value;
 } ngx_http_geo_high_ranges_t;
@@ -35,6 +43,9 @@
     ngx_str_t                       *net;
     ngx_http_geo_high_ranges_t       high;
     ngx_radix_tree_t                *tree;
+#if (NGX_HAVE_INET6)
+    ngx_radix_tree_t                *tree6;
+#endif
     ngx_rbtree_t                     rbtree;
     ngx_rbtree_node_t                sentinel;
     ngx_array_t                     *proxies;
@@ -57,7 +68,7 @@
 
 typedef struct {
     union {
-        ngx_radix_tree_t            *tree;
+        ngx_http_geo_trees_t         trees;
         ngx_http_geo_high_ranges_t   high;
     } u;
 
@@ -68,8 +79,8 @@
 } ngx_http_geo_ctx_t;
 
 
-static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r,
-    ngx_http_geo_ctx_t *ctx);
+static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r,
+    ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr);
 static ngx_int_t ngx_http_geo_real_addr(ngx_http_request_t *r,
     ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr);
 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -155,7 +166,7 @@
 };
 
 
-/* AF_INET only */
+/* geo range is AF_INET only */
 
 static ngx_int_t
 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
@@ -163,10 +174,56 @@
 {
     ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
 
+    in_addr_t                   inaddr;
+    ngx_addr_t                  addr;
+    struct sockaddr_in         *sin;
     ngx_http_variable_value_t  *vv;
+#if (NGX_HAVE_INET6)
+    u_char                     *p;
+    struct in6_addr            *inaddr6;
+#endif
+
+    if (ngx_http_geo_addr(r, ctx, &addr) != NGX_OK) {
+        vv = (ngx_http_variable_value_t *)
+                  ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE);
+        goto done;
+    }
+
+    switch (addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
+        p = inaddr6->s6_addr;
 
-    vv = (ngx_http_variable_value_t *)
-              ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx));
+        if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
+            inaddr = p[12] << 24;
+            inaddr += p[13] << 16;
+            inaddr += p[14] << 8;
+            inaddr += p[15];
+
+            vv = (ngx_http_variable_value_t *)
+                      ngx_radix32tree_find(ctx->u.trees.tree, inaddr);
+
+        } else {
+            vv = (ngx_http_variable_value_t *)
+                      ngx_radix128tree_find(ctx->u.trees.tree6, p);
+        }
+
+        break;
+#endif
+
+    default: /* AF_INET */
+        sin = (struct sockaddr_in *) addr.sockaddr;
+        inaddr = ntohl(sin->sin_addr.s_addr);
+
+        vv = (ngx_http_variable_value_t *)
+                  ngx_radix32tree_find(ctx->u.trees.tree, inaddr);
+
+        break;
+    }
+
+done:
 
     *v = *vv;
 
@@ -183,25 +240,65 @@
 {
     ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
 
-    in_addr_t              addr;
+    in_addr_t              inaddr;
+    ngx_addr_t             addr;
     ngx_uint_t             n;
+    struct sockaddr_in    *sin;
     ngx_http_geo_range_t  *range;
+#if (NGX_HAVE_INET6)
+    u_char                *p;
+    struct in6_addr       *inaddr6;
+#endif
 
     *v = *ctx->u.high.default_value;
 
-    addr = ngx_http_geo_addr(r, ctx);
+    if (ngx_http_geo_addr(r, ctx, &addr) == NGX_OK) {
+
+        switch (addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+        case AF_INET6:
+            inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
+
+            if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
+                p = inaddr6->s6_addr;
 
-    range = ctx->u.high.low[addr >> 16];
+                inaddr = p[12] << 24;
+                inaddr += p[13] << 16;
+                inaddr += p[14] << 8;
+                inaddr += p[15];
+
+            } else {
+                inaddr = INADDR_NONE;
+            }
+
+            break;
+#endif
 
-    if (range) {
-        n = addr & 0xffff;
-        do {
-            if (n >= (ngx_uint_t) range->start && n <= (ngx_uint_t) range->end)
-            {
-                *v = *range->value;
-                break;
-            }
-        } while ((++range)->value);
+        default: /* AF_INET */
+            sin = (struct sockaddr_in *) addr.sockaddr;
+            inaddr = ntohl(sin->sin_addr.s_addr);
+            break;
+        }
+
+    } else {
+        inaddr = INADDR_NONE;
+    }
+
+    if (ctx->u.high.low) {
+        range = ctx->u.high.low[inaddr >> 16];
+
+        if (range) {
+            n = inaddr & 0xffff;
+            do {
+                if (n >= (ngx_uint_t) range->start
+                    && n <= (ngx_uint_t) range->end)
+                {
+                    *v = *range->value;
+                    break;
+                }
+            } while ((++range)->value);
+        }
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -211,54 +308,25 @@
 }
 
 
-static in_addr_t
-ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
+static ngx_int_t
+ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx,
+    ngx_addr_t *addr)
 {
-    ngx_addr_t           addr;
-    ngx_table_elt_t     *xfwd;
-    struct sockaddr_in  *sin;
+    ngx_table_elt_t  *xfwd;
 
-    if (ngx_http_geo_real_addr(r, ctx, &addr) != NGX_OK) {
-        return INADDR_NONE;
+    if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) {
+        return NGX_ERROR;
     }
 
     xfwd = r->headers_in.x_forwarded_for;
 
     if (xfwd != NULL && ctx->proxies != NULL) {
-        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data,
+        (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data,
                                            xfwd->value.len, ctx->proxies,
                                            ctx->proxy_recursive);
     }
 
-#if (NGX_HAVE_INET6)
-
-    if (addr.sockaddr->sa_family == AF_INET6) {
-        u_char           *p;
-        in_addr_t         inaddr;
-        struct in6_addr  *inaddr6;
-
-        inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
-
-        if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
-            p = inaddr6->s6_addr;
-
-            inaddr = p[12] << 24;
-            inaddr += p[13] << 16;
-            inaddr += p[14] << 8;
-            inaddr += p[15];
-
-            return inaddr;
-        }
-    }
-
-#endif
-
-    if (addr.sockaddr->sa_family != AF_INET) {
-        return INADDR_NONE;
-    }
-
-    sin = (struct sockaddr_in *) addr.sockaddr;
-    return ntohl(sin->sin_addr.s_addr);
+    return NGX_OK;
 }
 
 
@@ -303,7 +371,6 @@
 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char                     *rv;
-    void                    **p;
     size_t                    len;
     ngx_str_t                *value, name;
     ngx_uint_t                i;
@@ -313,6 +380,9 @@
     ngx_http_variable_t      *var;
     ngx_http_geo_ctx_t       *geo;
     ngx_http_geo_conf_ctx_t   ctx;
+#if (NGX_HAVE_INET6)
+    static struct in6_addr    zero;
+#endif
 
     value = cf->args->elts;
 
@@ -322,6 +392,13 @@
     }
 
     name = value[1];
+
+    if (name.data[0] != '$') {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid variable name \"%V\"", &name);
+        return NGX_CONF_ERROR;
+    }
+
     name.len--;
     name.data++;
 
@@ -333,6 +410,13 @@
         }
 
         name = value[2];
+
+        if (name.data[0] != '$') {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid variable name \"%V\"", &name);
+            return NGX_CONF_ERROR;
+        }
+
         name.len--;
         name.data++;
 
@@ -378,9 +462,9 @@
     geo->proxies = ctx.proxies;
     geo->proxy_recursive = ctx.proxy_recursive;
 
-    if (ctx.high.low) {
+    if (ctx.ranges) {
 
-        if (!ctx.binary_include) {
+        if (ctx.high.low && !ctx.binary_include) {
             for (i = 0; i < 0x10000; i++) {
                 a = (ngx_array_t *) ctx.high.low[i];
 
@@ -395,8 +479,8 @@
                     return NGX_CONF_ERROR;
                 }
 
-                p = (void **) ngx_cpymem(ctx.high.low[i], a->elts, len);
-                *p = NULL;
+                ngx_memcpy(ctx.high.low[i], a->elts, len);
+                ctx.high.low[i][a->nelts].value = NULL;
                 ctx.data_size += len + sizeof(void *);
             }
 
@@ -429,7 +513,18 @@
             }
         }
 
-        geo->u.tree = ctx.tree;
+        geo->u.trees.tree = ctx.tree;
+
+#if (NGX_HAVE_INET6)
+        if (ctx.tree6 == NULL) {
+            ctx.tree6 = ngx_radix_tree_create(cf->pool, -1);
+            if (ctx.tree6 == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        geo->u.trees.tree6 = ctx.tree6;
+#endif
 
         var->get_handler = ngx_http_geo_cidr_variable;
         var->data = (uintptr_t) geo;
@@ -437,16 +532,23 @@
         ngx_destroy_pool(ctx.temp_pool);
         ngx_destroy_pool(pool);
 
-        if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) {
-            return rv;
-        }
-
         if (ngx_radix32tree_insert(ctx.tree, 0, 0,
                                    (uintptr_t) &ngx_http_variable_null_value)
             == NGX_ERROR)
         {
             return NGX_CONF_ERROR;
         }
+
+        /* NGX_BUSY is okay (default was set explicitly) */
+
+#if (NGX_HAVE_INET6)
+        if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr,
+                                    (uintptr_t) &ngx_http_variable_null_value)
+            == NGX_ERROR)
+        {
+            return NGX_CONF_ERROR;
+        }
+#endif
     }
 
     return rv;
@@ -469,7 +571,12 @@
 
         if (ngx_strcmp(value[0].data, "ranges") == 0) {
 
-            if (ctx->tree) {
+            if (ctx->tree
+#if (NGX_HAVE_INET6)
+                || ctx->tree6
+#endif
+               )
+            {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "the \"ranges\" directive must be "
                                    "the first directive inside \"geo\" block");
@@ -920,8 +1027,17 @@
         }
     }
 
+#if (NGX_HAVE_INET6)
+    if (ctx->tree6 == NULL) {
+        ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1);
+        if (ctx->tree6 == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+#endif
+
     if (ngx_strcmp(value[0].data, "default") == 0) {
-        /* cidr.family = AF_INET; */
+        cidr.family = AF_INET;
         cidr.u.in.addr = 0;
         cidr.u.in.mask = 0;
         net = &value[0];
@@ -940,20 +1056,29 @@
             return NGX_CONF_ERROR;
         }
 
-        if (cidr.family != AF_INET) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "\"geo\" supports IPv4 only");
-            return NGX_CONF_ERROR;
+        if (cidr.family == AF_INET) {
+            cidr.u.in.addr = ntohl(cidr.u.in.addr);
+            cidr.u.in.mask = ntohl(cidr.u.in.mask);
         }
 
-        cidr.u.in.addr = ntohl(cidr.u.in.addr);
-        cidr.u.in.mask = ntohl(cidr.u.in.mask);
+        if (del) {
+            switch (cidr.family) {
 
-        if (del) {
-            if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,
-                                       cidr.u.in.mask)
-                != NGX_OK)
-            {
+#if (NGX_HAVE_INET6)
+            case AF_INET6:
+                rc = ngx_radix128tree_delete(ctx->tree6,
+                                             cidr.u.in6.addr.s6_addr,
+                                             cidr.u.in6.mask.s6_addr);
+                break;
+#endif
+
+            default: /* AF_INET */
+                rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,
+                                            cidr.u.in.mask);
+                break;
+            }
+
+            if (rc != NGX_OK) {
                 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                                    "no network \"%V\" to delete", net);
             }
@@ -968,32 +1093,78 @@
         return NGX_CONF_ERROR;
     }
 
-    for (i = 2; i; i--) {
-        rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask,
-                                    (uintptr_t) val);
-        if (rc == NGX_OK) {
-            return NGX_CONF_OK;
-        }
+    switch (cidr.family) {
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        for (i = 2; i; i--) {
+            rc = ngx_radix128tree_insert(ctx->tree6, cidr.u.in6.addr.s6_addr,
+                                         cidr.u.in6.mask.s6_addr,
+                                         (uintptr_t) val);
+
+            if (rc == NGX_OK) {
+                return NGX_CONF_OK;
+            }
+
+            if (rc == NGX_ERROR) {
+                return NGX_CONF_ERROR;
+            }
 
-        if (rc == NGX_ERROR) {
-            return NGX_CONF_ERROR;
+            /* rc == NGX_BUSY */
+
+            old = (ngx_http_variable_value_t *)
+                       ngx_radix128tree_find(ctx->tree6,
+                                             cidr.u.in6.addr.s6_addr);
+
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                  "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
+                  net, val, old);
+
+            rc = ngx_radix128tree_delete(ctx->tree6,
+                                         cidr.u.in6.addr.s6_addr,
+                                         cidr.u.in6.mask.s6_addr);
+
+            if (rc == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
+                return NGX_CONF_ERROR;
+            }
         }
 
-        /* rc == NGX_BUSY */
+        break;
+#endif
+
+    default: /* AF_INET */
+        for (i = 2; i; i--) {
+            rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr,
+                                        cidr.u.in.mask, (uintptr_t) val);
 
-        old = (ngx_http_variable_value_t *)
-              ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask);
+            if (rc == NGX_OK) {
+                return NGX_CONF_OK;
+            }
+
+            if (rc == NGX_ERROR) {
+                return NGX_CONF_ERROR;
+            }
+
+            /* rc == NGX_BUSY */
 
-        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
-                net, val, old);
+            old = (ngx_http_variable_value_t *)
+                       ngx_radix32tree_find(ctx->tree, cidr.u.in.addr);
+
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                  "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
+                  net, val, old);
 
-        rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, cidr.u.in.mask);
+            rc = ngx_radix32tree_delete(ctx->tree,
+                                        cidr.u.in.addr, cidr.u.in.mask);
 
-        if (rc == NGX_ERROR) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
-            return NGX_CONF_ERROR;
+            if (rc == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
+                return NGX_CONF_ERROR;
+            }
         }
+
+        break;
     }
 
     return NGX_CONF_ERROR;
--- a/src/http/modules/ngx_http_gzip_filter_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_gzip_filter_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -321,7 +321,7 @@
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
 
-    if (ctx == NULL || ctx->done) {
+    if (ctx == NULL || ctx->done || r->header_only) {
         return ngx_http_next_body_filter(r, in);
     }
 
@@ -498,6 +498,10 @@
             wbits--;
             memlevel--;
         }
+
+        if (memlevel < 1) {
+            memlevel = 1;
+        }
     }
 
     ctx->wbits = wbits;
--- a/src/http/modules/ngx_http_headers_filter_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_headers_filter_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -74,7 +74,9 @@
 
     { ngx_string("Cache-Control"), 0, ngx_http_add_cache_control },
 
-    { ngx_string("Last-Modified"), 0, ngx_http_set_last_modified },
+    { ngx_string("Last-Modified"),
+                 offsetof(ngx_http_headers_out_t, last_modified),
+                 ngx_http_set_last_modified },
 
     { ngx_string("ETag"),
                  offsetof(ngx_http_headers_out_t, etag),
@@ -153,6 +155,7 @@
     if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL)
         || r != r->main
         || (r->headers_out.status != NGX_HTTP_OK
+            && r->headers_out.status != NGX_HTTP_CREATED
             && r->headers_out.status != NGX_HTTP_NO_CONTENT
             && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
             && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY
@@ -372,27 +375,12 @@
 ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
     ngx_str_t *value)
 {
-    ngx_table_elt_t  *h;
-
-    ngx_http_clear_last_modified(r);
-
-    if (value->len == 0) {
-        return NGX_OK;
-    }
-
-    r->headers_out.last_modified_time = ngx_http_parse_time(value->data,
-                                                            value->len);
-
-    h = ngx_list_push(&r->headers_out.headers);
-    if (h == NULL) {
+    if (ngx_http_set_response_header(r, hv, value) != NGX_OK) {
         return NGX_ERROR;
     }
 
-    r->headers_out.last_modified = h;
-
-    h->hash = 1;
-    h->key = hv->key;
-    h->value = *value;
+    r->headers_out.last_modified_time =
+        (value->len) ? ngx_http_parse_time(value->data, value->len) : -1;
 
     return NGX_OK;
 }
@@ -406,22 +394,27 @@
 
     old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
 
-    if (*old) {
-        (*old)->hash = 0;
-        *old = NULL;
-    }
+    if (value->len == 0) {
+        if (*old) {
+            (*old)->hash = 0;
+            *old = NULL;
+        }
 
-    if (value->len == 0) {
         return NGX_OK;
     }
 
-    h = ngx_list_push(&r->headers_out.headers);
-    if (h == NULL) {
-        return NGX_ERROR;
+    if (*old) {
+        h = *old;
+
+    } else {
+        h = ngx_list_push(&r->headers_out.headers);
+        if (h == NULL) {
+            return NGX_ERROR;
+        }
+
+        *old = h;
     }
 
-    *old = h;
-
     h->hash = 1;
     h->key = hv->key;
     h->value = *value;
--- a/src/http/modules/ngx_http_image_filter_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_image_filter_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -1169,10 +1169,22 @@
         return NULL;
     }
 
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->width = 0;
+     *     conf->height = 0;
+     *     conf->angle = 0;
+     *     conf->wcv = NULL;
+     *     conf->hcv = NULL;
+     *     conf->acv = NULL;
+     *     conf->jqcv = NULL;
+     *     conf->shcv = NULL;
+     */
+
     conf->filter = NGX_CONF_UNSET_UINT;
     conf->jpeg_quality = NGX_CONF_UNSET_UINT;
     conf->sharpen = NGX_CONF_UNSET_UINT;
-    conf->angle = NGX_CONF_UNSET_UINT;
     conf->transparency = NGX_CONF_UNSET;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
 
@@ -1195,27 +1207,29 @@
             conf->filter = prev->filter;
             conf->width = prev->width;
             conf->height = prev->height;
+            conf->angle = prev->angle;
             conf->wcv = prev->wcv;
             conf->hcv = prev->hcv;
+            conf->acv = prev->acv;
         }
     }
 
-    /* 75 is libjpeg default quality */
-    ngx_conf_merge_uint_value(conf->jpeg_quality, prev->jpeg_quality, 75);
+    if (conf->jpeg_quality == NGX_CONF_UNSET_UINT) {
 
-    if (conf->jqcv == NULL) {
-        conf->jqcv = prev->jqcv;
+        /* 75 is libjpeg default quality */
+        ngx_conf_merge_uint_value(conf->jpeg_quality, prev->jpeg_quality, 75);
+
+        if (conf->jqcv == NULL) {
+            conf->jqcv = prev->jqcv;
+        }
     }
 
-    ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0);
+    if (conf->sharpen == NGX_CONF_UNSET_UINT) {
+        ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0);
 
-    if (conf->shcv == NULL) {
-        conf->shcv = prev->shcv;
-    }
-
-    ngx_conf_merge_uint_value(conf->angle, prev->angle, 0);
-    if (conf->acv == NULL) {
-        conf->acv = prev->acv;
+        if (conf->shcv == NULL) {
+            conf->shcv = prev->shcv;
+        }
     }
 
     ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
--- a/src/http/modules/ngx_http_log_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_log_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -9,6 +9,10 @@
 #include <ngx_core.h>
 #include <ngx_http.h>
 
+#if (NGX_ZLIB)
+#include <zlib.h>
+#endif
+
 
 typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
 
@@ -41,6 +45,17 @@
 
 
 typedef struct {
+    u_char                     *start;
+    u_char                     *pos;
+    u_char                     *last;
+
+    ngx_event_t                *event;
+    ngx_msec_t                  flush;
+    ngx_int_t                   gzip;
+} ngx_http_log_buf_t;
+
+
+typedef struct {
     ngx_array_t                *lengths;
     ngx_array_t                *values;
 } ngx_http_log_script_t;
@@ -78,6 +93,17 @@
 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
     ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
 
+#if (NGX_ZLIB)
+static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
+    ngx_int_t level, ngx_log_t *log);
+
+static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
+static void ngx_http_log_gzip_free(void *opaque, void *address);
+#endif
+
+static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
+static void ngx_http_log_flush_handler(ngx_event_t *ev);
+
 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
@@ -132,7 +158,7 @@
 
     { ngx_string("access_log"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
-                        |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,
+                        |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
       ngx_http_log_set_log,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -216,8 +242,8 @@
     size_t                    len;
     ngx_uint_t                i, l;
     ngx_http_log_t           *log;
-    ngx_open_file_t          *file;
     ngx_http_log_op_t        *op;
+    ngx_http_log_buf_t       *buffer;
     ngx_http_log_loc_conf_t  *lcf;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -258,21 +284,25 @@
 
         len += NGX_LINEFEED_SIZE;
 
-        file = log[l].file;
+        buffer = log[l].file ? log[l].file->data : NULL;
 
-        if (file && file->buffer) {
+        if (buffer) {
 
-            if (len > (size_t) (file->last - file->pos)) {
+            if (len > (size_t) (buffer->last - buffer->pos)) {
 
-                ngx_http_log_write(r, &log[l], file->buffer,
-                                   file->pos - file->buffer);
+                ngx_http_log_write(r, &log[l], buffer->start,
+                                   buffer->pos - buffer->start);
 
-                file->pos = file->buffer;
+                buffer->pos = buffer->start;
             }
 
-            if (len <= (size_t) (file->last - file->pos)) {
+            if (len <= (size_t) (buffer->last - buffer->pos)) {
+
+                p = buffer->pos;
 
-                p = file->pos;
+                if (buffer->event && p == buffer->start) {
+                    ngx_add_timer(buffer->event, buffer->flush);
+                }
 
                 for (i = 0; i < log[l].format->ops->nelts; i++) {
                     p = op[i].run(r, p, &op[i]);
@@ -280,10 +310,14 @@
 
                 ngx_linefeed(p);
 
-                file->pos = p;
+                buffer->pos = p;
 
                 continue;
             }
+
+            if (buffer->event && buffer->event->timer_set) {
+                ngx_del_timer(buffer->event);
+            }
         }
 
         line = ngx_pnalloc(r->pool, len);
@@ -310,14 +344,29 @@
 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
     size_t len)
 {
-    u_char     *name;
-    time_t      now;
-    ssize_t     n;
-    ngx_err_t   err;
+    u_char              *name;
+    time_t               now;
+    ssize_t              n;
+    ngx_err_t            err;
+#if (NGX_ZLIB)
+    ngx_http_log_buf_t  *buffer;
+#endif
 
     if (log->script == NULL) {
         name = log->file->name.data;
+
+#if (NGX_ZLIB)
+        buffer = log->file->data;
+
+        if (buffer && buffer->gzip) {
+            n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
+                                  r->connection->log);
+        } else {
+            n = ngx_write_fd(log->file->fd, buf, len);
+        }
+#else
         n = ngx_write_fd(log->file->fd, buf, len);
+#endif
 
     } else {
         name = NULL;
@@ -465,6 +514,194 @@
 }
 
 
+#if (NGX_ZLIB)
+
+static ssize_t
+ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
+    ngx_log_t *log)
+{
+    int          rc, wbits, memlevel;
+    u_char      *out;
+    size_t       size;
+    ssize_t      n;
+    z_stream     zstream;
+    ngx_err_t    err;
+    ngx_pool_t  *pool;
+
+    wbits = MAX_WBITS;
+    memlevel = MAX_MEM_LEVEL - 1;
+
+    while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
+        wbits--;
+        memlevel--;
+    }
+
+    /*
+     * This is a formula from deflateBound() for conservative upper bound of
+     * compressed data plus 18 bytes of gzip wrapper.
+     */
+
+    size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
+
+    ngx_memzero(&zstream, sizeof(z_stream));
+
+    pool = ngx_create_pool(256, log);
+    if (pool == NULL) {
+        /* simulate successful logging */
+        return len;
+    }
+
+    pool->log = log;
+
+    zstream.zalloc = ngx_http_log_gzip_alloc;
+    zstream.zfree = ngx_http_log_gzip_free;
+    zstream.opaque = pool;
+
+    out = ngx_pnalloc(pool, size);
+    if (out == NULL) {
+        goto done;
+    }
+
+    zstream.next_in = buf;
+    zstream.avail_in = len;
+    zstream.next_out = out;
+    zstream.avail_out = size;
+
+    rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
+                      Z_DEFAULT_STRATEGY);
+
+    if (rc != Z_OK) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
+        goto done;
+    }
+
+    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
+                   "deflate in: ni:%p no:%p ai:%ud ao:%ud",
+                   zstream.next_in, zstream.next_out,
+                   zstream.avail_in, zstream.avail_out);
+
+    rc = deflate(&zstream, Z_FINISH);
+
+    if (rc != Z_STREAM_END) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      "deflate(Z_FINISH) failed: %d", rc);
+        goto done;
+    }
+
+    ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
+                   "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
+                   zstream.next_in, zstream.next_out,
+                   zstream.avail_in, zstream.avail_out,
+                   rc);
+
+    size -= zstream.avail_out;
+
+    rc = deflateEnd(&zstream);
+
+    if (rc != Z_OK) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
+        goto done;
+    }
+
+    n = ngx_write_fd(fd, out, size);
+
+    if (n != (ssize_t) size) {
+        err = (n == -1) ? ngx_errno : 0;
+
+        ngx_destroy_pool(pool);
+
+        ngx_set_errno(err);
+        return -1;
+    }
+
+done:
+
+    ngx_destroy_pool(pool);
+
+    /* simulate successful logging */
+    return len;
+}
+
+
+static void *
+ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
+{
+    ngx_pool_t *pool = opaque;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
+                   "gzip alloc: n:%ud s:%ud", items, size);
+
+    return ngx_palloc(pool, items * size);
+}
+
+
+static void
+ngx_http_log_gzip_free(void *opaque, void *address)
+{
+#if 0
+    ngx_pool_t *pool = opaque;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
+#endif
+}
+
+#endif
+
+
+static void
+ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
+{
+    size_t               len;
+    ssize_t              n;
+    ngx_http_log_buf_t  *buffer;
+
+    buffer = file->data;
+
+    len = buffer->pos - buffer->start;
+
+    if (len == 0) {
+        return;
+    }
+
+#if (NGX_ZLIB)
+    if (buffer->gzip) {
+        n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
+    } else {
+        n = ngx_write_fd(file->fd, buffer->start, len);
+    }
+#else
+    n = ngx_write_fd(file->fd, buffer->start, len);
+#endif
+
+    if (n == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                      ngx_write_fd_n " to \"%s\" failed",
+                      file->name.data);
+
+    } else if ((size_t) n != len) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
+                      file->name.data, n, len);
+    }
+
+    buffer->pos = buffer->start;
+
+    if (buffer->event && buffer->event->timer_set) {
+        ngx_del_timer(buffer->event);
+    }
+}
+
+
+static void
+ngx_http_log_flush_handler(ngx_event_t *ev)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                   "http log buffer flush handler");
+
+    ngx_http_log_flush(ev->data, ev->log);
+}
+
+
 static u_char *
 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op)
@@ -848,10 +1085,13 @@
 {
     ngx_http_log_loc_conf_t *llcf = conf;
 
-    ssize_t                     buf;
+    ssize_t                     size;
+    ngx_int_t                   gzip;
     ngx_uint_t                  i, n;
-    ngx_str_t                  *value, name;
+    ngx_msec_t                  flush;
+    ngx_str_t                  *value, name, s;
     ngx_http_log_t             *log;
+    ngx_http_log_buf_t         *buffer;
     ngx_http_log_fmt_t         *fmt;
     ngx_http_log_main_conf_t   *lmcf;
     ngx_http_script_compile_t   sc;
@@ -936,54 +1176,152 @@
             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
         {
             log->format = &fmt[i];
-            goto buffer;
+            break;
         }
     }
 
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "unknown log format \"%V\"", &name);
-    return NGX_CONF_ERROR;
+    if (log->format == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "unknown log format \"%V\"", &name);
+        return NGX_CONF_ERROR;
+    }
+
+    size = 0;
+    flush = 0;
+    gzip = 0;
+
+    for (i = 3; i < cf->args->nelts; i++) {
+
+        if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
+            s.len = value[i].len - 7;
+            s.data = value[i].data + 7;
+
+            size = ngx_parse_size(&s);
 
-buffer:
+            if (size == NGX_ERROR || size == 0) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid buffer size \"%V\"", &s);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
+        if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
+            s.len = value[i].len - 6;
+            s.data = value[i].data + 6;
+
+            flush = ngx_parse_time(&s, 0);
+
+            if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid flush time \"%V\"", &s);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
 
-    if (cf->args->nelts == 4) {
-        if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
+        if (ngx_strncmp(value[i].data, "gzip", 4) == 0
+            && (value[i].len == 4 || value[i].data[4] == '='))
+        {
+#if (NGX_ZLIB)
+            if (size == 0) {
+                size = 64 * 1024;
+            }
+
+            if (value[i].len == 4) {
+                gzip = Z_BEST_SPEED;
+                continue;
+            }
+
+            s.len = value[i].len - 5;
+            s.data = value[i].data + 5;
+
+            gzip = ngx_atoi(s.data, s.len);
+
+            if (gzip < 1 || gzip > 9) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid compression level \"%V\"", &s);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+
+#else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid parameter \"%V\"", &value[3]);
+                               "nginx was built without zlib support");
             return NGX_CONF_ERROR;
+#endif
         }
 
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid parameter \"%V\"", &value[i]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (flush && size == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "no buffer is defined for access_log \"%V\"",
+                           &value[1]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (size) {
+
         if (log->script) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "buffered logs cannot have variables in name");
             return NGX_CONF_ERROR;
         }
 
-        name.len = value[3].len - 7;
-        name.data = value[3].data + 7;
+        if (log->file->data) {
+            buffer = log->file->data;
 
-        buf = ngx_parse_size(&name);
+            if (buffer->last - buffer->start != size
+                || buffer->flush != flush
+                || buffer->gzip != gzip)
+            {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "access_log \"%V\" already defined "
+                                   "with conflicting parameters",
+                                   &value[1]);
+                return NGX_CONF_ERROR;
+            }
 
-        if (buf == NGX_ERROR) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid buffer value \"%V\"", &name);
+            return NGX_CONF_OK;
+        }
+
+        buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
+        if (buffer == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        if (log->file->buffer && log->file->last - log->file->pos != buf) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "access_log \"%V\" already defined "
-                               "with different buffer size", &value[1]);
+        buffer->start = ngx_pnalloc(cf->pool, size);
+        if (buffer->start == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        log->file->buffer = ngx_palloc(cf->pool, buf);
-        if (log->file->buffer == NULL) {
-            return NGX_CONF_ERROR;
+        buffer->pos = buffer->start;
+        buffer->last = buffer->start + size;
+
+        if (flush) {
+            buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
+            if (buffer->event == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            buffer->event->data = log->file;
+            buffer->event->handler = ngx_http_log_flush_handler;
+            buffer->event->log = &cf->cycle->new_log;
+
+            buffer->flush = flush;
         }
 
-        log->file->pos = log->file->buffer;
-        log->file->last = log->file->buffer + buf;
+        buffer->gzip = gzip;
+
+        log->file->flush = ngx_http_log_flush;
+        log->file->data = buffer;
     }
 
     return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_map_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_map_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -209,6 +209,13 @@
     }
 
     name = value[2];
+
+    if (name.data[0] != '$') {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid variable name \"%V\"", &name);
+        return NGX_CONF_ERROR;
+    }
+
     name.len--;
     name.data++;
 
--- a/src/http/modules/ngx_http_proxy_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_proxy_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -837,7 +837,7 @@
         return NGX_ERROR;
     }
 
-    if (plcf->cache_key.value.len) {
+    if (plcf->cache_key.value.data) {
 
         if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
             return NGX_ERROR;
@@ -1614,7 +1614,8 @@
         p->upstream_done = 1;
 
         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
-                      "upstream sent too much data");
+                      "upstream sent more data than specified in "
+                      "\"Content-Length\" header");
     }
 
     return NGX_OK;
@@ -3651,7 +3652,7 @@
 
     value = cf->args->elts;
 
-    if (plcf->cache_key.value.len) {
+    if (plcf->cache_key.value.data) {
         return "is duplicate";
     }
 
--- a/src/http/modules/ngx_http_scgi_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_scgi_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -1771,7 +1771,7 @@
 
     value = cf->args->elts;
 
-    if (scf->cache_key.value.len) {
+    if (scf->cache_key.value.data) {
         return "is duplicate";
     }
 
--- a/src/http/modules/ngx_http_split_clients_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_split_clients_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -139,7 +139,7 @@
 
     name = value[2];
 
-    if (name.len < 2 || name.data[0] != '$') {
+    if (name.data[0] != '$') {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "invalid variable name \"%V\"", &name);
         return NGX_CONF_ERROR;
--- a/src/http/modules/ngx_http_sub_filter_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_sub_filter_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -628,7 +628,7 @@
     ngx_str_t                         *value;
     ngx_http_compile_complex_value_t   ccv;
 
-    if (slcf->match.len) {
+    if (slcf->match.data) {
         return "is duplicate";
     }
 
@@ -688,7 +688,7 @@
     ngx_conf_merge_value(conf->once, prev->once, 1);
     ngx_conf_merge_str_value(conf->match, prev->match, "");
 
-    if (conf->value.value.len == 0) {
+    if (conf->value.value.data == NULL) {
         conf->value = prev->value;
     }
 
--- a/src/http/modules/ngx_http_upstream_least_conn_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_upstream_least_conn_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -313,7 +313,9 @@
         lcp->rrp.peers = peers->next;
         pc->tries = lcp->rrp.peers->number;
 
-        n = lcp->rrp.peers->number / (8 * sizeof(uintptr_t)) + 1;
+        n = (lcp->rrp.peers->number + (8 * sizeof(uintptr_t) - 1))
+                / (8 * sizeof(uintptr_t));
+
         for (i = 0; i < n; i++) {
              lcp->rrp.tried[i] = 0;
         }
--- a/src/http/modules/ngx_http_uwsgi_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_uwsgi_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -1807,7 +1807,7 @@
 
     value = cf->args->elts;
 
-    if (uwcf->cache_key.value.len) {
+    if (uwcf->cache_key.value.data) {
         return "is duplicate";
     }
 
--- a/src/http/modules/ngx_http_xslt_filter_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/ngx_http_xslt_filter_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -307,7 +307,7 @@
     ctx->done = 1;
 
     if (b == NULL) {
-        return ngx_http_filter_finalize_request(r, NULL,
+        return ngx_http_filter_finalize_request(r, &ngx_http_xslt_filter_module,
                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
     }
 
@@ -315,7 +315,7 @@
 
     if (cln == NULL) {
         ngx_free(b->pos);
-        return ngx_http_filter_finalize_request(r, NULL,
+        return ngx_http_filter_finalize_request(r, &ngx_http_xslt_filter_module,
                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
     }
 
--- a/src/http/modules/perl/Makefile.PL	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/perl/Makefile.PL	Tue Dec 25 00:00:00 2012 +0400
@@ -16,20 +16,9 @@
     CCFLAGS           => "$ENV{NGX_PM_CFLAGS}",
     OPTIMIZE          => '-O',
 
-    INC               => "-I ../../../../../src/core " .
-                         "-I ../../../../../src/event " .
-                         "-I ../../../../../src/os/unix " .
-                         "-I ../../../../../src/http " .
-                         "-I ../../../../../src/http/modules " .
-                         "-I ../../../../../src/http/modules/perl " .
-                         "-I ../../../../../$ENV{NGX_OBJS} " .
-                         ($ENV{NGX_PCRE} =~ /^(YES|NO)/ ? "" :
-                             ($ENV{NGX_PCRE} =~ m#^/# ? "-I $ENV{NGX_PCRE} " :
-                                  "-I ../../../../../$ENV{NGX_PCRE} ")) .
-                         ($ENV{NGX_OPENSSL} =~ /^(YES|NO)/ ? "" :
-                             ($ENV{NGX_OPENSSL} =~ m#^/# ?
-                                  "-I $ENV{NGX_OPENSSL}/.openssl/include " :
-                      "-I ../../../../../$ENV{NGX_OPENSSL}/.openssl/include ")),
+    INC               => join(" ", map {
+                             m#^/# ? "-I $_" : "-I ../../../../../$_"
+                         } (split /\s+/, $ENV{NGX_INCS})),
 
     depend => {
         'nginx.c'     =>
--- a/src/http/modules/perl/nginx.pm	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/modules/perl/nginx.pm	Tue Dec 25 00:00:00 2012 +0400
@@ -50,7 +50,7 @@
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '1.3.9';
+our $VERSION = '1.3.10';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
@@ -123,7 +123,7 @@
 
 =head1 SEE ALSO
 
-http://sysoev.ru/nginx/docs/http/ngx_http_perl_module.html
+http://nginx.org/en/docs/http/ngx_http_perl_module.html
 
 =head1 AUTHOR
 
--- a/src/http/ngx_http_core_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/ngx_http_core_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -1001,6 +1001,7 @@
                       "client intended to send too large body: %O bytes",
                       r->headers_in.content_length_n);
 
+        r->expect_tested = 1;
         (void) ngx_http_discard_request_body(r);
         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
         return NGX_OK;
@@ -4593,7 +4594,7 @@
 
     ngx_str_null(&args);
 
-    if (cv.lengths == NULL && uri.data[0] == '/') {
+    if (cv.lengths == NULL && uri.len && uri.data[0] == '/') {
         p = (u_char *) ngx_strchr(uri.data, '?');
 
         if (p) {
--- a/src/http/ngx_http_script.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/ngx_http_script.c	Tue Dec 25 00:00:00 2012 +0400
@@ -114,11 +114,6 @@
 
     v = ccv->value;
 
-    if (v->len == 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter");
-        return NGX_ERROR;
-    }
-
     nv = 0;
     nc = 0;
 
@@ -133,8 +128,9 @@
         }
     }
 
-    if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) {
-
+    if ((v->len == 0 || v->data[0] != '$')
+        && (ccv->conf_prefix || ccv->root_prefix))
+    {
         if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
             return NGX_ERROR;
         }
--- a/src/http/ngx_http_upstream.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/ngx_http_upstream.c	Tue Dec 25 00:00:00 2012 +0400
@@ -636,6 +636,14 @@
 
 found:
 
+    if (uscf == NULL) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "no upstream configuration");
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
     if (uscf->peer.init(r, uscf) != NGX_OK) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -3091,6 +3099,7 @@
     r->connection->log->action = "sending to client";
 
     if (rc == 0
+        && !r->header_only
 #if (NGX_HTTP_CACHE)
         && !r->cached
 #endif
--- a/src/http/ngx_http_upstream_round_robin.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/ngx_http_upstream_round_robin.c	Tue Dec 25 00:00:00 2012 +0400
@@ -474,7 +474,9 @@
         rrp->peers = peers->next;
         pc->tries = rrp->peers->number;
 
-        n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1;
+        n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
+                / (8 * sizeof(uintptr_t));
+
         for (i = 0; i < n; i++) {
              rrp->tried[i] = 0;
         }
--- a/src/http/ngx_http_variables.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/ngx_http_variables.c	Tue Dec 25 00:00:00 2012 +0400
@@ -330,6 +330,12 @@
     ngx_http_variable_t        *v;
     ngx_http_core_main_conf_t  *cmcf;
 
+    if (name->len == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid variable name \"$\"");
+        return NULL;
+    }
+
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
     key = cmcf->variables_keys->keys.elts;
@@ -393,6 +399,12 @@
     ngx_http_variable_t        *v;
     ngx_http_core_main_conf_t  *cmcf;
 
+    if (name->len == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid variable name \"$\"");
+        return NGX_ERROR;
+    }
+
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
     v = cmcf->variables.elts;
--- a/src/http/ngx_http_write_filter_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/http/ngx_http_write_filter_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -207,7 +207,7 @@
     }
 
     if (r->limit_rate) {
-        limit = r->limit_rate * (ngx_time() - r->start_sec + 1)
+        limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
                 - (c->sent - clcf->limit_rate_after);
 
         if (limit <= 0) {
--- a/src/mail/ngx_mail_auth_http_module.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/mail/ngx_mail_auth_http_module.c	Tue Dec 25 00:00:00 2012 +0400
@@ -1388,7 +1388,6 @@
     u.url = value[1];
     u.default_port = 80;
     u.uri_part = 1;
-    u.one_addr = 1;
 
     if (ngx_strncmp(u.url.data, "http://", 7) == 0) {
         u.url.len -= 7;
--- a/src/os/unix/ngx_files.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/os/unix/ngx_files.c	Tue Dec 25 00:00:00 2012 +0400
@@ -363,7 +363,7 @@
 {
     int  n;
 
-    n = glob((char *) gl->pattern, GLOB_NOSORT, NULL, &gl->pglob);
+    n = glob((char *) gl->pattern, 0, NULL, &gl->pglob);
 
     if (n == 0) {
         return NGX_OK;
--- a/src/os/unix/ngx_user.c	Tue Nov 27 00:00:00 2012 +0400
+++ b/src/os/unix/ngx_user.c	Tue Dec 25 00:00:00 2012 +0400
@@ -28,30 +28,27 @@
 {
     char               *value;
     size_t              len;
-    ngx_err_t           err;
     struct crypt_data   cd;
 
-    ngx_set_errno(0);
-
     cd.initialized = 0;
     /* work around the glibc bug */
     cd.current_salt[0] = ~salt[0];
 
     value = crypt_r((char *) key, (char *) salt, &cd);
 
-    err = ngx_errno;
-
-    if (err == 0) {
+    if (value) {
         len = ngx_strlen(value) + 1;
 
         *encrypted = ngx_pnalloc(pool, len);
-        if (*encrypted) {
-            ngx_memcpy(*encrypted, value, len);
-            return NGX_OK;
+        if (*encrypted == NULL) {
+            return NGX_ERROR;
         }
+
+        ngx_memcpy(*encrypted, value, len);
+        return NGX_OK;
     }
 
-    ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt_r() failed");
+    ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, "crypt_r() failed");
 
     return NGX_ERROR;
 }
@@ -75,18 +72,20 @@
 
 #endif
 
-    ngx_set_errno(0);
-
     value = crypt((char *) key, (char *) salt);
 
     if (value) {
         len = ngx_strlen(value) + 1;
 
         *encrypted = ngx_pnalloc(pool, len);
-        if (*encrypted) {
-            ngx_memcpy(*encrypted, value, len);
+        if (*encrypted == NULL) {
+#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
+            ngx_mutex_unlock(ngx_crypt_mutex);
+#endif
+            return NGX_ERROR;
         }
 
+        ngx_memcpy(*encrypted, value, len);
 #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
         ngx_mutex_unlock(ngx_crypt_mutex);
 #endif