changeset 570:9773720b845e

Merge with 0.8.16.
author Maxim Dounin <mdounin@mdounin.ru>
date Sat, 26 Sep 2009 01:25:07 +0400
parents 1e91f9968443 (current diff) b8ac674b0ec9 (diff)
children 5938746e70c2
files .hgtags auto/lib/pcre/patch.config.in auto/lib/pcre/patch.pcre.c auto/lib/pcre/patch.pcre.in auto/lib/pcre/patch.pcre.in.owc auto/modules src/event/modules/ngx_kqueue_module.h src/mail/ngx_mail.h src/mail/ngx_mail_auth_http_module.c src/mail/ngx_mail_core_module.c src/mail/ngx_mail_handler.c src/mail/ngx_mail_proxy_module.c src/mail/ngx_mail_smtp_handler.c src/os/unix/ngx_aio.h src/os/unix/ngx_sunpro_x86.map
diffstat 192 files changed, 9594 insertions(+), 3230 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -241,3 +241,32 @@ c8cfb6c462efa1a49e51fd193e4c645a5cfb212c
 9eda3153223b42932fec477da26be67a8a33b781 NGINX_0_7_45
 56baf312c1b57b425c331a325b7875fd92aff5b8 NGINX_0_7_46
 6866b490272ef912cd285ce6edc2c393546ea947 NGINX_0_7_47
+09f0ef15d5446d925a7b556925235563ef7932f7 NGINX_0_7_48
+3a4102b00f9753c6b851becebe0d04996b7ff50e NGINX_0_7_49
+09b45263c8178db911e60992a21df9278736dfe4 NGINX_0_7_50
+f2c6a737327477de6844021269e95333e03eba19 NGINX_0_7_51
+549994537f15f7212b5f09f1f4d6e00f2dc562f9 NGINX_0_7_52
+392c16f2d85815c32add2715607598013ce58014 NGINX_0_7_53
+ed5e10fb40fc02b64d6c5719141e33f74cccd02a NGINX_0_7_54
+6484cbba022236c1cd094abfa117dd3aa1b70181 NGINX_0_7_55
+829f9a66a65923d1765961bf1c5075869d421633 NGINX_0_7_56
+e66f886a83052c6a09dfbd77bfc78310dd7fd2d9 NGINX_0_7_57
+98143f74eb3d9d87babc0934c9cd7c40b7af277a NGINX_0_7_58
+499474178a112350895b502f16a2d1abe1b5b532 NGINX_0_7_59
+f39b9e29530de0464264608c33d84abf2e10b9f2 NGINX_0_8_0
+207ae3ff044452b1fb8ad28951ff566615a51939 NGINX_0_8_1
+13b908d5338a1db8365c33efc6189569bb9d58a7 NGINX_0_8_2
+f0cac61857ae53b080bb44fa899762c901079dee NGINX_0_8_3
+c178dbab489a192d9e40f7747777a0890e35e93b NGINX_0_8_4
+e8b686f230a83ac654d963d1d8e0f96893e0c372 NGINX_0_8_5
+4b0d7f0bf22b653698898aad108bf5452e25e65c NGINX_0_8_6
+24b676623d4fb72bb90fc2ad251e5c3220009a11 NGINX_0_8_7
+6557aef8a4b2479c0ae5d887e92c311150f75215 NGINX_0_8_8
+43cc6f0b77ce54e4e03b33189a34f99beecffe34 NGINX_0_8_9
+7efcdb93775276c87bcea0e51c889bd3e078430a NGINX_0_8_10
+86dad910eeb6b626d7f37123b464c89bdc110f66 NGINX_0_8_11
+d41628eb4d0a5a82c915b2684a4299f32b0ded22 NGINX_0_8_12
+1bc8c12d80ecec4f7f88c35359585ca5139248e3 NGINX_0_8_13
+80f7156c296569546cf57fa286749d84e0cc8b9d NGINX_0_8_14
+0161f31978175e258b8bb4989262b2ccb5fa9207 NGINX_0_8_15
+005a70f9573bc6bcf760786cb0573a62f1e570f3 NGINX_0_8_16
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,469 @@
 
+Changes with nginx 0.8.16                                        22 Sep 2009
+
+    *) Feature: the "image_filter_transparency" directive.
+
+    *) Bugfix: "addition_types" directive was incorrectly named 
+       "addtion_types".
+
+    *) Bugfix: resolver cache poisoning.
+       Thanks to Matthew Dempsky.
+
+    *) Bugfix: memory leak in resolver.
+       Thanks to Matthew Dempsky.
+
+    *) Bugfix: invalid request line in $request variable was written in 
+       access_log only if error_log was set to "info" or "debug" level.
+
+    *) Bugfix: in PNG alpha-channel support in the 
+       ngx_http_image_filter_module.
+
+    *) Bugfix: nginx always added "Vary: Accept-Encoding" response header 
+       line, if both "gzip_static" and "gzip_vary" were on.
+
+    *) Bugfix: in UTF-8 encoding support by "try_files" directive in 
+       nginx/Windows.
+
+    *) Bugfix: in "post_action" directive usage; the bug had appeared in 
+       0.8.11.
+       Thanks to Igor Artemiev.
+
+
+Changes with nginx 0.8.15                                        14 Sep 2009
+
+    *) Security: a segmentation fault might occur in worker process while 
+       specially crafted request handling.
+       Thanks to Chris Ries.
+
+    *) Bugfix: if names .domain.tld, .sub.domain.tld, and .domain-some.tld 
+       were defined, then the name .sub.domain.tld was matched by 
+       .domain.tld.
+
+    *) Bugfix: in transparency support in the ngx_http_image_filter_module.
+
+    *) Bugfix: in file AIO.
+
+    *) Bugfix: in X-Accel-Redirect usage; the bug had appeared in 0.8.11.
+
+    *) Bugfix: in embedded perl module; the bug had appeared in 0.8.11.
+
+
+Changes with nginx 0.8.14                                        07 Sep 2009
+
+    *) Bugfix: an expired cached response might stick in the "UPDATING" 
+       state.
+
+    *) Bugfix: a segmentation fault might occur in worker process, if 
+       error_log was set to info or debug level.
+       Thanks to Sergey Bochenkov.
+
+    *) Bugfix: in embedded perl module; the bug had appeared in 0.8.11.
+
+    *) Bugfix: an "error_page" directive did not redirect a 413 error; the 
+       bug had appeared in 0.6.10.
+
+
+Changes with nginx 0.8.13                                        31 Aug 2009
+
+    *) Bugfix: in the "aio sendfile" directive; the bug had appeared in 
+       0.8.12.
+
+    *) Bugfix: nginx could not be built without the --with-file-aio option 
+       on FreeBSD; the bug had appeared in 0.8.12.
+
+
+Changes with nginx 0.8.12                                        31 Aug 2009
+
+    *) Feature: the "sendfile" parameter in the "aio" directive on FreeBSD.
+
+    *) Bugfix: in try_files; the bug had appeared in 0.8.11.
+
+    *) Bugfix: in memcached; the bug had appeared in 0.8.11.
+
+
+Changes with nginx 0.8.11                                        28 Aug 2009
+
+    *) Change: now directive "gzip_disable msie6" does not disable gzipping 
+       for MSIE 6.0 SV1.
+
+    *) Feature: file AIO support on FreeBSD and Linux.
+
+    *) Feature: the "directio_alignment" directive.
+
+
+Changes with nginx 0.8.10                                        24 Aug 2009
+
+    *) Bugfix: memory leaks if GeoIP City database was used.
+
+    *) Bugfix: in copying temporary files to permanent storage area; the 
+       bug had appeared in 0.8.9.
+
+
+Changes with nginx 0.8.9                                         17 Aug 2009
+
+    *) Feature: now the start cache loader runs in a separate process; this 
+       should improve large caches handling.
+
+    *) Feature: now temporary files and permanent storage area may reside 
+       at different file systems.
+
+
+Changes with nginx 0.8.8                                         10 Aug 2009
+
+    *) Bugfix: in handling FastCGI headers split in records.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if a 
+       request was handled in two proxied or FastCGIed locations and a 
+       caching was enabled in the first location; the bug had appeared in 
+       0.8.7.
+
+
+Changes with nginx 0.8.7                                         27 Jul 2009
+
+    *) Change: minimum supported OpenSSL version is 0.9.7.
+
+    *) Change: the "ask" parameter of the "ssl_verify_client" directive was 
+       changed to the "optional" parameter and now it checks a client 
+       certificate if it was offered.
+       Thanks to Brice Figureau.
+
+    *) Feature: the $ssl_client_verify variable.
+       Thanks to Brice Figureau.
+
+    *) Feature: the "ssl_crl" directive.
+       Thanks to Brice Figureau.
+
+    *) Feature: the "proxy" parameter of the "geo" directive.
+
+    *) Feature: the "image_filter" directive supports variables for setting 
+       size.
+
+    *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the 
+       bug had appeared in 0.7.7.
+       Thanks to Sergey Zhuravlev.
+
+    *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did 
+       not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", 
+       "X-Accel-Buffering", and "X-Accel-Charset" lines from backend 
+       response header.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend 
+       response header lines; the bug had appeared in 0.7.44.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the "[alert] zero size buf" error if subrequest returns an 
+       empty response; the bug had appeared in 0.8.5.
+
+
+Changes with nginx 0.8.6                                         20 Jul 2009
+
+    *) Feature: the ngx_http_geoip_module.
+
+    *) Bugfix: XSLT filter may fail with message "not well formed XML 
+       document" for valid XML document.
+       Thanks to Kuramoto Eiji.
+
+    *) Bugfix: now in MacOSX, Cygwin, and nginx/Windows locations given by 
+       a regular expression are always tested in case insensitive mode.
+
+    *) Bugfix: now nginx/Windows ignores trailing dots in URI.
+       Thanks to Hugo Leisink.
+
+    *) Bugfix: name of file specified in --conf-path was not honored during 
+       installation; the bug had appeared in 0.6.6.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.8.5                                         13 Jul 2009
+
+    *) Bugfix: now nginx allows underscores in a request method.
+
+    *) Bugfix: a 500 error code was returned for invalid login/password 
+       while HTTP Basic authentication on Windows.
+
+    *) Bugfix: ngx_http_perl_module responses did not work in subrequests.
+
+    *) Bugfix: in ngx_http_limit_req_module.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.8.4                                         22 Jun 2009
+
+    *) Bugfix: nginx could not be built --without-http-cache; the bug had 
+       appeared in 0.8.3.
+
+
+Changes with nginx 0.8.3                                         19 Jun 2009
+
+    *) Feature: the $upstream_cache_status variable.
+
+    *) Bugfix: nginx could not be built on MacOSX 10.6.
+
+    *) Bugfix: nginx could not be built --without-http-cache; the bug had 
+       appeared in 0.8.2.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if a 
+       backend 401 error was intercepted and the backend did not set the 
+       "WWW-Authenticate" response header line.
+       Thanks to Eugene Mychlo.
+
+
+Changes with nginx 0.8.2                                         15 Jun 2009
+
+    *) Bugfix: in open_file_cache and proxy/fastcgi cache interaction on 
+       start up.
+
+    *) Bugfix: open_file_cache might cache open file descriptors too long; 
+       the bug had appeared in 0.7.4.
+
+
+Changes with nginx 0.8.1                                         08 Jun 2009
+
+    *) Feature: the "updating" parameter in "proxy_cache_use_stale" and 
+       "fastcgi_cache_use_stale" directives.
+
+    *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request 
+       header lines were passed to backend while caching if no 
+       "proxy_set_header" directive was used with any parameters.
+
+    *) Bugfix: the "Set-Cookie" and "P3P" response header lines were not 
+       hidden while caching if no "proxy_hide_header/fastcgi_hide_header" 
+       directives were used with any parameters.
+
+    *) Bugfix: the ngx_http_image_filter_module did not support GIF87a 
+       format.
+       Thanks to Denis Ilyinyh.
+
+    *) Bugfix: nginx could not be built modules on Solaris 10 and early; 
+       the bug had appeared in 0.7.56.
+
+
+Changes with nginx 0.8.0                                         02 Jun 2009
+
+    *) Feature: the "keepalive_requests" directive.
+
+    *) Feature: the "limit_rate_after" directive.
+       Thanks to Ivan Debnar.
+
+    *) Bugfix: XLST filter did not work in subrequests.
+
+    *) Bugfix: in relative paths handling in nginx/Windows.
+
+    *) Bugfix: in proxy_store, fastcgi_store, proxy_cache, and 
+       fastcgi_cache in nginx/Windows.
+
+    *) Bugfix: in memory allocation error handling.
+       Thanks to Maxim Dounin and Kirill A. Korinskiy.
+
+
+Changes with nginx 0.7.59                                        25 May 2009
+
+    *) Feature: the "proxy_cache_methods" and "fastcgi_cache_methods" 
+       directives.
+
+    *) Bugfix: socket leak; the bug had appeared in 0.7.25.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault occurred in worker process, 
+       if a request had no body and the $request_body variable was used;
+       the bug had appeared in 0.7.58.
+
+    *) Bugfix: the SSL modules might not built on Solaris and Linux;
+       the bug had appeared in 0.7.56.
+
+    *) Bugfix: ngx_http_xslt_filter_module responses were not handled by 
+       SSI, charset, and gzip filters.
+
+    *) Bugfix: a "charset" directive did not set a charset to 
+       ngx_http_gzip_static_module responses.
+
+
+Changes with nginx 0.7.58                                        18 May 2009
+
+    *) Feature: a "listen" directive of the mail proxy module supports IPv6.
+
+    *) Feature: the "image_filter_jpeg_quality" directive.
+
+    *) Feature: the "client_body_in_single_buffer" directive.
+
+    *) Feature: the $request_body variable.
+
+    *) Bugfix: in ngx_http_autoindex_module in file name links having a ":" 
+       symbol in the name.
+
+    *) Bugfix: "make upgrade" procedure did not work; the bug had appeared 
+       in 0.7.53.
+       Thanks to Denis F. Latypoff.
+
+
+Changes with nginx 0.7.57                                        12 May 2009
+
+    *) Bugfix: a floating-point fault occurred in worker process, if the 
+       ngx_http_image_filter_module errors were redirected to named 
+       location; the bug had appeared in 0.7.56.
+
+
+Changes with nginx 0.7.56                                        11 May 2009
+
+    *) Feature: nginx/Windows supports IPv6 in a "listen" directive of the 
+       HTTP module.
+
+    *) Bugfix: in ngx_http_image_filter_module.
+
+
+Changes with nginx 0.7.55                                        06 May 2009
+
+    *) Bugfix: the http_XXX parameters in "proxy_cache_use_stale" and 
+       "fastcgi_cache_use_stale" directives did not work.
+
+    *) Bugfix: fastcgi cache did not cache header only responses.
+
+    *) Bugfix: of "select() failed (9: Bad file descriptor)" error in 
+       nginx/Unix and "select() failed (10038: ...)" error in nginx/Windows.
+
+    *) Bugfix: a segmentation fault might occur in worker process, if an 
+       "debug_connection" directive was used; the bug had appeared in 
+       0.7.54.
+
+    *) Bugfix: fix ngx_http_image_filter_module building errors.
+
+    *) Bugfix: the files bigger than 2G could not be transferred using 
+       $r->sendfile.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.7.54                                        01 May 2009
+
+    *) Feature: the ngx_http_image_filter_module.
+
+    *) Feature: the "proxy_ignore_headers" and "fastcgi_ignore_headers" 
+       directives.
+
+    *) Bugfix: a segmentation fault might occur in worker process, if an 
+       "open_file_cache_errors off" directive was used; the bug had 
+       appeared in 0.7.53.
+
+    *) Bugfix: the "port_in_redirect off" directive did not work; the bug 
+       had appeared in 0.7.39.
+
+    *) Bugfix: improve handling of "select" method errors.
+
+    *) Bugfix: of "select() failed (10022: ...)" error in nginx/Windows.
+
+    *) Bugfix: in error text descriptions in nginx/Windows; the bug had 
+       appeared in 0.7.53.
+
+
+Changes with nginx 0.7.53                                        27 Apr 2009
+
+    *) Change: now a log set by --error-log-path is created from the very 
+       start-up.
+
+    *) Feature: now the start up errors and warnings are outputted to an 
+       error_log and stderr.
+
+    *) Feature: the empty --prefix= configure parameter forces nginx to use 
+       a directory where it was run as prefix.
+
+    *) Feature: the -p switch.
+
+    *) Feature: the -s switch on Unix platforms.
+
+    *) Feature: the -? and -h switches.
+       Thanks to Jerome Loyet.
+
+    *) Feature: now switches may be set in condensed form.
+
+    *) Bugfix: nginx/Windows did not work if configuration file was given 
+       by the -c switch.
+
+    *) Bugfix: temporary files might be not removed if the "proxy_store", 
+       "fastcgi_store", "proxy_cache", or "fastcgi_cache" were used.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: an incorrect value was passed to mail proxy authentication 
+       server in "Auth-Method" header line; the bug had appeared
+       in 0.7.34.
+       Thanks to Simon Lecaille.
+
+    *) Bugfix: system error text descriptions were not logged on Linux;
+       the bug had appeared in 0.7.45.
+
+    *) Bugfix: the "fastcgi_cache_min_uses" directive did not work.
+       Thanks to Andrew Vorobyoff.
+
+
+Changes with nginx 0.7.52                                        20 Apr 2009
+
+    *) Feature: the first native Windows binary release.
+
+    *) Bugfix: in processing HEAD method while caching.
+
+    *) Bugfix: in processing the "If-Modified-Since", "If-Range", etc. 
+       client request header lines while caching.
+
+    *) Bugfix: now the "Set-Cookie" and "P3P" header lines are hidden in 
+       cacheable responses.
+
+    *) Bugfix: if nginx was built with the ngx_http_perl_module and with a 
+       perl which supports threads, then during a master process exit the 
+       message "panic: MUTEX_LOCK" might be issued.
+
+    *) Bugfix: nginx could not be built --without-http-cache; the bug had 
+       appeared in 0.7.48.
+
+    *) Bugfix: nginx could not be built on platforms different from i386, 
+       amd64, sparc, and ppc; the bug had appeared in 0.7.42.
+
+
+Changes with nginx 0.7.51                                        12 Apr 2009
+
+    *) Feature: the "try_files" directive supports a response code in the 
+       fallback parameter.
+
+    *) Feature: now any response code can be used in the "return" directive.
+
+    *) Bugfix: the "error_page" directive made an external redirect without 
+       query string; the bug had appeared in 0.7.44.
+
+    *) Bugfix: if servers listened on several defined explicitly addresses, 
+       then virtual servers might not work; the bug had appeared in 0.7.39.
+
+
+Changes with nginx 0.7.50                                        06 Apr 2009
+
+    *) Bugfix: the $arg_... variables did not work; the bug had appeared in 
+       0.7.49.
+
+
+Changes with nginx 0.7.49                                        06 Apr 2009
+
+    *) Bugfix: a segmentation fault might occur in worker process, if the 
+       $arg_... variables were used; the bug had appeared in 0.7.48.
+
+
+Changes with nginx 0.7.48                                        06 Apr 2009
+
+    *) Feature: the "proxy_cache_key" directive.
+
+    *) Bugfix: now nginx takes into account the "X-Accel-Expires", 
+       "Expires", and "Cache-Control" header lines in a backend response.
+
+    *) Bugfix: now nginx caches responses for the GET requests only.
+
+    *) Bugfix: the "fastcgi_cache_key" directive was not inherited.
+
+    *) Bugfix: the $arg_... variables did not work with SSI subrequests.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: nginx could not be built with uclibc library.
+       Thanks to Timothy Redaelli.
+
+    *) Bugfix: nginx could not be built on OpenBSD; the bug had 
+       appeared in 0.7.46.
+
+
 Changes with nginx 0.7.47                                        01 Apr 2009
 
     *) Bugfix: nginx could not be built on FreeBSD 6 and early versions; 
@@ -180,7 +645,7 @@ Changes with nginx 0.7.35               
        original request extension.
 
     *) Bugfix: "*domain.tld" names were handled incorrectly in 
-       "server_name", "valid_referers", and "map" directives, if an 
+       "server_name", "valid_referers", and "map" directives, if 
        ".domain.tld" and ".subdomain.domain.tld" wildcards were used; 
        the bug had appeared in 0.7.9.
 
@@ -198,7 +663,7 @@ Changes with nginx 0.7.34               
        Thanks to Maxim Dounin.
 
     *) Bugfix: in a redirect rewrite directive original arguments were 
-       concatenated with new arguments by an "?" rather than an "&";
+       concatenated with new arguments by a "?" rather than an "&";
        the bug had appeared in 0.1.18.
        Thanks to Maxim Dounin.
 
@@ -1572,8 +2037,8 @@ Changes with nginx 0.5.12               
        amd64, sparc, and ppc; the bug had appeared in 0.5.8.
 
     *) Bugfix: a segmentation fault might occur in worker process if the 
-       temporarily files were used while working with FastCGI server; the 
-       bug had appeared in 0.5.8.
+       temporary files were used while working with FastCGI server; the bug 
+       had appeared in 0.5.8.
 
     *) Bugfix: a segmentation fault might occur in worker process if the 
        $fastcgi_script_name variable was logged.
@@ -2476,8 +2941,8 @@ Changes with nginx 0.3.31               
        in 0.3.18.
 
     *) Bugfix: if the HTTPS protocol was used in the "proxy_pass" directive 
-       and the request body was in temporarily file then the request was 
-       not transferred.
+       and the request body was in temporary file then the request was not 
+       transferred.
 
     *) Bugfix: perl 5.8.8 compatibility.
 
@@ -3630,7 +4095,7 @@ Changes with nginx 0.1.18               
        inherited.
 
     *) Bugfix: in a redirect rewrite directive arguments were concatenated 
-       with URI by an "&" rather than an "?".
+       with URI by an "&" rather than a "?".
 
     *) Bugfix: the lines without trailing ";" in the file being included by 
        the ngx_http_geo_module were silently ignored.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,481 @@
 
+éÚÍÅÎÅÎÉÑ × nginx 0.8.16                                          22.09.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á image_filter_transparency.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á "addition_types" ÂÙÌÁ ÎÅ×ÅÒÎÏ ÎÁÚ×ÁÎÁ 
+       "addtion_types".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÏÒÞÉ ËÜÛÁ resolver'Á.
+       óÐÁÓÉÂÏ Matthew Dempsky.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÐÁÍÑÔÉ × resolver'Å.
+       óÐÁÓÉÂÏ Matthew Dempsky.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÎÅ×ÅÒÎÁÑ ÓÔÒÏËÁ ÚÁÐÒÏÓÁ × ÐÅÒÅÍÅÎÎÏÊ $request 
+       ÚÁÐÉÓÙ×ÁÌÁÓØ × access_log ÔÏÌØËÏ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ error_log ÎÁ 
+       ÕÒÏ×ÎÅ info ÉÌÉ debug.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÏÄÄÅÒÖËÅ ÁÌØÆÁ-ËÁÎÁÌÁ PNG × ÍÏÄÕÌÅ 
+       ngx_http_image_filter_module.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ×ÓÅÇÄÁ ÄÏÂÁ×ÌÑÌ ÓÔÒÏËÕ "Vary: Accept-Encoding" × 
+       ÚÁÇÏÌÏ×ÏË ÏÔ×ÅÔÁ, ÅÓÌÉ ÏÂÅ ÄÉÒÅËÔÉ×Ù gzip_static É gzip_vary ÂÙÌÉ 
+       ×ËÌÀÞÅÎÙ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÏÄÄÅÒÖËÅ ËÏÄÉÒÏ×ËÉ UTF-8 ÄÉÒÅËÔÉ×ÏÊ try_files × 
+       nginx/Windows.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ post_action; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.8.11.
+       óÐÁÓÉÂÏ éÇÏÒÀ áÒÔÅÍØÅ×Õ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.15                                          14.09.2009
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÐÒÉ ÏÂÒÁÂÏÔËÅ ÓÐÅÃÉÁÌØÎÏ ÓÏÚÄÁÎÎÏÇÏ ÚÁÐÒÏÓÁ × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault.
+       óÐÁÓÉÂÏ Chris Ries.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÂÙÌÉ ÏÐÉÓÁÎÙ ÉÍÅÎÁ .domain.tld, .sub.domain.tld É 
+       .domain-some.tld, ÔÏ ÉÍÑ .sub.domain.tld ÐÏÐÁÄÁÌÏ ÐÏÄ ÍÁÓËÕ 
+       .domain.tld.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÏÄÄÅÒÖËÅ ÐÒÏÚÒÁÞÎÏÓÔÉ × ÍÏÄÕÌÅ 
+       ngx_http_image_filter_module.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÆÁÊÌÏ×ÏÍ AIO.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ X-Accel-Redirect; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ×ÓÔÒÏÅÎÎÏÇÏ ÐÅÒÌÁ; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.14                                          07.09.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÓÔÁÒÅ×ÛÉÊ ÚÁËÜÛÉÒÏ×ÁÎÎÙÊ ÚÁÐÒÏÓ ÍÏÇ ÚÁÌÉÐÎÕÔØ × 
+       ÓÏÓÔÏÑÎÉÉ "UPDATING".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ error_log ÎÁ ÕÒÏ×ÎÅ info ÉÌÉ debug × 
+       ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault.
+       óÐÁÓÉÂÏ óÅÒÇÅÀ âÏÞÅÎËÏ×Õ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ×ÓÔÒÏÅÎÎÏÇÏ ÐÅÒÌÁ; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á error_page ÎÅ ÐÅÒÅÎÁÐÒÁ×ÌÑÌÁ ÏÛÉÂËÕ 413; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.10.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.13                                          31.08.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÄÉÒÅËÔÉ×Å "aio sendfile"; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.12.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÂÅÚ ÐÁÒÁÍÅÔÒÁ --with-file-aio ÎÁ 
+       FreeBSD; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.12.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.12                                          31.08.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ sendfile × ÄÉÒÅËÔÉ×Å aio ×Ï FreeBSD.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ try_files; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.8.11.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ memcached; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.8.11.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.11                                          28.08.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á "gzip_disable msie6" ÎÅ ÚÁÐÒÅÝÁÅÔ ÓÖÁÔÉÅ 
+       ÄÌÑ MSIE 6.0 SV1.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ ÆÁÊÌÏ×ÏÇÏ AIO ×Ï FreeBSD É Linux.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á directio_alignment.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.10                                          24.08.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞÅË ÐÁÍÑÔÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÂÁÚÙ GeoIP City.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ËÏÐÉÒÏ×ÁÎÉÉ ×ÒÅÍÅÎÎÙÈ ÆÁÊÌÏ× × ÐÏÓÔÏÑÎÎÏÅ 
+       ÍÅÓÔÏ ÈÒÁÎÅÎÉÑ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.9.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.9                                           17.08.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÓÔÁÒÔÏ×ÙÊ ÚÁÇÒÕÚÞÉË ËÜÛÁ ÒÁÂÏÔÁÅÔ × ÏÔÄÅÌØÎÏÍ 
+       ÐÒÏÃÅÓÓ; ÜÔÏ ÄÏÌÖÎÏ ÕÌÕÞÛÉÔØ ÏÂÒÁÂÏÔËÕ ÂÏÌØÛÉÈ ËÜÛÅÊ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ×ÒÅÍÅÎÎÙÅ ÆÁÊÌÙ É ÐÏÓÔÏÑÎÎÏÅ ÍÅÓÔÏ ÈÒÁÎÅÎÉÑ ÍÏÇÕÔ 
+       ÒÁÓÐÏÌÁÇÁÔØÓÑ ÎÁ ÒÁÚÎÙÈ ÆÁÊÌÏ×ÙÈ ÓÉÓÔÅÍÁÈ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.8                                           10.08.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÏÂÒÁÂÏÔËÅ ÚÁÇÏÌÏ×ËÏ× ÏÔ×ÅÔÁ, ÒÁÚÄÅÌ£ÎÎÙÈ × 
+       FastCGI-ÚÁÐÉÓÑÈ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÚÁÐÒÏÓ ÏÂÒÁÂÁÔÙ×ÁÌÓÑ × Ä×ÕÈ ÐÒÏËÓÉÒÏ×ÁÎÎÙÈ ÉÌÉ 
+       FastCGI location'ÁÈ É × ÐÅÒ×ÏÍ ÉÚ ÎÉÈ ÉÓÐÏÌØÚÏ×ÁÌÏÓØ ËÜÛÉÒÏ×ÁÎÉÅ, ÔÏ 
+       × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.8.7.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.7                                           27.07.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÍÉÎÉÍÁÌØÎÁÑ ÐÏÄÄÅÒÖÉ×ÁÅÍÁÑ ×ÅÒÓÉÑ OpenSSL - 0.9.7.
+
+    *) éÚÍÅÎÅÎÉÅ: ÐÁÒÁÍÅÔÒ ask ÄÉÒÅËÔÉ×Ù ssl_verify_client ÉÚÍÅΣΠÎÁ 
+       ÐÁÒÁÍÅÔÒ optional É ÔÅÐÅÒØ ÏÎ ÐÒÏ×ÅÒÑÅÔ ËÌÉÅÎÔÓËÉÊ ÓÅÒÔÉÆÉËÁÔ, ÅÓÌÉ 
+       ÏÎ ÂÙÌ ÐÒÅÄÌÏÖÅÎ.
+       óÐÁÓÉÂÏ Brice Figureau.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $ssl_client_verify.
+       óÐÁÓÉÂÏ Brice Figureau.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á ssl_crl.
+       óÐÁÓÉÂÏ Brice Figureau.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ proxy ÄÉÒÅËÔÉ×Ù geo.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á image_filter ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÅÒÅÍÅÎÎÙÅ ÄÌÑ 
+       ÚÁÄÁÎÉÑ ÒÁÚÍÅÒÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÐÅÒÅÍÅÎÎÏÊ $ssl_client_cert ÐÏÒÔÉÌÏ 
+       ÐÁÍÑÔØ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.7.
+       óÐÁÓÉÂÏ óÅÒÇÅÀ öÕÒÁ×Ì£×Õ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_pass_header É fastcgi_pass_header" ÎÅ 
+       ÐÅÒÅÄÁ×ÁÌÉ ËÌÉÅÎÔÕ ÓÔÒÏËÉ "X-Accel-Redirect", "X-Accel-Limit-Rate", 
+       "X-Accel-Buffering" É "X-Accel-Charset" ÉÚ ÚÁÇÏÌÏ×ËÁ ÏÔ×ÅÔÁ 
+       ÂÜËÅÎÄÁ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÏÂÒÁÂÏÔËÅ ÓÔÒÏË "Last-Modified" É "Accept-Ranges" × 
+       ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.44
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ "[alert] zero size buf" ÐÒÉ ÐÏÌÕÞÅÎÉÉ ÐÕÓÔÙÈ 
+       ÏÔ×ÅÔÙ × ÐÏÄÚÁÐÒÏÓÁÈ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.5.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.6                                           20.07.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_geoip_module.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: XSLT-ÆÉÌØÔÒ ÍÏÇ ×ÙÄÁ×ÁÔØ ÏÛÉÂËÕ "not well formed XML 
+       document" ÄÌÑ ÐÒÁ×ÉÌØÎÏÇÏ ÄÏËÕÍÅÎÔÁ.
+       óÐÁÓÉÂÏ Kuramoto Eiji.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × MacOSX, Cygwin É nginx/Windows ÐÒÉ ÐÒÏ×ÅÒËÅ 
+       location'Ï×, ÚÁÄÁÎÎÙÈ ÒÅÇÕÌÑÒÎÙÍ ×ÙÒÁÖÅÎÉÅÍ, ÔÅÐÅÒØ ×ÓÅÇÄÁ ÄÅÌÁÅÔÓÑ 
+       ÓÒÁ×ÎÅÎÉÅ ÂÅÚ ÕÞ£ÔÁ ÒÅÇÉÓÔÒÁ ÓÉÍ×ÏÌÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ nginx/Windows ÉÇÎÏÒÉÒÕÅÔ ÔÏÞËÉ × ËÏÎÃÅ URI.
+       óÐÁÓÉÂÏ Hugo Leisink.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÉÍÑ ÆÁÊÌÁ ÕËÁÚÁÎÎÏÇÏ × --conf-path ÉÇÎÏÒÉÒÏ×ÁÌÏÓØ ÐÒÉ 
+       ÕÓÔÁÎÏ×ËÅ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.6.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.5                                           13.07.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ nginx ÒÁÚÒÅÛÁÅÔ ÐÏÄÞ£ÒËÉ×ÁÎÉÑ × ÍÅÔÏÄÅ ÚÁÐÒÏÓÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ HTTP Basic-ÁÕÔÅÎÔÉÆÉËÁÃÉÉ ÎÁ Windows 
+       ÄÌÑ ÎÅ×ÅÒÎÙÈ ÉÍÅÎÉ/ÐÁÒÏÌÑ ×ÏÚ×ÒÁÝÁÌÁÓØ 500-ÁÑ ÏÛÉÂËÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÔ×ÅÔÙ ÍÏÄÕÌÑ ngx_http_perl_module ÎÅ ÒÁÂÏÔÁÌÉ × 
+       ÐÏÄÚÁÐÒÏÓÁÈ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÍÏÄÕÌÅ ngx_http_limit_req_module.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.4                                           22.06.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÐÁÒÁÍÅÔÒÏÍ --without-http-cache; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.3.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.3                                           19.06.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $upstream_cache_status.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ MacOSX 10.6.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÐÁÒÁÍÅÔÒÏÍ --without-http-cache; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.2.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÐÅÒÅÈ×ÁÔ 401 ÏÛÉÂËÉ ÏÔ ÂÜËÅÎÄÁ É 
+       ÂÜËÅÎÄ ÎÅ ×ÏÚ×ÒÁÝÁÌ ÓÔÒÏËÕ "WWW-Authenticate" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ, ÔÏ 
+       × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault.
+       óÐÁÓÉÂÏ å×ÇÅÎÉÀ íÙÞÌÏ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.2                                           15.06.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ×Ï ×ÚÁÉÍÏÄÅÊÓÔ×ÉÉ open_file_cache É proxy/fastcgi ËÜÛÁ 
+       ÎÁ ÓÔÁÒÔÅ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: open_file_cache ÍÏÇ ËÜÛÉÒÏ×ÁÔØ ÏÔËÒÙÔÙÅ ÆÁÊÌÙ ÏÞÅÎØ 
+       ÄÏÌÇÏ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.4.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.1                                           08.06.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ updating × ÄÉÒÅËÔÉ×ÁÈ proxy_cache_use_stale É 
+       fastcgi_cache_use_stale.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÔÒÏËÉ "If-Modified-Since", "If-Range" É ÉÍ ÐÏÄÏÂÎÙÅ × 
+       ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ ËÌÉÅÎÔÁ ÐÅÒÅÄÁ×ÁÌÉÓØ ÂÜËÅÎÄÕ ÐÒÉ ËÜÛÉÒÏ×ÁÎÉÉ, ÅÓÌÉ 
+       ÎÅ ÉÓÐÏÌØÚÏ×ÁÌÁÓØ ÄÉÒÅËÔÉ×Á proxy_set_header Ó ÌÀÂÙÍÉ ÐÁÒÁÍÅÔÒÁÍÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÔÒÏËÉ "Set-Cookie" É "P3P" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ 
+       ÎÅ ÓËÒÙ×ÁÌÉÓØ ÐÒÉ ËÜÛÉÒÏ×ÁÎÉÉ, ÅÓÌÉ ÎÅ ÉÓÐÏÌØÚÏ×ÁÌÉÓØ ÄÉÒÅËÔÉ×Ù 
+       proxy_hide_header/fastcgi_hide_header Ó ÌÀÂÙÍÉ ÐÁÒÁÍÅÔÒÁÍÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_image_filter_module ÎÅ ÐÏÎÉÍÁÌ ÆÏÒÍÁÔ 
+       GIF87a.
+       óÐÁÓÉÂÏ äÅÎÉÓÕ éÌØÉÎÙÈ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ Solaris 10 É ÂÏÌÅÅ ÒÁÎÎÉÈ; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.7.56.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.0                                           02.06.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á keepalive_requests.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á limit_rate_after.
+       óÐÁÓÉÂÏ Ivan Debnar.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: XSLT-ÆÉÌØÔÒ ÎÅ ÒÁÂÏÔÁÌ × ÐÏÄÚÁÐÒÏÓÁÈ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÂÒÁÂÏÔËÅ ÏÔÎÏÓÉÔÅÌØÎÙÈ ÐÕÔÅÊ × nginx/Windows.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × proxy_store, fastcgi_store, proxy_cache É 
+       fastcgi_cache × nginx/Windows.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÏÂÒÁÂÏÔËÅ ÏÛÉÂÏË ×ÙÄÅÌÅÎÉÑ ÐÁÍÑÔÉ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ É ëÉÒÉÌÌÕ ëÏÒÉÎÓËÏÍÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.59                                          25.05.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_cache_methods É fastcgi_cache_methods.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ×; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.25.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÏÊ $request_body × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault, ÅÓÌÉ × ÚÁÐÒÏÓÅ ÎÅ ÂÙÌÏ ÔÅÌÁ; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.58.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: SSL-ÍÏÄÕÌÉ ÍÏÇÌÉ ÎÅ ÓÏÂÉÒÁÔØÓÑ ÎÁ Solaris É Linux; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.56.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÔ×ÅÔÙ ÍÏÄÕÌÑ ngx_http_xslt_filter_module ÎÅ 
+       ÏÂÒÁÂÁÔÙ×ÁÌÉÓØ SSI-, charset- É gzip-ÆÉÌØÔÒÁÍÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á charset ÎÅ ÓÔÁ×ÉÌÁ ËÏÄÉÒÏ×ËÕ ÄÌÑ ÏÔ×ÅÔÏ× 
+       ÍÏÄÕÌÑ ngx_http_gzip_static_module.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.58                                          18.05.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á listen ÐÏÞÔÏ×ÏÇÏ ÐÒÏËÓÉ-ÓÅÒ×ÅÒÁ ÐÏÄÄÅÒÖÉ×ÁÅÔ 
+       IPv6.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á image_filter_jpeg_quality.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á client_body_in_single_buffer.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $request_body.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÍÏÄÕÌÅ ngx_http_autoindex_module × ÓÓÙÌËÁÈ ÎÁ ÉÍÅÎÁ 
+       ÆÁÊÌÏ×, ÓÏÄÅÒÖÁÝÉÈ ÓÉÍ×ÏÌ ":".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÏÃÅÄÕÒÁ "make upgrade" ÎÅ ÒÁÂÏÔÁÌÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.7.53.
+       óÐÁÓÉÂÏ äÅÎÉÓÕ ìÁÔÙÐÏ×Õ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.57                                          12.05.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÉ ÏÛÉÂÏË ÍÏÄÕÌÑ 
+       ngx_http_image_filter_module × ÉÍÅÎÏ×ÁÎÎÙÊ location × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ floating-point fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.56.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.56                                          11.05.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: nginx/Windows ÐÏÄÄÅÒÖÉ×ÁÅÔ IPv6 × ÄÉÒÅËÔÉ×Å listen 
+       ÍÏÄÕÌÑ HTTP.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÍÏÄÕÌÅ ngx_http_image_filter_module.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.55                                          06.05.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒÙ http_XXX × ÄÉÒÅËÔÉ×ÁÈ proxy_cache_use_stale É 
+       fastcgi_cache_use_stale ÎÅ ÒÁÂÏÔÁÌÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: fastcgi ËÜÛ ÎÅ ËÜÛÉÒÏ×ÁÌ ÏÔ×ÅÔÙ, ÓÏÓÔÏÑÝÉÅ ÔÏÌØËÏ ÉÚ 
+       ÚÁÇÏÌÏ×ËÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ "select() failed (9: Bad file descriptor)" × 
+       nginx/Unix É "select() failed (10038: ...)" × nginx/Windows.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù debug_connection × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.54.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÓÂÏÒËÅ ÍÏÄÕÌÑ ngx_http_image_filter_module.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÆÁÊÌÙ ÂÏÌØÛÅ 2G ÎÅ ÐÅÒÅÄÁ×ÁÌÉÓØ Ó ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ 
+       $r->sendfile.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.54                                          01.05.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_image_filter_module.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_ignore_headers É fastcgi_ignore_headers.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÙÈ "open_file_cache_errors 
+       on" × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.7.53.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á "port_in_redirect off" ÎÅ ÒÁÂÏÔÁÌÁ; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.7.39.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÌÕÞÛÅÎÉÅ ÏÂÒÁÂÏÔËÉ ÏÛÉÂÏË ÍÅÔÏÄÁ select.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ "select() failed (10022: ...)" × nginx/Windows.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÔÅËÓÔÏ×ÙÈ ÓÏÏÂÝÅÎÉÑÈ Ï ÏÛÉÂËÁÈ × nginx/Windows; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.53.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.53                                          27.04.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÌÏÇ, ÕËÁÚÁÎÎÙÊ × --error-log-path, ÓÏÚÄÁ£ÔÓÑ Ó 
+       ÓÁÍÏÇÏ ÎÁÞÁÌÁ ÒÁÂÏÔÙ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÏÛÉÂËÉ É ÐÒÅÄÕÐÒÅÖÄÅÎÉÑ ÐÒÉ ÓÔÁÒÔÅ ÚÁÐÉÓÙ×ÁÀÔÓÑ × 
+       error_log É ×Ù×ÏÄÑÔÓÑ ÎÁ stderr.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÒÉ ÓÂÏÒËÅ Ó ÐÕÓÔÙÍ ÐÁÒÁÍÅÔÒÏÍ --prefix= nginx 
+       ÉÓÐÏÌØÚÕÅÔ ËÁË ÐÒÅÆÉËÓ ËÁÔÁÌÏÇ, × ËÏÔÏÒÏÍ ÏÎ ÂÙÌ ÚÁÐÕÝÅÎ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ËÌÀÞ -p.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ËÌÀÞ -s ÎÁ Unix-ÐÌÁÔÆÏÒÍÁÈ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ËÌÀÞÉ -? É -h.
+       óÐÁÓÉÂÏ Jerome Loyet.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ËÌÀÞÉ ÍÏÖÎÏ ÚÁÄÁ×ÁÔØ × ÓÖÁÔÏÊ ÆÏÒÍÅ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÎÅ ÒÁÂÏÔÁÌ, ÅÓÌÉ ÆÁÊÌ ËÏÎÆÉÇÕÒÁÃÉÉ ÂÙÌ 
+       ÚÁÄÁÎ ËÌÀÞÏÍ -c.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ× proxy_store, fastcgi_store, 
+       proxy_cache ÉÌÉ fastcgi_cache ×ÒÅÍÅÎÎÙÅ ÆÁÊÌÙ ÍÏÇÌÉ ÎÅ ÕÄÁÌÑÔØÓÑ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÚÁÇÏÌÏ×ËÅ Auth-Method ÚÁÐÒÏÓÁ ÓÅÒ×ÅÒÕ ÁÕÔÅÎÔÉÆÉËÁÃÉÉ 
+       ÐÏÞÔÏ×ÏÇÏ ÐÒÏËÓÉ-ÓÅÒ×ÅÒÁ ÐÅÒÅÄÁ×ÁÌÏÓØ ÎÅ×ÅÒÎÏÅ ÚÎÁÞÅÎÉÅ; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.7.34.
+       óÐÁÓÉÂÏ Simon Lecaille.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÌÏÇÇÉÒÏ×ÁÎÉÉ ÎÁ Linux ÎÅ ÐÉÓÁÌÉÓØ ÔÅËÓÔÏ×ÙÅ 
+       ÏÐÉÓÁÎÉÑ ÓÉÓÔÅÍÎÙÈ ÏÛÉÂÏË; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.45.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á fastcgi_cache_min_uses ÎÅ ÒÁÂÏÔÁÌÁ.
+       óÐÁÓÉÂÏ áÎÄÒÅÀ ÷ÏÒÏÂØ£×Õ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.52                                          20.04.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒ×ÁÑ ÂÉÎÁÒÎÁÑ ×ÅÒÓÉÑ ÐÏÄ Windows.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ËÏÒÒÅËÔÎÁÑ ÏÂÒÁÂÏÔËÁ ÍÅÔÏÄÁ HEAD ÐÒÉ ËÜÛÉÒÏ×ÁÎÉÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ËÏÒÒÅËÔÎÁÑ ÏÂÒÁÂÏÔËÁ ÓÔÒÏË "If-Modified-Since", 
+       "If-Range" É ÉÍ ÐÏÄÏÂÎÙÈ × ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ ËÌÉÅÎÔÁ ÐÒÉ ËÜÛÉÒÏ×ÁÎÉÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÓÔÒÏËÉ "Set-Cookie" É "P3P" ÓËÒÙ×ÁÀÔÓÑ × 
+       ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÄÌÑ ÚÁËÜÛÉÒÏ×ÁÎÎÙÈ ÏÔ×ÅÔÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ nginx ÂÙÌ ÓÏÂÒÁÎ Ó ÍÏÄÕÌÅÍ ngx_http_perl_module É 
+       perl ÐÏÄÄÅÒÖÉ×ÁÌ ÐÏÔÏËÉ, ÔÏ ÐÒÉ ×ÙÈÏÄÅ ÏÓÎÏ×ÎÏÇÏ ÐÒÏÃÅÓÓÁ ÍÏÇÌÁ 
+       ×ÙÄÁ×ÁÔØÓÑ ÏÛÉÂËÁ "panic: MUTEX_LOCK".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÐÁÒÁÍÅÔÒÏÍ --without-http-cache; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.48.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ ÐÌÁÔÆÏÒÍÁÈ, ÏÔÌÉÞÎÙÈ ÏÔ i386, 
+       amd64, sparc É ppc; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.42.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.51                                          12.04.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á try_files ÐÏÄÄÅÒÖÉ×ÁÅÔ ËÏÄ ÏÔ×ÅÔÁ × ÐÏÓÌÅÄÎÅÍ 
+       ÐÁÒÁÍÅÔÒÅ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ × ÄÉÒÅËÔÉ×Å return ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÌÀÂÏÊ ËÏÄ 
+       ÏÔ×ÅÔÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á error_page ÄÅÌÁÌÁ ×ÎÅÛÎÉÊ ÒÅÄÉÒÅËÔ ÂÅÚ ÓÔÒÏËÉ 
+       ÚÁÐÒÏÓÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.44.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÓÅÒ×ÅÒÁ ÓÌÕÛÁÌÉ ÎÁ ÎÅÓËÏÌØËÉÈ Ñ×ÎÏ ÏÐÉÓÁÎÎÙÈ 
+       ÁÄÒÅÓÁÈ, ÔÏ ×ÉÒÔÕÁÌØÎÙÅ ÓÅÒ×ÅÒÁ ÍÏÇÌÉ ÎÅ ÒÁÂÏÔÁÔØ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.7.39.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.50                                          06.04.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÙÅ $arg_... ÎÅ ÒÁÂÏÔÁÌÉ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.7.49.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.49                                          06.04.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÙÈ $arg_... × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.48.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.7.48                                          06.04.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_cache_key.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ nginx ÕÞÉÔÙ×ÁÅÔ ÐÒÉ ËÜÛÉÒÏ×ÁÎÉÉ ÓÔÒÏËÉ 
+       "X-Accel-Expires", "Expires" É "Cache-Control" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ 
+       ÂÜËÅÎÄÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ nginx ËÜÛÉÒÕÅÔ ÔÏÌØËÏ ÏÔ×ÅÔÙ ÎÁ ÚÁÐÒÏÓÙ GET.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á fastcgi_cache_key ÎÅ ÎÁÓÌÅÄÏ×ÁÌÁÓØ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÙÅ $arg_... ÎÅ ÒÁÂÏÔÁÌÉ Ó SSI-ÐÏÄÚÁÐÒÏÓÁÍÉ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÂÉÂÌÉÏÔÅËÏÊ uclibc.
+       óÐÁÓÉÂÏ Timothy Redaelli.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ OpenBSD; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.7.46.
+
+
 éÚÍÅÎÅÎÉÑ × nginx 0.7.47                                          01.04.2009
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ FreeBSD 6 É ÂÏÌÅÅ ÒÁÎÎÉÈ ×ÅÒÓÉÑÈ; 
@@ -1193,7 +1670,7 @@
     *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù open_file_cache, open_file_cache_retest É 
        open_file_cache_errors.
 
-    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÁ ÓÏËÅÔÏ×; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.7.
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ×; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.7.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ÷ ÓÔÒÏËÕ ÚÁÇÏÌÏ×ËÁ ÏÔ×ÅÔÁ "Content-Type", ÕËÁÚÁÎÎÕÀ × 
        ÍÅÔÏÄÅ $r->send_http_header(), ÎÅ ÄÏÂÁ×ÌÑÌÁÓØ ËÏÄÉÒÏ×ËÁ, ÕËÁÚÁÎÎÁÑ × 
--- a/auto/cc/bcc
+++ b/auto/cc/bcc
@@ -24,7 +24,7 @@ esac
 # __stdcall
 #CPU_OPT="$CPU_OPT -ps"
 # __fastcall
-CPU_OPT="$CPU_OPT -pr"
+#CPU_OPT="$CPU_OPT -pr"
 
 CFLAGS="$CFLAGS $CPU_OPT"
 
@@ -46,7 +46,7 @@ NGX_USE_PCH="-Hu -H=$NGX_OBJS/ngx_config
 
 
 # Win32 GUI mode application
-LINK="\$(CC) -laa"
+#LINK="\$(CC) -laa"
 
 
 # the resource file
--- a/auto/cc/gcc
+++ b/auto/cc/gcc
@@ -158,9 +158,10 @@ case "$NGX_GCC_VER" in
     3.* | 4.* )
         # we have a lot of the unused function arguments
         CFLAGS="$CFLAGS -Wno-unused-parameter"
-        CFLAGS="$CFLAGS -Wno-unused-function"
+        CFLAGS="$CFLAGS -Wunused-function"
         CFLAGS="$CFLAGS -Wunused-variable"
         CFLAGS="$CFLAGS -Wunused-value"
+        # 4.2.1 shows the warning in wrong places
         #CFLAGS="$CFLAGS -Wunreachable-code"
     ;;
 
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -51,12 +51,12 @@ case $CPU in
     ;;
 esac
 
-# __cdecl, use with OpenSSL, md5 asm, and sha1 asm
+# __cdecl, default, must be used with OpenSSL, md5 asm, and sha1 asm
 #CPU_OPT="$CPU_OPT -Gd"
 # __stdcall
 #CPU_OPT="$CPU_OPT -Gz"
 # __fastcall
-CPU_OPT="$CPU_OPT -Gr"
+#CPU_OPT="$CPU_OPT -Gr"
 
 
 CFLAGS="$CFLAGS $CPU_OPT"
@@ -86,17 +86,26 @@ LIBC="-MT"
 
 CFLAGS="$CFLAGS $LIBC"
 
+CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib"
+
 # Win32 GUI mode application
-CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib"
-CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup"
+#CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup"
 
 # debug
+# msvc8 under Wine issues
+#     Program database manager mismatch; please check your installation
 if [ $NGX_CC_NAME != msvc8 ]; then
    CFLAGS="$CFLAGS -Zi"
    CORE_LINK="$CORE_LINK -debug"
 fi
 
 
+# MSVC 2005 supports C99 variadic macros
+if [ $NGX_CC_NAME = msvc8 ]; then
+   have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have
+fi
+
+
 # precompiled headers
 CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
 NGX_PCH="$NGX_OBJS/ngx_config.pch"
@@ -115,24 +124,13 @@ ngx_binout="-Fe"
 ngx_objext="obj"
 ngx_binext=".exe"
 
-if [ "$BMAKE" = nmake ]; then
-    # MS nmake
-
-    ngx_long_start='@<<
-        '
-    ngx_long_end='<<'
-    ngx_long_regex_cont=' \
+ngx_long_start='@<<
 	'
-    ngx_long_cont='
+ngx_long_end='<<'
+ngx_long_regex_cont=' \
 	'
-
-else
-    # Borland make
-
-    ngx_long_start='@&&|
-        '
-    ngx_long_end='|'
-fi
+ngx_long_cont='
+	'
 
 # MSVC understand / in path
 #ngx_regex_dirsep='\\'
--- a/auto/cc/owc
+++ b/auto/cc/owc
@@ -71,7 +71,7 @@ NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pc
 
 
 # the link flags, built target is NT GUI mode application
-CORE_LINK="$CORE_LINK -l=nt_win"
+#CORE_LINK="$CORE_LINK -l=nt_win"
 
 
 # the resource file
@@ -87,3 +87,17 @@ ngx_binext=".exe"
 
 ngx_regex_dirsep='\\'
 ngx_dirsep="\\"
+
+ngx_long_start=' '
+ngx_long_end=' '
+ngx_long_regex_cont=' \&\
+	'
+ngx_long_cont=' &
+	'
+
+ngx_regex_cont=' \&\
+	'
+ngx_cont=' &
+	'
+ngx_tab=' &
+		'
--- a/auto/cc/sunc
+++ b/auto/cc/sunc
@@ -45,21 +45,6 @@ fi
 case "$NGX_MACHINE" in
 
     i86pc)
-        ngx_feature="PAUSE hardware capability bug"
-        ngx_feature_name=
-        ngx_feature_run=bug
-        ngx_feature_incs=
-        ngx_feature_path=
-        ngx_feature_libs=
-        ngx_feature_test='__asm ("pause")'
-
-        . auto/feature
-
-        if [ $ngx_found = yes ]; then
-            # disable [ PAUSE ] hwcap for Sun Studio 11
-            CORE_LINK="$CORE_LINK -Msrc/os/unix/ngx_sunpro_x86.map"
-        fi
-
         NGX_AUX=" src/os/unix/ngx_sunpro_x86.il"
     ;;
 
--- a/auto/init
+++ b/auto/init
@@ -43,36 +43,8 @@ fi
 
 cat << END > Makefile
 
-build:
-	\$(MAKE) -f $NGX_MAKEFILE
-
-install:
-	\$(MAKE) -f $NGX_MAKEFILE install
+default:	build
 
 clean:
 	rm -rf Makefile $NGX_OBJS
-
-upgrade:
-	$NGX_SBIN_PATH -t
-
-	kill -USR2 \`cat $NGX_PID_PATH\`
-	sleep 1
-	test -f $NGX_PID_PATH.oldbin
-
-	kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
-
-upgrade1:
-	# upgrade 0.1.x to 0.2+
-
-	$NGX_SBIN_PATH -t
-
-	cp $NGX_PID_PATH $NGX_PID_PATH.oldbin
-
-	kill -USR2 \`cat $NGX_PID_PATH\`
-	sleep 1
-	test -f $NGX_PID_PATH.oldbin
-
-	cp $NGX_PID_PATH $NGX_PID_PATH.newbin
-
-	kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
 END
--- a/auto/install
+++ b/auto/install
@@ -15,6 +15,63 @@ END
 fi
 
 
+case ".$NGX_SBIN_PATH" in
+    ./*)
+    ;;
+
+    .)
+        NGX_SBIN_PATH=$NGX_PREFIX/sbin/nginx
+    ;;
+
+    *)
+        NGX_SBIN_PATH=$NGX_PREFIX/$NGX_SBIN_PATH
+    ;;
+esac
+
+
+case ".$NGX_CONF_PATH" in
+    ./*)
+    ;;
+
+    *)
+        NGX_CONF_PATH=$NGX_PREFIX/$NGX_CONF_PATH
+    ;;
+esac
+
+
+NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH`
+
+
+case ".$NGX_PID_PATH" in
+    ./*)
+    ;;
+
+    *)
+        NGX_PID_PATH=$NGX_PREFIX/$NGX_PID_PATH
+    ;;
+esac
+
+
+case ".$NGX_ERROR_LOG_PATH" in
+    ./*)
+    ;;
+
+    *)
+        NGX_ERROR_LOG_PATH=$NGX_PREFIX/$NGX_ERROR_LOG_PATH
+    ;;
+esac
+
+
+case ".$NGX_HTTP_LOG_PATH" in
+    ./*)
+    ;;
+
+    *)
+        NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH
+    ;;
+esac
+
+
 cat << END                                                    >> $NGX_MAKEFILE
 
 install:	$NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \
@@ -45,7 +102,7 @@ install:	$NGX_OBJS${ngx_dirsep}nginx${ng
 		'\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default'
 
 	test -f '\$(DESTDIR)$NGX_CONF_PATH' \
-		|| cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX'
+		|| cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH'
 	cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default'
 
 	test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \
@@ -67,3 +124,39 @@ if test -n "\$(DESTDIR)$NGX_ERROR_LOG_PA
 END
 
 fi
+
+
+# create Makefile
+
+cat << END >> Makefile
+
+build:
+	\$(MAKE) -f $NGX_MAKEFILE
+
+install:
+	\$(MAKE) -f $NGX_MAKEFILE install
+
+upgrade:
+	$NGX_SBIN_PATH -t
+
+	kill -USR2 \`cat $NGX_PID_PATH\`
+	sleep 1
+	test -f $NGX_PID_PATH.oldbin
+
+	kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
+
+upgrade1:
+	# upgrade 0.1.x to 0.2+
+
+	$NGX_SBIN_PATH -t
+
+	cp $NGX_PID_PATH $NGX_PID_PATH.oldbin
+
+	kill -USR2 \`cat $NGX_PID_PATH\`
+	sleep 1
+	test -f $NGX_PID_PATH.oldbin
+
+	cp $NGX_PID_PATH $NGX_PID_PATH.newbin
+
+	kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
+END
--- a/auto/lib/conf
+++ b/auto/lib/conf
@@ -4,15 +4,29 @@
 
 if [ $USE_PCRE = YES -o $PCRE != NONE ]; then
     . auto/lib/pcre/conf
+
+else
+    if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then
+
+cat << END
+
+$0: error: the HTTP rewrite module requires the PCRE library.
+You can either disable the module by using --without-http_rewrite_module
+option or you have to enable the PCRE support.
+
+END
+        exit 1
+    fi
 fi
 
+
 if [ $USE_OPENSSL = YES ]; then
     . auto/lib/openssl/conf
 fi
 
 if [ $USE_MD5 = YES ]; then
 
-    if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then
+    if [ $USE_OPENSSL = YES ]; then
         have=NGX_HAVE_OPENSSL_MD5_H . auto/have
         have=NGX_OPENSSL_MD5 . auto/have
         MD5=YES
@@ -26,7 +40,7 @@ fi
 
 if [ $USE_SHA1 = YES ]; then
 
-    if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then
+    if [ $USE_OPENSSL = YES ]; then
         have=NGX_HAVE_OPENSSL_SHA1_H . auto/have
         SHA1=YES
         SHA1_LIB=OpenSSL
@@ -45,10 +59,17 @@ if [ $USE_LIBXSLT = YES ]; then
     . auto/lib/libxslt/conf
 fi
 
+if [ $USE_LIBGD = YES ]; then
+    . auto/lib/libgd/conf
+fi
+
 if [ $USE_PERL = YES ]; then
     . auto/lib/perl/conf
 fi
 
+if [ $HTTP_GEOIP = YES ]; then
+    . auto/lib/geoip/conf
+fi
 if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then
     . auto/lib/google-perftools/conf
 fi
new file mode 100644
--- /dev/null
+++ b/auto/lib/geoip/conf
@@ -0,0 +1,78 @@
+
+# Copyright (C) Igor Sysoev
+
+
+    ngx_feature="GeoIP library"
+    ngx_feature_name=
+    ngx_feature_run=no
+    ngx_feature_incs=
+    ngx_feature_path=
+    ngx_feature_libs="-lGeoIP"
+    ngx_feature_test="GeoIP_open(NULL, 0)"
+    . auto/feature
+
+
+if [ $ngx_found = no ]; then
+
+    # FreeBSD port
+
+    ngx_feature="GeoIP library in /usr/local/"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lGeoIP"
+    else
+        ngx_feature_libs="-L/usr/local/lib -lGeoIP"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+    # NetBSD port
+
+    ngx_feature="GeoIP library in /usr/pkg/"
+    ngx_feature_path="/usr/pkg/include/"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lGeoIP"
+    else
+        ngx_feature_libs="-L/usr/pkg/lib -lGeoIP"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+    # MacPorts
+
+    ngx_feature="GeoIP library in /opt/local/"
+    ngx_feature_path="/opt/local/include"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lGeoIP"
+    else
+        ngx_feature_libs="-L/opt/local/lib -lGeoIP"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = yes ]; then
+    CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+else
+
+cat << END
+
+$0: error: the GeoIP module requires the GeoIP library.
+You can either do not enable the module or install the library.
+
+END
+
+    exit 1
+fi
--- a/auto/lib/google-perftools/conf
+++ b/auto/lib/google-perftools/conf
@@ -30,4 +30,15 @@ fi
 
 if [ $ngx_found = yes ]; then
     CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+else
+
+cat << END
+
+$0: error: the Google perftool module requires the Google perftools
+library. You can either do not enable the module or install the library.
+
+END
+
+    exit 1
 fi
new file mode 100644
--- /dev/null
+++ b/auto/lib/libgd/conf
@@ -0,0 +1,82 @@
+
+# Copyright (C) Igor Sysoev
+
+
+    ngx_feature="GD library"
+    ngx_feature_name=
+    ngx_feature_run=no
+    ngx_feature_incs="#include <gd.h>"
+    ngx_feature_path=
+    ngx_feature_libs="-lgd"
+    ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);"
+    . auto/feature
+
+
+if [ $ngx_found = no ]; then
+
+    # FreeBSD port
+
+    ngx_feature="GD library in /usr/local/"
+    ngx_feature_path="/usr/local/include"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lgd"
+    else
+        ngx_feature_libs="-L/usr/local/lib -lgd"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+    # NetBSD port
+
+    ngx_feature="GD library in /usr/pkg/"
+    ngx_feature_path="/usr/pkg/include/"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lgd"
+    else
+        ngx_feature_libs="-L/usr/pkg/lib -lgd"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+    # MacPorts
+
+    ngx_feature="GD library in /opt/local/"
+    ngx_feature_path="/opt/local/include"
+
+    if [ $NGX_RPATH = YES ]; then
+        ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lgd"
+    else
+        ngx_feature_libs="-L/opt/local/lib -lgd"
+    fi
+
+    . auto/feature
+fi
+
+
+if [ $ngx_found = yes ]; then
+
+    CORE_INCS="$CORE_INCS $ngx_feature_path"
+    CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+else
+
+cat << END
+
+$0: error: the HTTP image filter module requires the GD library.
+You can either do not enable the module or install the libraries.
+
+END
+
+    exit 1
+
+fi
--- a/auto/lib/md5/conf
+++ b/auto/lib/md5/conf
@@ -4,7 +4,7 @@
 
 if [ $MD5 != NONE ]; then
 
-    if grep MD5_Init $MD5/md5.h >/dev/null; then
+    if grep MD5_Init $MD5/md5.h 2>&1 >/dev/null; then
         # OpenSSL md5
         OPENSSL_MD5=YES
         have=NGX_HAVE_OPENSSL_MD5 . auto/have
@@ -46,30 +46,30 @@ else
 
     if [ "$NGX_PLATFORM" != win32 ]; then
 
-        MD5=NO
+            MD5=NO
 
-        # Solaris 8/9
+            # FreeBSD, Solaris 10
 
-        ngx_feature="rsaref md5 library"
-        ngx_feature_name=
-        ngx_feature_run=no
-        ngx_feature_incs="#include <md5.h>"
-        ngx_feature_path=
-        ngx_feature_libs="-lmd5"
-        ngx_feature_test="MD5_CTX md5; MD5Init(&md5)"
-        . auto/feature
+            ngx_feature="system md library"
+            ngx_feature_name=
+            ngx_feature_run=no
+            ngx_feature_incs="#include <md5.h>"
+            ngx_feature_path=
+            ngx_feature_libs="-lmd"
+            ngx_feature_test="MD5_CTX md5; MD5Init(&md5)"
+            . auto/feature
 
-        ngx_md5_lib="system md5"
+            ngx_md5_lib="system md"
 
         if [ $ngx_found = no ]; then
 
-            # FreeBSD
+            # Solaris 8/9
 
-            ngx_feature="rsaref md library"
-            ngx_feature_libs="-lmd"
+            ngx_feature="system md5 library"
+            ngx_feature_libs="-lmd5"
             . auto/feature
 
-            ngx_md5_lib="system md"
+            ngx_md5_lib="system md5"
         fi
 
         if [ $ngx_found = no ]; then
@@ -94,6 +94,18 @@ else
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             MD5=YES
             MD5_LIB=$ngx_md5_lib
+        else
+
+cat << END
+
+$0: error: the HTTP cache module requires md5 functions
+from OpenSSL library.  You can either disable the module by using
+--without-http-cache option, or install the OpenSSL library into the system,
+or build the OpenSSL library statically from the source with nginx by using
+--with-http_ssl_module --with-openssl=<path> options.
+
+END
+            exit 1
         fi
 
     fi
--- a/auto/lib/md5/make
+++ b/auto/lib/md5/make
@@ -7,16 +7,19 @@ case "$NGX_CC_NAME" in
     msvc*)
         ngx_makefile=makefile.msvc
         ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC MD5_ASM=$MD5_ASM"
+        ngx_md5="MD5=\"$MD5\""
     ;;
 
     owc*)
         ngx_makefile=makefile.owc
         ngx_opt="CPU_OPT=\"$CPU_OPT\""
+        ngx_md5=`echo MD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
     bcc)
         ngx_makefile=makefile.bcc
         ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DMD5_ASM=$MD5_ASM"
+        ngx_md5=`echo \-DMD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
 esac
@@ -28,14 +31,10 @@ done=NO
 case "$NGX_PLATFORM" in
 
     win32)
-        cp auto/lib/md5/$ngx_makefile $MD5
-
         cat << END                                        >> $NGX_MAKEFILE
 
 `echo "$MD5/md5.lib:	$NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
-	cd `echo $MD5 | sed -e "s/\//$ngx_regex_dirsep/g"`
-	\$(MAKE) -f $ngx_makefile $ngx_opt
-	cd ..\\..\\..
+	\$(MAKE) -f auto/lib/md5/$ngx_makefile $ngx_opt $ngx_md5
 
 END
 
--- a/auto/lib/md5/makefile.bcc
+++ b/auto/lib/md5/makefile.bcc
@@ -7,12 +7,14 @@ CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDI
 !if "$(MD5_ASM)" == "YES"
 
 md5.lib:
+	cd $(MD5)
 	bcc32 -c $(CFLAGS) -DMD5_ASM md5_dgst.c
 	tlib md5.lib +md5_dgst.obj +"asm\m-win32.obj"
 
 !else
 
 md5.lib:
+	cd $(MD5)
 	bcc32 -c $(CFLAGS) md5_dgst.c
 	tlib md5.lib +md5_dgst.obj
 
--- a/auto/lib/md5/makefile.msvc
+++ b/auto/lib/md5/makefile.msvc
@@ -7,12 +7,14 @@ CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC
 !IF "$(MD5_ASM)" == "YES"
 
 md5.lib:
+	cd $(MD5)
 	cl -c $(CFLAGS) -D MD5_ASM md5_dgst.c
 	link -lib -out:md5.lib md5_dgst.obj asm/m-win32.obj
 
 !ELSE
 
 md5.lib:
+	cd $(MD5)
 	cl -c $(CFLAGS) md5_dgst.c
 	link -lib -out:md5.lib md5_dgst.obj
 
--- a/auto/lib/md5/makefile.owc
+++ b/auto/lib/md5/makefile.owc
@@ -5,5 +5,6 @@
 CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT)
 
 md5.lib:
+	cd $(MD5)
 	wcl386 -c $(CFLAGS) -dL_ENDIAN md5_dgst.c
 	wlib -n md5.lib md5_dgst.obj
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -3,24 +3,36 @@
 
 
 if [ $OPENSSL != NONE ]; then
-    CORE_INCS="$CORE_INCS $OPENSSL/include"
 
     case "$CC" in
+
+        cl | bcc32)
+            have=NGX_OPENSSL . auto/have
+            have=NGX_SSL . auto/have
+
+            CFLAGS="$CFLAGS -DNO_SYS_TYPES_H"
+
+            CORE_INCS="$CORE_INCS $OPENSSL/openssl/include"
+            CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h"
+            CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/ssleay32.lib"
+            CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libeay32.lib"
+
+            # libeay32.lib requires gdi32.lib
+            CORE_LIBS="$CORE_LIBS gdi32.lib"
+        ;;
+
         *)
             have=NGX_OPENSSL . auto/have
             have=NGX_SSL . auto/have
-            LINK_DEPS="$LINK_DEPS $OPENSSL/libssl.a $OPENSSL/libcrypto.a"
-            CORE_LIBS="$CORE_LIBS $OPENSSL/libssl.a $OPENSSL/libcrypto.a"
+
+            CORE_INCS="$CORE_INCS $OPENSSL/openssl/include"
+            CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h"
+            CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libssl.a"
+            CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libcrypto.a"
+            CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
         ;;
     esac
 
-    case "$NGX_SYSTEM" in
-        SunOS|Linux)
-            CORE_LIBS="$CORE_LIBS -ldl"
-        ;;
-    esac
-
-
 else
 
     case "$NGX_PLATFORM" in
@@ -36,8 +48,6 @@ else
 
             # libeay32.lib requires gdi32.lib
             CORE_LIBS="$CORE_LIBS gdi32.lib"
-            # OpenSSL 0.8's libeay32.lib requires advapi32.lib
-            CORE_LIBS="$CORE_LIBS advapi32.lib"
         ;;
 
         *)
@@ -54,14 +64,19 @@ else
 
             if [ $ngx_found = yes ]; then
                 have=NGX_SSL . auto/have
-                CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+                CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL"
                 OPENSSL=YES
+            else
+
+cat << END
 
-                case "$NGX_SYSTEM" in
-                    SunOS)
-                        CORE_LIBS="$CORE_LIBS -ldl"
-                    ;;
-                esac
+$0: error: SSL modules require the OpenSSL library.
+You can either do not enable the modules, or install the OpenSSL library
+into the system, or build the OpenSSL library statically from the source
+with nginx by using --with-openssl=<path> option.
+
+END
+                exit 1
             fi
         ;;
 
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -2,26 +2,62 @@
 # Copyright (C) Igor Sysoev
 
 
-if test -n "$OPENSSL_OPT"; then
-    NGX_OPENSSL_CONFIG="./Configure \"$OPENSSL_OPT\""
-else
-    NGX_OPENSSL_CONFIG="./config"
-fi
+case "$CC" in
+
+    cl)
+
+        cat << END                                            >> $NGX_MAKEFILE
+
+$OPENSSL/openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
+	\$(MAKE) -f auto/lib/openssl/makefile.msvc			\
+		OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT"
 
-case $USE_THREADS in
-    NO) NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG no-threads" ;;
-    *)  NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads" ;;
-esac
+END
+
+    ;;
 
-case "$NGX_PLATFORM" in
-    *)
+    bcc32)
+
+        ngx_opt=`echo "-DOPENSSL=\"$OPENSSL\" -DOPENSSL_OPT=\"$OPENSSL_OPT\"" \
+            | sed -e "s/\//$ngx_regex_dirsep/g"`
+
         cat << END                                            >> $NGX_MAKEFILE
 
-$OPENSSL/libssl.a:
+`echo "$OPENSSL\\openssl\\lib\\libeay32.lib:				\
+	$OPENSSL\\openssl\\include\\openssl\\ssl.h"			\
+	| sed -e "s/\//$ngx_regex_dirsep/g"`
+
+`echo "$OPENSSL\\openssl\\lib\\ssleay32.lib:				\
+	$OPENSSL\\openssl\\include\\openssl\\ssl.h"			\
+	| sed -e "s/\//$ngx_regex_dirsep/g"`
+
+`echo "$OPENSSL\\openssl\\include\\openssl\\ssl.h:	$NGX_MAKEFILE"	\
+	| sed -e "s/\//$ngx_regex_dirsep/g"`
+	\$(MAKE) -f auto/lib/openssl/makefile.bcc $ngx_opt
+
+END
+
+    ;;
+
+    *)
+        case $USE_THREADS in
+            NO) OPENSSL_OPT="$OPENSSL_OPT no-threads" ;;
+            *)  OPENSSL_OPT="$OPENSSL_OPT threads" ;;
+        esac
+
+        case $OPENSSL in
+            /*) ngx_prefix="$OPENSSL/openssl" ;;
+            *)  ngx_prefix="$PWD/$OPENSSL/openssl" ;;
+        esac
+
+        cat << END                                            >> $NGX_MAKEFILE
+
+$OPENSSL/openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
 	cd $OPENSSL \\
 	&& \$(MAKE) clean \\
-	&& $NGX_OPENSSL_CONFIG no-shared \\
-	&& \$(MAKE)
+	&& ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\
+	&& \$(MAKE) \\
+	&& \$(MAKE) install
 
 END
 
new file mode 100644
--- /dev/null
+++ b/auto/lib/openssl/makefile.bcc
@@ -0,0 +1,18 @@
+
+# Copyright (C) Igor Sysoev
+
+
+all:
+	cd $(OPENSSL)
+
+	perl Configure BC-32 no-shared --prefix=openssl -DNO_SYS_TYPES_H \
+		$(OPENSSL_OPT)
+
+	ms\do_nasm
+
+	$(MAKE) -f ms\bcb.mak
+	$(MAKE) -f ms\bcb.mak install
+
+	# Borland's make does not expand "[ch]" in
+	#    copy "inc32\openssl\*.[ch]" "openssl\include\openssl"
+	copy inc32\openssl\*.h openssl\include\openssl
new file mode 100644
--- /dev/null
+++ b/auto/lib/openssl/makefile.msvc
@@ -0,0 +1,14 @@
+
+# Copyright (C) Igor Sysoev
+
+
+all:
+	cd $(OPENSSL)
+
+	perl Configure VC-WIN32 no-shared --prefix=openssl -DNO_SYS_TYPES_H \
+		$(OPENSSL_OPT)
+
+	ms\do_ms
+
+	$(MAKE) -f ms\nt.mak
+	$(MAKE) -f ms\nt.mak install
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -161,6 +161,18 @@ else
             CORE_INCS="$CORE_INCS $ngx_feature_path"
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             PCRE=YES
+        else
+
+cat << END
+
+$0: error: the HTTP rewrite module requires the PCRE library.
+You can either disable the module by using --without-http_rewrite_module
+option, or install the PCRE library into the system, or build the PCRE library
+statically from the source with nginx by using --with-pcre=<path> option.
+
+END
+            exit 1
+
         fi
 
     fi
--- a/auto/lib/pcre/make
+++ b/auto/lib/pcre/make
@@ -7,16 +7,19 @@ case "$NGX_CC_NAME" in
     msvc*)
         ngx_makefile=makefile.msvc
         ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC"
+        ngx_pcre="PCRE=\"$PCRE\""
     ;;
 
     owc*)
         ngx_makefile=makefile.owc
         ngx_opt="CPU_OPT=\"$CPU_OPT\""
+        ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
     bcc)
         ngx_makefile=makefile.bcc
         ngx_opt="-DCPU_OPT=\"$CPU_OPT\""
+        ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
 esac
@@ -25,26 +28,14 @@ esac
 case "$NGX_PLATFORM" in
 
     win32)
-        cp auto/lib/pcre/patch.pcre.in $PCRE
-        cp auto/lib/pcre/patch.pcre.in.owc $PCRE
-        cp auto/lib/pcre/patch.config.in $PCRE
-        cp auto/lib/pcre/patch.pcre.c $PCRE
-        cp auto/lib/pcre/$ngx_makefile $PCRE
-
-        ngx_pcre=`echo $PCRE | sed -e "s/\//$ngx_regex_dirsep/g"`
 
         cat << END                                            >> $NGX_MAKEFILE
 
-`echo "$PCRE/pcre.h:	$NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
-	cd $ngx_pcre
-	\$(MAKE) -f $ngx_makefile pcre.h
-	cd ..\\..\\..
+`echo "$PCRE/pcre.lib:	$NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
+	\$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre $ngx_opt
 
-
-`echo "$PCRE/pcre.lib:	$PCRE/pcre.h" | sed -e "s/\//$ngx_regex_dirsep/g"`
-	cd $ngx_pcre
-	\$(MAKE) -f $ngx_makefile $ngx_opt
-	cd ..\\..\\..
+`echo "$PCRE/pcre.h:" | sed -e "s/\//$ngx_regex_dirsep/g"`
+	\$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre pcre.h
 
 END
 
@@ -61,7 +52,6 @@ END
 	&& CC="\$(CC)" CFLAGS="$PCRE_OPT" \\
 	./configure --disable-shared
 
-
 $PCRE/.libs/libpcre.a:	$PCRE/Makefile
 	cd $PCRE \\
 	&& \$(MAKE) libpcre.la
--- a/auto/lib/pcre/makefile.bcc
+++ b/auto/lib/pcre/makefile.bcc
@@ -3,19 +3,23 @@
 
 
 CFLAGS =	-q -O2 -tWM -w-8004 $(CPU_OPT)
-PCREFLAGS =	-DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
+PCREFLAGS =	-DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
 
 
-pcre.lib:	pcre.h
-	bcc32 -q -edftables dftables.c
+pcre.lib:
+	cd $(PCRE)
+
+	bcc32 -c $(CFLAGS) -I. $(PCREFLAGS) pcre_*.c
 
-	dftables > chartables.c
+	> pcre.lst
+	for %n in (*.obj) do @echo +%n & >> pcre.lst
+	echo + >> pcre.lst
 
-	bcc32 -c $(CFLAGS) $(PCREFLAGS) maketables.c get.c study.c pcre.c
-
-	tlib pcre.lib +maketables.obj +get.obj +study.obj +pcre.obj
+	tlib pcre.lib @pcre.lst
 
 pcre.h:
-	patch -o pcre.h pcre.in patch.pcre.in
-	patch -o config.h config.in patch.config.in
-	patch -o pcre.c pcre.c patch.pcre.c
+	cd $(PCRE)
+
+	copy /y pcre.h.generic pcre.h
+	copy /y config.h.generic config.h
+	copy /y pcre_chartables.c.dist pcre_chartables.c
--- a/auto/lib/pcre/makefile.msvc
+++ b/auto/lib/pcre/makefile.msvc
@@ -3,21 +3,19 @@
 
 
 CFLAGS =	-O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT)
-PCREFLAGS =	-DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
+PCREFLAGS =	-DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
 
 
-pcre.lib:	pcre.h
-	cl -Fedftables dftables.c
-
-	dftables > chartables.c
+pcre.lib:
+	cd $(PCRE)
 
-	cl -nologo -c $(CFLAGS) $(PCREFLAGS)				\
-		maketables.c get.c study.c pcre.c
+	cl -nologo -c $(CFLAGS) -I . $(PCREFLAGS) pcre_*.c
 
-	link -lib -out:pcre.lib -verbose:lib				\
-		maketables.obj get.obj study.obj pcre.obj
+	link -lib -out:pcre.lib -verbose:lib pcre_*.obj
 
 pcre.h:
-	patch -o pcre.h pcre.in patch.pcre.in
-	patch -o config.h config.in patch.config.in
-	patch -o pcre.c pcre.c patch.pcre.c
+	cd $(PCRE)
+
+	copy /y pcre.h.generic pcre.h
+	copy /y config.h.generic config.h
+	copy /y pcre_chartables.c.dist pcre_chartables.c
--- a/auto/lib/pcre/makefile.owc
+++ b/auto/lib/pcre/makefile.owc
@@ -3,17 +3,21 @@
 
 
 CFLAGS =	-c -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT)
-PCREFLAGS =	-DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
+PCREFLAGS =	-DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
 
 
-pcre.lib:	pcre.h
-	wcl386 -zq -bt=nt -l=nt -fe=dftables dftables.c
-	dftables > chartables.c
+pcre.lib:
+	cd $(PCRE)
 
-	wcl386 $(CFLAGS) $(PCREFLAGS) maketables.c get.c study.c pcre.c
-	wlib -n pcre.lib maketables.obj get.obj study.obj pcre.obj
+	wcl386 $(CFLAGS) -i=. $(PCREFLAGS) pcre_*.c
 
+	dir /b *.obj > pcre.lst
+
+	wlib -n pcre.lib @pcre.lst
 
 pcre.h:
-	patch -o pcre.h pcre.in patch.pcre.in.owc
-	patch -o config.h config.in patch.config.in
+	cd $(PCRE)
+
+	copy /y pcre.h.generic pcre.h
+	copy /y config.h.generic config.h
+	copy /y pcre_chartables.c.dist pcre_chartables.c
deleted file mode 100644
--- a/auto/lib/pcre/patch.config.in
+++ /dev/null
@@ -1,11 +0,0 @@
---- config.in	Thu Aug 21 14:43:07 2003
-+++ config.in	Sun Mar  7 02:37:24 2004
-@@ -28,7 +28,7 @@
- found. */
- 
- #define HAVE_STRERROR 0
--#define HAVE_MEMMOVE  0
-+#define HAVE_MEMMOVE 1
- 
- /* There are some non-Unix systems that don't even have bcopy(). If this macro
- is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
deleted file mode 100644
--- a/auto/lib/pcre/patch.pcre.c
+++ /dev/null
@@ -1,13 +0,0 @@
---- pcre.c	Thu Aug 21 14:43:07 2003
-+++ pcre.c	Tue Mar 22 12:56:59 2005
-@@ -246,8 +246,8 @@
- extern "C" void  (*pcre_free)(void *) = free;
- extern "C" int   (*pcre_callout)(pcre_callout_block *) = NULL;
- #else
--void *(*pcre_malloc)(size_t) = malloc;
--void  (*pcre_free)(void *) = free;
-+void *(__cdecl *pcre_malloc)(size_t) = malloc;
-+void  (__cdecl *pcre_free)(void *) = free;
- int   (*pcre_callout)(pcre_callout_block *) = NULL;
- #endif
- #endif
deleted file mode 100644
--- a/auto/lib/pcre/patch.pcre.in
+++ /dev/null
@@ -1,26 +0,0 @@
---- pcre.in	Thu Aug 21 14:43:07 2003
-+++ pcre.h	Tue Mar 22 12:56:59 2005
-@@ -10,9 +10,9 @@
- /* The file pcre.h is build by "configure". Do not edit it; instead
- make changes to pcre.in. */
- 
--#define PCRE_MAJOR          @PCRE_MAJOR@
--#define PCRE_MINOR          @PCRE_MINOR@
--#define PCRE_DATE           @PCRE_DATE@
-+#define PCRE_MAJOR          4
-+#define PCRE_MINOR          4
-+#define PCRE_DATE           21-August-2003
- 
- /* Win32 uses DLL by default */
- 
-@@ -143,8 +143,8 @@
- have to be different again. */
- 
- #ifndef VPCOMPAT
--PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
--PCRE_DATA_SCOPE void  (*pcre_free)(void *);
-+PCRE_DATA_SCOPE void *(__cdecl *pcre_malloc)(size_t);
-+PCRE_DATA_SCOPE void  (__cdecl *pcre_free)(void *);
- PCRE_DATA_SCOPE int   (*pcre_callout)(pcre_callout_block *);
- #else   /* VPCOMPAT */
- extern void *pcre_malloc(size_t);
deleted file mode 100644
--- a/auto/lib/pcre/patch.pcre.in.owc
+++ /dev/null
@@ -1,15 +0,0 @@
---- pcre.in	Thu Aug 21 14:43:07 2003
-+++ pcre.h	Tue Mar 22 12:56:59 2005
-@@ -10,9 +10,9 @@
- /* The file pcre.h is build by "configure". Do not edit it; instead
- make changes to pcre.in. */
- 
--#define PCRE_MAJOR          @PCRE_MAJOR@
--#define PCRE_MINOR          @PCRE_MINOR@
--#define PCRE_DATE           @PCRE_DATE@
-+#define PCRE_MAJOR          4
-+#define PCRE_MINOR          4
-+#define PCRE_DATE           21-August-2003
- 
- /* Win32 uses DLL by default */
- 
--- a/auto/lib/sha1/make
+++ b/auto/lib/sha1/make
@@ -7,16 +7,19 @@ case "$NGX_CC_NAME" in
     msvc*)
         ngx_makefile=makefile.msvc
         ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC SHA1_ASM=$SHA1_ASM"
+        ngx_sha1="SHA1=\"$SHA1\""
     ;;
 
     owc*)
         ngx_makefile=makefile.owc
         ngx_opt="CPU_OPT=\"$CPU_OPT\""
+        ngx_sha1=`echo SHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
     bcc)
         ngx_makefile=makefile.bcc
         ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DSHA1_ASM=$SHA1_ASM"
+        ngx_sha1=`echo \-DSHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
 esac
@@ -28,14 +31,10 @@ done=NO
 case "$NGX_PLATFORM" in
 
     win32)
-        cp auto/lib/sha1/$ngx_makefile $SHA1
-
         cat << END                                        >> $NGX_MAKEFILE
 
 `echo "$SHA1/sha1.lib:	$NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
-	cd `echo $SHA1 | sed -e "s/\//$ngx_regex_dirsep/g"`
-	\$(MAKE) -f $ngx_makefile $ngx_opt
-	cd ..\\..\\..
+	\$(MAKE) -f auto/lib/sha1/$ngx_makefile $ngx_opt $ngx_sha1
 
 END
 
--- a/auto/lib/sha1/makefile.bcc
+++ b/auto/lib/sha1/makefile.bcc
@@ -7,12 +7,14 @@ CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDI
 !if "$(SHA1_ASM)" == "YES"
 
 sha1.lib:
+	cd $(SHA1)
 	bcc32 -c $(CFLAGS) -DSHA1_ASM sha1dgst.c
 	tlib sha1.lib +sha1dgst.obj +"asm\s-win32.obj"
 
 !else
 
 sha1.lib:
+	cd $(SHA1)
 	bcc32 -c $(CFLAGS) sha1dgst.c
 	tlib sha1.lib +sha1dgst.obj
 
--- a/auto/lib/sha1/makefile.msvc
+++ b/auto/lib/sha1/makefile.msvc
@@ -7,12 +7,14 @@ CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC
 !IF "$(SHA1_ASM)" == "YES"
 
 sha1.lib:
+	cd $(SHA1)
 	cl -c $(CFLAGS) -D SHA1_ASM sha1dgst.c
 	link -lib -out:sha1.lib sha1dgst.obj asm/s-win32.obj
 
 !ELSE
 
 sha1.lib:
+	cd $(SHA1)
 	cl -c $(CFLAGS) sha1dgst.c
 	link -lib -out:sha1.lib sha1dgst.obj
 
--- a/auto/lib/sha1/makefile.owc
+++ b/auto/lib/sha1/makefile.owc
@@ -5,5 +5,6 @@
 CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT)
 
 sha1.lib:
+	cd $(SHA1)
 	wcl386 -c $(CFLAGS) -dL_ENDIAN sha1dgst.c
 	wlib -n sha1.lib sha1dgst.obj
--- a/auto/lib/zlib/conf
+++ b/auto/lib/zlib/conf
@@ -57,6 +57,17 @@ else
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             ZLIB=YES
             ngx_found=no
+        else
+
+cat << END
+
+$0: error: the HTTP gzip module requires the zlib library.
+You can either disable the module by using --without-http_gzip_module
+option, or install the zlib library into the system, or build the zlib library
+statically from the source with nginx by using --with-zlib=<path> option.
+
+END
+            exit 1
         fi
     fi
 
--- a/auto/lib/zlib/make
+++ b/auto/lib/zlib/make
@@ -7,17 +7,20 @@ case "$NGX_CC_NAME" in
     msvc*)
         ngx_makefile=makefile.msvc
         ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC"
+        ngx_zlib="ZLIB=\"$ZLIB\""
 
     ;;
 
     owc*)
         ngx_makefile=makefile.owc
         ngx_opt="CPU_OPT=\"$CPU_OPT\""
+        ngx_zlib=`echo ZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
     bcc)
         ngx_makefile=makefile.bcc
         ngx_opt="-DCPU_OPT=\"$CPU_OPT\""
+        ngx_zlib=`echo \-DZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"`
     ;;
 
 esac
@@ -29,14 +32,10 @@ done=NO
 case "$NGX_PLATFORM" in
 
     win32)
-        cp auto/lib/zlib/$ngx_makefile $ZLIB
-
         cat << END                                            >> $NGX_MAKEFILE
 
 `echo "$ZLIB/zlib.lib:	$NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
-	cd `echo $ZLIB | sed -e "s/\//$ngx_regex_dirsep/g"`
-	\$(MAKE) -f $ngx_makefile $ngx_opt
-	cd ..\\..\\..
+	\$(MAKE) -f auto/lib/zlib/$ngx_makefile $ngx_opt $ngx_zlib
 
 END
 
--- a/auto/lib/zlib/makefile.bcc
+++ b/auto/lib/zlib/makefile.bcc
@@ -5,6 +5,8 @@
 CFLAGS = -q -O2 -tWM -w-8004 -w-8012 $(CPU_OPT)
 
 zlib.lib:
+	cd $(ZLIB)
+
 	bcc32 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c \
 		compress.c
 
--- a/auto/lib/zlib/makefile.msvc
+++ b/auto/lib/zlib/makefile.msvc
@@ -5,6 +5,8 @@
 CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT)
 
 zlib.lib:
+	cd $(ZLIB)
+
 	cl -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c compress.c
 
 	link -lib -out:zlib.lib adler32.obj crc32.obj deflate.obj \
--- a/auto/lib/zlib/makefile.owc
+++ b/auto/lib/zlib/makefile.owc
@@ -5,5 +5,9 @@
 CFLAGS = -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT)
 
 zlib.lib:
-	wcl386 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c compress.c
-	wlib -n zlib.lib adler32.obj crc32.obj deflate.obj trees.obj zutil.obj compress.obj
+	cd $(ZLIB)
+
+	wcl386 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c &
+		compress.c
+	wlib -n zlib.lib adler32.obj crc32.obj deflate.obj trees.obj &
+		zutil.obj compress.obj
--- a/auto/make
+++ b/auto/make
@@ -2,6 +2,8 @@
 # Copyright (C) Igor Sysoev
 
 
+echo "creating $NGX_MAKEFILE"
+
 mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \
          $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \
          $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \
@@ -23,22 +25,12 @@ LINK =	$LINK
 
 END
 
+
 if test -n "$NGX_PERL_CFLAGS"; then
     echo NGX_PERL_CFLAGS = $NGX_PERL_CFLAGS                   >> $NGX_MAKEFILE
     echo NGX_PM_CFLAGS = $NGX_PM_CFLAGS                       >> $NGX_MAKEFILE
 fi
 
-if [ "$BMAKE" = wmake ]; then
-    echo MAKE = wmake                                         >> $NGX_MAKEFILE
-
-    ngx_regex_cont=' '
-    ngx_long_regex_cont=' '
-    ngx_cont=' '
-    ngx_long_cont=' '
-    ngx_tab=' '
-
-fi
-
 
 # ALL_INCS, required by the addons and by OpenWatcom C precompiled headers
 
--- a/auto/modules
+++ b/auto/modules
@@ -41,6 +41,7 @@ fi
 
 if [ $NGX_TEST_BUILD_EPOLL = YES ]; then
     have=NGX_HAVE_EPOLL . auto/have
+    have=NGX_HAVE_EVENTFD . auto/have
     have=NGX_TEST_BUILD_EPOLL . auto/have
     EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
     CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
@@ -104,6 +105,7 @@ fi
 #     ngx_http_charset_filter
 #     ngx_http_ssi_filter
 #         ngx_http_xslt_filter
+#         ngx_http_image_filter_filter
 #         ngx_http_sub_filter
 #         ngx_http_addition_filter
 #         ngx_http_userid_filter
@@ -148,6 +150,12 @@ if [ $HTTP_XSLT = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_XSLT_SRCS"
 fi
 
+if [ $HTTP_IMAGE_FILTER = YES ]; then
+    USE_LIBGD=YES
+    HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_IMAGE_FILTER_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_IMAGE_SRCS"
+fi
+
 if [ $HTTP_SUB = YES ]; then
     HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SUB_FILTER_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_SUB_SRCS"
@@ -233,6 +241,12 @@ if [ $HTTP_GEO = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_GEO_SRCS"
 fi
 
+if [ $HTTP_GEOIP = YES ]; then
+    have=NGX_HTTP_GEOIP . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_GEOIP_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_GEOIP_SRCS"
+fi
+
 if [ $HTTP_MAP = YES ]; then
     have=NGX_HTTP_MAP . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_MAP_MODULE"
--- a/auto/options
+++ b/auto/options
@@ -43,6 +43,7 @@ EVENT_AIO=NO
 
 USE_THREADS=NO
 
+NGX_FILE_AIO=NO
 NGX_IPV6=NO
 
 HTTP=YES
@@ -60,6 +61,7 @@ HTTP_SSI=YES
 HTTP_POSTPONE=NO
 HTTP_REALIP=NO
 HTTP_XSLT=NO
+HTTP_IMAGE_FILTER=NO
 HTTP_SUB=NO
 HTTP_ADDITION=NO
 HTTP_DAV=NO
@@ -70,6 +72,7 @@ HTTP_AUTOINDEX=YES
 HTTP_RANDOM_INDEX=NO
 HTTP_STATUS=NO
 HTTP_GEO=YES
+HTTP_GEOIP=NO
 HTTP_MAP=YES
 HTTP_REFERER=YES
 HTTP_REWRITE=YES
@@ -123,15 +126,19 @@ USE_PERL=NO
 NGX_PERL=perl
 
 USE_LIBXSLT=NO
+USE_LIBGD=NO
 
 NGX_GOOGLE_PERFTOOLS=NO
 NGX_CPP_TEST=NO
 
 NGX_CPU_CACHE_LINE=
 
+opt=
 
 for option
 do
+    opt="$opt `echo $option | sed -e \"s/\(--[^=]*=\)\(.* .*\)/\1'\2'/\"`"
+
     case "$option" in
         -*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;;
            *) value="" ;;
@@ -140,6 +147,7 @@ do
     case "$option" in
         --help)                          help=yes                   ;;
 
+        --prefix=)                       NGX_PREFIX="!"             ;;
         --prefix=*)                      NGX_PREFIX="$value"        ;;
         --sbin-path=*)                   NGX_SBIN_PATH="$value"     ;;
         --conf-path=*)                   NGX_CONF_PATH="$value"     ;;
@@ -163,6 +171,7 @@ do
         #--with-threads=*)                USE_THREADS="$value"       ;;
         #--with-threads)                  USE_THREADS="pthreads"     ;;
 
+        --with-file-aio)                 NGX_FILE_AIO=YES           ;;
         --with-ipv6)                     NGX_IPV6=YES               ;;
 
         --without-http)                  HTTP=NO                    ;;
@@ -177,6 +186,8 @@ do
         --with-http_realip_module)       HTTP_REALIP=YES            ;;
         --with-http_addition_module)     HTTP_ADDITION=YES          ;;
         --with-http_xslt_module)         HTTP_XSLT=YES              ;;
+        --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES      ;;
+        --with-http_geoip_module)        HTTP_GEOIP=YES             ;;
         --with-http_sub_module)          HTTP_SUB=YES               ;;
         --with-http_dav_module)          HTTP_DAV=YES               ;;
         --with-http_flv_module)          HTTP_FLV=YES               ;;
@@ -267,6 +278,9 @@ do
 done
 
 
+NGX_CONFIGURE="$opt"
+
+
 if [ $help = yes ]; then
 
 cat << END
@@ -293,12 +307,15 @@ cat << END
   --with-poll_module                 enable poll module
   --without-poll_module              disable poll module
 
+  --with-file-aio                    enable file aio support
   --with-ipv6                        enable ipv6 support
 
   --with-http_ssl_module             enable ngx_http_ssl_module
   --with-http_realip_module          enable ngx_http_realip_module
   --with-http_addition_module        enable ngx_http_addition_module
   --with-http_xslt_module            enable ngx_http_xslt_module
+  --with-http_image_filter_module    enable ngx_http_image_filter_module
+  --with-http_geoip_module           enable ngx_http_geoip_module
   --with-http_sub_module             enable ngx_http_sub_module
   --with-http_dav_module             enable ngx_http_dav_module
   --with-http_flv_module             enable ngx_http_flv_module
@@ -409,141 +426,21 @@ if [ ".$NGX_PLATFORM" = ".win32" ]; then
 fi
 
 
-NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}
-
-
-case ".$NGX_SBIN_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_SBIN_PATH=$NGX_PREFIX/sbin/nginx
-    ;;
-
-    *)
-        NGX_SBIN_PATH=$NGX_PREFIX/$NGX_SBIN_PATH
-    ;;
-esac
-
-
-case ".$NGX_CONF_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_CONF_PATH=$NGX_PREFIX/conf/nginx.conf
-    ;;
-
-    *)
-        NGX_CONF_PATH=$NGX_PREFIX/$NGX_CONF_PATH
-    ;;
-esac
-
-
+NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf}
 NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH`
-
-
-case ".$NGX_PID_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_PID_PATH=$NGX_PREFIX/logs/nginx.pid
-    ;;
-
-    *)
-        NGX_PID_PATH=$NGX_PREFIX/$NGX_PID_PATH
-    ;;
-esac
-
-
-case ".$NGX_LOCK_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_LOCK_PATH=$NGX_PREFIX/logs/nginx.lock
-    ;;
-
-    *)
-        NGX_LOCK_PATH=$NGX_PREFIX/$NGX_LOCK_PATH
-    ;;
-esac
-
-
-case ".$NGX_ERROR_LOG_PATH" in
-    ./*)
-    ;;
+NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid}
+NGX_LOCK_PATH=${NGX_LOCK_PATH:-logs/nginx.lock}
 
-    .)
-        NGX_ERROR_LOG_PATH=$NGX_PREFIX/logs/error.log
-    ;;
-
-    .stderr)
-        NGX_ERROR_LOG_PATH=
-    ;;
-
-    *)
-        NGX_ERROR_LOG_PATH=$NGX_PREFIX/$NGX_ERROR_LOG_PATH
-    ;;
-esac
-
-
-case ".$NGX_HTTP_LOG_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_HTTP_LOG_PATH=$NGX_PREFIX/logs/access.log
-    ;;
-
-    *)
-        NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH
-    ;;
-esac
-
-
-case ".$NGX_HTTP_CLIENT_TEMP_PATH" in
-    ./*)
-    ;;
+if [ ".$NGX_ERROR_LOG_PATH" = ".stderr" ]; then
+    NGX_ERROR_LOG_PATH=
+else
+    NGX_ERROR_LOG_PATH=${NGX_ERROR_LOG_PATH:-logs/error.log}
+fi
 
-    .)
-        NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/client_body_temp
-    ;;
-
-    *)
-        NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_CLIENT_TEMP_PATH
-    ;;
-esac
-
-
-case ".$NGX_HTTP_PROXY_TEMP_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/proxy_temp
-    ;;
-
-    *)
-        NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_PROXY_TEMP_PATH
-    ;;
-esac
-
-
-case ".$NGX_HTTP_FASTCGI_TEMP_PATH" in
-    ./*)
-    ;;
-
-    .)
-        NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/fastcgi_temp
-    ;;
-
-    *)
-        NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_FASTCGI_TEMP_PATH
-    ;;
-esac
-
+NGX_HTTP_LOG_PATH=${NGX_HTTP_LOG_PATH:-logs/access.log}
+NGX_HTTP_CLIENT_TEMP_PATH=${NGX_HTTP_CLIENT_TEMP_PATH:-client_body_temp}
+NGX_HTTP_PROXY_TEMP_PATH=${NGX_HTTP_PROXY_TEMP_PATH:-proxy_temp}
+NGX_HTTP_FASTCGI_TEMP_PATH=${NGX_HTTP_FASTCGI_TEMP_PATH:-fastcgi_temp}
 
 case ".$NGX_PERL_MODULES" in
     ./*)
--- a/auto/os/features
+++ b/auto/os/features
@@ -230,3 +230,96 @@ ngx_feature_libs=
 ngx_feature_test="struct statvfs  fs;
                   statvfs(NULL, &fs);"
 . auto/feature
+
+
+ngx_feature="dlopen()"
+ngx_feature_name=
+ngx_feature_run=no
+ngx_feature_incs="#include <dlfcn.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="dlopen(NULL, 0)"
+. auto/feature
+
+
+if [ $ngx_found != yes ]; then
+
+    ngx_feature="dlopen() in libdl"
+    ngx_feature_libs="-ldl"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        NGX_LIBDL="-ldl"
+    fi
+fi
+
+
+ngx_feature="sched_yield()"
+ngx_feature_name="NGX_HAVE_SCHED_YIELD"
+ngx_feature_run=no
+ngx_feature_incs="#include <sched.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="sched_yield()"
+. auto/feature
+
+
+if [ $ngx_found != yes ]; then
+
+    ngx_feature="sched_yield() in librt"
+    ngx_feature_libs="-lrt"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        CORE_LIBS="$CORE_LIBS -lrt"
+    fi
+fi
+
+
+if [ $NGX_FILE_AIO = YES ]; then
+
+    ngx_feature="kqueue AIO support"
+    ngx_feature_name="NGX_HAVE_FILE_AIO"
+    ngx_feature_run=no
+    ngx_feature_incs="#include <aio.h>"
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test="int  n; struct aiocb  iocb;
+                      iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+                      n = aio_read(&iocb)"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        CORE_SRCS="$CORE_SRCS $FILE_AIO_SRCS"
+
+    elif [ $ngx_found = no ]; then
+
+        ngx_feature="Linux AIO support"
+        ngx_feature_name="NGX_HAVE_FILE_AIO"
+        ngx_feature_run=no
+        ngx_feature_incs="#include <linux/aio_abi.h>
+                          #include <sys/syscall.h>"
+        ngx_feature_path=
+        ngx_feature_libs=
+        ngx_feature_test="int  n = SYS_eventfd;
+                          struct iocb  iocb;
+                          iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+                          iocb.aio_flags = IOCB_FLAG_RESFD;
+                          iocb.aio_resfd = -1;"
+        . auto/feature
+
+        if [ $ngx_found = yes ]; then
+            have=NGX_HAVE_EVENTFD . auto/have
+            CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS"
+
+        else
+            cat << END
+
+$0: no supported file AIO was found
+Currently file AIO is supported on FreeBSD 4.3+ and Linux 2.6.22+ only
+
+END
+           exit 1
+        fi
+    fi
+fi
--- a/auto/os/freebsd
+++ b/auto/os/freebsd
@@ -43,6 +43,12 @@ if [ $osreldate -gt 300007 ]; then
     CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS"
 fi
 
+if [ $osreldate -gt 502103 ]; then
+    echo " + sendfile()'s SF_NODISKIO found"
+
+    have=NGX_HAVE_AIO_SENDFILE . auto/have
+fi
+
 
 # kqueue
 
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -18,7 +18,7 @@ CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURC
 # Linux kernel version
 
 version=$((`uname -r \
-         | sed 's/^\([^.]*\)\.\([^.]*\)\.\([^.-]*\).*/\1*256*256+\2*256+\3/'`))
+       | sed 's/^\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1*256*256+\2*256+\3/'`))
 
 version=${version:-0}
 
@@ -124,7 +124,20 @@ ngx_feature_test="long mask = 0;
 . auto/feature
 
 
+# crypt_r()
+
+ngx_feature="crypt_r()"
+ngx_feature_name="NGX_HAVE_GNU_CRYPT_R"
+ngx_feature_run=no
+ngx_feature_incs="#include <crypt.h>"
+ngx_feature_path=
+ngx_feature_libs=-lcrypt
+ngx_feature_test="struct crypt_data  cd;
+                  crypt_r(NULL, NULL, &cd);"
+. auto/feature
+
+
 ngx_include="sys/vfs.h";     . auto/include
 
 
-CC_AUX_FLAGS=$cc_aux_flags
+CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
--- a/auto/os/solaris
+++ b/auto/os/solaris
@@ -7,14 +7,14 @@ have=NGX_SOLARIS . auto/have_headers
 CORE_INCS="$UNIX_INCS"
 CORE_DEPS="$UNIX_DEPS $SOLARIS_DEPS"
 CORE_SRCS="$UNIX_SRCS $SOLARIS_SRCS "
-CORE_LIBS="$CORE_LIBS -lsocket -lnsl -lrt"
+CORE_LIBS="$CORE_LIBS -lsocket -lnsl"
 
 NGX_RPATH=YES
 
 # Solaris's make does not support a blank line between target and rules
 ngx_spacer=
 
-CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64 -lsocket -lnsl -lrt"
+CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64 -lsocket -lnsl"
 
 
 if [ $ZLIB_ASM != NO ]; then
--- a/auto/os/win32
+++ b/auto/os/win32
@@ -8,8 +8,9 @@ CORE_INCS="$WIN32_INCS"
 CORE_DEPS="$WIN32_DEPS"
 CORE_SRCS="$WIN32_SRCS $IOCP_SRCS"
 OS_CONFIG="$WIN32_CONFIG"
-CORE_LIBS="$CORE_LIBS shell32.lib ws2_32.lib"
+CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib"
 NGX_ICONS="$NGX_WIN32_ICONS"
+SELECT_SRCS=$WIN32_SELECT_SRCS
 
 EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE"
 EVENT_FOUND=YES
@@ -19,5 +20,9 @@ if [ $EVENT_SELECT = NO ]; then
     EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE"
 fi
 
+if [ $NGX_IPV6 = YES ]; then
+    have=NGX_HAVE_INET6 . auto/have
+fi
+
 have=NGX_HAVE_AIO . auto/have
 have=NGX_HAVE_IOCP . auto/have
--- a/auto/sources
+++ b/auto/sources
@@ -95,6 +95,7 @@ EVENT_SRCS="src/event/ngx_event.c \
 
 SELECT_MODULE=ngx_select_module
 SELECT_SRCS=src/event/modules/ngx_select_module.c
+WIN32_SELECT_SRCS=src/event/modules/ngx_win32_select_module.c
 
 POLL_MODULE=ngx_poll_module
 POLL_SRCS=src/event/modules/ngx_poll_module.c
@@ -124,6 +125,8 @@ AIO_SRCS="src/event/modules/ngx_aio_modu
           src/os/unix/ngx_aio_read_chain.c \
           src/os/unix/ngx_aio_write_chain.c"
 
+FILE_AIO_SRCS="src/os/unix/ngx_file_aio_read.c"
+LINUX_AIO_SRCS="src/os/unix/ngx_linux_aio_read.c"
 
 UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"
 
@@ -215,8 +218,6 @@ WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/win32/ngx_socket.h \
             src/os/win32/ngx_os.h \
             src/os/win32/ngx_user.h \
-            src/os/win32/ngx_gui.h \
-            src/os/win32/ngx_gui_resources.h \
             src/os/win32/ngx_process_cycle.h"
 
 WIN32_CONFIG=src/os/win32/ngx_win32_config.h
@@ -233,14 +234,15 @@ WIN32_SRCS="$CORE_SRCS $EVENT_SRCS \
             src/os/win32/ngx_wsarecv.c \
             src/os/win32/ngx_wsarecv_chain.c \
             src/os/win32/ngx_udp_wsarecv.c \
+            src/os/win32/ngx_wsasend.c \
             src/os/win32/ngx_wsasend_chain.c \
             src/os/win32/ngx_win32_init.c \
             src/os/win32/ngx_user.c \
-            src/os/win32/ngx_gui.c \
+            src/os/win32/ngx_event_log.c \
             src/os/win32/ngx_process_cycle.c \
             src/event/ngx_event_acceptex.c"
 
-NGX_WIN32_ICONS="src/os/win32/nginx.ico src/os/win32/nginx_tray.ico"
+NGX_WIN32_ICONS="src/os/win32/nginx.ico"
 NGX_WIN32_RC="src/os/win32/nginx.rc"
 
 
@@ -329,6 +331,10 @@ HTTP_XSLT_FILTER_MODULE=ngx_http_xslt_fi
 HTTP_XSLT_SRCS=src/http/modules/ngx_http_xslt_filter_module.c
 
 
+HTTP_IMAGE_FILTER_MODULE=ngx_http_image_filter_module
+HTTP_IMAGE_SRCS=src/http/modules/ngx_http_image_filter_module.c
+
+
 HTTP_SUB_FILTER_MODULE=ngx_http_sub_filter_module
 HTTP_SUB_SRCS=src/http/modules/ngx_http_sub_filter_module.c
 
@@ -373,6 +379,10 @@ HTTP_GEO_MODULE=ngx_http_geo_module
 HTTP_GEO_SRCS=src/http/modules/ngx_http_geo_module.c
 
 
+HTTP_GEOIP_MODULE=ngx_http_geoip_module
+HTTP_GEOIP_SRCS=src/http/modules/ngx_http_geoip_module.c
+
+
 HTTP_MAP_MODULE=ngx_http_map_module
 HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c
 
--- a/auto/stubs
+++ b/auto/stubs
@@ -2,7 +2,6 @@
 # Copyright (C) Igor Sysoev
 
 
-have=NGX_USE_HTTP_FILE_CACHE_UNIQ . auto/have
 have=NGX_SUPPRESS_WARN . auto/have
 
 have=NGX_SMP . auto/have
--- a/auto/summary
+++ b/auto/summary
@@ -74,65 +74,6 @@ esac
 echo
 
 
-if [ $HTTP_REWRITE = YES ]; then
-    if [ $USE_PCRE = DISABLED ]; then
-
-cat << END
-$0: error: the HTTP rewrite module requires the PCRE library.
-You can either disable the module by using --without-http_rewrite_module
-option or you have to enable the PCRE support.
-
-END
-        exit 1
-    fi
-
-    if [ $PCRE = NONE -o $PCRE = NO ]; then
-
-cat << END
-$0: error: the HTTP rewrite module requires the PCRE library.
-You can either disable the module by using --without-http_rewrite_module
-option, or install the PCRE library into the system, or build the PCRE library
-statically from the source with nginx by using --with-pcre=<path> option.
-
-END
-
-        exit 1
-    fi
-fi
-
-
-if [ $HTTP_GZIP = YES ]; then
-    if [ $ZLIB = NONE -o $ZLIB = NO ]; then
-
-cat << END
-$0: error: the HTTP gzip module requires the zlib library.
-You can either disable the module by using --without-http_gzip_module
-option, or install the zlib library into the system, or build the zlib library
-statically from the source with nginx by using --with-zlib=<path> option.
-
-END
-
-        exit 1
-    fi
-fi
-
-
-if [ $HTTP_SSL = YES ]; then
-    if [ $OPENSSL = NONE -o $OPENSSL = NO ]; then
-
-cat << END
-$0: error: the HTTP SSL module requires the OpenSSL library.
-You can either do not enable the module, or install the OpenSSL library
-into the system, or build the OpenSSL library statically from the source
-with nginx by using --with-openssl=<path> option.
-
-END
-
-        exit 1
-    fi
-fi
-
-
 cat << END
   nginx path prefix: "$NGX_PREFIX"
   nginx binary file: "$NGX_SBIN_PATH"
--- a/auto/unix
+++ b/auto/unix
@@ -163,16 +163,6 @@ ngx_feature_test="void *p; p = memalign(
 . auto/feature
 
 
-ngx_feature="sched_yield()"
-ngx_feature_name="NGX_HAVE_SCHED_YIELD"
-ngx_feature_run=no
-ngx_feature_incs="#include <sched.h>"
-ngx_feature_path=
-ngx_feature_libs=
-ngx_feature_test="sched_yield()"
-. auto/feature
-
-
 ngx_feature="mmap(MAP_ANON|MAP_SHARED)"
 ngx_feature_name="NGX_HAVE_MAP_ANON"
 ngx_feature_run=yes
--- a/conf/nginx.conf
+++ b/conf/nginx.conf
@@ -19,7 +19,7 @@ http {
     default_type  application/octet-stream;
 
     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
-    #                  '"$status" $body_bytes_sent "$http_referer" '
+    #                  '$status $body_bytes_sent "$http_referer" '
     #                  '"$http_user_agent" "$http_x_forwarded_for"';
 
     #access_log  logs/access.log  main;
--- a/configure
+++ b/configure
@@ -3,8 +3,6 @@
 # Copyright (C) Igor Sysoev
 
 
-NGX_CONFIGURE=`echo $@ | sed 's/"/\\\\"/g'`
-
 . auto/options
 . auto/init
 . auto/sources
@@ -33,6 +31,12 @@ if test -z "$NGX_PLATFORM"; then
 
     NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE";
 
+    case "$NGX_SYSTEM" in
+        MINGW32_*)
+            NGX_PLATFORM=win32
+        ;;
+    esac
+
 else
     echo "building for $NGX_PLATFORM"
     NGX_SYSTEM=$NGX_PLATFORM
@@ -54,6 +58,39 @@ fi
 . auto/modules
 . auto/lib/conf
 
+case ".$NGX_PREFIX" in
+    .)
+        NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}
+        have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
+    ;;
+
+    .!)
+        NGX_PREFIX=
+    ;;
+
+    *)
+        have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
+    ;;
+esac
+
+if [ ".$NGX_CONF_PREFIX" != "." ]; then
+    have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define
+fi
+
+have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define
+have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define
+have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define
+have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define
+have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define
+
+have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define
+have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\""
+. auto/define
+have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\""
+. auto/define
+have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\""
+. auto/define
+
 . auto/make
 . auto/lib/make
 . auto/install
@@ -65,24 +102,6 @@ fi
 # STUB
 . auto/stubs
 
-have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
-have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define
-have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define
-have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define
-have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define
-have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define
-if test -n "$NGX_ERROR_LOG_PATH"; then
-    have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define
-fi
-
-have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define
-have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\""
-. auto/define
-have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\""
-. auto/define
-have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\""
-. auto/define
-
 have=NGX_USER value="\"$NGX_USER\"" . auto/define
 have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define
 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -10,7 +10,8 @@
 
 
 static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle);
-static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv);
+static ngx_int_t ngx_get_options(int argc, char *const *argv);
+static ngx_int_t ngx_process_options(ngx_cycle_t *cycle);
 static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv);
 static void *ngx_core_module_create_conf(ngx_cycle_t *cycle);
 static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf);
@@ -180,10 +181,16 @@ ngx_module_t  ngx_core_module = {
 };
 
 
-ngx_uint_t  ngx_max_module;
+ngx_uint_t          ngx_max_module;
 
-static ngx_uint_t  ngx_show_version;
-static ngx_uint_t  ngx_show_configure;
+static ngx_uint_t   ngx_show_help;
+static ngx_uint_t   ngx_show_version;
+static ngx_uint_t   ngx_show_configure;
+static u_char      *ngx_prefix;
+static u_char      *ngx_conf_file;
+static u_char      *ngx_conf_params;
+static char        *ngx_signal;
+
 
 static char **ngx_os_environ;
 
@@ -191,13 +198,55 @@ static char **ngx_os_environ;
 int ngx_cdecl
 main(int argc, char *const *argv)
 {
-    char             *p;
-    ssize_t           n;
     ngx_int_t         i;
     ngx_log_t        *log;
     ngx_cycle_t      *cycle, init_cycle;
     ngx_core_conf_t  *ccf;
 
+    if (ngx_get_options(argc, argv) != NGX_OK) {
+        return 1;
+    }
+
+    if (ngx_show_version) {
+        ngx_log_stderr(0, "nginx version: " NGINX_VER);
+
+        if (ngx_show_help) {
+            ngx_log_stderr(0,
+                "Usage: nginx [-?hvVt] [-s signal] [-c filename] "
+                             "[-p prefix] [-g directives]" CRLF CRLF
+                "Options:" CRLF
+                "  -?,-h         : this help" CRLF
+                "  -v            : show version and exit" CRLF
+                "  -V            : show version and configure options then exit"
+                                   CRLF
+                "  -t            : test configuration and exit" CRLF
+                "  -s signal     : send signal to a master process: "
+                                   "stop, quit, reopen, reload" CRLF
+#ifdef NGX_PREFIX
+                "  -p prefix     : set prefix path (default: "
+                                   NGX_PREFIX ")" CRLF
+#else
+                "  -p prefix     : set prefix path (default: NONE)" CRLF
+#endif
+                "  -c filename   : set configuration file (default: "
+                                   NGX_CONF_PATH ")" CRLF
+                "  -g directives : set global directives out of configuration "
+                                   "file" CRLF
+                );
+        }
+
+        if (ngx_show_configure) {
+#ifdef NGX_COMPILER
+            ngx_log_stderr(0, "built by " NGX_COMPILER);
+#endif
+            ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE);
+        }
+
+        if (!ngx_test_config) {
+            return 0;
+        }
+    }
+
 #if (NGX_FREEBSD)
     ngx_debug_init();
 #endif
@@ -212,7 +261,7 @@ main(int argc, char *const *argv)
 
     ngx_pid = ngx_getpid();
 
-    log = ngx_log_init();
+    log = ngx_log_init(ngx_prefix);
     if (log == NULL) {
         return 1;
     }
@@ -222,7 +271,10 @@ main(int argc, char *const *argv)
     ngx_ssl_init(log);
 #endif
 
-    /* init_cycle->log is required for signal handlers and ngx_getopt() */
+    /*
+     * init_cycle->log is required for signal handlers and
+     * ngx_process_options()
+     */
 
     ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
     init_cycle.log = log;
@@ -237,46 +289,10 @@ main(int argc, char *const *argv)
         return 1;
     }
 
-    if (ngx_getopt(&init_cycle, argc, ngx_argv) != NGX_OK) {
+    if (ngx_process_options(&init_cycle) != NGX_OK) {
         return 1;
     }
 
-    if (ngx_show_version) {
-
-        p = "nginx version: " NGINX_VER CRLF;
-        n = sizeof("nginx version: " NGINX_VER CRLF) - 1;
-
-        if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) {
-            return 1;
-        }
-
-        if (ngx_show_configure) {
-#ifdef NGX_COMPILER
-            p = "built by " NGX_COMPILER CRLF;
-            n = sizeof("built by " NGX_COMPILER CRLF) - 1;
-
-            if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) {
-                return 1;
-            }
-#endif
-
-            p = "configure arguments: " NGX_CONFIGURE CRLF;
-            n = sizeof("configure arguments :" NGX_CONFIGURE CRLF) - 1;
-
-            if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) {
-                return 1;
-            }
-        }
-
-        if (!ngx_test_config) {
-            return 0;
-        }
-    }
-
-    if (ngx_test_config) {
-        log->log_level = NGX_LOG_INFO;
-    }
-
     if (ngx_os_init(log) != NGX_OK) {
         return 1;
     }
@@ -301,45 +317,34 @@ main(int argc, char *const *argv)
     cycle = ngx_init_cycle(&init_cycle);
     if (cycle == NULL) {
         if (ngx_test_config) {
-            ngx_log_error(NGX_LOG_EMERG, log, 0,
-                          "the configuration file %s test failed",
-                          init_cycle.conf_file.data);
+            ngx_log_stderr(0, "configuration file %s test failed",
+                           init_cycle.conf_file.data);
         }
 
         return 1;
     }
 
     if (ngx_test_config) {
-        ngx_log_error(NGX_LOG_INFO, log, 0,
-                      "the configuration file %s was tested successfully",
-                      cycle->conf_file.data);
+        ngx_log_stderr(0, "configuration file %s test is successful",
+                       cycle->conf_file.data);
         return 0;
     }
 
+    if (ngx_signal) {
+        return ngx_signal_process(cycle, ngx_signal);
+    }
+
     ngx_os_status(cycle->log);
 
     ngx_cycle = cycle;
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
-    ngx_process = ccf->master ? NGX_PROCESS_MASTER : NGX_PROCESS_SINGLE;
-
-#if (NGX_WIN32)
-
-#if 0
-
-    TODO:
+    if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) {
+        ngx_process = NGX_PROCESS_MASTER;
+    }
 
-    if (ccf->run_as_service) {
-        if (ngx_service(cycle->log) != NGX_OK) {
-            return 1;
-        }
-
-        return 0;
-    }
-#endif
-
-#else
+#if !(NGX_WIN32)
 
     if (ngx_init_signals(cycle->log) != NGX_OK) {
         return 1;
@@ -353,17 +358,28 @@ main(int argc, char *const *argv)
         ngx_daemonized = 1;
     }
 
+#endif
+
     if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
         return 1;
     }
 
-#endif
+    if (cycle->log->file->fd != ngx_stderr) {
 
-    if (ngx_process == NGX_PROCESS_MASTER) {
-        ngx_master_process_cycle(cycle);
+        if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          ngx_set_stderr_n " failed");
+            return 1;
+        }
+    }
+
+    ngx_use_stderr = 0;
+
+    if (ngx_process == NGX_PROCESS_SINGLE) {
+        ngx_single_process_cycle(cycle);
 
     } else {
-        ngx_single_process_cycle(cycle);
+        ngx_master_process_cycle(cycle);
     }
 
     return 0;
@@ -533,6 +549,8 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, 
     ngx_core_conf_t   *ccf;
     ngx_listening_t   *ls;
 
+    ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t));
+
     ctx.path = argv[0];
     ctx.name = "new binary process";
     ctx.argv = argv;
@@ -616,64 +634,118 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, 
 
 
 static ngx_int_t
-ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv)
+ngx_get_options(int argc, char *const *argv)
 {
-    ngx_int_t  i;
+    u_char     *p;
+    ngx_int_t   i;
 
     for (i = 1; i < argc; i++) {
-        if (argv[i][0] != '-') {
-            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-                          "invalid option: \"%s\"", argv[i]);
+
+        p = (u_char *) argv[i];
+
+        if (*p++ != '-') {
+            ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);
             return NGX_ERROR;
         }
 
-        switch (argv[i][1]) {
+        while (*p) {
+
+            switch (*p++) {
+
+            case '?':
+            case 'h':
+                ngx_show_version = 1;
+                ngx_show_help = 1;
+                break;
+
+            case 'v':
+                ngx_show_version = 1;
+                break;
+
+            case 'V':
+                ngx_show_version = 1;
+                ngx_show_configure = 1;
+                break;
 
-        case 'v':
-            ngx_show_version = 1;
-            break;
+            case 't':
+                ngx_test_config = 1;
+                break;
+
+            case 'p':
+                if (*p) {
+                    ngx_prefix = p;
+                    goto next;
+                }
+
+                if (argv[++i]) {
+                    ngx_prefix = (u_char *) argv[i];
+                    goto next;
+                }
+
+                ngx_log_stderr(0, "option \"-p\" requires directory name");
+                return NGX_ERROR;
+
+            case 'c':
+                if (*p) {
+                    ngx_conf_file = p;
+                    goto next;
+                }
 
-        case 'V':
-            ngx_show_version = 1;
-            ngx_show_configure = 1;
-            break;
+                if (argv[++i]) {
+                    ngx_conf_file = (u_char *) argv[i];
+                    goto next;
+                }
+
+                ngx_log_stderr(0, "option \"-c\" requires file name");
+                return NGX_ERROR;
+
+            case 'g':
+                if (*p) {
+                    ngx_conf_params = p;
+                    goto next;
+                }
+
+                if (argv[++i]) {
+                    ngx_conf_params = (u_char *) argv[i];
+                    goto next;
+                }
+
+                ngx_log_stderr(0, "option \"-g\" requires parameter");
+                return NGX_ERROR;
 
-        case 't':
-            ngx_test_config = 1;
-            break;
+            case 's':
+                if (*p) {
+                    ngx_signal = (char *) p;
+
+                } else if (argv[++i]) {
+                    ngx_signal = argv[i];
+
+                } else {
+                    ngx_log_stderr(0, "option \"-s\" requires parameter");
+                    return NGX_ERROR;
+                }
 
-        case 'c':
-            if (argv[i + 1] == NULL) {
-                ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-                              "the option \"-c\" requires file name");
+                if (ngx_strcmp(ngx_signal, "stop") == 0
+                    || ngx_strcmp(ngx_signal, "quit") == 0
+                    || ngx_strcmp(ngx_signal, "reopen") == 0
+                    || ngx_strcmp(ngx_signal, "reload") == 0)
+                {
+                    ngx_process = NGX_PROCESS_SIGNALLER;
+                    goto next;
+                }
+
+                ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
+                return NGX_ERROR;
+
+            default:
+                ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
                 return NGX_ERROR;
             }
-
-            cycle->conf_file.data = (u_char *) argv[++i];
-            cycle->conf_file.len = ngx_strlen(cycle->conf_file.data);
-            break;
-
-        case 'g':
-            if (argv[i + 1] == NULL) {
-                ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-                              "the option \"-g\" requires parameter");
-                return NGX_ERROR;
-            }
+        }
 
-            cycle->conf_param.data = (u_char *) argv[++i];
-            cycle->conf_param.len = ngx_strlen(cycle->conf_param.data);
-            break;
+    next:
 
-        default:
-            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-                          "invalid option: \"%s\"", argv[i]);
-            return NGX_ERROR;
-        }
-    }
-
-    if (cycle->conf_file.data == NULL) {
-        cycle->conf_file.len = sizeof(NGX_CONF_PATH) - 1;
-        cycle->conf_file.data = (u_char *) NGX_CONF_PATH;
+        continue;
     }
 
     return NGX_OK;
@@ -722,6 +794,106 @@ ngx_save_argv(ngx_cycle_t *cycle, int ar
 }
 
 
+static ngx_int_t
+ngx_process_options(ngx_cycle_t *cycle)
+{
+    u_char  *p;
+    size_t   len;
+
+    if (ngx_prefix) {
+        len = ngx_strlen(ngx_prefix);
+        p = ngx_prefix;
+
+        if (!ngx_path_separator(*p)) {
+            p = ngx_pnalloc(cycle->pool, len + 1);
+            if (p == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(p, ngx_prefix, len);
+            p[len++] = '/';
+        }
+
+        cycle->conf_prefix.len = len;
+        cycle->conf_prefix.data = p;
+        cycle->prefix.len = len;
+        cycle->prefix.data = p;
+
+    } else {
+
+#ifndef NGX_PREFIX
+
+        p = ngx_pnalloc(cycle->pool, NGX_MAX_PATH);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        if (ngx_getcwd(p, NGX_MAX_PATH) == 0) {
+            ngx_log_stderr(ngx_errno, "[emerg]: " ngx_getcwd_n " failed");
+            return NGX_ERROR;
+        }
+
+        len = ngx_strlen(p);
+
+        p[len++] = '/';
+
+        cycle->conf_prefix.len = len;
+        cycle->conf_prefix.data = p;
+        cycle->prefix.len = len;
+        cycle->prefix.data = p;
+
+#else
+
+#ifdef NGX_CONF_PREFIX
+        cycle->conf_prefix.len = sizeof(NGX_CONF_PREFIX) - 1;
+        cycle->conf_prefix.data = (u_char *) NGX_CONF_PREFIX;
+#else
+        cycle->conf_prefix.len = sizeof(NGX_PREFIX) - 1;
+        cycle->conf_prefix.data = (u_char *) NGX_PREFIX;
+#endif
+        cycle->prefix.len = sizeof(NGX_PREFIX) - 1;
+        cycle->prefix.data = (u_char *) NGX_PREFIX;
+
+#endif
+    }
+
+    if (ngx_conf_file) {
+        cycle->conf_file.len = ngx_strlen(ngx_conf_file);
+        cycle->conf_file.data = ngx_conf_file;
+
+    } else {
+        cycle->conf_file.len = sizeof(NGX_CONF_PATH) - 1;
+        cycle->conf_file.data = (u_char *) NGX_CONF_PATH;
+    }
+
+    if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    for (p = cycle->conf_file.data + cycle->conf_file.len - 1;
+         p > cycle->conf_file.data;
+         p--)
+    {
+        if (ngx_path_separator(*p)) {
+            cycle->conf_prefix.len = p - ngx_cycle->conf_file.data + 1;
+            cycle->conf_prefix.data = ngx_cycle->conf_file.data;
+            break;
+        }
+    }
+
+    if (ngx_conf_params) {
+        cycle->conf_param.len = ngx_strlen(ngx_conf_params);
+        cycle->conf_param.data = ngx_conf_params;
+    }
+
+    if (ngx_test_config) {
+        cycle->log->log_level = NGX_LOG_INFO;
+    }
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_core_module_create_conf(ngx_cycle_t *cycle)
 {
@@ -805,6 +977,27 @@ ngx_core_module_init_conf(ngx_cycle_t *c
 
 #endif
 
+
+    if (ccf->pid.len == 0) {
+        ccf->pid.len = sizeof(NGX_PID_PATH) - 1;
+        ccf->pid.data = (u_char *) NGX_PID_PATH;
+    }
+
+    if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT);
+
+    ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len);
+    if (ccf->oldpid.data == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len),
+               NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT));
+
+
 #if !(NGX_WIN32)
 
     if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) {
@@ -833,25 +1026,6 @@ ngx_core_module_init_conf(ngx_cycle_t *c
         ccf->group = grp->gr_gid;
     }
 
-    if (ccf->pid.len == 0) {
-        ccf->pid.len = sizeof(NGX_PID_PATH) - 1;
-        ccf->pid.data = (u_char *) NGX_PID_PATH;
-    }
-
-    if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) {
-        return NGX_CONF_ERROR;
-    }
-
-    ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT);
-
-    ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len);
-    if (ccf->oldpid.data == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len),
-               NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT));
-
 
     if (ccf->lock_file.len == 0) {
         ccf->lock_file.len = sizeof(NGX_LOCK_PATH) - 1;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version       007047
-#define NGINX_VERSION      "0.7.47"
+#define nginx_version         8016
+#define NGINX_VERSION      "0.8.16"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -67,21 +67,35 @@ typedef struct {
 } ngx_bufs_t;
 
 
+typedef struct ngx_output_chain_ctx_s  ngx_output_chain_ctx_t;
+
 typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
 
-typedef struct {
+#if (NGX_HAVE_FILE_AIO)
+typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx,
+    ngx_file_t *file);
+#endif
+
+struct ngx_output_chain_ctx_s {
     ngx_buf_t                   *buf;
     ngx_chain_t                 *in;
     ngx_chain_t                 *free;
     ngx_chain_t                 *busy;
 
-    unsigned                     sendfile;
-    unsigned                     directio;
+    unsigned                     sendfile:1;
+    unsigned                     directio:1;
 #if (NGX_HAVE_ALIGNED_DIRECTIO)
-    unsigned                     unaligned;
+    unsigned                     unaligned:1;
 #endif
-    unsigned                     need_in_memory;
-    unsigned                     need_in_temp;
+    unsigned                     need_in_memory:1;
+    unsigned                     need_in_temp:1;
+#if (NGX_HAVE_FILE_AIO)
+    unsigned                     aio:1;
+
+    ngx_output_chain_aio_pt      aio_handler;
+#endif
+
+    off_t                        alignment;
 
     ngx_pool_t                  *pool;
     ngx_int_t                    allocated;
@@ -90,7 +104,7 @@ typedef struct {
 
     ngx_output_chain_filter_pt   output_filter;
     void                        *filter_ctx;
-} ngx_output_chain_ctx_t;
+};
 
 
 typedef struct {
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -12,6 +12,7 @@
 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
 static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name);
 static void ngx_conf_flush_files(ngx_cycle_t *cycle);
 
 
@@ -61,6 +62,7 @@ static ngx_uint_t argument_number[] = {
 char *
 ngx_conf_param(ngx_conf_t *cf)
 {
+    char             *rv;
     ngx_str_t        *param;
     ngx_buf_t         b;
     ngx_conf_file_t   conf_file;
@@ -82,13 +84,17 @@ ngx_conf_param(ngx_conf_t *cf)
     b.temporary = 1;
 
     conf_file.file.fd = NGX_INVALID_FILE;
-    conf_file.file.name.data = (u_char *) "command line";
-    conf_file.line = 1;
+    conf_file.file.name.data = NULL;
+    conf_file.line = 0;
 
     cf->conf_file = &conf_file;
     cf->conf_file->buffer = &b;
 
-    return ngx_conf_parse(cf, NULL);
+    rv = ngx_conf_parse(cf, NULL);
+
+    cf->conf_file = NULL;
+
+    return rv;
 }
 
 
@@ -441,7 +447,9 @@ ngx_conf_read_token(ngx_conf_t *cf)
     last_space = 1;
     sharp_comment = 0;
     variable = 0;
-    quoted = s_quoted = d_quoted = 0;
+    quoted = 0;
+    s_quoted = 0;
+    d_quoted = 0;
 
     cf->args->nelts = 0;
     b = cf->conf_file->buffer;
@@ -795,46 +803,94 @@ ngx_int_t
 ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
 {
     size_t      len;
-    u_char     *p, *prefix;
-    ngx_str_t   old;
+    u_char     *p, *n, *prefix;
+    ngx_int_t   rc;
+
+    rc = ngx_conf_test_full_name(name);
+
+    if (rc == NGX_OK) {
+        return rc;
+    }
+
+    if (conf_prefix) {
+        len = cycle->conf_prefix.len;
+        prefix = cycle->conf_prefix.data;
+
+    } else {
+        len = cycle->prefix.len;
+        prefix = cycle->prefix.data;
+    }
+
+#if (NGX_WIN32)
+
+    if (rc == 2) {
+        len = rc;
+    }
+
+#endif
+
+    n = ngx_pnalloc(cycle->pool, len + name->len + 1);
+    if (n == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = ngx_cpymem(n, prefix, len);
+    ngx_cpystrn(p, name->data, name->len + 1);
+
+    name->len += len;
+    name->data = n;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_conf_test_full_name(ngx_str_t *name)
+{
+#if (NGX_WIN32)
+    u_char  c0, c1;
+
+    c0 = name->data[0];
+
+    if (name->len < 2) {
+        if (c0 == '/') {
+            return 2;
+        }
+
+        return NGX_DECLINED;
+    }
+
+    c1 = name->data[1];
+
+    if (c1 == ':') {
+        c0 |= 0x20;
+
+        if ((c0 >= 'a' && c0 <= 'z')) {
+            return NGX_OK;
+        }
+
+        return NGX_DECLINED;
+    }
+
+    if (c1 == '/') {
+        return NGX_OK;
+    }
+
+    if (c0 == '/') {
+        return 2;
+    }
+
+    return NGX_DECLINED;
+
+#else
 
     if (name->data[0] == '/') {
         return NGX_OK;
     }
 
-#if (NGX_WIN32)
-
-    if (name->len > 2
-        && name->data[1] == ':'
-        && ((name->data[0] >= 'a' && name->data[0] <= 'z')
-             || (name->data[0] >= 'A' && name->data[0] <= 'Z')))
-    {
-        return NGX_OK;
-    }
+    return NGX_DECLINED;
 
 #endif
-
-    old = *name;
-
-    if (conf_prefix) {
-        len = sizeof(NGX_CONF_PREFIX) - 1;
-        prefix = (u_char *) NGX_CONF_PREFIX;
-
-    } else {
-        len = cycle->root.len;
-        prefix = cycle->root.data;
-    }
-
-    name->len = len + old.len;
-    name->data = ngx_pnalloc(cycle->pool, name->len + 1);
-    if (name->data == NULL) {
-        return NGX_ERROR;
-    }
-
-    p = ngx_cpymem(name->data, prefix, len);
-    ngx_cpystrn(p, old.data, old.len + 1);
-
-    return NGX_OK;
 }
 
 
@@ -851,7 +907,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n
     full.data = NULL;
 #endif
 
-    if (name) {
+    if (name->len) {
         full = *name;
 
         if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) {
@@ -887,14 +943,13 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n
         return NULL;
     }
 
-    if (name) {
+    if (name->len) {
         file->fd = NGX_INVALID_FILE;
         file->name = full;
 
     } else {
-        file->fd = ngx_stderr_fileno;
-        file->name.len = 0;
-        file->name.data = NULL;
+        file->fd = ngx_stderr;
+        file->name = *name;
     }
 
     file->buffer = NULL;
@@ -959,31 +1014,11 @@ ngx_conf_log_error(ngx_uint_t level, ngx
     last = errstr + NGX_MAX_CONF_ERRSTR;
 
     va_start(args, fmt);
-    p = ngx_vsnprintf(errstr, last - errstr, fmt, args);
+    p = ngx_vslprintf(errstr, last, fmt, args);
     va_end(args);
 
     if (err) {
-
-        if (p > last - 50) {
-
-            /* leave a space for an error code */
-
-            p = last - 50;
-            *p++ = '.';
-            *p++ = '.';
-            *p++ = '.';
-        }
-
-#if (NGX_WIN32)
-        p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000)
-                                           ? " (%d: " : " (%Xd: ", err);
-#else
-        p = ngx_snprintf(p, last - p, " (%d: ", err);
-#endif
-
-        p = ngx_strerror_r(err, p, last - p);
-
-        *p++ = ')';
+        p = ngx_log_errno(p, last, err);
     }
 
     if (cf->conf_file == NULL) {
@@ -991,6 +1026,12 @@ ngx_conf_log_error(ngx_uint_t level, ngx
         return;
     }
 
+    if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
+        ngx_log_error(level, cf->log, 0, "%*s in command line",
+                      p - errstr, errstr);
+        return;
+    }
+
     ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
                   p - errstr, errstr,
                   cf->conf_file->file.name.data, cf->conf_file->line);
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -13,11 +13,11 @@ ngx_os_io_t  ngx_io;
 
 
 ngx_listening_t *
-ngx_listening_inet_stream_socket(ngx_conf_t *cf, in_addr_t addr, in_port_t port)
+ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
 {
-    size_t               len;
-    ngx_listening_t     *ls;
-    struct sockaddr_in  *sin;
+    ngx_listening_t  *ls;
+    struct sockaddr  *sa;
+    u_char            text[NGX_SOCKADDR_STRLEN];
 
     ls = ngx_array_push(&cf->cycle->listening);
     if (ls == NULL) {
@@ -26,33 +26,45 @@ ngx_listening_inet_stream_socket(ngx_con
 
     ngx_memzero(ls, sizeof(ngx_listening_t));
 
-    sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in));
-    if (sin == NULL) {
+    sa = ngx_palloc(cf->pool, socklen);
+    if (sa == NULL) {
         return NULL;
     }
 
-    sin->sin_family = AF_INET;
-    sin->sin_addr.s_addr = addr;
-    sin->sin_port = htons(port);
+    ngx_memcpy(sa, sockaddr, socklen);
 
+    ls->sockaddr = sa;
+    ls->socklen = socklen;
 
-    ls->addr_text.data = ngx_pnalloc(cf->pool,
-                                    NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1);
+    ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
+
+    ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len);
     if (ls->addr_text.data == NULL) {
         return NULL;
     }
 
-    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;
+    ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len);
 
     ls->fd = (ngx_socket_t) -1;
     ls->type = SOCK_STREAM;
-    ls->sockaddr = (struct sockaddr *) sin;
-    ls->socklen = sizeof(struct sockaddr_in);
-    ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
+
+    switch (ls->sockaddr->sa_family) {
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+         ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
+         break;
+#endif
+    case AF_INET:
+         ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
+         break;
+    default:
+         ls->addr_text_max_len = NGX_SOCKADDR_STRLEN;
+         break;
+    }
+
+    ls->backlog = NGX_LISTEN_BACKLOG;
+    ls->rcvbuf = -1;
+    ls->sndbuf = -1;
 
     return ls;
 }
@@ -293,7 +305,7 @@ ngx_open_listening_sockets(ngx_cycle_t *
                                (const void *) &ipv6only, sizeof(int))
                     == -1)
                 {
-                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   "setsockopt(IPV6_V6ONLY) %V failed, ignored",
                                   &ls[i].addr_text);
                 }
@@ -317,7 +329,7 @@ ngx_open_listening_sockets(ngx_cycle_t *
                 }
             }
 
-            ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+            ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0,
                            "bind() %V #%d ", &ls[i].addr_text, s);
 
             if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
@@ -386,7 +398,7 @@ ngx_open_listening_sockets(ngx_cycle_t *
 
 
 void
-ngx_configure_listening_socket(ngx_cycle_t *cycle)
+ngx_configure_listening_sockets(ngx_cycle_t *cycle)
 {
     ngx_uint_t                 i;
     ngx_listening_t           *ls;
@@ -401,6 +413,8 @@ ngx_configure_listening_socket(ngx_cycle
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
 
+        ls[i].log = *ls[i].logp;
+
         if (ls[i].rcvbuf != -1) {
             if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF,
                            (const void *) &ls[i].rcvbuf, sizeof(int))
@@ -557,29 +571,31 @@ ngx_close_listening_sockets(ngx_cycle_t 
 
         c = ls[i].connection;
 
-        if (c->read->active) {
-            if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
-                ngx_del_conn(c, NGX_CLOSE_EVENT);
+        if (c) {
+            if (c->read->active) {
+                if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
+                    ngx_del_conn(c, NGX_CLOSE_EVENT);
 
-            } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+                } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
 
-                /*
-                 * it seems that Linux-2.6.x OpenVZ sends events
-                 * for closed shared listening sockets unless
-                 * the events was explicity deleted
-                 */
+                    /*
+                     * it seems that Linux-2.6.x OpenVZ sends events
+                     * for closed shared listening sockets unless
+                     * the events was explicity deleted
+                     */
 
-                ngx_del_event(c->read, NGX_READ_EVENT, 0);
+                    ngx_del_event(c->read, NGX_READ_EVENT, 0);
 
-            } else {
-                ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
+                } else {
+                    ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
+                }
             }
+
+            ngx_free_connection(c);
+
+            c->fd = (ngx_socket_t) -1;
         }
 
-        ngx_free_connection(c);
-
-        c->fd = (ngx_socket_t) -1;
-
         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                        "close listening %V #%d ", &ls[i].addr_text, ls[i].fd);
 
@@ -587,6 +603,8 @@ ngx_close_listening_sockets(ngx_cycle_t 
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                           ngx_close_socket_n " %V failed", &ls[i].addr_text);
         }
+
+        ls[i].fd = (ngx_socket_t) -1;
     }
 }
 
@@ -795,11 +813,78 @@ ngx_close_connection(ngx_connection_t *c
 
 
 ngx_int_t
+ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
+    ngx_uint_t port)
+{
+    socklen_t             len;
+    ngx_uint_t            addr;
+    u_char                sa[NGX_SOCKADDRLEN];
+    struct sockaddr_in   *sin;
+#if (NGX_HAVE_INET6)
+    ngx_uint_t            i;
+    struct sockaddr_in6  *sin6;
+#endif
+
+    switch (c->local_sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
+
+        for (addr = 0, i = 0; addr == 0 && i < 16; i++) {
+            addr |= sin6->sin6_addr.s6_addr[i];
+        }
+
+        break;
+#endif
+
+    default: /* AF_INET */
+        sin = (struct sockaddr_in *) c->local_sockaddr;
+        addr = sin->sin_addr.s_addr;
+        break;
+    }
+
+    if (addr == 0) {
+
+        len = NGX_SOCKADDRLEN;
+
+        if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) {
+            ngx_connection_error(c, ngx_socket_errno, "getsockname() failed");
+            return NGX_ERROR;
+        }
+
+        c->local_sockaddr = ngx_palloc(c->pool, len);
+        if (c->local_sockaddr == NULL) {
+            return NGX_ERROR;
+        }
+
+        c->local_socklen = len;
+        ngx_memcpy(c->local_sockaddr, &sa, len);
+    }
+
+    if (s == NULL) {
+        return NGX_OK;
+    }
+
+    s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, port);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text)
 {
     ngx_uint_t  level;
 
-    if (err == NGX_ECONNRESET && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) {
+    /* Winsock may return NGX_ECONNABORTED instead of NGX_ECONNRESET */
+
+    if ((err == NGX_ECONNRESET
+#if (NGX_WIN32)
+         || err == NGX_ECONNABORTED
+#endif
+        ) && c->log_error == NGX_ERROR_IGNORE_ECONNRESET)
+    {
         return 0;
     }
 
@@ -811,7 +896,9 @@ ngx_connection_error(ngx_connection_t *c
 
     if (err == 0
         || err == NGX_ECONNRESET
-#if !(NGX_WIN32)
+#if (NGX_WIN32)
+        || err == NGX_ECONNABORTED
+#else
         || err == NGX_EPIPE
 #endif
         || err == NGX_ENOTCONN
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -34,6 +34,7 @@ struct ngx_listening_s {
     void               *servers;  /* array of ngx_http_in_addr_t, for example */
 
     ngx_log_t           log;
+    ngx_log_t          *logp;
 
     size_t              pool_size;
     /* should be here because of the AcceptEx() preread */
@@ -134,6 +135,8 @@ struct ngx_connection_s {
 
     ngx_atomic_uint_t   number;
 
+    ngx_uint_t          requests;
+
     unsigned            buffered:8;
 
     unsigned            log_error:3;     /* ngx_connection_log_error_e */
@@ -156,24 +159,26 @@ struct ngx_connection_s {
     unsigned            accept_context_updated:1;
 #endif
 
+#if (NGX_HAVE_AIO_SENDFILE)
+    unsigned            aio_sendfile:1;
+    ngx_buf_t          *busy_sendfile;
+#endif
+
 #if (NGX_THREADS)
     ngx_atomic_t        lock;
 #endif
 };
 
 
-#ifndef ngx_ssl_set_nosendshut
-#define ngx_ssl_set_nosendshut(ssl)
-#endif
-
-
-ngx_listening_t *ngx_listening_inet_stream_socket(ngx_conf_t *cf,
-    in_addr_t addr, in_port_t port);
+ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, void *sockaddr,
+    socklen_t socklen);
 ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle);
 ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle);
-void ngx_configure_listening_socket(ngx_cycle_t *cycle);
+void ngx_configure_listening_sockets(ngx_cycle_t *cycle);
 void ngx_close_listening_sockets(ngx_cycle_t *cycle);
 void ngx_close_connection(ngx_connection_t *c);
+ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
+    ngx_uint_t port);
 ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text);
 
 ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log);
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -19,6 +19,7 @@ typedef struct ngx_open_file_s   ngx_ope
 typedef struct ngx_command_s     ngx_command_t;
 typedef struct ngx_file_s        ngx_file_t;
 typedef struct ngx_event_s       ngx_event_t;
+typedef struct ngx_event_aio_s   ngx_event_aio_t;
 typedef struct ngx_connection_s  ngx_connection_t;
 
 typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -9,9 +9,11 @@
 #include <ngx_event.h>
 
 
-static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log);
 static void ngx_destroy_cycle_pools(ngx_conf_t *conf);
 static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2);
+static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle,
+    ngx_shm_zone_t *shm_zone);
+static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log);
 static void ngx_clean_old_cycles(ngx_event_t *ev);
 
 
@@ -32,11 +34,7 @@ ngx_tls_key_t          ngx_core_tls_key;
 static ngx_connection_t  dumb;
 /* STUB */
 
-#ifdef NGX_ERROR_LOG_PATH
 static ngx_str_t  error_log = ngx_string(NGX_ERROR_LOG_PATH);
-#else
-static ngx_str_t  error_log = ngx_null_string;
-#endif
 
 
 ngx_cycle_t *
@@ -44,7 +42,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 {
     void                *rv;
     char               **senv, **env;
-    u_char              *lock_file;
     ngx_uint_t           i, n;
     ngx_log_t           *log;
     ngx_time_t          *tp;
@@ -52,7 +49,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     ngx_pool_t          *pool;
     ngx_cycle_t         *cycle, **old;
     ngx_shm_zone_t      *shm_zone, *oshm_zone;
-    ngx_slab_pool_t     *shpool;
     ngx_list_part_t     *part, *opart;
     ngx_open_file_t     *file;
     ngx_listening_t     *ls, *nls;
@@ -86,10 +82,22 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 
     cycle->pool = pool;
     cycle->log = log;
+    cycle->new_log.log_level = NGX_LOG_ERR;
     cycle->old_cycle = old_cycle;
-    cycle->root.len = sizeof(NGX_PREFIX) - 1;
-    cycle->root.data = (u_char *) NGX_PREFIX;
 
+    cycle->conf_prefix.len = old_cycle->conf_prefix.len;
+    cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
+    if (cycle->conf_prefix.data == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+    cycle->prefix.len = old_cycle->prefix.len;
+    cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
+    if (cycle->prefix.data == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
 
     cycle->conf_file.len = old_cycle->conf_file.len;
     cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
@@ -100,15 +108,12 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
                 old_cycle->conf_file.len + 1);
 
-
     cycle->conf_param.len = old_cycle->conf_param.len;
-    cycle->conf_param.data = ngx_pnalloc(pool, old_cycle->conf_param.len);
+    cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
     if (cycle->conf_param.data == NULL) {
         ngx_destroy_pool(pool);
         return NULL;
     }
-    ngx_memcpy(cycle->conf_param.data, old_cycle->conf_param.data,
-               old_cycle->conf_param.len);
 
 
     n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10;
@@ -161,16 +166,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         return NULL;
     }
 
-
-    cycle->new_log = ngx_log_create_errlog(cycle, NULL);
-    if (cycle->new_log == NULL) {
-        ngx_destroy_pool(pool);
-        return NULL;
-    }
-
-    cycle->new_log->file->name = error_log;
-
-
     n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
 
     cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
@@ -221,7 +216,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 
         if (module->create_conf) {
             rv = module->create_conf(cycle);
-            if (rv == NGX_CONF_ERROR) {
+            if (rv == NULL) {
                 ngx_destroy_pool(pool);
                 return NULL;
             }
@@ -260,22 +255,22 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 #endif
 
     if (ngx_conf_param(&conf) != NGX_CONF_OK) {
+        environ = senv;
         ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
 
     if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
+        environ = senv;
         ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
 
     if (ngx_test_config) {
-        ngx_log_error(NGX_LOG_INFO, log, 0,
-                      "the configuration file %s syntax is ok",
-                      cycle->conf_file.data);
+        ngx_log_stderr(0, "the configuration file %s syntax is ok",
+                       cycle->conf_file.data);
     }
 
-
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->type != NGX_CORE_MODULE) {
             continue;
@@ -287,17 +282,19 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                 == NGX_CONF_ERROR)
             {
+                environ = senv;
                 ngx_destroy_cycle_pools(&conf);
                 return NULL;
             }
         }
     }
 
+    if (ngx_process == NGX_PROCESS_SIGNALLER) {
+        return cycle;
+    }
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
-#if !(NGX_WIN32)
-
     if (ngx_test_config) {
 
         if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
@@ -326,8 +323,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
     }
 
-#endif
-
 
     if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {
         goto failed;
@@ -339,6 +334,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     }
 
 
+    if (cycle->new_log.file == NULL) {
+        cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);
+        if (cycle->new_log.file == NULL) {
+            goto failed;
+        }
+    }
+
     /* open the new files */
 
     part = &cycle->open_files.part;
@@ -355,7 +357,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             i = 0;
         }
 
-        if (file[i].name.data == NULL) {
+        if (file[i].name.len == 0) {
             continue;
         }
 
@@ -375,14 +377,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             goto failed;
         }
 
-#if (NGX_WIN32)
-        if (ngx_file_append_mode(file[i].fd) != NGX_OK) {
-            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                          ngx_file_append_mode_n " \"%s\" failed",
-                          file[i].name.data);
-            goto failed;
-        }
-#else
+#if !(NGX_WIN32)
         if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                           "fcntl(FD_CLOEXEC) \"%s\" failed",
@@ -392,12 +387,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 #endif
     }
 
-    cycle->log = cycle->new_log;
-    pool->log = cycle->new_log;
-
-    if (cycle->log->log_level == 0) {
-        cycle->log->log_level = NGX_LOG_ERR;
-    }
+    cycle->log = &cycle->new_log;
+    pool->log = &cycle->new_log;
 
 
     /* create shared memory */
@@ -419,7 +410,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         if (shm_zone[i].shm.size == 0) {
             ngx_log_error(NGX_LOG_EMERG, log, 0,
                           "zero size shared memory zone \"%V\"",
-                          &shm_zone[i].name);
+                          &shm_zone[i].shm.name);
             goto failed;
         }
 
@@ -444,12 +435,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
                 n = 0;
             }
 
-            if (shm_zone[i].name.len != oshm_zone[n].name.len) {
+            if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
                 continue;
             }
 
-            if (ngx_strncmp(shm_zone[i].name.data, oshm_zone[n].name.data,
-                            shm_zone[i].name.len)
+            if (ngx_strncmp(shm_zone[i].shm.name.data,
+                            oshm_zone[n].shm.name.data,
+                            shm_zone[i].shm.name.len)
                 != 0)
             {
                 continue;
@@ -476,38 +468,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             goto failed;
         }
 
-        shpool = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
-
-        shpool->end = shm_zone[i].shm.addr + shm_zone[i].shm.size;
-        shpool->min_shift = 3;
-
-#if (NGX_HAVE_ATOMIC_OPS)
-
-        lock_file = NULL;
-
-#else
-
-        lock_file = ngx_pnalloc(cycle->pool,
-                                cycle->lock_file.len + shm_zone[i].name.len);
-
-        if (lock_file == NULL) {
+        if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
             goto failed;
         }
 
-        (void) ngx_cpystrn(ngx_cpymem(lock_file, cycle->lock_file.data,
-                                      cycle->lock_file.len),
-                           shm_zone[i].name.data, shm_zone[i].name.len + 1);
-
-#endif
-
-        if (ngx_shmtx_create(&shpool->mutex, (void *) &shpool->lock, lock_file)
-            != NGX_OK)
-        {
-            goto failed;
-        }
-
-        ngx_slab_init(shpool);
-
         if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
             goto failed;
         }
@@ -610,31 +574,20 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     }
 
     if (!ngx_test_config) {
-        ngx_configure_listening_socket(cycle);
+        ngx_configure_listening_sockets(cycle);
     }
 
 
     /* commit the new cycle configuration */
 
-#if !(NGX_WIN32)
-
-    if (!ngx_test_config && cycle->log->file->fd != STDERR_FILENO) {
+    if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) {
 
-        ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
-                       "dup2: %p %d \"%s\"",
-                       cycle->log->file,
-                       cycle->log->file->fd, cycle->log->file->name.data);
-
-        if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
-            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                          "dup2(STDERR) failed");
-            /* fatal */
-            exit(1);
+        if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          ngx_set_stderr_n " failed");
         }
     }
 
-#endif
-
     pool->log = cycle->log;
 
     for (i = 0; ngx_modules[i]; i++) {
@@ -679,10 +632,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
                 n = 0;
             }
 
-            if (oshm_zone[i].name.len == shm_zone[n].name.len
-                && ngx_strncmp(oshm_zone[i].name.data,
-                               shm_zone[n].name.data,
-                               oshm_zone[i].name.len)
+            if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len
+                && ngx_strncmp(oshm_zone[i].shm.name.data,
+                               shm_zone[n].shm.name.data,
+                               oshm_zone[i].shm.name.len)
                 == 0)
             {
                 goto live_shm_zone;
@@ -703,7 +656,8 @@ old_shm_zone_done:
 
     ls = old_cycle->listening.elts;
     for (i = 0; i < old_cycle->listening.nelts; i++) {
-        if (ls[i].remain) {
+
+        if (ls[i].remain || ls[i].fd == -1) {
             continue;
         }
 
@@ -731,7 +685,7 @@ old_shm_zone_done:
             i = 0;
         }
 
-        if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
+        if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
             continue;
         }
 
@@ -747,8 +701,8 @@ old_shm_zone_done:
     if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
 
         /*
-         * perl_destruct() frees environ if it is not the same as it was at
-         * perl_construct() time.  So we have saved an previous cycle
+         * perl_destruct() frees environ, if it is not the same as it was at
+         * perl_construct() time, therefore we save the previous cycle
          * environment before ngx_conf_parse() where it will be changed.
          */
 
@@ -831,7 +785,7 @@ failed:
             i = 0;
         }
 
-        if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
+        if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
             continue;
         }
 
@@ -924,26 +878,76 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s
 }
 
 
-#if !(NGX_WIN32)
+static ngx_int_t
+ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn)
+{
+    u_char           *file;
+    ngx_slab_pool_t  *sp;
+
+    sp = (ngx_slab_pool_t *) zn->shm.addr;
+
+    if (zn->shm.exists) {
+
+        if (sp == sp->addr) {
+            return NGX_OK;
+        }
+
+        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                      "shared zone \"%V\" has no equal addresses: %p vs %p",
+                      &zn->shm.name, sp->addr, sp);
+        return NGX_ERROR;
+    }
+
+    sp->end = zn->shm.addr + zn->shm.size;
+    sp->min_shift = 3;
+    sp->addr = zn->shm.addr;
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+    file = NULL;
+
+#else
+
+    file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len);
+    if (file == NULL) {
+        return NGX_ERROR;
+    }
+
+    (void) ngx_sprintf(file, "%V%V%Z", &cycle->lock_file, &zn->shm.name);
+
+#endif
+
+    if (ngx_shmtx_create(&sp->mutex, (void *) &sp->lock, file) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    ngx_slab_init(sp);
+
+    return NGX_OK;
+}
+
 
 ngx_int_t
 ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
 {
-    size_t            len;
-    ngx_uint_t        trunc;
-    ngx_file_t        file;
-    u_char            pid[NGX_INT64_LEN + 2];
+    size_t      len;
+    ngx_uint_t  create;
+    ngx_file_t  file;
+    u_char      pid[NGX_INT64_LEN + 2];
+
+    if (ngx_process > NGX_PROCESS_MASTER) {
+        return NGX_OK;
+    }
 
     ngx_memzero(&file, sizeof(ngx_file_t));
 
     file.name = *name;
     file.log = log;
 
-    trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE;
+    create = ngx_test_config ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE;
 
     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
-                            NGX_FILE_CREATE_OR_OPEN|trunc,
-                            NGX_FILE_DEFAULT_ACCESS);
+                            create, NGX_FILE_DEFAULT_ACCESS);
 
     if (file.fd == NGX_INVALID_FILE) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
@@ -984,7 +988,57 @@ ngx_delete_pidfile(ngx_cycle_t *cycle)
     }
 }
 
-#endif
+
+ngx_int_t
+ngx_signal_process(ngx_cycle_t *cycle, char *sig)
+{
+    ssize_t           n;
+    ngx_int_t         pid;
+    ngx_file_t        file;
+    ngx_core_conf_t  *ccf;
+    u_char            buf[NGX_INT64_LEN + 2];
+
+    ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started");
+
+    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+    file.name = ccf->pid;
+    file.log = cycle->log;
+
+    file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY,
+                            NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS);
+
+    if (file.fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", file.name.data);
+        return 1;
+    }
+
+    n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0);
+
+    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", file.name.data);
+    }
+
+    if (n == NGX_ERROR) {
+        return 1;
+    }
+
+    while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ }
+
+    pid = ngx_atoi(buf, ++n);
+
+    if (pid == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
+                      "invalid PID number \"%*s\" in \"%s\"",
+                      n, buf, file.name.data);
+        return 1;
+    }
+
+    return ngx_os_signal_process(cycle, sig, pid);
+
+}
 
 
 static ngx_int_t
@@ -1041,7 +1095,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx
             i = 0;
         }
 
-        if (file[i].name.data == NULL) {
+        if (file[i].name.len == 0) {
             continue;
         }
 
@@ -1078,25 +1132,13 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx
             continue;
         }
 
-#if (NGX_WIN32)
-        if (ngx_file_append_mode(fd) == NGX_ERROR) {
-            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
-                          ngx_file_append_mode_n " \"%s\" failed",
-                          file[i].name.data);
-
-            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed",
-                              file[i].name.data);
-            }
-
-            continue;
-        }
-#else
+#if !(NGX_WIN32)
         if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
             ngx_file_info_t  fi;
 
-            if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) {
+            if (ngx_file_info((const char *) file[i].name.data, &fi)
+                == NGX_FILE_ERROR)
+            {
                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                               ngx_file_info_n " \"%s\" failed",
                               file[i].name.data);
@@ -1197,27 +1239,29 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng
             i = 0;
         }
 
-        if (name->len != shm_zone[i].name.len) {
+        if (name->len != shm_zone[i].shm.name.len) {
             continue;
         }
 
-        if (ngx_strncmp(name->data, shm_zone[i].name.data, name->len) != 0) {
+        if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len)
+            != 0)
+        {
             continue;
         }
 
         if (size && size != shm_zone[i].shm.size) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "the size %uz of shared memory zone \"%V\" "
-                               "conflicts with already declared size %uz",
-                               size, &shm_zone[i].name, shm_zone[i].shm.size);
+                            "the size %uz of shared memory zone \"%V\" "
+                            "conflicts with already declared size %uz",
+                            size, &shm_zone[i].shm.name, shm_zone[i].shm.size);
             return NULL;
         }
 
         if (tag != shm_zone[i].tag) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "the shared memory zone \"%V\" is "
-                               "already declared for a different use",
-                               &shm_zone[i].name);
+                            "the shared memory zone \"%V\" is "
+                            "already declared for a different use",
+                            &shm_zone[i].shm.name);
             return NULL;
         }
 
@@ -1233,8 +1277,9 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng
     shm_zone->data = NULL;
     shm_zone->shm.log = cf->cycle->log;
     shm_zone->shm.size = size;
+    shm_zone->shm.name = *name;
+    shm_zone->shm.exists = 0;
     shm_zone->init = NULL;
-    shm_zone->name = *name;
     shm_zone->tag = tag;
 
     return shm_zone;
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -29,7 +29,6 @@ struct ngx_shm_zone_s {
     void                     *data;
     ngx_shm_t                 shm;
     ngx_shm_zone_init_pt      init;
-    ngx_str_t                 name;
     void                     *tag;
 };
 
@@ -39,7 +38,7 @@ struct ngx_cycle_s {
     ngx_pool_t               *pool;
 
     ngx_log_t                *log;
-    ngx_log_t                *new_log;
+    ngx_log_t                 new_log;
 
     ngx_connection_t        **files;
     ngx_connection_t         *free_connections;
@@ -61,7 +60,8 @@ struct ngx_cycle_s {
 
     ngx_str_t                 conf_file;
     ngx_str_t                 conf_param;
-    ngx_str_t                 root;
+    ngx_str_t                 conf_prefix;
+    ngx_str_t                 prefix;
     ngx_str_t                 lock_file;
     ngx_str_t                 hostname;
 };
@@ -117,6 +117,7 @@ typedef struct {
 ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);
 ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log);
 void ngx_delete_pidfile(ngx_cycle_t *cycle);
+ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig);
 void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
 char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last);
 ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -8,8 +8,9 @@
 #include <ngx_core.h>
 
 
-static ngx_atomic_uint_t  ngx_temp_number;
-static ngx_atomic_uint_t  ngx_random_number;
+static ngx_atomic_t   temp_number = 0;
+ngx_atomic_t         *ngx_temp_number = &temp_number;
+ngx_atomic_int_t      ngx_random_number = 123456;
 
 
 ssize_t
@@ -99,13 +100,7 @@ ngx_create_temp_file(ngx_file_t *file, n
             continue;
         }
 
-        if ((path->level[0] == 0)
-            || (err != NGX_ENOENT
-#if (NGX_WIN32)
-                && err != NGX_ENOTDIR
-#endif
-            ))
-        {
+        if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
             ngx_log_error(NGX_LOG_CRIT, file->log, err,
                           ngx_open_tempfile_n " \"%s\" failed",
                           file->name.data);
@@ -211,22 +206,16 @@ ngx_create_full_path(u_char *dir, ngx_ui
 }
 
 
-void
-ngx_init_temp_number(void)
-{
-    ngx_temp_number = 0;
-    ngx_random_number = 123456;
-}
-
-
 ngx_atomic_uint_t
 ngx_next_temp_number(ngx_uint_t collision)
 {
-    if (collision) {
-        ngx_temp_number += ngx_random_number;
-    }
+    ngx_atomic_uint_t  n, add;
+
+    add = collision ? ngx_random_number : 1;
 
-    return ngx_temp_number++;
+    n = ngx_atomic_fetch_add(ngx_temp_number, add);
+
+    return n + add;
 }
 
 
@@ -264,7 +253,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n
     }
 
     path->len = 0;
-    path->manager = (ngx_path_manager_pt) cmd->post;
+    path->manager = NULL;
+    path->loader = NULL;
     path->conf_file = cf->conf_file->file.name.data;
     path->line = cf->conf_file->line;
 
@@ -325,6 +315,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf
                    + init->level[2] + (init->level[2] ? 1 : 0);
 
     (*path)->manager = NULL;
+    (*path)->loader = NULL;
     (*path)->conf_file = NULL;
 
     if (ngx_add_path(cf, path) != NGX_OK) {
@@ -489,7 +480,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng
         {
         ngx_file_info_t   fi;
 
-        if (ngx_file_info((const char *) path[i]->name.data, &fi) == -1) {
+        if (ngx_file_info((const char *) path[i]->name.data, &fi)
+            == NGX_FILE_ERROR)
+        {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                           ngx_file_info_n " \"%s\" failed", path[i]->name.data);
             return NGX_ERROR;
@@ -526,7 +519,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng
 ngx_int_t
 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
 {
-    ngx_err_t  err;
+    u_char           *name;
+    ngx_err_t         err;
+    ngx_copy_file_t   cf;
 
 #if !(NGX_WIN32)
 
@@ -556,7 +551,7 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 
     err = ngx_errno;
 
-    if (err == NGX_ENOENT) {
+    if (err == NGX_ENOPATH) {
 
         if (!ext->create_path) {
             goto failed;
@@ -576,7 +571,6 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
         }
 
         err = ngx_errno;
-        goto failed;
     }
 
 #if (NGX_WIN32)
@@ -597,6 +591,53 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 
 #endif
 
+    if (err == NGX_EXDEV) {
+
+        cf.size = -1;
+        cf.buf_size = 0;
+        cf.access = ext->access;
+        cf.time = ext->time;
+        cf.log = ext->log;
+
+        name = ngx_alloc(to->len + 1 + 10 + 1, ext->log);
+        if (name == NULL) {
+            return NGX_ERROR;
+        }
+
+        (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data,
+                           (uint32_t) ngx_next_temp_number(0));
+
+        if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {
+
+            if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) {
+                ngx_free(name);
+
+                if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
+                    ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
+                                  ngx_delete_file_n " \"%s\" failed",
+                                  src->data);
+                    return NGX_ERROR;
+                }
+
+                return NGX_OK;
+            }
+
+            ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
+                          ngx_rename_file_n " \"%s\" to \"%s\" failed",
+                          name, to->data);
+
+            if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
+                              ngx_delete_file_n " \"%s\" failed", name);
+
+            }
+        }
+
+        ngx_free(name);
+
+        err = 0;
+    }
+
 failed:
 
     if (ext->delete_file) {
@@ -606,15 +647,141 @@ failed:
         }
     }
 
-    if (err && ext->log_rename_error) {
+    if (err) {
         ngx_log_error(NGX_LOG_CRIT, ext->log, err,
                       ngx_rename_file_n " \"%s\" to \"%s\" failed",
                       src->data, to->data);
     }
 
-    ext->rename_error = err;
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
+{
+    char             *buf;
+    off_t             size;
+    size_t            len;
+    ssize_t           n;
+    ngx_fd_t          fd, nfd;
+    ngx_int_t         rc;
+    ngx_file_info_t   fi;
+
+    rc = NGX_ERROR;
+    buf = NULL;
+    nfd = NGX_INVALID_FILE;
+
+    fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+
+    if (fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", from);
+        goto failed;
+    }
+
+    if (cf->size != -1) {
+        size = cf->size;
+
+    } else {
+        if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_fd_info_n " \"%s\" failed", from);
+
+            goto failed;
+        }
+
+        size = ngx_file_size(&fi);
+    }
+
+    len = cf->buf_size ? cf->buf_size : 65536;
+
+    if ((off_t) len > size) {
+        len = (size_t) size;
+    }
+
+    buf = ngx_alloc(len, cf->log);
+    if (buf == NULL) {
+        goto failed;
+    }
+
+    nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
+                        cf->access);
+
+    if (nfd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", to);
+        goto failed;
+    }
+
+    while (size > 0) {
 
-    return NGX_ERROR;
+        if ((off_t) len > size) {
+            len = (size_t) size;
+        }
+
+        n = ngx_read_fd(fd, buf, len);
+
+        if (n == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_read_fd_n " \"%s\" failed", from);
+            goto failed;
+        }
+
+        if ((size_t) n != len) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_read_fd_n " has read only %z of %uz from %s",
+                          n, size, from);
+            goto failed;
+        }
+
+        n = ngx_write_fd(nfd, buf, len);
+
+        if (n == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_write_fd_n " \"%s\" failed", to);
+            goto failed;
+        }
+
+        if ((size_t) n != len) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_write_fd_n " has written only %z of %uz to %s",
+                          n, size, to);
+            goto failed;
+        }
+
+        size -= n;
+    }
+
+    if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
+        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                      ngx_set_file_time_n " \"%s\" failed", to);
+        goto failed;
+    }
+
+    rc = NGX_OK;
+
+failed:
+
+    if (nfd != NGX_INVALID_FILE) {
+        if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", to);
+        }
+    }
+
+    if (fd != NGX_INVALID_FILE) {
+        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", from);
+        }
+    }
+
+    if (buf) {
+        ngx_free(buf);
+    }
+
+    return rc;
 }
 
 
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -22,14 +22,20 @@ struct ngx_file_s {
 
     ngx_log_t                 *log;
 
+#if (NGX_HAVE_FILE_AIO)
+    ngx_event_aio_t           *aio;
+#endif
+
     unsigned                   valid_info:1;
     unsigned                   directio:1;
 };
 
+
 #define NGX_MAX_PATH_LEVEL  3
 
 
 typedef time_t (*ngx_path_manager_pt) (void *data);
+typedef void (*ngx_path_loader_pt) (void *data);
 
 
 typedef struct {
@@ -38,6 +44,7 @@ typedef struct {
     size_t                     level[3];
 
     ngx_path_manager_pt        manager;
+    ngx_path_loader_pt         loader;
     void                      *data;
 
     u_char                    *conf_file;
@@ -71,16 +78,25 @@ typedef struct {
     ngx_uint_t                 path_access;
     time_t                     time;
     ngx_fd_t                   fd;
-    ngx_err_t                  rename_error;
 
     unsigned                   create_path:1;
     unsigned                   delete_file:1;
-    unsigned                   log_rename_error:1;
 
     ngx_log_t                 *log;
 } ngx_ext_rename_file_t;
 
 
+typedef struct {
+    off_t                      size;
+    size_t                     buf_size;
+
+    ngx_uint_t                 access;
+    time_t                     time;
+
+    ngx_log_t                 *log;
+} ngx_copy_file_t;
+
+
 typedef struct ngx_tree_ctx_s  ngx_tree_ctx_t;
 
 typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev);
@@ -115,9 +131,9 @@ ngx_int_t ngx_add_path(ngx_conf_t *cf, n
 ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user);
 ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to,
     ngx_ext_rename_file_t *ext);
+ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf);
 ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree);
 
-void ngx_init_temp_number(void);
 ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
 
 char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -126,4 +142,8 @@ char *ngx_conf_merge_path_value(ngx_conf
 char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
+extern ngx_atomic_t      *ngx_temp_number;
+extern ngx_atomic_int_t   ngx_random_number;
+
+
 #endif /* _NGX_FILE_H_INCLUDED_ */
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -534,7 +534,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t *
 
             next_name->key.len = names[n].key.len - len;
             next_name->key.data = names[n].key.data + len;
-            next_name->key_hash= 0;
+            next_name->key_hash = 0;
             next_name->value = names[n].value;
 
 #if 0
@@ -562,7 +562,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t *
 
             next_name->key.len = names[i].key.len - dot_len;
             next_name->key.data = names[i].key.data + dot_len;
-            next_name->key_hash= 0;
+            next_name->key_hash = 0;
             next_name->value = names[i].value;
 
 #if 0
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -518,7 +518,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
 
         (void) ngx_cpystrn(p, host, len);
 
-        u->addr.in_addr = inet_addr((const char *) p);
         sin->sin_addr.s_addr = inet_addr((const char *) p);
 
         if (sin->sin_addr.s_addr == INADDR_NONE) {
@@ -530,7 +529,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
                 return NGX_ERROR;
             }
 
-            u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
             sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]);
         }
 
@@ -541,7 +539,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
         ngx_free(p);
 
     } else {
-        u->addr.in_addr = INADDR_ANY;
         sin->sin_addr.s_addr = INADDR_ANY;
         u->wildcard = 1;
     }
@@ -649,8 +646,22 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng
 
     (void) ngx_cpystrn(p, host, len);
 
+#if (NGX_WIN32)
+
+    rc = WSAStringToAddress((char *) p, AF_INET6, NULL,
+                            (SOCKADDR *) sin6, &u->socklen);
+    rc = !rc;
+
+    if (u->port) {
+        sin6->sin6_port = htons(u->port);
+    }
+
+#else
+
     rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr);
 
+#endif
+
     ngx_free(p);
 
     if (rc == 0) {
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -61,11 +61,6 @@ typedef struct {
 } ngx_cidr_t;
 
 
-typedef union {
-    in_addr_t                 in_addr;
-} ngx_url_addr_t;
-
-
 typedef struct {
     struct sockaddr          *sockaddr;
     socklen_t                 socklen;
@@ -91,8 +86,6 @@ typedef struct {
     unsigned                  no_port:1;
     unsigned                  wildcard:1;
 
-    ngx_url_addr_t            addr;
-
     socklen_t                 socklen;
     u_char                    sockaddr[NGX_SOCKADDRLEN];
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -8,14 +8,14 @@
 #include <ngx_core.h>
 
 
-static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
 static ngx_command_t  ngx_errlog_commands[] = {
 
     {ngx_string("error_log"),
      NGX_MAIN_CONF|NGX_CONF_1MORE,
-     ngx_set_error_log,
+     ngx_error_log,
      0,
      0,
      NULL},
@@ -48,12 +48,20 @@ ngx_module_t  ngx_errlog_module = {
 
 
 static ngx_log_t        ngx_log;
-static ngx_open_file_t  ngx_stderr;
+static ngx_open_file_t  ngx_log_file;
+ngx_uint_t              ngx_use_stderr = 1;
 
 
-static const char *err_levels[] = {
-    "stderr", "emerg", "alert", "crit", "error",
-    "warn", "notice", "info", "debug"
+static ngx_str_t err_levels[] = {
+    ngx_null_string,
+    ngx_string("emerg"),
+    ngx_string("alert"),
+    ngx_string("crit"),
+    ngx_string("error"),
+    ngx_string("warn"),
+    ngx_string("notice"),
+    ngx_string("info"),
+    ngx_string("debug")
 };
 
 static const char *debug_levels[] = {
@@ -79,7 +87,8 @@ ngx_log_error_core(ngx_uint_t level, ngx
 #if (NGX_HAVE_VARIADIC_MACROS)
     va_list  args;
 #endif
-    u_char   errstr[NGX_MAX_ERROR_STR], *p, *last;
+    u_char  *p, *last, *msg;
+    u_char   errstr[NGX_MAX_ERROR_STR];
 
     if (log->file->fd == NGX_INVALID_FILE) {
         return;
@@ -92,52 +101,32 @@ ngx_log_error_core(ngx_uint_t level, ngx
 
     p = errstr + ngx_cached_err_log_time.len;
 
-    p = ngx_snprintf(p, last - p, " [%s] ", err_levels[level]);
+    p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);
 
     /* pid#tid */
-    p = ngx_snprintf(p, last - p, "%P#" NGX_TID_T_FMT ": ",
+    p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",
                     ngx_log_pid, ngx_log_tid);
 
     if (log->connection) {
-        p = ngx_snprintf(p, last - p, "*%uA ", log->connection);
+        p = ngx_slprintf(p, last, "*%uA ", log->connection);
     }
 
+    msg = p;
+
 #if (NGX_HAVE_VARIADIC_MACROS)
 
     va_start(args, fmt);
-    p = ngx_vsnprintf(p, last - p, fmt, args);
+    p = ngx_vslprintf(p, last, fmt, args);
     va_end(args);
 
 #else
 
-    p = ngx_vsnprintf(p, last - p, fmt, args);
+    p = ngx_vslprintf(p, last, fmt, args);
 
 #endif
 
     if (err) {
-
-        if (p > last - 50) {
-
-            /* leave a space for an error code */
-
-            p = last - 50;
-            *p++ = '.';
-            *p++ = '.';
-            *p++ = '.';
-        }
-
-#if (NGX_WIN32)
-        p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000)
-                                           ? " (%d: " : " (%Xd: ", err);
-#else
-        p = ngx_snprintf(p, last - p, " (%d: ", err);
-#endif
-
-        p = ngx_strerror_r(err, p, last - p);
-
-        if (p < last) {
-            *p++ = ')';
-        }
+        p = ngx_log_errno(p, last, err);
     }
 
     if (level != NGX_LOG_DEBUG && log->handler) {
@@ -151,6 +140,19 @@ ngx_log_error_core(ngx_uint_t level, ngx
     ngx_linefeed(p);
 
     (void) ngx_write_fd(log->file->fd, errstr, p - errstr);
+
+    if (!ngx_use_stderr
+        || level > NGX_LOG_WARN
+        || log->file->fd == ngx_stderr)
+    {
+        return;
+    }
+
+    msg -= (err_levels[level].len + 4);
+
+    (void) ngx_sprintf(msg, "[%V]: ", &err_levels[level]);
+
+    (void) ngx_write_console(ngx_stderr, msg, p - msg);
 }
 
 
@@ -183,58 +185,169 @@ ngx_log_debug_core(ngx_log_t *log, ngx_e
 #endif
 
 
-void
-ngx_log_abort(ngx_err_t err, const char *text)
+void ngx_cdecl
+ngx_log_abort(ngx_err_t err, const char *fmt, ...)
+{
+    u_char   *p;
+    va_list   args;
+    u_char    errstr[NGX_MAX_CONF_ERRSTR];
+
+    va_start(args, fmt);
+    p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);
+    va_end(args);
+
+    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
+                  "%*s", p - errstr, errstr);
+}
+
+
+void ngx_cdecl
+ngx_log_stderr(ngx_err_t err, const char *fmt, ...)
 {
-    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, text);
+    u_char   *p, *last;
+    va_list   args;
+    u_char    errstr[NGX_MAX_ERROR_STR];
+
+    last = errstr + NGX_MAX_ERROR_STR;
+
+    va_start(args, fmt);
+    p = ngx_vslprintf(errstr, last, fmt, args);
+    va_end(args);
+
+    if (err) {
+        p = ngx_log_errno(p, last, err);
+    }
+
+    if (p > last - NGX_LINEFEED_SIZE) {
+        p = last - NGX_LINEFEED_SIZE;
+    }
+
+    ngx_linefeed(p);
+
+    (void) ngx_write_console(ngx_stderr, errstr, p - errstr);
+}
+
+
+u_char *
+ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err)
+{
+    if (buf > last - 50) {
+
+        /* leave a space for an error code */
+
+        buf = last - 50;
+        *buf++ = '.';
+        *buf++ = '.';
+        *buf++ = '.';
+    }
+
+#if (NGX_WIN32)
+    buf = ngx_slprintf(buf, last, ((unsigned) err < 0x80000000)
+                                       ? " (%d: " : " (%Xd: ", err);
+#else
+    buf = ngx_slprintf(buf, last, " (%d: ", err);
+#endif
+
+    buf = ngx_strerror_r(err, buf, last - buf);
+
+    if (buf < last) {
+        *buf++ = ')';
+    }
+
+    return buf;
 }
 
 
 ngx_log_t *
-ngx_log_init(void)
+ngx_log_init(u_char *prefix)
 {
-    ngx_log.file = &ngx_stderr;
+    u_char  *p, *name;
+    size_t   nlen, plen;
+
+    ngx_log.file = &ngx_log_file;
     ngx_log.log_level = NGX_LOG_NOTICE;
 
+    name = (u_char *) NGX_ERROR_LOG_PATH;
+
+    /*
+     * we use ngx_strlen() here since BCC warns about
+     * condition is always false and unreachable code
+     */
+
+    nlen = ngx_strlen(name);
+
+    if (nlen == 0) {
+        ngx_log_file.fd = ngx_stderr;
+        return &ngx_log;
+    }
+
+    p = NULL;
+
 #if (NGX_WIN32)
+    if (name[1] != ':') {
+#else
+    if (name[0] != '/') {
+#endif
 
-    ngx_stderr_fileno = GetStdHandle(STD_ERROR_HANDLE);
+        if (prefix) {
+            plen = ngx_strlen(prefix);
+
+        } else {
+#ifdef NGX_PREFIX
+            prefix = (u_char *) NGX_PREFIX;
+            plen = ngx_strlen(prefix);
+#else
+            plen = 0;
+#endif
+        }
 
-    ngx_stderr.fd = ngx_open_file((u_char *) NGX_ERROR_LOG_PATH,
-                                  NGX_FILE_APPEND,
-                                  NGX_FILE_CREATE_OR_OPEN,
-                                  NGX_FILE_DEFAULT_ACCESS);
+        if (plen) {
+            name = malloc(plen + nlen + 2);
+            if (name == NULL) {
+                return NULL;
+            }
+
+            p = ngx_cpymem(name, prefix, plen);
 
-    if (ngx_stderr.fd == NGX_INVALID_FILE) {
-        ngx_message_box("nginx", MB_OK, ngx_errno,
-                        "Could not open error log file: "
-                        ngx_open_file_n " \"" NGX_ERROR_LOG_PATH "\" failed");
-        return NULL;
+            if (!ngx_path_separator(*(p - 1))) {
+                *p++ = '/';
+            }
+
+            ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1);
+
+            p = name;
+        }
     }
 
-#else
+    ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,
+                                    NGX_FILE_CREATE_OR_OPEN,
+                                    NGX_FILE_DEFAULT_ACCESS);
 
-    ngx_stderr.fd = STDERR_FILENO;
+    if (ngx_log_file.fd == NGX_INVALID_FILE) {
+        ngx_log_stderr(ngx_errno,
+                       "[alert]: could not open error log file: "
+                       ngx_open_file_n " \"%s\" failed", name);
+#if (NGX_WIN32)
+        ngx_event_log(ngx_errno,
+                       "could not open error log file: "
+                       ngx_open_file_n " \"%s\" failed", name);
+#endif
 
-#endif
+        ngx_log_file.fd = ngx_stderr;
+    }
+
+    if (p) {
+        ngx_free(p);
+    }
 
     return &ngx_log;
 }
 
 
 ngx_log_t *
-ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args)
+ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name)
 {
     ngx_log_t  *log;
-    ngx_str_t  *value, *name;
-
-    if (args) {
-        value = args->elts;
-        name = &value[1];
-
-    } else {
-        name = NULL;
-    }
 
     log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
     if (log == NULL) {
@@ -251,7 +364,7 @@ ngx_log_create_errlog(ngx_cycle_t *cycle
 
 
 char *
-ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log)
+ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
 {
     ngx_uint_t   i, n, d;
     ngx_str_t   *value;
@@ -261,12 +374,12 @@ ngx_set_error_log_levels(ngx_conf_t *cf,
     for (i = 2; i < cf->args->nelts; i++) {
 
         for (n = 1; n <= NGX_LOG_DEBUG; n++) {
-            if (ngx_strcmp(value[i].data, err_levels[n]) == 0) {
+            if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) {
 
                 if (log->log_level != 0) {
                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                       "duplicate log level \"%s\"",
-                                       value[i].data);
+                                       "duplicate log level \"%V\"",
+                                       &value[i]);
                     return NGX_CONF_ERROR;
                 }
 
@@ -279,8 +392,8 @@ ngx_set_error_log_levels(ngx_conf_t *cf,
             if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) {
                 if (log->log_level & ~NGX_LOG_DEBUG_ALL) {
                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                       "invalid log level \"%s\"",
-                                       value[i].data);
+                                       "invalid log level \"%V\"",
+                                       &value[i]);
                     return NGX_CONF_ERROR;
                 }
 
@@ -291,15 +404,12 @@ ngx_set_error_log_levels(ngx_conf_t *cf,
 
         if (log->log_level == 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid log level \"%s\"", value[i].data);
+                               "invalid log level \"%V\"", &value[i]);
             return NGX_CONF_ERROR;
         }
     }
 
-    if (log->log_level == 0) {
-        log->log_level = NGX_LOG_ERR;
-
-    } else if (log->log_level == NGX_LOG_DEBUG) {
+    if (log->log_level == NGX_LOG_DEBUG) {
         log->log_level = NGX_LOG_DEBUG_ALL;
     }
 
@@ -308,26 +418,35 @@ ngx_set_error_log_levels(ngx_conf_t *cf,
 
 
 static char *
-ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_str_t  *value;
+    ngx_str_t  *value, name;
+
+    if (cf->cycle->new_log.file) {
+        return "is duplicate";
+    }
 
     value = cf->args->elts;
 
-    if (value[1].len == 6 && ngx_strcmp(value[1].data, "stderr") == 0) {
-        cf->cycle->new_log->file->fd = ngx_stderr.fd;
-        cf->cycle->new_log->file->name.len = 0;
-        cf->cycle->new_log->file->name.data = NULL;
+    if (ngx_strcmp(value[1].data, "stderr") == 0) {
+        name.len = 0;
+        name.data = NULL;
 
     } else {
-        cf->cycle->new_log->file->name = value[1];
+        name = value[1];
+    }
 
-        if (ngx_conf_full_name(cf->cycle, &cf->cycle->new_log->file->name, 0)
-            != NGX_OK)
-        {
-            return NGX_CONF_ERROR;
-        }
+    cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name);
+    if (cf->cycle->new_log.file == NULL) {
+        return NULL;
     }
 
-    return ngx_set_error_log_levels(cf, cf->cycle->new_log);
+    if (cf->args->nelts == 2) {
+        cf->cycle->new_log.log_level = NGX_LOG_ERR;
+        return NGX_CONF_OK;
+    }
+
+    cf->cycle->new_log.log_level = 0;
+
+    return ngx_log_set_levels(cf, &cf->cycle->new_log);
 }
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -195,13 +195,16 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo
 
 /*********************************/
 
-ngx_log_t *ngx_log_init(void);
-ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args);
-char *ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log);
-void ngx_log_abort(ngx_err_t err, const char *text);
+ngx_log_t *ngx_log_init(u_char *prefix);
+ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name);
+char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
+void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...);
+void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
+u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err);
 
 
 extern ngx_module_t  ngx_errlog_module;
+extern ngx_uint_t    ngx_use_stderr;
 
 
 #endif /* _NGX_LOG_H_INCLUDED_ */
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -130,6 +130,7 @@ ngx_open_cached_file(ngx_open_file_cache
     time_t                          now;
     uint32_t                        hash;
     ngx_int_t                       rc;
+    ngx_file_info_t                 fi;
     ngx_pool_cleanup_t             *cln;
     ngx_cached_open_file_t         *file;
     ngx_pool_cleanup_file_t        *clnf;
@@ -140,6 +141,25 @@ ngx_open_cached_file(ngx_open_file_cache
 
     if (cache == NULL) {
 
+        if (of->test_only) {
+
+            if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
+                of->err = ngx_errno;
+                of->failed = ngx_file_info_n;
+                return NGX_ERROR;
+            }
+
+            of->uniq = ngx_file_uniq(&fi);
+            of->mtime = ngx_file_mtime(&fi);
+            of->size = ngx_file_size(&fi);
+            of->is_dir = ngx_is_dir(&fi);
+            of->is_file = ngx_is_file(&fi);
+            of->is_link = ngx_is_link(&fi);
+            of->is_exec = ngx_is_exec(&fi);
+
+            return NGX_OK;
+        }
+
         cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
         if (cln == NULL) {
             return NGX_ERROR;
@@ -214,6 +234,7 @@ ngx_open_cached_file(ngx_open_file_cache
 
             } else {
                 of->err = file->err;
+                of->failed = ngx_open_file_n;
             }
 
             goto found;
@@ -339,6 +360,7 @@ create:
 
     file->uses = 1;
     file->count = 0;
+    file->use_event = 0;
     file->event = NULL;
 
 add_event:
@@ -443,7 +465,8 @@ ngx_open_and_stat_file(u_char *name, ngx
 
     if (of->fd != NGX_INVALID_FILE) {
 
-        if (ngx_file_info(name, &fi) == -1) {
+        if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
+            of->failed = ngx_file_info_n;
             goto failed;
         }
 
@@ -453,7 +476,8 @@ ngx_open_and_stat_file(u_char *name, ngx
 
     } else if (of->test_dir) {
 
-        if (ngx_file_info(name, &fi) == -1) {
+        if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
+            of->failed = ngx_file_info_n;
             goto failed;
         }
 
@@ -471,6 +495,7 @@ ngx_open_and_stat_file(u_char *name, ngx
     }
 
     if (fd == NGX_INVALID_FILE) {
+        of->failed = ngx_open_file_n;
         goto failed;
     }
 
--- a/src/core/ngx_open_file_cache.h
+++ b/src/core/ngx_open_file_cache.h
@@ -21,13 +21,16 @@ typedef struct {
     time_t                   mtime;
     off_t                    size;
     off_t                    directio;
+
     ngx_err_t                err;
+    char                    *failed;
 
     time_t                   valid;
 
     ngx_uint_t               min_uses;
 
     unsigned                 test_dir:1;
+    unsigned                 test_only:1;
     unsigned                 log:1;
     unsigned                 errors:1;
     unsigned                 events:1;
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -16,14 +16,12 @@
 /*
  * When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly
  * to an application memory from a device if parameters are aligned
- * to device sector boundary(512 bytes).  They fallback to usual read
+ * to device sector boundary (512 bytes).  They fallback to usual read
  * operation if the parameters are not aligned.
  * Linux allows DIRECTIO only if the parameters are aligned to a filesystem
  * sector boundary, otherwise it returns EINVAL.  The sector size is
  * usually 512 bytes, however, on XFS it may be 4096 bytes.
  */
-#define NGX_DIRECTIO_BLOCK  4096
-
 
 #define NGX_NONE            1
 
@@ -76,6 +74,12 @@ ngx_output_chain(ngx_output_chain_ctx_t 
         }
     }
 
+#if (NGX_HAVE_FILE_AIO)
+    if (ctx->aio) {
+        return NGX_AGAIN;
+    }
+#endif
+
     out = NULL;
     last_out = &out;
     last = NGX_NONE;
@@ -314,12 +318,11 @@ ngx_output_chain_add_copy(ngx_pool_t *po
 
 #endif
 
+        cl->next = NULL;
         *ll = cl;
         ll = &cl->next;
     }
 
-    *ll = NULL;
-
     return NGX_OK;
 }
 
@@ -338,7 +341,7 @@ ngx_output_chain_align_file_buf(ngx_outp
 
     ctx->directio = 1;
 
-    size = (size_t) (in->file_pos - (in->file_pos & ~(NGX_DIRECTIO_BLOCK - 1)));
+    size = (size_t) (in->file_pos - (in->file_pos & ~(ctx->alignment - 1)));
 
     if (size == 0) {
 
@@ -349,7 +352,7 @@ ngx_output_chain_align_file_buf(ngx_outp
         size = (size_t) bsize;
 
     } else {
-        size = NGX_DIRECTIO_BLOCK - size;
+        size = (size_t) ctx->alignment - size;
 
         if ((off_t) size > bsize) {
             size = (size_t) bsize;
@@ -424,7 +427,7 @@ ngx_output_chain_get_buf(ngx_output_chai
          * userland buffer direct usage conjunctly with directio
          */
 
-        b->start = ngx_pmemalign(ctx->pool, size, NGX_DIRECTIO_BLOCK);
+        b->start = ngx_pmemalign(ctx->pool, size, (size_t) ctx->alignment);
         if (b->start == NULL) {
             return NGX_ERROR;
         }
@@ -503,6 +506,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
         if (src->pos == src->last) {
             dst->flush = src->flush;
             dst->last_buf = src->last_buf;
+            dst->last_in_chain = src->last_in_chain;
         }
 
     } else {
@@ -519,8 +523,26 @@ ngx_output_chain_copy_buf(ngx_output_cha
 
 #endif
 
+#if (NGX_HAVE_FILE_AIO)
+
+        if (ctx->aio_handler) {
+            n = ngx_file_aio_read(src->file, dst->pos, (size_t) size,
+                                  src->file_pos, ctx->pool);
+            if (n == NGX_AGAIN) {
+                ctx->aio_handler(ctx, src->file);
+                return NGX_AGAIN;
+            }
+
+        } else {
+            n = ngx_read_file(src->file, dst->pos, (size_t) size,
+                              src->file_pos);
+        }
+#else
+
         n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
 
+#endif
+
 #if (NGX_HAVE_ALIGNED_DIRECTIO)
 
         if (ctx->unaligned) {
@@ -545,19 +567,11 @@ ngx_output_chain_copy_buf(ngx_output_cha
             return (ngx_int_t) n;
         }
 
-#if (NGX_FILE_AIO_READ)
-        if (n == NGX_AGAIN) {
-            return (ngx_int_t) n;
-        }
-#endif
-
         if (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;
-            }
+            return NGX_ERROR;
         }
 
         dst->last += n;
@@ -577,6 +591,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
         if (src->file_pos == src->file_last) {
             dst->flush = src->flush;
             dst->last_buf = src->last_buf;
+            dst->last_in_chain = src->last_in_chain;
         }
     }
 
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -25,6 +25,7 @@ ngx_create_pool(size_t size, ngx_log_t *
     p->d.last = (u_char *) p + sizeof(ngx_pool_t);
     p->d.end = (u_char *) p + size;
     p->d.next = NULL;
+    p->d.failed = 0;
 
     size = size - sizeof(ngx_pool_t);
     p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
@@ -189,6 +190,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_
 
     new->d.end = m + psize;
     new->d.next = NULL;
+    new->d.failed = 0;
 
     m += sizeof(ngx_pool_data_t);
     m = ngx_align_ptr(m, NGX_ALIGNMENT);
@@ -197,7 +199,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_
     current = pool->current;
 
     for (p = current; p->d.next; p = p->d.next) {
-        if ((size_t) (p->d.end - p->d.last) < NGX_ALIGNMENT) {
+        if (p->d.failed++ > 4) {
             current = p->d.next;
         }
     }
@@ -214,6 +216,7 @@ static void *
 ngx_palloc_large(ngx_pool_t *pool, size_t size)
 {
     void              *p;
+    ngx_uint_t         n;
     ngx_pool_large_t  *large;
 
     p = ngx_alloc(size, pool->log);
@@ -221,6 +224,19 @@ ngx_palloc_large(ngx_pool_t *pool, size_
         return NULL;
     }
 
+    n = 0;
+
+    for (large = pool->large; large; large = large->next) {
+        if (large->alloc == NULL) {
+            large->alloc = p;
+            return p;
+        }
+
+        if (n++ > 3) {
+            break;
+        }
+    }
+
     large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
     if (large == NULL) {
         ngx_free(p);
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -46,6 +46,7 @@ typedef struct {
     u_char               *last;
     u_char               *end;
     ngx_pool_t           *next;
+    ngx_uint_t            failed;
 } ngx_pool_data_t;
 
 
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -131,14 +131,14 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_
 
     r->event->handler = ngx_resolver_resend_handler;
     r->event->data = r;
-    r->event->log = cf->cycle->new_log;
+    r->event->log = &cf->cycle->new_log;
     r->ident = -1;
 
     r->resend_timeout = 5;
     r->expire = 30;
     r->valid = 300;
 
-    r->log = cf->cycle->new_log;
+    r->log = &cf->cycle->new_log;
     r->log_level = NGX_LOG_ALERT;
 
     if (addr) {
@@ -152,7 +152,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_
         uc->sockaddr = addr->sockaddr;
         uc->socklen = addr->socklen;
         uc->server = addr->name;
-        uc->log = cf->cycle->new_log;
+        uc->log = &cf->cycle->new_log;
     }
 
     return r;
@@ -1149,6 +1149,8 @@ ngx_resolver_process_a(ngx_resolver_t *r
         goto failed;
     }
 
+    ngx_resolver_free(r, name.data);
+
     if (code == 0 && nan == 0) {
         code = 3; /* NXDOMAIN */
     }
@@ -1400,6 +1402,8 @@ failed:
 
     /* unlock name mutex */
 
+    ngx_resolver_free(r, name.data);
+
     return;
 }
 
@@ -1595,7 +1599,6 @@ static ngx_resolver_node_t *
 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
 {
     ngx_int_t             rc;
-    size_t                len;
     ngx_rbtree_node_t    *node, *sentinel;
     ngx_resolver_node_t  *rn;
 
@@ -1619,9 +1622,7 @@ ngx_resolver_lookup_name(ngx_resolver_t 
         do {
             rn = (ngx_resolver_node_t *) node;
 
-            len = (name->len > (size_t) rn->nlen) ? rn->nlen : name->len;
-
-            rc = ngx_strncmp(name->data, rn->name, len);
+            rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
 
             if (rc == 0) {
                 return rn;
@@ -1675,7 +1676,6 @@ static void
 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
 {
-    size_t                 len;
     ngx_rbtree_node_t    **p;
     ngx_resolver_node_t   *rn, *rn_temp;
 
@@ -1694,10 +1694,8 @@ ngx_resolver_rbtree_insert_value(ngx_rbt
             rn = (ngx_resolver_node_t *) node;
             rn_temp = (ngx_resolver_node_t *) temp;
 
-            len = (rn->nlen > rn_temp->nlen) ? rn_temp->nlen : rn->nlen;
-
-            p = (ngx_strncmp(rn->name, rn_temp->name, len) < 0)
-                    ? &temp->left : &temp->right;
+            p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
+                 < 0) ? &temp->left : &temp->right;
         }
 
         if (*p == sentinel) {
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -584,9 +584,9 @@ ngx_slab_free_locked(ngx_slab_pool_t *po
 
         ngx_slab_free_pages(pool, &pool->pages[n], size);
 
-        size <<= ngx_pagesize_shift;
+        ngx_slab_junk(p, size << ngx_pagesize_shift);
 
-        goto done;
+        return;
     }
 
     /* not reached */
--- a/src/core/ngx_slab.h
+++ b/src/core/ngx_slab.h
@@ -37,6 +37,9 @@ typedef struct {
 
     u_char           *log_ctx;
     u_char            zero;
+
+    void             *data;
+    void             *addr;
 } ngx_slab_pool_t;
 
 
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -30,12 +30,15 @@ ngx_cpystrn(u_char *dst, u_char *src, si
         return dst;
     }
 
-    for ( /* void */ ; --n; dst++, src++) {
+    while (--n) {
         *dst = *src;
 
         if (*dst == '\0') {
             return dst;
         }
+
+        dst++;
+        src++;
     }
 
     *dst = '\0';
@@ -87,7 +90,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t 
  *
  *  reserved:
  *    %t                        ptrdiff_t
- *    %S                        null-teminated wchar string
+ *    %S                        null-terminated wchar string
  *    %C                        wchar
  */
 
@@ -99,7 +102,7 @@ ngx_sprintf(u_char *buf, const char *fmt
     va_list   args;
 
     va_start(args, fmt);
-    p = ngx_vsnprintf(buf, /* STUB */ 65536, fmt, args);
+    p = ngx_vslprintf(buf, (void *) -1, fmt, args);
     va_end(args);
 
     return p;
@@ -113,7 +116,21 @@ ngx_snprintf(u_char *buf, size_t max, co
     va_list   args;
 
     va_start(args, fmt);
-    p = ngx_vsnprintf(buf, max, fmt, args);
+    p = ngx_vslprintf(buf, buf + max, fmt, args);
+    va_end(args);
+
+    return p;
+}
+
+
+u_char * ngx_cdecl
+ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
+{
+    u_char   *p;
+    va_list   args;
+
+    va_start(args, fmt);
+    p = ngx_vslprintf(buf, last, fmt, args);
     va_end(args);
 
     return p;
@@ -121,9 +138,9 @@ ngx_snprintf(u_char *buf, size_t max, co
 
 
 u_char *
-ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
+ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
 {
-    u_char                *p, zero, *last;
+    u_char                *p, zero;
     int                    d;
     float                  f, scale;
     size_t                 len, slen;
@@ -134,12 +151,6 @@ ngx_vsnprintf(u_char *buf, size_t max, c
     ngx_str_t             *v;
     ngx_variable_value_t  *vv;
 
-    if (max == 0) {
-        return buf;
-    }
-
-    last = buf + max;
-
     while (*fmt && buf < last) {
 
         /*
@@ -557,8 +568,8 @@ ngx_strcasecmp(u_char *s1, u_char *s2)
         c1 = (ngx_uint_t) *s1++;
         c2 = (ngx_uint_t) *s2++;
 
-        c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
-        c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
 
         if (c1 == c2) {
 
@@ -583,8 +594,8 @@ ngx_strncasecmp(u_char *s1, u_char *s2, 
         c1 = (ngx_uint_t) *s1++;
         c2 = (ngx_uint_t) *s2++;
 
-        c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
-        c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
 
         if (c1 == c2) {
 
@@ -672,7 +683,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si
     ngx_uint_t  c1, c2;
 
     c2 = (ngx_uint_t) *s2++;
-    c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+    c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
 
     do {
         do {
@@ -682,7 +693,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si
                 return NULL;
             }
 
-            c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+            c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
 
         } while (c1 != c2);
 
@@ -692,6 +703,39 @@ ngx_strcasestrn(u_char *s1, char *s2, si
 }
 
 
+/*
+ * ngx_strlcasestrn() is intended to search for static substring
+ * with known length in string until the argument last. The argument n
+ * must be length of the second substring - 1.
+ */
+
+u_char *
+ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
+{
+    ngx_uint_t  c1, c2;
+
+    c2 = (ngx_uint_t) *s2++;
+    c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+    last -= n;
+
+    do {
+        do {
+            if (s1 >= last) {
+                return NULL;
+            }
+
+            c1 = (ngx_uint_t) *s1++;
+
+            c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+
+        } while (c1 != c2);
+
+    } while (ngx_strncasecmp(s1, s2, n) != 0);
+
+    return --s1;
+}
+
+
 ngx_int_t
 ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
 {
@@ -776,6 +820,37 @@ ngx_memn2cmp(u_char *s1, u_char *s2, siz
 
 
 ngx_int_t
+ngx_dns_strcmp(u_char *s1, u_char *s2)
+{
+    ngx_uint_t  c1, c2;
+
+    for ( ;; ) {
+        c1 = (ngx_uint_t) *s1++;
+        c2 = (ngx_uint_t) *s2++;
+
+        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+
+        if (c1 == c2) {
+
+            if (c1) {
+                continue;
+            }
+
+            return 0;
+        }
+
+        /* in ASCII '.' > '-', but we need '.' to be the lowest character */
+
+        c1 = (c1 == '.') ? ' ' : c1;
+        c2 = (c2 == '.') ? ' ' : c2;
+
+        return c1 - c2;
+    }
+}
+
+
+ngx_int_t
 ngx_atoi(u_char *line, size_t n)
 {
     ngx_int_t  value;
@@ -1296,7 +1371,7 @@ ngx_escape_uri(u_char *dst, u_char *src,
 
         /* find the number of the characters to be escaped */
 
-        n  = 0;
+        n = 0;
 
         for (i = 0; i < size; i++) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -140,7 +140,11 @@ u_char *ngx_cpystrn(u_char *dst, u_char 
 u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src);
 u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...);
 u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
-u_char *ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args);
+u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt,
+    ...);
+u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args);
+#define ngx_vsnprintf(buf, max, fmt, args)                                   \
+    ngx_vslprintf(buf, buf + (max), fmt, args)
 
 ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2);
 ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n);
@@ -149,10 +153,12 @@ u_char *ngx_strnstr(u_char *s1, char *s2
 
 u_char *ngx_strstrn(u_char *s1, char *s2, size_t n);
 u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n);
+u_char *ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n);
 
 ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);
 ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);
 ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);
+ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2);
 
 ngx_int_t ngx_atoi(u_char *line, size_t n);
 ssize_t ngx_atosz(u_char *line, size_t n);
--- a/src/event/modules/ngx_aio_module.c
+++ b/src/event/modules/ngx_aio_module.c
@@ -7,11 +7,9 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
+
 
-#if (NGX_HAVE_KQUEUE)
-#include <ngx_kqueue_module.h>
-#endif
+extern ngx_event_module_t  ngx_kqueue_module_ctx;
 
 
 static ngx_int_t ngx_aio_init(ngx_cycle_t *cycle, ngx_msec_t timer);
@@ -73,7 +71,6 @@ ngx_module_t  ngx_aio_module = {
 };
 
 
-
 #if (NGX_HAVE_KQUEUE)
 
 static ngx_int_t
@@ -134,12 +131,14 @@ ngx_aio_del_connection(ngx_connection_t 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_cancel: %d", rc);
 
     if (rc == AIO_CANCELED) {
-        c->read->active = c->write->active = 0;
+        c->read->active = 0;
+        c->write->active = 0;
         return NGX_OK;
     }
 
     if (rc == AIO_ALLDONE) {
-        c->read->active = c->write->active = 0;
+        c->read->active = 0;
+        c->write->active = 0;
         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                       "aio_cancel() returned AIO_ALLDONE");
         return NGX_OK;
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -369,11 +369,7 @@ ngx_devpoll_process_events(ngx_cycle_t *
     dvp.dp_timeout = timer;
     events = ioctl(dp, DP_POLL, &dvp);
 
-    if (events == -1) {
-        err = ngx_errno;
-    } else {
-        err = 0;
-    }
+    err = (events == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
@@ -550,7 +546,7 @@ ngx_devpoll_create_conf(ngx_cycle_t *cyc
 
     dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
     if (dpcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     dpcf->changes = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -43,10 +43,6 @@ struct epoll_event {
     epoll_data_t  data;
 };
 
-int epoll_create(int size);
-int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout);
-
 int epoll_create(int size)
 {
     return -1;
@@ -62,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_ev
     return -1;
 }
 
+#if (NGX_HAVE_FILE_AIO)
+
+#define SYS_io_setup      245
+#define SYS_io_destroy    246
+#define SYS_io_getevents  247
+#define SYS_eventfd       323
+
+typedef u_int  aio_context_t;
+
+struct io_event {
+    uint64_t  data;  /* the data field from the iocb */
+    uint64_t  obj;   /* what iocb this event came from */
+    int64_t   res;   /* result code for this event */
+    int64_t   res2;  /* secondary result */
+};
+
+
+int eventfd(u_int initval)
+{
+    return -1;
+}
+
+#endif
 #endif
 
 
@@ -82,6 +101,10 @@ static ngx_int_t ngx_epoll_del_connectio
 static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
     ngx_uint_t flags);
 
+#if (NGX_HAVE_FILE_AIO)
+static void ngx_epoll_eventfd_handler(ngx_event_t *ev);
+#endif
+
 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
 
@@ -89,6 +112,15 @@ static int                  ep = -1;
 static struct epoll_event  *event_list;
 static ngx_uint_t           nevents;
 
+#if (NGX_HAVE_FILE_AIO)
+
+int                         ngx_eventfd = -1;
+aio_context_t               ngx_aio_ctx = 0;
+
+static ngx_event_t          ngx_eventfd_event;
+static ngx_connection_t     ngx_eventfd_conn;
+
+#endif
 
 static ngx_str_t      epoll_name = ngx_string("epoll");
 
@@ -140,6 +172,42 @@ ngx_module_t  ngx_epoll_module = {
 };
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+/*
+ * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly
+ * as syscalls instead of libaio usage, because the library header file
+ * supports eventfd() since 0.3.107 version only.
+ *
+ * Also we do not use eventfd() in glibc, because glibc supports it
+ * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2()
+ * into single eventfd() function with different number of parameters.
+ */
+
+static long
+io_setup(u_int nr_reqs, aio_context_t *ctx)
+{
+    return syscall(SYS_io_setup, nr_reqs, ctx);
+}
+
+
+static int
+io_destroy(aio_context_t ctx)
+{
+    return syscall(SYS_io_destroy, ctx);
+}
+
+
+static long
+io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events,
+    struct timespec *tmo)
+{
+    return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo);
+}
+
+#endif
+
+
 static ngx_int_t
 ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
 {
@@ -155,6 +223,55 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m
                           "epoll_create() failed");
             return NGX_ERROR;
         }
+
+#if (NGX_HAVE_FILE_AIO)
+        {
+        int                 n;
+        struct epoll_event  ee;
+
+        ngx_eventfd = syscall(SYS_eventfd, 0);
+
+        if (ngx_eventfd == -1) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          "eventfd() failed");
+            return NGX_ERROR;
+        }
+
+        n = 1;
+
+        if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          "ioctl(eventfd, FIONBIO) failed");
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                       "eventfd: %d", ngx_eventfd);
+
+        n = io_setup(1024, &ngx_aio_ctx);
+
+        if (n != 0) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, -n, "io_setup() failed");
+            return NGX_ERROR;
+        }
+
+        ngx_eventfd_event.data = &ngx_eventfd_conn;
+        ngx_eventfd_event.handler = ngx_epoll_eventfd_handler;
+        ngx_eventfd_event.log = cycle->log;
+        ngx_eventfd_event.active = 1;
+        ngx_eventfd_conn.fd = ngx_eventfd;
+        ngx_eventfd_conn.read = &ngx_eventfd_event;
+        ngx_eventfd_conn.log = cycle->log;
+
+        ee.events = EPOLLIN|EPOLLET;
+        ee.data.ptr = &ngx_eventfd_conn;
+
+        if (epoll_ctl(ep, EPOLL_CTL_ADD, ngx_eventfd, &ee) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
+            return NGX_ERROR;
+        }
+        }
+#endif
     }
 
     if (nevents < epcf->events) {
@@ -197,6 +314,17 @@ ngx_epoll_done(ngx_cycle_t *cycle)
 
     ep = -1;
 
+#if (NGX_HAVE_FILE_AIO)
+
+    if (io_destroy(ngx_aio_ctx) != 0) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      "io_destroy() failed");
+    }
+
+    ngx_aio_ctx = 0;
+
+#endif
+
     ngx_free(event_list);
 
     event_list = NULL;
@@ -401,11 +529,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 
     events = epoll_wait(ep, event_list, (int) nevents, timer);
 
-    if (events == -1) {
-        err = ngx_errno;
-    } else {
-        err = 0;
-    }
+    err = (events == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
@@ -545,6 +669,91 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 }
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+static void
+ngx_epoll_eventfd_handler(ngx_event_t *ev)
+{
+    int               n;
+    long              i, events;
+    uint64_t          ready;
+    ngx_err_t         err;
+    ngx_event_t      *e;
+    ngx_event_aio_t  *aio;
+    struct io_event   event[64];
+    struct timespec   ts;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler");
+
+    n = read(ngx_eventfd, &ready, 8);
+
+    err = ngx_errno;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd: %d", n);
+
+    if (n != 8) {
+        if (n == -1) {
+            if (err == NGX_EAGAIN) {
+                return;
+            }
+
+            ngx_log_error(NGX_LOG_ALERT, ev->log, err, "read(eventfd) failed");
+            return;
+        }
+
+        ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+                      "read(eventfd) returned only %d bytes", n);
+        return;
+    }
+
+    ts.tv_sec = 0;
+    ts.tv_nsec = 0;
+
+    while (ready) {
+
+        events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                       "io_getevents: %l", events);
+
+        if (events > 0) {
+            ready -= events;
+
+            for (i = 0; i < events; i++) {
+
+                ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                               "io_event: %uXL %uXL %L %L",
+                                event[i].data, event[i].obj,
+                                event[i].res, event[i].res2);
+
+                e = (ngx_event_t *) (uintptr_t) event[i].data;
+
+                e->complete = 1;
+                e->active = 0;
+                e->ready = 1;
+
+                aio = e->data;
+                aio->res = event[i].res;
+
+                ngx_post_event(e, &ngx_posted_events);
+            }
+
+            continue;
+        }
+
+        if (events == 0) {
+            return;
+        }
+
+        /* events < 0 */
+        ngx_log_error(NGX_LOG_ALERT, ev->log, -events, "io_getevents() failed");
+        return;
+    }
+}
+
+#endif
+
+
 static void *
 ngx_epoll_create_conf(ngx_cycle_t *cycle)
 {
@@ -552,7 +761,7 @@ ngx_epoll_create_conf(ngx_cycle_t *cycle
 
     epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t));
     if (epcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     epcf->events = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -581,7 +581,7 @@ ngx_eventport_create_conf(ngx_cycle_t *c
 
     epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
     if (epcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     epcf->events = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_kqueue_module.h>
 
 
 typedef struct {
@@ -113,7 +112,6 @@ ngx_module_t  ngx_kqueue_module = {
 };
 
 
-
 static ngx_int_t
 ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
 {
@@ -537,11 +535,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c
 
     events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
 
-    if (events == -1) {
-        err = ngx_errno;
-    } else {
-        err = 0;
-    }
+    err = (events == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
@@ -768,7 +762,7 @@ ngx_kqueue_create_conf(ngx_cycle_t *cycl
 
     kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
     if (kcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     kcf->changes = NGX_CONF_UNSET;
deleted file mode 100644
--- a/src/event/modules/ngx_kqueue_module.h
+++ /dev/null
@@ -1,16 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_KQUEUE_MODULE_H_INCLUDED_
-#define _NGX_KQUEUE_MODULE_H_INCLUDED_
-
-
-extern int                 ngx_kqueue;
-extern ngx_module_t        ngx_kqueue_module;
-extern ngx_event_module_t  ngx_kqueue_module_ctx;
-
-
-#endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -260,11 +260,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc
 
     ready = poll(event_list, (u_int) nevents, (int) timer);
 
-    if (ready == -1) {
-        err = ngx_errno;
-    } else {
-        err = 0;
-    }
+    err = (ready == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -691,7 +691,7 @@ ngx_rtsig_create_conf(ngx_cycle_t *cycle
 
     rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t));
     if (rtscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     rtscf->signo = NGX_CONF_UNSET;
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -9,7 +9,6 @@
 #include <ngx_event.h>
 
 
-
 static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
 static void ngx_select_done(ngx_cycle_t *cycle);
 static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
@@ -18,6 +17,7 @@ static ngx_int_t ngx_select_del_event(ng
     ngx_uint_t flags);
 static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
     ngx_uint_t flags);
+static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
 static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
 
 
@@ -26,13 +26,7 @@ static fd_set         master_write_fd_se
 static fd_set         work_read_fd_set;
 static fd_set         work_write_fd_set;
 
-#if (NGX_WIN32)
-static ngx_uint_t     max_read;
-static ngx_uint_t     max_write;
-#else
 static ngx_int_t      max_fd;
-#endif
-
 static ngx_uint_t     nevents;
 
 static ngx_event_t  **event_index;
@@ -111,11 +105,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_
 
     ngx_event_flags = NGX_USE_LEVEL_EVENT;
 
-#if (NGX_WIN32)
-    max_read = max_write = 0;
-#else
     max_fd = -1;
-#endif
 
     return NGX_OK;
 }
@@ -146,30 +136,17 @@ ngx_select_add_event(ngx_event_t *ev, ng
         return NGX_OK;
     }
 
-#if (NGX_WIN32)
-
-    if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE)
-        || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE))
+    if ((event == NGX_READ_EVENT && ev->write)
+        || (event == NGX_WRITE_EVENT && !ev->write))
     {
-        ngx_log_error(NGX_LOG_ERR, ev->log, 0,
-                      "maximum number of descriptors "
-                      "supported by select() is %d", FD_SETSIZE);
+        ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+                      "invalid select %s event fd:%d ev:%i",
+                      ev->write ? "write" : "read", c->fd, event);
         return NGX_ERROR;
     }
 
     if (event == NGX_READ_EVENT) {
         FD_SET(c->fd, &master_read_fd_set);
-        max_read++;
-
-    } else if (event == NGX_WRITE_EVENT) {
-        FD_SET(c->fd, &master_write_fd_set);
-        max_write++;
-    }
-
-#else
-
-    if (event == NGX_READ_EVENT) {
-        FD_SET(c->fd, &master_read_fd_set);
 
     } else if (event == NGX_WRITE_EVENT) {
         FD_SET(c->fd, &master_write_fd_set);
@@ -179,8 +156,6 @@ ngx_select_add_event(ngx_event_t *ev, ng
         max_fd = c->fd;
     }
 
-#endif
-
     ev->active = 1;
 
     event_index[nevents] = ev;
@@ -194,6 +169,7 @@ ngx_select_add_event(ngx_event_t *ev, ng
 static ngx_int_t
 ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
 {
+    ngx_event_t       *e;
     ngx_connection_t  *c;
 
     c = ev->data;
@@ -207,19 +183,6 @@ ngx_select_del_event(ngx_event_t *ev, ng
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                    "select del event fd:%d ev:%i", c->fd, event);
 
-#if (NGX_WIN32)
-
-    if (event == NGX_READ_EVENT) {
-        FD_CLR(c->fd, &master_read_fd_set);
-        max_read--;
-
-    } else if (event == NGX_WRITE_EVENT) {
-        FD_CLR(c->fd, &master_write_fd_set);
-        max_write--;
-    }
-
-#else
-
     if (event == NGX_READ_EVENT) {
         FD_CLR(c->fd, &master_read_fd_set);
 
@@ -231,11 +194,10 @@ ngx_select_del_event(ngx_event_t *ev, ng
         max_fd = -1;
     }
 
-#endif
-
     if (ev->index < --nevents) {
-        event_index[ev->index] = event_index[nevents];
-        event_index[ev->index]->index = ev->index;
+        e = event_index[nevents];
+        event_index[ev->index] = e;
+        e->index = ev->index;
     }
 
     ev->index = NGX_INVALID_INDEX;
@@ -248,14 +210,12 @@ static ngx_int_t
 ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
     ngx_uint_t flags)
 {
-    int                 ready, nready;
-    ngx_uint_t          i, found;
-    ngx_err_t           err;
-    ngx_event_t        *ev, **queue;
-    ngx_connection_t   *c;
-    struct timeval      tv, *tp;
-
-#if !(NGX_WIN32)
+    int                ready, nready;
+    ngx_err_t          err;
+    ngx_uint_t         i, found;
+    ngx_event_t       *ev, **queue;
+    struct timeval     tv, *tp;
+    ngx_connection_t  *c;
 
     if (max_fd == -1) {
         for (i = 0; i < nevents; i++) {
@@ -269,8 +229,6 @@ ngx_select_process_events(ngx_cycle_t *c
                        "change max_fd: %d", max_fd);
     }
 
-#endif
-
 #if (NGX_DEBUG)
     if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
         for (i = 0; i < nevents; i++) {
@@ -280,10 +238,8 @@ ngx_select_process_events(ngx_cycle_t *c
                            "select event: fd:%d wr:%d", c->fd, ev->write);
         }
 
-#if !(NGX_WIN32)
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "max_fd: %d", max_fd);
-#endif
     }
 #endif
 
@@ -302,31 +258,9 @@ ngx_select_process_events(ngx_cycle_t *c
     work_read_fd_set = master_read_fd_set;
     work_write_fd_set = master_write_fd_set;
 
-#if 1
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                   /*
-                    * (void *) disables "dereferencing type-punned
-                    * pointer will break strict-aliasing rules
-                    */
-                   "select read fd_set: %08Xd",
-                   *(int *) (void *) &work_read_fd_set);
-#endif
-
-#if (NGX_WIN32)
-
-    ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
-
-#else
-
     ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
 
-#endif
-
-    if (ready == -1) {
-        err = ngx_socket_errno;
-    } else {
-        err = 0;
-    }
+    err = (ready == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
@@ -335,15 +269,6 @@ ngx_select_process_events(ngx_cycle_t *c
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    "select ready %d", ready);
 
-#if (NGX_WIN32)
-
-    if (err) {
-        ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
-        return NGX_ERROR;
-    }
-
-#else
-
     if (err) {
         ngx_uint_t  level;
 
@@ -361,11 +286,14 @@ ngx_select_process_events(ngx_cycle_t *c
         }
 
         ngx_log_error(level, cycle->log, err, "select() failed");
+
+        if (err == EBADF) {
+            ngx_select_repair_fd_sets(cycle);
+        }
+
         return NGX_ERROR;
     }
 
-#endif
-
     if (ready == 0) {
         if (timer != NGX_TIMER_INFINITE) {
             return NGX_OK;
@@ -414,13 +342,64 @@ ngx_select_process_events(ngx_cycle_t *c
     ngx_mutex_unlock(ngx_posted_events_mutex);
 
     if (ready != nready) {
-        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events");
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                      "select ready != events: %d:%d", ready, nready);
+
+        ngx_select_repair_fd_sets(cycle);
     }
 
     return NGX_OK;
 }
 
 
+static void
+ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
+{
+    int           n;
+    socklen_t     len;
+    ngx_err_t     err;
+    ngx_socket_t  s;
+
+    for (s = 0; s <= max_fd; s++) {
+
+        if (FD_ISSET(s, &master_read_fd_set) == 0) {
+            continue;
+        }
+
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in read fd_set", s);
+
+            FD_CLR(s, &master_read_fd_set);
+        }
+    }
+
+    for (s = 0; s <= max_fd; s++) {
+
+        if (FD_ISSET(s, &master_write_fd_set) == 0) {
+            continue;
+        }
+
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in write fd_set", s);
+
+            FD_CLR(s, &master_write_fd_set);
+        }
+    }
+
+    max_fd = -1;
+}
+
+
 static char *
 ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
 {
@@ -434,8 +413,6 @@ ngx_select_init_conf(ngx_cycle_t *cycle,
 
     /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */
 
-#if !(NGX_WIN32)
-
     if (cycle->connection_n > FD_SETSIZE) {
         ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                       "the maximum number of files "
@@ -443,9 +420,7 @@ ngx_select_init_conf(ngx_cycle_t *cycle,
         return NGX_CONF_ERROR;
     }
 
-#endif
-
-#if (NGX_THREADS) && !(NGX_WIN32)
+#if (NGX_THREADS)
 
     ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                   "select() is not supported in the threaded mode");
new file mode 100644
--- /dev/null
+++ b/src/event/modules/ngx_win32_select_module.c
@@ -0,0 +1,399 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_select_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
+    ngx_uint_t flags);
+static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
+    ngx_uint_t flags);
+static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+    ngx_uint_t flags);
+static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
+static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+static fd_set         master_read_fd_set;
+static fd_set         master_write_fd_set;
+static fd_set         work_read_fd_set;
+static fd_set         work_write_fd_set;
+
+static ngx_uint_t     max_read;
+static ngx_uint_t     max_write;
+static ngx_uint_t     nevents;
+
+static ngx_event_t  **event_index;
+
+
+static ngx_str_t    select_name = ngx_string("select");
+
+ngx_event_module_t  ngx_select_module_ctx = {
+    &select_name,
+    NULL,                                  /* create configuration */
+    ngx_select_init_conf,                  /* init configuration */
+
+    {
+        ngx_select_add_event,              /* add an event */
+        ngx_select_del_event,              /* delete an event */
+        ngx_select_add_event,              /* enable an event */
+        ngx_select_del_event,              /* disable an event */
+        NULL,                              /* add an connection */
+        NULL,                              /* delete an connection */
+        NULL,                              /* process the changes */
+        ngx_select_process_events,         /* process the events */
+        ngx_select_init,                   /* init the events */
+        ngx_select_done                    /* done the events */
+    }
+
+};
+
+ngx_module_t  ngx_select_module = {
+    NGX_MODULE_V1,
+    &ngx_select_module_ctx,                /* module context */
+    NULL,                                  /* module directives */
+    NGX_EVENT_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_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+    ngx_event_t  **index;
+
+    if (event_index == NULL) {
+        FD_ZERO(&master_read_fd_set);
+        FD_ZERO(&master_write_fd_set);
+        nevents = 0;
+    }
+
+    if (ngx_process == NGX_PROCESS_WORKER
+        || cycle->old_cycle == NULL
+        || cycle->old_cycle->connection_n < cycle->connection_n)
+    {
+        index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
+                          cycle->log);
+        if (index == NULL) {
+            return NGX_ERROR;
+        }
+
+        if (event_index) {
+            ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
+            ngx_free(event_index);
+        }
+
+        event_index = index;
+    }
+
+    ngx_io = ngx_os_io;
+
+    ngx_event_actions = ngx_select_module_ctx.actions;
+
+    ngx_event_flags = NGX_USE_LEVEL_EVENT;
+
+    max_read = 0;
+    max_write = 0;
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_select_done(ngx_cycle_t *cycle)
+{
+    ngx_free(event_index);
+
+    event_index = NULL;
+}
+
+
+static ngx_int_t
+ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+    ngx_connection_t  *c;
+
+    c = ev->data;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                   "select add event fd:%d ev:%i", c->fd, event);
+
+    if (ev->index != NGX_INVALID_INDEX) {
+        ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+                      "select event fd:%d ev:%i is already set", c->fd, event);
+        return NGX_OK;
+    }
+
+    if ((event == NGX_READ_EVENT && ev->write)
+        || (event == NGX_WRITE_EVENT && !ev->write))
+    {
+        ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+                      "invalid select %s event fd:%d ev:%i",
+                      ev->write ? "write" : "read", c->fd, event);
+        return NGX_ERROR;
+    }
+
+    if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE)
+        || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE))
+    {
+        ngx_log_error(NGX_LOG_ERR, ev->log, 0,
+                      "maximum number of descriptors "
+                      "supported by select() is %d", FD_SETSIZE);
+        return NGX_ERROR;
+    }
+
+    if (event == NGX_READ_EVENT) {
+        FD_SET(c->fd, &master_read_fd_set);
+        max_read++;
+
+    } else if (event == NGX_WRITE_EVENT) {
+        FD_SET(c->fd, &master_write_fd_set);
+        max_write++;
+    }
+
+    ev->active = 1;
+
+    event_index[nevents] = ev;
+    ev->index = nevents;
+    nevents++;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+    ngx_event_t       *e;
+    ngx_connection_t  *c;
+
+    c = ev->data;
+
+    ev->active = 0;
+
+    if (ev->index == NGX_INVALID_INDEX) {
+        return NGX_OK;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                   "select del event fd:%d ev:%i", c->fd, event);
+
+    if (event == NGX_READ_EVENT) {
+        FD_CLR(c->fd, &master_read_fd_set);
+        max_read--;
+
+    } else if (event == NGX_WRITE_EVENT) {
+        FD_CLR(c->fd, &master_write_fd_set);
+        max_write--;
+    }
+
+    if (ev->index < --nevents) {
+        e = event_index[nevents];
+        event_index[ev->index] = e;
+        e->index = ev->index;
+    }
+
+    ev->index = NGX_INVALID_INDEX;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+    ngx_uint_t flags)
+{
+    int                ready, nready;
+    ngx_err_t          err;
+    ngx_uint_t         i, found;
+    ngx_event_t       *ev, **queue;
+    struct timeval     tv, *tp;
+    ngx_connection_t  *c;
+
+#if (NGX_DEBUG)
+    if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
+        for (i = 0; i < nevents; i++) {
+            ev = event_index[i];
+            c = ev->data;
+            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                           "select event: fd:%d wr:%d", c->fd, ev->write);
+        }
+    }
+#endif
+
+    if (timer == NGX_TIMER_INFINITE) {
+        tp = NULL;
+
+    } else {
+        tv.tv_sec = (long) (timer / 1000);
+        tv.tv_usec = (long) ((timer % 1000) * 1000);
+        tp = &tv;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                   "select timer: %M", timer);
+
+    work_read_fd_set = master_read_fd_set;
+    work_write_fd_set = master_write_fd_set;
+
+    if (max_read || max_write) {
+        ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
+
+    } else {
+
+        /*
+         * Winsock select() requires that at least one descriptor set must be
+         * be non-null, and any non-null descriptor set must contain at least
+         * one handle to a socket.  Otherwise select() returns WSAEINVAL.
+         */
+
+        ngx_msleep(timer);
+
+        ready = 0;
+    }
+
+    err = (ready == -1) ? ngx_socket_errno : 0;
+
+    if (flags & NGX_UPDATE_TIME) {
+        ngx_time_update(0, 0);
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                   "select ready %d", ready);
+
+    if (err) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
+
+        if (err == WSAENOTSOCK) {
+            ngx_select_repair_fd_sets(cycle);
+        }
+
+        return NGX_ERROR;
+    }
+
+    if (ready == 0) {
+        if (timer != NGX_TIMER_INFINITE) {
+            return NGX_OK;
+        }
+
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                      "select() returned no events without timeout");
+        return NGX_ERROR;
+    }
+
+    ngx_mutex_lock(ngx_posted_events_mutex);
+
+    nready = 0;
+
+    for (i = 0; i < nevents; i++) {
+        ev = event_index[i];
+        c = ev->data;
+        found = 0;
+
+        if (ev->write) {
+            if (FD_ISSET(c->fd, &work_write_fd_set)) {
+                found = 1;
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                               "select write %d", c->fd);
+            }
+
+        } else {
+            if (FD_ISSET(c->fd, &work_read_fd_set)) {
+                found = 1;
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                               "select read %d", c->fd);
+            }
+        }
+
+        if (found) {
+            ev->ready = 1;
+
+            queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
+                                                   &ngx_posted_events);
+            ngx_locked_post_event(ev, queue);
+
+            nready++;
+        }
+    }
+
+    ngx_mutex_unlock(ngx_posted_events_mutex);
+
+    if (ready != nready) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                      "select ready != events: %d:%d", ready, nready);
+
+        ngx_select_repair_fd_sets(cycle);
+    }
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
+{
+    int           n;
+    u_int         i;
+    socklen_t     len;
+    ngx_err_t     err;
+    ngx_socket_t  s;
+
+    for (i = 0; i < master_read_fd_set.fd_count; i++) {
+
+        s = master_read_fd_set.fd_array[i];
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in read fd_set", s);
+
+            FD_CLR(s, &master_read_fd_set);
+        }
+    }
+
+    for (i = 0; i < master_write_fd_set.fd_count; i++) {
+
+        s = master_write_fd_set.fd_array[i];
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in write fd_set", s);
+
+            FD_CLR(s, &master_write_fd_set);
+        }
+    }
+}
+
+
+static char *
+ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+    ngx_event_conf_t  *ecf;
+
+    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
+
+    if (ecf->use != ngx_select_module.ctx_index) {
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_OK;
+}
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -43,7 +43,7 @@ ngx_uint_t            ngx_event_flags;
 ngx_event_actions_t   ngx_event_actions;
 
 
-ngx_atomic_t          connection_counter = 1;
+static ngx_atomic_t   connection_counter = 1;
 ngx_atomic_t         *ngx_connection_counter = &connection_counter;
 
 
@@ -429,6 +429,7 @@ ngx_event_module_init(ngx_cycle_t *cycle
     u_char              *shared;
     size_t               size, cl;
     ngx_shm_t            shm;
+    ngx_time_t          *tp;
     ngx_core_conf_t     *ccf;
     ngx_event_conf_t    *ecf;
 
@@ -442,7 +443,7 @@ ngx_event_module_init(ngx_cycle_t *cycle
 
     ecf = (*cf)[ngx_event_core_module.ctx_index];
 
-    if (!ngx_test_config) {
+    if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) {
         ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
                       "using the \"%s\" event method", ecf->name);
     }
@@ -492,7 +493,8 @@ ngx_event_module_init(ngx_cycle_t *cycle
     cl = 128;
 
     size = cl            /* ngx_accept_mutex */
-           + cl;         /* ngx_connection_counter */
+           + cl          /* ngx_connection_counter */
+           + cl;         /* ngx_temp_number */
 
 #if (NGX_STAT_STUB)
 
@@ -506,6 +508,8 @@ ngx_event_module_init(ngx_cycle_t *cycle
 #endif
 
     shm.size = size;
+    shm.name.len = sizeof("nginx_shared_zone");
+    shm.name.data = (u_char *) "nginx_shared_zone";
     shm.log = cycle->log;
 
     if (ngx_shm_alloc(&shm) != NGX_OK) {
@@ -524,23 +528,29 @@ ngx_event_module_init(ngx_cycle_t *cycle
 
     ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl);
 
-#if (NGX_STAT_STUB)
-
-    ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * cl);
-    ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * cl);
-    ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * cl);
-    ngx_stat_active = (ngx_atomic_t *) (shared + 5 * cl);
-    ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * cl);
-    ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * cl);
-
-#endif
-
-    *ngx_connection_counter = 1;
+    (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    "counter: %p, %d",
                    ngx_connection_counter, *ngx_connection_counter);
 
+    ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl);
+
+    tp = ngx_timeofday();
+
+    ngx_random_number = (tp->msec << 16) + ngx_pid;
+
+#if (NGX_STAT_STUB)
+
+    ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl);
+    ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl);
+    ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl);
+    ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl);
+    ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl);
+    ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl);
+
+#endif
+
     return NGX_OK;
 }
 
@@ -774,6 +784,10 @@ ngx_event_process_init(ngx_cycle_t *cycl
 
             rev->handler = ngx_event_acceptex;
 
+            if (ngx_use_accept_mutex) {
+                continue;
+            }
+
             if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) {
                 return NGX_ERROR;
             }
@@ -790,6 +804,10 @@ ngx_event_process_init(ngx_cycle_t *cycl
         } else {
             rev->handler = ngx_event_accept;
 
+            if (ngx_use_accept_mutex) {
+                continue;
+            }
+
             if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
                 return NGX_ERROR;
             }
@@ -1103,7 +1121,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle
 
     ecf = ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t));
     if (ecf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     ecf->connections = NGX_CONF_UNSET_UINT;
@@ -1118,7 +1136,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle
     if (ngx_array_init(&ecf->debug_connection, cycle->pool, 4,
                        sizeof(ngx_event_debug_t)) == NGX_ERROR)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
 #endif
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -189,6 +189,37 @@ struct ngx_event_s {
 };
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+struct ngx_event_aio_s {
+    void                      *data;
+    ngx_event_handler_pt       handler;
+    ngx_file_t                *file;
+
+    ngx_fd_t                   fd;
+
+#if (NGX_HAVE_EVENTFD)
+    int64_t                    res;
+#if (NGX_TEST_BUILD_EPOLL)
+    ngx_err_t                  err;
+    size_t                     nbytes;
+#endif
+#else
+    ngx_err_t                  err;
+    size_t                     nbytes;
+#endif
+
+#if (NGX_HAVE_AIO_SENDFILE)
+    off_t                      last_offset;
+#endif
+
+    ngx_aiocb_t                aiocb;
+    ngx_event_t                event;
+};
+
+#endif
+
+
 typedef struct {
     in_addr_t  mask;
     in_addr_t  addr;
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -57,8 +57,8 @@ ngx_event_accept(ngx_event_t *ev)
                 return;
             }
 
-            ngx_log_error((err == NGX_ECONNABORTED) ? NGX_LOG_ERR:
-                                                      NGX_LOG_ALERT,
+            ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ?
+                                             NGX_LOG_ERR : NGX_LOG_ALERT),
                           ev->log, err, "accept() failed");
 
             if (err == NGX_ECONNABORTED) {
@@ -75,7 +75,7 @@ ngx_event_accept(ngx_event_t *ev)
         }
 
 #if (NGX_STAT_STUB)
-        ngx_atomic_fetch_add(ngx_stat_accepted, 1);
+        (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
 #endif
 
         ngx_accept_disabled = ngx_cycle->connection_n / 8
@@ -93,7 +93,7 @@ ngx_event_accept(ngx_event_t *ev)
         }
 
 #if (NGX_STAT_STUB)
-        ngx_atomic_fetch_add(ngx_stat_active, 1);
+        (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
 #endif
 
         c->pool = ngx_create_pool(ls->pool_size, ev->log);
@@ -188,7 +188,7 @@ ngx_event_accept(ngx_event_t *ev)
         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
 
 #if (NGX_STAT_STUB)
-        ngx_atomic_fetch_add(ngx_stat_handled, 1);
+        (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
 #endif
 
 #if (NGX_THREADS)
@@ -379,7 +379,7 @@ ngx_close_accepted_connection(ngx_connec
     }
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_active, -1);
+    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
 #endif
 }
 
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -97,16 +97,12 @@ int  ngx_ssl_session_cache_index;
 ngx_int_t
 ngx_ssl_init(ngx_log_t *log)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x00907000
     OPENSSL_config(NULL);
-#endif
 
     SSL_library_init();
     SSL_load_error_strings();
 
-#if (NGX_SSL_ENGINE)
     ENGINE_load_builtin_engines();
-#endif
 
     ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
 
@@ -169,9 +165,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
 
-#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
     SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
-#endif
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
 
@@ -267,6 +261,51 @@ ngx_ssl_client_certificate(ngx_conf_t *c
 }
 
 
+ngx_int_t
+ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
+{
+    X509_STORE   *store;
+    X509_LOOKUP  *lookup;
+
+    if (crl->len == 0) {
+        return NGX_OK;
+    }
+
+    if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    store = SSL_CTX_get_cert_store(ssl->ctx);
+
+    if (store == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "SSL_CTX_get_cert_store() failed");
+        return NGX_ERROR;
+    }
+
+    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+
+    if (lookup == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "X509_STORE_add_lookup() failed");
+        return NGX_ERROR;
+    }
+
+    if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM)
+        == 0)
+    {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "X509_LOOKUP_load_file(\"%s\") failed", crl->data);
+        return NGX_ERROR;
+    }
+
+    X509_STORE_set_flags(store,
+                         X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+
+    return NGX_OK;
+}
+
+
 static int
 ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
 {
@@ -1201,9 +1240,7 @@ ngx_ssl_connection_error(ngx_connection_
         if (err == NGX_ECONNRESET
             || err == NGX_EPIPE
             || err == NGX_ENOTCONN
-#if !(NGX_CRIT_ETIMEDOUT)
             || err == NGX_ETIMEDOUT
-#endif
             || err == NGX_ECONNREFUSED
             || err == NGX_ENETDOWN
             || err == NGX_ENETUNREACH
@@ -1306,7 +1343,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_
     last = errstr + NGX_MAX_CONF_ERRSTR;
 
     va_start(args, fmt);
-    p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);
+    p = ngx_vslprintf(errstr, last - 1, fmt, args);
     va_end(args);
 
     p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
@@ -1387,7 +1424,7 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
         }
     }
 
-    SSL_CTX_set_timeout(ssl->ctx, timeout);
+    SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
 
     if (shm_zone) {
         shm_zone->init = ngx_ssl_session_cache_init;
@@ -1421,6 +1458,11 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
         return NGX_OK;
     }
 
+    if (shm_zone->shm.exists) {
+        shm_zone->data = data;
+        return NGX_OK;
+    }
+
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
     cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
@@ -1428,12 +1470,15 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
         return NGX_ERROR;
     }
 
+    shpool->data = cache;
+    shm_zone->data = cache;
+
     ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,
                     ngx_ssl_session_rbtree_insert_value);
 
     ngx_queue_init(&cache->expire_queue);
 
-    len = sizeof(" in SSL session shared cache \"\"") + shm_zone->name.len;
+    len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len;
 
     shpool->log_ctx = ngx_slab_alloc(shpool, len);
     if (shpool->log_ctx == NULL) {
@@ -1441,9 +1486,7 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
     }
 
     ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
-                &shm_zone->name);
-
-    shm_zone->data = cache;
+                &shm_zone->shm.name);
 
     return NGX_OK;
 }
@@ -1968,7 +2011,7 @@ ngx_ssl_get_certificate(ngx_connection_t
 
     p = s->data;
 
-    for (i = 0; i < len; i++) {
+    for (i = 0; i < cert.len - 1; i++) {
         *p++ = cert.data[i];
         if (cert.data[i] == LF) {
             *p++ = '\t';
@@ -2102,6 +2145,35 @@ ngx_ssl_get_serial_number(ngx_connection
 }
 
 
+ngx_int_t
+ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    X509  *cert;
+
+    if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
+        s->len = sizeof("FAILED") - 1;
+        s->data = (u_char *) "FAILED";
+
+        return NGX_OK;
+    }
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+
+    if (cert) {
+        s->len = sizeof("SUCCESS") - 1;
+        s->data = (u_char *) "SUCCESS";
+
+    } else {
+        s->len = sizeof("NONE") - 1;
+        s->data = (u_char *) "NONE";
+    }
+
+    X509_free(cert);
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_openssl_create_conf(ngx_cycle_t *cycle)
 {
@@ -2109,7 +2181,7 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc
 
     oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
     if (oscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -2125,7 +2197,6 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc
 static char *
 ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-#if (NGX_SSL_ENGINE)
     ngx_openssl_conf_t *oscf = conf;
 
     ENGINE     *engine;
@@ -2160,23 +2231,11 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c
     ENGINE_free(engine);
 
     return NGX_CONF_OK;
-
-#else
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"ssl_engine\" directive is available only in "
-                       "OpenSSL 0.9.7 and higher,");
-
-    return NGX_CONF_ERROR;
-
-#endif
 }
 
 
 static void
 ngx_openssl_exit(ngx_cycle_t *cycle)
 {
-#if (NGX_SSL_ENGINE)
     ENGINE_cleanup();
-#endif
 }
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -13,12 +13,8 @@
 
 #include <openssl/ssl.h>
 #include <openssl/err.h>
-
-#if OPENSSL_VERSION_NUMBER >= 0x00907000
 #include <openssl/conf.h>
 #include <openssl/engine.h>
-#define NGX_SSL_ENGINE   1
-#endif
 
 #define NGX_SSL_NAME     "OpenSSL"
 
@@ -100,6 +96,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t
     ngx_str_t *cert, ngx_str_t *key);
 ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
     ngx_str_t *cert, ngx_int_t depth);
+ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);
 ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl);
 ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
 ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
@@ -131,6 +128,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_conn
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 
 
 ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -24,15 +24,22 @@ ngx_int_t
 ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
 {
     u_int         flags;
+    ngx_int_t     rc;
     ngx_event_t  *rev, *wev;
 
     for ( ;; ) {
         if (do_write) {
             p->log->action = "sending to client";
 
-            if (ngx_event_pipe_write_to_downstream(p) == NGX_ABORT) {
+            rc = ngx_event_pipe_write_to_downstream(p);
+
+            if (rc == NGX_ABORT) {
                 return NGX_ABORT;
             }
+
+            if (rc == NGX_BUSY) {
+                return NGX_OK;
+            }
         }
 
         p->read = 0;
@@ -397,7 +404,7 @@ ngx_event_pipe_read_upstream(ngx_event_p
 
         p->free_raw_bufs = p->free_raw_bufs->next;
 
-        if (p->free_bufs) {
+        if (p->free_bufs && p->buf_to_file == NULL) {
             for (cl = p->free_raw_bufs; cl; cl = cl->next) {
                 if (cl->buf->shadow == NULL) {
                     ngx_pfree(p->pool, cl->buf->start);
@@ -422,7 +429,7 @@ ngx_event_pipe_write_to_downstream(ngx_e
     u_char            *prev;
     size_t             bsize;
     ngx_int_t          rc;
-    ngx_uint_t         flush, prev_last_shadow;
+    ngx_uint_t         flush, flushed, prev_last_shadow;
     ngx_chain_t       *out, **ll, *cl, file;
     ngx_connection_t  *downstream;
 
@@ -431,6 +438,8 @@ ngx_event_pipe_write_to_downstream(ngx_e
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
                    "pipe write downstream: %d", downstream->write->ready);
 
+    flushed = 0;
+
     for ( ;; ) {
         if (p->downstream_error) {
             return ngx_event_pipe_drain_chains(p);
@@ -454,10 +463,6 @@ ngx_event_pipe_write_to_downstream(ngx_e
 
                 rc = p->output_filter(p->output_ctx, p->out);
 
-                if (downstream->destroyed) {
-                    return NGX_ABORT;
-                }
-
                 if (rc == NGX_ERROR) {
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
@@ -476,10 +481,6 @@ ngx_event_pipe_write_to_downstream(ngx_e
 
                 rc = p->output_filter(p->output_ctx, p->in);
 
-                if (downstream->destroyed) {
-                    return NGX_ABORT;
-                }
-
                 if (rc == NGX_ERROR) {
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
@@ -618,16 +619,20 @@ ngx_event_pipe_write_to_downstream(ngx_e
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
                        "pipe write: out:%p, f:%d", out, flush);
 
-        if (out == NULL && !flush) {
-            break;
+        if (out == NULL) {
+
+            if (!flush) {
+                break;
+            }
+
+            /* a workaround for AIO */
+            if (flushed++ > 10) {
+                return NGX_BUSY;
+            }
         }
 
         rc = p->output_filter(p->output_ctx, out);
 
-        if (downstream->destroyed) {
-            return NGX_ABORT;
-        }
-
         if (rc == NGX_ERROR) {
             p->downstream_error = 1;
             return ngx_event_pipe_drain_chains(p);
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -201,7 +201,7 @@ ngx_http_access_create_loc_conf(ngx_conf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return conf;
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -45,7 +45,7 @@ static ngx_command_t  ngx_http_addition_
       offsetof(ngx_http_addition_conf_t, after_body),
       NULL },
 
-    { ngx_string("addtion_types"),
+    { ngx_string("addition_types"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_types_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
@@ -212,7 +212,7 @@ ngx_http_addition_create_conf(ngx_conf_t
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -372,7 +372,7 @@ ngx_http_auth_basic_create_loc_conf(ngx_
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return conf;
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -25,8 +25,11 @@ typedef struct {
 typedef struct {
     ngx_str_t      name;
     size_t         utf_len;
-    ngx_uint_t     escape;
-    ngx_uint_t     dir;
+    size_t         escape;
+
+    unsigned       dir:1;
+    unsigned       colon:1;
+
     time_t         mtime;
     off_t          size;
 } ngx_http_autoindex_entry_t;
@@ -142,7 +145,7 @@ ngx_http_autoindex_handler(ngx_http_requ
     ngx_int_t                       rc, size;
     ngx_str_t                       path;
     ngx_dir_t                       dir;
-    ngx_uint_t                      i, level;
+    ngx_uint_t                      i, level, utf8;
     ngx_pool_t                     *pool;
     ngx_time_t                     *tp;
     ngx_chain_t                     out;
@@ -157,7 +160,6 @@ ngx_http_autoindex_handler(ngx_http_requ
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
@@ -250,6 +252,16 @@ ngx_http_autoindex_handler(ngx_http_requ
     filename = path.data;
     filename[path.len] = '/';
 
+    if (r->headers_out.charset.len == 5
+        && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
+           == 0)
+    {
+        utf8 = 1;
+
+    } else {
+        utf8 = 0;
+    }
+
     for ( ;; ) {
         ngx_set_errno(0);
 
@@ -333,12 +345,14 @@ ngx_http_autoindex_handler(ngx_http_requ
         entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
                                            NGX_ESCAPE_HTML);
 
-        if (r->utf8) {
+        if (utf8) {
             entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
         } else {
             entry->utf_len = len;
         }
 
+        entry->colon = (ngx_strchr(entry->name.data, ':') != NULL);
+
         entry->dir = ngx_de_is_dir(&dir);
         entry->mtime = ngx_de_mtime(&dir);
         entry->size = ngx_de_size(&dir);
@@ -364,7 +378,7 @@ ngx_http_autoindex_handler(ngx_http_requ
             + entry[i].name.len + entry[i].escape
             + 1                                          /* 1 is for "/" */
             + sizeof("\">") - 1
-            + entry[i].name.len - entry[i].utf_len
+            + entry[i].name.len - entry[i].utf_len + entry[i].colon * 2
             + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 2
             + sizeof("</a>") - 1
             + sizeof(" 28-Sep-1970 12:00 ") - 1
@@ -397,6 +411,11 @@ ngx_http_autoindex_handler(ngx_http_requ
     for (i = 0; i < entries.nelts; i++) {
         b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);
 
+        if (entry[i].colon) {
+            *b->last++ = '.';
+            *b->last++ = '/';
+        }
+
         if (entry[i].escape) {
             ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len,
                            NGX_ESCAPE_HTML);
@@ -613,7 +632,7 @@ ngx_http_autoindex_create_loc_conf(ngx_c
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_browser_module.c
+++ b/src/http/modules/ngx_http_browser_module.c
@@ -423,7 +423,7 @@ ngx_http_browser_create_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_browser_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -9,8 +9,9 @@
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_NO_CHARSET    -2
-#define NGX_HTTP_CHARSET_VAR   0x10000
+#define NGX_HTTP_CHARSET_OFF    -2
+#define NGX_HTTP_NO_CHARSET     -3
+#define NGX_HTTP_CHARSET_VAR    0x10000
 
 /* 1 byte length and up to 3 bytes for the UTF-8 encoding of the UCS-2 */
 #define NGX_UTF_LEN             4
@@ -61,6 +62,7 @@ typedef struct {
 typedef struct {
     u_char                     *table;
     ngx_int_t                   charset;
+    ngx_str_t                   charset_name;
 
     ngx_chain_t                *busy;
     ngx_chain_t                *free_bufs;
@@ -82,9 +84,16 @@ typedef struct {
 } ngx_http_charset_conf_ctx_t;
 
 
-static ngx_int_t ngx_http_charset_get_charset(ngx_http_charset_t *charsets,
-    ngx_uint_t n, ngx_str_t *charset);
-static ngx_int_t ngx_http_charset_set_charset(ngx_http_request_t *r,
+static ngx_int_t ngx_http_destination_charset(ngx_http_request_t *r,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_main_request_charset(ngx_http_request_t *r,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_source_charset(ngx_http_request_t *r,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name);
+static ngx_inline void ngx_http_set_charset(ngx_http_request_t *r,
+    ngx_str_t *charset);
+static ngx_int_t ngx_http_charset_ctx(ngx_http_request_t *r,
     ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset);
 static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table);
 static ngx_chain_t *ngx_http_charset_recode_from_utf8(ngx_pool_t *pool,
@@ -207,206 +216,264 @@ static ngx_int_t
 ngx_http_charset_header_filter(ngx_http_request_t *r)
 {
     ngx_int_t                      charset, source_charset;
-    ngx_str_t                     *mc, *from, *to, s;
-    ngx_uint_t                     n;
+    ngx_str_t                      dst, src;
     ngx_http_charset_t            *charsets;
-    ngx_http_charset_ctx_t        *ctx;
-    ngx_http_variable_value_t     *vv;
-    ngx_http_charset_loc_conf_t   *lcf, *mlcf;
     ngx_http_charset_main_conf_t  *mcf;
 
-    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
-
-    charsets = mcf->charsets.elts;
-    n = mcf->charsets.nelts;
-
-    /* destination charset */
-
     if (r == r->main) {
-
-        if (r->headers_out.content_encoding
-            && r->headers_out.content_encoding->value.len)
-        {
-            return ngx_http_next_header_filter(r);
-        }
-
-        if (r->headers_out.content_type.len == 0) {
-            return ngx_http_next_header_filter(r);
-        }
-
-        if (r->headers_out.override_charset
-            && r->headers_out.override_charset->len)
-        {
-            charset = ngx_http_charset_get_charset(charsets, n,
-                                              r->headers_out.override_charset);
-
-            if (charset == NGX_HTTP_NO_CHARSET) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "unknown charset \"%V\" to override",
-                              r->headers_out.override_charset);
-
-                return ngx_http_next_header_filter(r);
-            }
-
-        } else {
-            mlcf = ngx_http_get_module_loc_conf(r,
-                                                ngx_http_charset_filter_module);
-            charset = mlcf->charset;
-
-            if (charset == NGX_HTTP_NO_CHARSET) {
-                return ngx_http_next_header_filter(r);
-            }
-
-            if (r->headers_out.charset.len) {
-                if (mlcf->override_charset == 0) {
-                    return ngx_http_next_header_filter(r);
-                }
-
-            } else {
-                if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
-                    return ngx_http_next_header_filter(r);
-                }
-            }
-
-            if (charset >= NGX_HTTP_CHARSET_VAR) {
-                vv = ngx_http_get_indexed_variable(r,
-                                               charset - NGX_HTTP_CHARSET_VAR);
-
-                if (vv == NULL || vv->not_found) {
-                    return NGX_ERROR;
-                }
-
-                s.len = vv->len;
-                s.data = vv->data;
-
-                charset = ngx_http_charset_get_charset(charsets, n, &s);
-            }
-        }
+        charset = ngx_http_destination_charset(r, &dst);
 
     } else {
-        ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);
-
-        if (ctx == NULL) {
-
-            mc = &r->main->headers_out.charset;
-
-            if (mc->len == 0) {
-                return ngx_http_next_header_filter(r);
-            }
+        charset = ngx_http_main_request_charset(r, &dst);
+    }
 
-            ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
-            if (ctx == NULL) {
-                return NGX_ERROR;
-            }
-
-            ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module);
+    if (charset == NGX_ERROR) {
+        return NGX_ERROR;
+    }
 
-            charset = ngx_http_charset_get_charset(charsets, n, mc);
-
-            ctx->charset = charset;
-
-        } else {
-            charset = ctx->charset;
-        }
+    if (charset == NGX_DECLINED) {
+        return ngx_http_next_header_filter(r);
     }
 
-    /* source charset */
-
-    if (r->headers_out.charset.len == 0) {
-        lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
-
-        source_charset = lcf->source_charset;
-
-        if (source_charset >= NGX_HTTP_CHARSET_VAR) {
-            vv = ngx_http_get_indexed_variable(r,
-                                        source_charset - NGX_HTTP_CHARSET_VAR);
-
-            if (vv == NULL || vv->not_found) {
-                return NGX_ERROR;
-            }
+    /* charset: charset index or NGX_HTTP_NO_CHARSET */
 
-            s.len = vv->len;
-            s.data = vv->data;
-
-            source_charset = ngx_http_charset_get_charset(charsets, n, &s);
-        }
+    source_charset = ngx_http_source_charset(r, &src);
 
-        if (charset != NGX_HTTP_NO_CHARSET) {
-            return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
-                                                source_charset);
-        }
-
-        if (source_charset == NGX_CONF_UNSET) {
-            return ngx_http_next_header_filter(r);
-        }
-
-        from = &charsets[source_charset].name;
-        to = &r->main->headers_out.charset;
-
-        goto no_charset_map;
+    if (source_charset == NGX_ERROR) {
+        return NGX_ERROR;
     }
 
-    source_charset = ngx_http_charset_get_charset(charsets, n,
-                                                  &r->headers_out.charset);
+    /*
+     * source_charset: charset index, NGX_HTTP_NO_CHARSET,
+     *                 or NGX_HTTP_CHARSET_OFF
+     */
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "charset: \"%V\" > \"%V\"", &src, &dst);
+
+    if (source_charset == NGX_HTTP_CHARSET_OFF) {
+        ngx_http_set_charset(r, &dst);
+
+        return ngx_http_next_header_filter(r);
+    }
 
     if (charset == NGX_HTTP_NO_CHARSET
         || source_charset == NGX_HTTP_NO_CHARSET)
     {
-        if (charset != source_charset
-            || ngx_strcasecmp(r->main->headers_out.charset.data,
-                              r->headers_out.charset.data)
-                != 0)
+        if (source_charset != charset
+            || ngx_strncasecmp(dst.data, src.data, dst.len) != 0)
         {
-            from = &r->headers_out.charset;
-            to = (charset == NGX_HTTP_NO_CHARSET) ?
-                                           &r->main->headers_out.charset:
-                                           &charsets[charset].name;
-
             goto no_charset_map;
         }
 
+        ngx_http_set_charset(r, &dst);
+
         return ngx_http_next_header_filter(r);
     }
 
+    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+    charsets = mcf->charsets.elts;
+
     if (source_charset != charset
         && (charsets[source_charset].tables == NULL
             || charsets[source_charset].tables[charset] == NULL))
     {
-        from = &charsets[source_charset].name;
-        to = &charsets[charset].name;
-
         goto no_charset_map;
     }
 
     r->headers_out.content_type.len = r->headers_out.content_type_len;
 
-    return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
-                                        source_charset);
+    ngx_http_set_charset(r, &dst);
+
+    if (source_charset != charset) {
+        return ngx_http_charset_ctx(r, charsets, charset, source_charset);
+    }
+
+    return ngx_http_next_header_filter(r);
 
 no_charset_map:
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
-                  from, to);
+                  &src, &dst);
 
     return ngx_http_next_header_filter(r);
 }
 
 
 static ngx_int_t
-ngx_http_charset_get_charset(ngx_http_charset_t *charsets, ngx_uint_t n,
-    ngx_str_t *charset)
+ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_int_t                      charset;
+    ngx_http_charset_t            *charsets;
+    ngx_http_variable_value_t     *vv;
+    ngx_http_charset_loc_conf_t   *mlcf;
+    ngx_http_charset_main_conf_t  *mcf;
+
+    if (!r->ignore_content_encoding
+        && r->headers_out.content_encoding
+        && r->headers_out.content_encoding->value.len)
+    {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_out.content_type.len == 0) {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_out.override_charset
+        && r->headers_out.override_charset->len)
+    {
+        *name = *r->headers_out.override_charset;
+
+        charset = ngx_http_get_charset(r, name);
+
+        if (charset != NGX_HTTP_NO_CHARSET) {
+            return charset;
+        }
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "unknown charset \"%V\" to override", name);
+
+        return NGX_DECLINED;
+    }
+
+    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+    charset = mlcf->charset;
+
+    if (charset == NGX_HTTP_CHARSET_OFF) {
+        return NGX_DECLINED;
+    }
+
+    if (r->headers_out.charset.len) {
+        if (mlcf->override_charset == 0) {
+            return NGX_DECLINED;
+        }
+
+    } else {
+        if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
+            return NGX_DECLINED;
+        }
+    }
+
+    if (charset < NGX_HTTP_CHARSET_VAR) {
+        mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+        charsets = mcf->charsets.elts;
+        *name = charsets[charset].name;
+        return charset;
+    }
+
+    vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR);
+
+    if (vv == NULL || vv->not_found) {
+        return NGX_ERROR;
+    }
+
+    name->len = vv->len;
+    name->data = vv->data;
+
+    return ngx_http_get_charset(r, name);
+}
+
+
+static ngx_int_t
+ngx_http_main_request_charset(ngx_http_request_t *r, ngx_str_t *src)
 {
-    ngx_uint_t  i;
+    ngx_int_t                charset;
+    ngx_str_t               *main_charset;
+    ngx_http_charset_ctx_t  *ctx;
+
+    ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);
+
+    if (ctx) {
+        *src = ctx->charset_name;
+        return ctx->charset;
+    }
+
+    main_charset = &r->main->headers_out.charset;
+
+    if (main_charset->len == 0) {
+        return NGX_DECLINED;
+    }
+
+    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
+    if (ctx == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module);
+
+    charset = ngx_http_get_charset(r, main_charset);
+
+    ctx->charset = charset;
+    ctx->charset_name = *main_charset;
+    *src = *main_charset;
+
+    return charset;
+}
+
+
+static ngx_int_t
+ngx_http_source_charset(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_int_t                      charset;
+    ngx_http_charset_t            *charsets;
+    ngx_http_variable_value_t     *vv;
+    ngx_http_charset_loc_conf_t   *lcf;
+    ngx_http_charset_main_conf_t  *mcf;
+
+    if (r->headers_out.charset.len) {
+        *name = r->headers_out.charset;
+        return ngx_http_get_charset(r, name);
+    }
+
+    lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+
+    charset = lcf->source_charset;
+
+    if (charset == NGX_HTTP_CHARSET_OFF) {
+        name->len = 0;
+        return charset;
+    }
+
+    if (charset < NGX_HTTP_CHARSET_VAR) {
+        mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+        charsets = mcf->charsets.elts;
+        *name = charsets[charset].name;
+        return charset;
+    }
+
+    vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR);
+
+    if (vv == NULL || vv->not_found) {
+        return NGX_ERROR;
+    }
+
+    name->len = vv->len;
+    name->data = vv->data;
+
+    return ngx_http_get_charset(r, name);
+}
+
+
+static ngx_int_t
+ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_uint_t                     i, n;
+    ngx_http_charset_t            *charset;
+    ngx_http_charset_main_conf_t  *mcf;
+
+    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
+
+    charset = mcf->charsets.elts;
+    n = mcf->charsets.nelts;
 
     for (i = 0; i < n; i++) {
-        if (charsets[i].name.len != charset->len) {
+        if (charset[i].name.len != name->len) {
             continue;
         }
 
-        if (ngx_strncasecmp(charsets[i].name.data, charset->data, charset->len)
-            == 0)
-        {
+        if (ngx_strncasecmp(charset[i].name.data, name->data, name->len) == 0) {
             return i;
         }
     }
@@ -415,11 +482,12 @@ ngx_http_charset_get_charset(ngx_http_ch
 }
 
 
-static ngx_int_t
-ngx_http_charset_set_charset(ngx_http_request_t *r,
-    ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset)
+static ngx_inline void
+ngx_http_set_charset(ngx_http_request_t *r, ngx_str_t *charset)
 {
-    ngx_http_charset_ctx_t  *ctx;
+    if (r != r->main) {
+        return;
+    }
 
     if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY
         || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY)
@@ -430,16 +498,18 @@ ngx_http_charset_set_charset(ngx_http_re
          */
 
         r->headers_out.charset.len = 0;
-
-        return ngx_http_next_header_filter(r);
+        return;
     }
 
-    r->headers_out.charset = charsets[charset].name;
-    r->utf8 = charsets[charset].utf8;
+    r->headers_out.charset = *charset;
+}
+
 
-    if (source_charset == NGX_CONF_UNSET || source_charset == charset) {
-        return ngx_http_next_header_filter(r);
-    }
+static ngx_int_t
+ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets,
+    ngx_int_t charset, ngx_int_t source_charset)
+{
+    ngx_http_charset_ctx_t  *ctx;
 
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
     if (ctx == NULL) {
@@ -450,6 +520,7 @@ ngx_http_charset_set_charset(ngx_http_re
 
     ctx->table = charsets[source_charset].tables[charset];
     ctx->charset = charset;
+    ctx->charset_name = charsets[charset].name;
     ctx->length = charsets[charset].length;
     ctx->from_utf8 = charsets[source_charset].utf8;
     ctx->to_utf8 = charsets[charset].utf8;
@@ -1337,7 +1408,7 @@ ngx_http_set_charset_slot(ngx_conf_t *cf
     if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, charset)
         && ngx_strcmp(value[1].data, "off") == 0)
     {
-        *cp = NGX_HTTP_NO_CHARSET;
+        *cp = NGX_HTTP_CHARSET_OFF;
         return NGX_CONF_OK;
     }
 
@@ -1417,27 +1488,27 @@ ngx_http_charset_create_main_conf(ngx_co
 
     mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t));
     if (mcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&mcf->tables, cf->pool, 1,
                        sizeof(ngx_http_charset_tables_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&mcf->recodes, cf->pool, 2,
                        sizeof(ngx_http_charset_recode_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return mcf;
@@ -1451,7 +1522,7 @@ ngx_http_charset_create_loc_conf(ngx_con
 
     lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t));
     if (lcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -1488,14 +1559,12 @@ ngx_http_charset_merge_loc_conf(ngx_conf
     }
 
     ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0);
-    ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET);
+    ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_CHARSET_OFF);
+    ngx_conf_merge_value(conf->source_charset, prev->source_charset,
+                         NGX_HTTP_CHARSET_OFF);
 
-    if (conf->source_charset == NGX_CONF_UNSET) {
-        conf->source_charset = prev->source_charset;
-    }
-
-    if (conf->charset == NGX_HTTP_NO_CHARSET
-        || conf->source_charset == NGX_CONF_UNSET
+    if (conf->charset == NGX_HTTP_CHARSET_OFF
+        || conf->source_charset == NGX_HTTP_CHARSET_OFF
         || conf->charset == conf->source_charset)
     {
         return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -53,8 +53,6 @@ static ngx_int_t ngx_http_dav_copy_dir_t
     ngx_str_t *path);
 static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
     ngx_str_t *path);
-static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from,
-    u_char *to);
 
 static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt);
 static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
@@ -148,7 +146,6 @@ ngx_http_dav_handler(ngx_http_request_t 
     ngx_int_t                 rc;
     ngx_http_dav_loc_conf_t  *dlcf;
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
@@ -217,12 +214,14 @@ ngx_http_dav_put_handler(ngx_http_reques
 
     ngx_http_map_uri_to_path(r, &path, &root, 0);
 
+    path.len--;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http put filename: \"%s\"", path.data);
 
     temp = &r->request_body->temp_file->file.name;
 
-    if (ngx_file_info(path.data, &fi) == -1) {
+    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
         status = NGX_HTTP_CREATED;
 
     } else {
@@ -250,7 +249,6 @@ ngx_http_dav_put_handler(ngx_http_reques
     ext.time = -1;
     ext.create_path = dlcf->create_full_put_path;
     ext.delete_file = 1;
-    ext.log_rename_error = 1;
     ext.log = r->connection->log;
 
     if (r->headers_in.date) {
@@ -327,7 +325,7 @@ ok:
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http delete filename: \"%s\"", path.data);
 
-    if (ngx_file_info(path.data, &fi) == -1) {
+    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
         err = ngx_errno;
 
         rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND;
@@ -521,6 +519,7 @@ ngx_http_dav_copy_move_handler(ngx_http_
     ngx_uint_t                overwrite, slash, dir;
     ngx_str_t                 path, uri;
     ngx_tree_ctx_t            tree;
+    ngx_copy_file_t           cf;
     ngx_file_info_t           fi;
     ngx_table_elt_t          *dest, *over;
     ngx_ext_rename_file_t     ext;
@@ -679,7 +678,7 @@ overwrite_done:
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http copy to: \"%s\"", copy.path.data);
 
-    if (ngx_file_info(copy.path.data, &fi) == -1) {
+    if (ngx_file_info(copy.path.data, &fi) == NGX_FILE_ERROR) {
         err = ngx_errno;
 
         if (err != NGX_ENOENT) {
@@ -713,7 +712,7 @@ overwrite_done:
         dir = ngx_is_dir(&fi);
     }
 
-    if (ngx_file_info(path.data, &fi) == -1) {
+    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
         return ngx_http_dav_error(r->connection->log, ngx_errno,
                                   NGX_HTTP_NOT_FOUND, ngx_file_info_n,
                                   path.data);
@@ -792,43 +791,24 @@ overwrite_done:
             ext.time = -1;
             ext.create_path = 1;
             ext.delete_file = 0;
-            ext.log_rename_error = 0;
             ext.log = r->connection->log;
 
             if (ngx_ext_rename_file(&path, &copy.path, &ext) == NGX_OK) {
                 return NGX_HTTP_NO_CONTENT;
             }
 
-            if (ext.rename_error != NGX_EXDEV) {
-
-                if (ext.rename_error) {
-                    ngx_log_error(NGX_LOG_CRIT, r->connection->log,
-                                  ext.rename_error,
-                                  ngx_rename_file_n " \"%s\" to \"%s\" failed",
-                                  path.data, copy.path.data);
-                }
-
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
         dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
 
-        tree.size = ngx_file_size(&fi);
-        tree.mtime = ngx_file_mtime(&fi);
-        tree.access = dlcf->access;
-        tree.log = r->connection->log;
+        cf.size = ngx_file_size(&fi);
+        cf.buf_size = 0;
+        cf.access = dlcf->access;
+        cf.time = ngx_file_mtime(&fi);
+        cf.log = r->connection->log;
 
-        if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK)
-        {
-            if (r->method == NGX_HTTP_MOVE) {
-                rc = ngx_http_dav_delete_path(r, &path, 0);
-
-                if (rc != NGX_OK) {
-                    return rc;
-                }
-            }
-
+        if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) {
             return NGX_HTTP_NO_CONTENT;
         }
     }
@@ -942,6 +922,7 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
 {
     u_char                   *p, *file;
     size_t                    len;
+    ngx_copy_file_t           cf;
     ngx_http_dav_copy_ctx_t  *copy;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
@@ -962,7 +943,13 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
                    "http copy file to: \"%s\"", file);
 
-    (void) ngx_http_dav_copy_file(ctx, path->data, file);
+    cf.size = ctx->size;
+    cf.buf_size = 0;
+    cf.access = ctx->access;
+    cf.time = ctx->mtime;
+    cf.log = ctx->log;
+
+    (void) ngx_copy_file(path->data, file, &cf);
 
     ngx_free(file);
 
@@ -971,75 +958,6 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
 
 
 static ngx_int_t
-ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to)
-{
-    off_t       size;
-    ssize_t     n;
-    ngx_fd_t    fd, cfd;
-    ngx_int_t   rc;
-    u_char      buf[NGX_HTTP_DAV_COPY_BLOCK];
-
-    fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
-
-    if (fd == NGX_INVALID_FILE) {
-        (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n,
-                                  from);
-        return NGX_ERROR;
-    }
-
-    cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
-                        ctx->access);
-
-    rc = NGX_ERROR;
-
-    if (cfd == NGX_INVALID_FILE) {
-        (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to);
-        goto failed;
-    }
-
-    for (size = ctx->size; size > 0; size -= n) {
-
-        n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK);
-
-        if (n == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                          ngx_read_fd_n " \"%s\" failed", from);
-            goto failed;
-        }
-
-        if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                          ngx_write_fd_n " \"%s\" failed", to);
-            goto failed;
-        }
-    }
-
-    if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                      ngx_set_file_time_n " \"%s\" failed", to);
-        goto failed;
-    }
-
-    if (ngx_close_file(cfd) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                      ngx_close_file_n " \"%s\" failed", to);
-        goto failed;
-    }
-
-    rc = NGX_OK;
-
-failed:
-
-    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
-                      ngx_close_file_n " \"%s\" failed", from);
-    }
-
-    return rc;
-}
-
-
-static ngx_int_t
 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt)
 {
     ngx_table_elt_t  *depth;
@@ -1155,7 +1073,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -178,11 +178,21 @@ static ngx_conf_bitmask_t  ngx_http_fast
     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+    { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
     { ngx_null_string, 0 }
 };
 
 
+static ngx_conf_bitmask_t  ngx_http_fastcgi_ignore_headers_masks[] = {
+    { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT },
+    { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES },
+    { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES },
+    { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL },
+    { ngx_null_string, 0 }
+};
+
+
 ngx_module_t  ngx_http_fastcgi_module;
 
 
@@ -330,7 +340,7 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid),
       NULL },
 
-    { ngx_string("proxy_cache_min_uses"),
+    { ngx_string("fastcgi_cache_min_uses"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_num_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
@@ -344,6 +354,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale),
       &ngx_http_fastcgi_next_upstream_masks },
 
+    { ngx_string("fastcgi_cache_methods"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
+      &ngx_http_upstream_cache_method_mask },
+
 #endif
 
     { ngx_string("fastcgi_temp_path"),
@@ -409,6 +426,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
       NULL },
 
+    { ngx_string("fastcgi_ignore_headers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers),
+      &ngx_http_fastcgi_ignore_headers_masks },
+
     { ngx_string("fastcgi_catch_stderr"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_str_array_slot,
@@ -519,20 +543,17 @@ ngx_http_fastcgi_handler(ngx_http_reques
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    if (ngx_http_upstream_create(r) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
     if (f == NULL) {
-        return NGX_ERROR;
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
 
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
-    if (u == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->upstream = u;
-
     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
     if (flcf->fastcgi_lengths) {
@@ -541,15 +562,11 @@ ngx_http_fastcgi_handler(ngx_http_reques
         }
     }
 
+    u = r->upstream;
+
     u->schema.len = sizeof("fastcgi://") - 1;
     u->schema.data = (u_char *) "fastcgi://";
 
-    u->peer.log = r->connection->log;
-    u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
-
     u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
 
     u->conf = &flcf->upstream;
@@ -1048,9 +1065,10 @@ ngx_http_fastcgi_reinit_request(ngx_http
 static ngx_int_t
 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
 {
-    u_char                         *p, *start, *last, *part_start;
+    u_char                         *p, *msg, *start, *last,
+                                   *part_start, *part_end;
     size_t                          size;
-    ngx_str_t                      *status_line, line, *pattern;
+    ngx_str_t                      *status_line, *pattern;
     ngx_int_t                       rc, status;
     ngx_buf_t                       buf;
     ngx_uint_t                      i;
@@ -1134,40 +1152,39 @@ ngx_http_fastcgi_process_header(ngx_http
         if (f->type == NGX_HTTP_FASTCGI_STDERR) {
 
             if (f->length) {
-                line.data = u->buffer.pos;
+                msg = u->buffer.pos;
 
                 if (u->buffer.pos + f->length <= u->buffer.last) {
-                    line.len = f->length;
                     u->buffer.pos += f->length;
                     f->length = 0;
                     f->state = ngx_http_fastcgi_st_padding;
 
                 } else {
-                    line.len = u->buffer.last - u->buffer.pos;
                     f->length -= u->buffer.last - u->buffer.pos;
                     u->buffer.pos = u->buffer.last;
                 }
 
-                while (line.data[line.len - 1] == LF
-                       || line.data[line.len - 1] == CR
-                       || line.data[line.len - 1] == '.'
-                       || line.data[line.len - 1] == ' ')
-                {
-                    line.len--;
+                for (p = u->buffer.pos - 1; msg < p; p--) {
+                    if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
+                        break;
+                    }
                 }
 
+                p++;
+
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "FastCGI sent in stderr: \"%V\"", &line);
+                              "FastCGI sent in stderr: \"%*s\"", p - msg, msg);
 
                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
                 if (flcf->catch_stderr) {
                     pattern = flcf->catch_stderr->elts;
 
-                    line.data[line.len - 1] = '\0';
-
                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
-                        if (ngx_strstr(line.data, pattern[i].data)) {
+                        if (ngx_strnstr(msg, (char *) pattern[i].data,
+                                        p - msg)
+                            != NULL)
+                        {
                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
                         }
                     }
@@ -1220,6 +1237,7 @@ ngx_http_fastcgi_process_header(ngx_http
         for ( ;; ) {
 
             part_start = u->buffer.pos;
+            part_end = u->buffer.last;
 
             rc = ngx_http_parse_header_line(r, &u->buffer, 1);
 
@@ -1420,7 +1438,11 @@ ngx_http_fastcgi_process_header(ngx_http
         part = ngx_array_push(f->split_parts);
 
         part->start = part_start;
-        part->end = u->buffer.last;
+        part->end = part_end;
+
+        if (u->buffer.pos < u->buffer.last) {
+            continue;
+        }
 
         return NGX_AGAIN;
     }
@@ -1430,9 +1452,9 @@ ngx_http_fastcgi_process_header(ngx_http
 static ngx_int_t
 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
 {
+    u_char                  *m, *msg;
     ngx_int_t                rc;
     ngx_buf_t               *b, **prev;
-    ngx_str_t                line;
     ngx_chain_t             *cl;
     ngx_http_request_t      *r;
     ngx_http_fastcgi_ctx_t  *f;
@@ -1516,30 +1538,27 @@ ngx_http_fastcgi_input_filter(ngx_event_
                     break;
                 }
 
-                line.data = f->pos;
+                msg = f->pos;
 
                 if (f->pos + f->length <= f->last) {
-                    line.len = f->length;
                     f->pos += f->length;
                     f->length = 0;
                     f->state = ngx_http_fastcgi_st_padding;
 
                 } else {
-                    line.len = f->last - f->pos;
                     f->length -= f->last - f->pos;
                     f->pos = f->last;
                 }
 
-                while (line.data[line.len - 1] == LF
-                       || line.data[line.len - 1] == CR
-                       || line.data[line.len - 1] == '.'
-                       || line.data[line.len - 1] == ' ')
-                {
-                    line.len--;
+                for (m = f->pos - 1; msg < m; m--) {
+                    if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
+                        break;
+                    }
                 }
 
                 ngx_log_error(NGX_LOG_ERR, p->log, 0,
-                              "FastCGI sent in stderr: \"%V\"", &line);
+                              "FastCGI sent in stderr: \"%*s\"",
+                              m + 1 - msg, msg);
 
                 if (f->pos == f->last) {
                     break;
@@ -1810,15 +1829,17 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
      * set by ngx_pcalloc():
      *
      *     conf->upstream.bufs.num = 0;
+     *     conf->upstream.ignore_headers = 0;
      *     conf->upstream.next_upstream = 0;
-     *     conf->upstream.use_stale_cache = 0;
+     *     conf->upstream.cache_use_stale = 0;
+     *     conf->upstream.cache_methods = 0;
      *     conf->upstream.temp_path = NULL;
      *     conf->upstream.hide_headers_hash = { NULL, 0 };
      *     conf->upstream.uri = { 0, NULL };
@@ -1886,7 +1907,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store,
-                                  prev->upstream.store, 0);
+                              prev->upstream.store, 0);
 
         if (conf->upstream.store_lengths == NULL) {
             conf->upstream.store_lengths = prev->upstream.store_lengths;
@@ -2012,6 +2033,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     }
 
 
+    ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
+                              prev->upstream.ignore_headers,
+                              NGX_CONF_BITMASK_SET);
+
+
     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
                               prev->upstream.next_upstream,
                               (NGX_CONF_BITMASK_SET
@@ -2043,7 +2069,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "\"fastcgi_cache\" zone \"%V\" is unknown",
-                           &shm_zone->name);
+                           &shm_zone->shm.name);
 
         return NGX_CONF_ERROR;
     }
@@ -2061,9 +2087,19 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
                                          |NGX_HTTP_UPSTREAM_FT_OFF;
     }
 
+    if (conf->upstream.cache_methods == 0) {
+        conf->upstream.cache_methods = prev->upstream.cache_methods;
+    }
+
+    conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
+
     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                              prev->upstream.cache_valid, NULL);
 
+    if (conf->cache_key.value.data == NULL) {
+        conf->cache_key = prev->cache_key;
+    }
+
 #endif
 
     ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -2397,8 +2433,13 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng
     }
 
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
     clcf->handler = ngx_http_fastcgi_handler;
 
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
     value = cf->args->elts;
 
     url = &value[1];
@@ -2434,10 +2475,6 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng
         return NGX_CONF_ERROR;
     }
 
-    if (clcf->name.data[clcf->name.len - 1] == '/') {
-        clcf->auto_redirect = 1;
-    }
-
     return NGX_CONF_OK;
 }
 
@@ -2501,20 +2538,31 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, n
     ngx_str_t                  *value;
     ngx_http_script_compile_t   sc;
 
-    if (flcf->upstream.store != NGX_CONF_UNSET || flcf->upstream.store_lengths)
+    if (flcf->upstream.store != NGX_CONF_UNSET
+        || flcf->upstream.store_lengths)
     {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    if (ngx_strcmp(value[1].data, "on") == 0) {
-        flcf->upstream.store = 1;
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        flcf->upstream.store = 0;
         return NGX_CONF_OK;
     }
 
-    if (ngx_strcmp(value[1].data, "off") == 0) {
-        flcf->upstream.store = 0;
+#if (NGX_HTTP_CACHE)
+
+    if (flcf->upstream.cache != NGX_CONF_UNSET_PTR
+        && flcf->upstream.cache != NULL)
+    {
+        return "is incompatible with \"fastcgi_cache\"";
+    }
+
+#endif
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        flcf->upstream.store = 1;
         return NGX_CONF_OK;
     }
 
@@ -2559,6 +2607,10 @@ ngx_http_fastcgi_cache(ngx_conf_t *cf, n
         return NGX_CONF_OK;
     }
 
+    if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) {
+        return "is incompatible with \"fastcgi_store\"";
+    }
+
     flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
                                                  &ngx_http_fastcgi_module);
     if (flcf->upstream.cache == NULL) {
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -80,7 +80,6 @@ ngx_http_flv_handler(ngx_http_request_t 
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
@@ -144,7 +143,7 @@ ngx_http_flv_handler(ngx_http_request_t 
 
         if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
             ngx_log_error(level, log, of.err,
-                          ngx_open_file_n " \"%s\" failed", path.data);
+                          "%s \"%s\" failed", of.failed, path.data);
         }
 
         return rc;
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -35,6 +35,7 @@ typedef struct {
     ngx_radix_tree_t                *tree;
     ngx_rbtree_t                     rbtree;
     ngx_rbtree_node_t                sentinel;
+    ngx_array_t                     *proxies;
     ngx_pool_t                      *pool;
     ngx_pool_t                      *temp_pool;
 } ngx_http_geo_conf_ctx_t;
@@ -46,12 +47,16 @@ typedef struct {
         ngx_http_geo_high_ranges_t  *high;
     } u;
 
+    ngx_array_t                     *proxies;
+
     ngx_int_t                        index;
 } ngx_http_geo_ctx_t;
 
 
 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r,
     ngx_http_geo_ctx_t *ctx);
+static in_addr_t ngx_http_geo_real_addr(ngx_http_request_t *r,
+    ngx_http_geo_ctx_t *ctx);
 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
@@ -64,6 +69,10 @@ static char *ngx_http_geo_cidr(ngx_conf_
     ngx_str_t *value);
 static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf,
     ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value);
+static char *ngx_http_geo_add_proxy(ngx_conf_t *cf,
+    ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr);
+static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
+    ngx_cidr_t *cidr);
 
 
 static ngx_command_t  ngx_http_geo_commands[] = {
@@ -168,6 +177,50 @@ ngx_http_geo_range_variable(ngx_http_req
 static in_addr_t
 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
 {
+    u_char           *p, *ip;
+    size_t            len;
+    in_addr_t         addr;
+    ngx_uint_t        i, n;
+    ngx_in_cidr_t    *proxies;
+    ngx_table_elt_t  *xfwd;
+
+    addr = ngx_http_geo_real_addr(r, ctx);
+
+    xfwd = r->headers_in.x_forwarded_for;
+
+    if (xfwd == NULL || ctx->proxies == NULL) {
+        return addr;
+    }
+
+    proxies = ctx->proxies->elts;
+    n = ctx->proxies->nelts;
+
+    for (i = 0; i < n; i++) {
+        if ((addr & proxies[i].mask) == proxies[i].addr) {
+
+            len = xfwd->value.len;
+            ip = xfwd->value.data;
+
+            for (p = ip + len - 1; p > ip; p--) {
+                if (*p == ' ' || *p == ',') {
+                    p++;
+                    len -= p - ip;
+                    ip = p;
+                    break;
+                }
+            }
+
+            return ntohl(ngx_inet_addr(ip, len));
+        }
+    }
+
+    return addr;
+}
+
+
+static in_addr_t
+ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
+{
     struct sockaddr_in         *sin;
     ngx_http_variable_value_t  *v;
 
@@ -259,6 +312,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
 
     ctx.high = NULL;
     ctx.tree = NULL;
+    ctx.proxies = NULL;
     ctx.pool = cf->pool;
 
     save = *cf;
@@ -271,6 +325,8 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
 
     *cf = save;
 
+    geo->proxies = ctx.proxies;
+
     if (ctx.high) {
 
         for (i = 0; i < 0x10000; i++) {
@@ -341,6 +397,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
 {
     char                     *rv;
     ngx_str_t                *value, file;
+    ngx_cidr_t                cidr;
     ngx_http_geo_conf_ctx_t  *ctx;
 
     ctx = cf->ctx;
@@ -394,6 +451,16 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
         rv = ngx_conf_parse(cf, &file);
 
         goto done;
+
+    } else if (ngx_strcmp(value[0].data, "proxy") == 0) {
+
+        if (ngx_http_geo_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
+            goto failed;
+        }
+
+        rv = ngx_http_geo_add_proxy(cf, ctx, &cidr);
+
+        goto done;
     }
 
     if (ctx->high) {
@@ -803,33 +870,8 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht
             del = 0;
         }
 
-        if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
-            cidr.u.in.addr = 0xffffffff;
-            cidr.u.in.mask = 0xffffffff;
-
-        } else {
-            rc = ngx_ptocidr(net, &cidr);
-
-            if (rc == NGX_ERROR) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "invalid network \"%V\"", net);
-                return NGX_CONF_ERROR;
-            }
-
-            if (cidr.family != AF_INET) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "\"geo\" supports IPv4 only");
-                return NGX_CONF_ERROR;
-            }
-
-            if (rc == NGX_DONE) {
-                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                                   "low address bits of %V are meaningless",
-                                   net);
-            }
-
-            cidr.u.in.addr = ntohl(cidr.u.in.addr);
-            cidr.u.in.mask = ntohl(cidr.u.in.mask);
+        if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) {
+            return NGX_CONF_ERROR;
         }
 
         if (del) {
@@ -864,7 +906,7 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht
 
         /* rc == NGX_BUSY */
 
-        old  = (ngx_http_variable_value_t *)
+        old = (ngx_http_variable_value_t *)
               ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask);
 
         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
@@ -927,3 +969,64 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_h
 
     return val;
 }
+
+
+static char *
+ngx_http_geo_add_proxy(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
+    ngx_cidr_t *cidr)
+{
+    ngx_in_cidr_t  *c;
+
+    if (ctx->proxies == NULL) {
+        ctx->proxies = ngx_array_create(ctx->pool, 4, sizeof(ngx_in_cidr_t));
+        if (ctx->proxies == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    c = ngx_array_push(ctx->proxies);
+    if (c == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    c->addr = cidr->u.in.addr;
+    c->mask = cidr->u.in.mask;
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
+{
+    ngx_int_t  rc;
+
+    if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
+        cidr->u.in.addr = 0xffffffff;
+        cidr->u.in.mask = 0xffffffff;
+
+        return NGX_OK;
+    }
+
+    rc = ngx_ptocidr(net, cidr);
+
+    if (rc == NGX_ERROR) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
+        return NGX_ERROR;
+    }
+
+    if (cidr->family != AF_INET) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"geo\" supports IPv4 only");
+        return NGX_ERROR;
+    }
+
+    if (rc == NGX_DONE) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "low address bits of %V are meaningless", net);
+    }
+
+    cidr->u.in.addr = ntohl(cidr->u.in.addr);
+    cidr->u.in.mask = ntohl(cidr->u.in.mask);
+
+    return NGX_OK;
+}
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_geoip_module.c
@@ -0,0 +1,376 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include <GeoIP.h>
+#include <GeoIPCity.h>
+
+
+typedef struct {
+    GeoIP      *country;
+    GeoIP      *city;
+} ngx_http_geoip_conf_t;
+
+
+typedef struct {
+    ngx_str_t  *name;
+    uintptr_t   data;
+} ngx_http_geoip_var_t;
+
+
+typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
+
+static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+
+static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
+static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
+static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static void ngx_http_geoip_cleanup(void *data);
+
+
+static ngx_command_t  ngx_http_geoip_commands[] = {
+
+    { ngx_string("geoip_country"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_http_geoip_country,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("geoip_city"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_http_geoip_city,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_geoip_module_ctx = {
+    ngx_http_geoip_add_variables,          /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    ngx_http_geoip_create_conf,            /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_geoip_module = {
+    NGX_MODULE_V1,
+    &ngx_http_geoip_module_ctx,            /* module context */
+    ngx_http_geoip_commands,               /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_http_variable_t  ngx_http_geoip_vars[] = {
+
+    { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable,
+      (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 },
+
+    { ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable,
+      (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
+
+    { ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable,
+      (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
+
+    { ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, country_code), 0, 0 },
+
+    { ngx_string("geoip_city_country_code3"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, country_code3), 0, 0 },
+
+    { ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, country_name), 0, 0 },
+
+    { ngx_string("geoip_region"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, region), 0, 0 },
+
+    { ngx_string("geoip_city"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, city), 0, 0 },
+
+    { ngx_string("geoip_postal_code"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, postal_code), 0, 0 },
+
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
+};
+
+
+static ngx_int_t
+ngx_http_geoip_country_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_http_geoip_variable_handler_pt  handler =
+        (ngx_http_geoip_variable_handler_pt) data;
+
+    u_long                  addr;
+    const char             *val;
+    struct sockaddr_in     *sin;
+    ngx_http_geoip_conf_t  *gcf;
+
+    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
+
+    if (gcf->country == NULL) {
+        goto not_found;
+    }
+
+    if (r->connection->sockaddr->sa_family != AF_INET) {
+        goto not_found;
+    }
+
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
+    addr = ntohl(sin->sin_addr.s_addr);
+
+    val = handler(gcf->country, addr);
+
+    if (val == NULL) {
+        goto not_found;
+    }
+
+    v->len = ngx_strlen(val);
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = (u_char *) val;
+
+    return NGX_OK;
+
+not_found:
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geoip_city_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_long                  addr;
+    char                   *val;
+    size_t                  len;
+    GeoIPRecord            *gr;
+    struct sockaddr_in     *sin;
+    ngx_http_geoip_conf_t  *gcf;
+
+    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
+
+    if (gcf->city == NULL) {
+        goto not_found;
+    }
+
+    if (r->connection->sockaddr->sa_family != AF_INET) {
+        goto not_found;
+    }
+
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
+    addr = ntohl(sin->sin_addr.s_addr);
+
+    gr = GeoIP_record_by_ipnum(gcf->city, addr);
+
+    if (gr == NULL) {
+        goto not_found;
+    }
+
+    val = *(char **) ((char *) gr + data);
+
+    if (val == NULL) {
+        goto no_value;
+    }
+
+    len = ngx_strlen(val);
+    v->data = ngx_pnalloc(r->pool, len);
+
+    if (v->data == NULL) {
+        GeoIPRecord_delete(gr);
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(v->data, val, len);
+
+    v->len = len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    GeoIPRecord_delete(gr);
+
+    return NGX_OK;
+
+no_value:
+
+    GeoIPRecord_delete(gr);
+
+not_found:
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geoip_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_geoip_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->get_handler = v->get_handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK;
+}
+
+
+static void *
+ngx_http_geoip_create_conf(ngx_conf_t *cf)
+{
+    ngx_pool_cleanup_t     *cln;
+    ngx_http_geoip_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    cln = ngx_pool_cleanup_add(cf->pool, 0);
+    if (cln == NULL) {
+        return NULL;
+    }
+
+    cln->handler = ngx_http_geoip_cleanup;
+    cln->data = conf;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_geoip_conf_t  *gcf = conf;
+
+    ngx_str_t  *value;
+
+    if (gcf->country) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
+
+    if (gcf->country == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "GeoIO_open(\"%V\") failed", &value[1]);
+
+        return NGX_CONF_ERROR;
+    }
+
+    switch (gcf->country->databaseType) {
+
+    case GEOIP_COUNTRY_EDITION:
+    case GEOIP_PROXY_EDITION:
+    case GEOIP_NETSPEED_EDITION:
+
+        return NGX_CONF_OK;
+
+    default:
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid GeoIP database \"%V\" type:%d",
+                           &value[1], gcf->country->databaseType);
+        return NGX_CONF_ERROR;
+    }
+}
+
+
+static char *
+ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_geoip_conf_t  *gcf = conf;
+
+    ngx_str_t  *value;
+
+    if (gcf->city) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
+
+    if (gcf->city == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "GeoIO_open(\"%V\") failed", &value[1]);
+
+        return NGX_CONF_ERROR;
+    }
+
+    switch (gcf->city->databaseType) {
+
+    case GEOIP_CITY_EDITION_REV0:
+    case GEOIP_CITY_EDITION_REV1:
+
+        return NGX_CONF_OK;
+
+    default:
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid GeoIP City database \"%V\" type:%d",
+                           &value[1], gcf->city->databaseType);
+        return NGX_CONF_ERROR;
+    }
+}
+
+
+static void
+ngx_http_geoip_cleanup(void *data)
+{
+    ngx_http_geoip_conf_t  *gcf = data;
+
+    if (gcf->country) {
+        GeoIP_delete(gcf->country);
+    }
+
+    if (gcf->city) {
+        GeoIP_delete(gcf->city);
+    }
+}
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -1069,7 +1069,7 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -89,14 +89,19 @@ ngx_http_gzip_static_handler(ngx_http_re
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
 
     gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
 
-    if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) {
+    if (!gzcf->enable) {
+        return NGX_DECLINED;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) {
         return NGX_DECLINED;
     }
 
@@ -117,8 +122,6 @@ ngx_http_gzip_static_handler(ngx_http_re
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", path.data);
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
     of.directio = clcf->directio;
@@ -139,6 +142,7 @@ ngx_http_gzip_static_handler(ngx_http_re
         case NGX_ENOTDIR:
         case NGX_ENAMETOOLONG:
 
+            r->gzip = 0;
             return NGX_DECLINED;
 
         case NGX_EACCES:
@@ -153,7 +157,7 @@ ngx_http_gzip_static_handler(ngx_http_re
         }
 
         ngx_log_error(level, log, of.err,
-                      ngx_open_file_n " \"%s\" failed", path.data);
+                      "%s \"%s\" failed", of.failed, path.data);
 
         return NGX_DECLINED;
     }
@@ -206,6 +210,7 @@ ngx_http_gzip_static_handler(ngx_http_re
     h->value.data = (u_char *) "gzip";
 
     r->headers_out.content_encoding = h;
+    r->ignore_content_encoding = 1;
 
     /* we need to allocate all before the header would be sent */
 
@@ -251,7 +256,7 @@ ngx_http_gzip_static_create_conf(ngx_con
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -421,7 +421,7 @@ ngx_http_headers_create_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -0,0 +1,1222 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include <gd.h>
+
+
+#define NGX_HTTP_IMAGE_OFF       0
+#define NGX_HTTP_IMAGE_TEST      1
+#define NGX_HTTP_IMAGE_SIZE      2
+#define NGX_HTTP_IMAGE_RESIZE    3
+#define NGX_HTTP_IMAGE_CROP      4
+
+
+#define NGX_HTTP_IMAGE_START     0
+#define NGX_HTTP_IMAGE_READ      1
+#define NGX_HTTP_IMAGE_PROCESS   2
+#define NGX_HTTP_IMAGE_PASS      3
+#define NGX_HTTP_IMAGE_DONE      4
+
+
+#define NGX_HTTP_IMAGE_NONE      0
+#define NGX_HTTP_IMAGE_JPEG      1
+#define NGX_HTTP_IMAGE_GIF       2
+#define NGX_HTTP_IMAGE_PNG       3
+
+
+#define NGX_HTTP_IMAGE_BUFFERED  0x08
+
+
+typedef struct {
+    ngx_uint_t                   filter;
+    ngx_uint_t                   width;
+    ngx_uint_t                   height;
+    ngx_int_t                    jpeg_quality;
+
+    ngx_flag_t                   transparency;
+
+    ngx_http_complex_value_t    *wcv;
+    ngx_http_complex_value_t    *hcv;
+
+    size_t                       buffer_size;
+} ngx_http_image_filter_conf_t;
+
+
+typedef struct {
+    u_char                      *image;
+    u_char                      *last;
+
+    size_t                       length;
+
+    ngx_uint_t                   width;
+    ngx_uint_t                   height;
+
+    ngx_uint_t                   max_width;
+    ngx_uint_t                   max_height;
+
+    ngx_uint_t                   phase;
+    ngx_uint_t                   type;
+} ngx_http_image_filter_ctx_t;
+
+
+static ngx_int_t ngx_http_image_send(ngx_http_request_t *r,
+    ngx_http_image_filter_ctx_t *ctx, ngx_chain_t *in);
+static ngx_uint_t ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in);
+static ngx_int_t ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in);
+static ngx_buf_t *ngx_http_image_process(ngx_http_request_t *r);
+static ngx_buf_t *ngx_http_image_json(ngx_http_request_t *r,
+    ngx_http_image_filter_ctx_t *ctx);
+static ngx_buf_t *ngx_http_image_asis(ngx_http_request_t *r,
+    ngx_http_image_filter_ctx_t *ctx);
+static void ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b);
+static ngx_int_t ngx_http_image_size(ngx_http_request_t *r,
+    ngx_http_image_filter_ctx_t *ctx);
+
+static ngx_buf_t *ngx_http_image_resize(ngx_http_request_t *r,
+    ngx_http_image_filter_ctx_t *ctx);
+static gdImagePtr ngx_http_image_source(ngx_http_request_t *r,
+    ngx_http_image_filter_ctx_t *ctx);
+static gdImagePtr ngx_http_image_new(ngx_http_request_t *r, int w, int h,
+    int colors);
+static u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type,
+    gdImagePtr img, int *size);
+static void ngx_http_image_cleanup(void *data);
+static ngx_uint_t ngx_http_image_filter_get_value(ngx_http_request_t *r,
+    ngx_http_complex_value_t *cv, ngx_uint_t v);
+static ngx_uint_t ngx_http_image_filter_value(ngx_str_t *value);
+
+
+static void *ngx_http_image_filter_create_conf(ngx_conf_t *cf);
+static char *ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+static char *ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf);
+
+
+static ngx_command_t  ngx_http_image_filter_commands[] = {
+
+    { ngx_string("image_filter"),
+      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
+      ngx_http_image_filter,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("image_filter_jpeg_quality"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_image_filter_conf_t, jpeg_quality),
+      NULL },
+
+    { ngx_string("image_filter_transparency"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_image_filter_conf_t, transparency),
+      NULL },
+
+    { ngx_string("image_filter_buffer"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_image_filter_conf_t, buffer_size),
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_image_filter_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_image_filter_init,            /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_image_filter_create_conf,     /* create location configuration */
+    ngx_http_image_filter_merge_conf       /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_image_filter_module = {
+    NGX_MODULE_V1,
+    &ngx_http_image_filter_module_ctx,     /* module context */
+    ngx_http_image_filter_commands,        /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
+static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
+
+
+static ngx_str_t  ngx_http_image_types[] = {
+    ngx_string("image/jpeg"),
+    ngx_string("image/gif"),
+    ngx_string("image/png")
+};
+
+
+static ngx_int_t
+ngx_http_image_header_filter(ngx_http_request_t *r)
+{
+    off_t                          len;
+    ngx_http_image_filter_ctx_t   *ctx;
+    ngx_http_image_filter_conf_t  *conf;
+
+    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
+        return ngx_http_next_header_filter(r);
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module);
+
+    if (ctx) {
+        ngx_http_set_ctx(r, NULL, ngx_http_image_filter_module);
+        return ngx_http_next_header_filter(r);
+    }
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
+
+    if (conf->filter == NGX_HTTP_IMAGE_OFF) {
+        return ngx_http_next_header_filter(r);
+    }
+
+    if (r->headers_out.content_type.len
+            >= sizeof("multipart/x-mixed-replace") - 1
+        && ngx_strncasecmp(r->headers_out.content_type.data,
+                           (u_char *) "multipart/x-mixed-replace",
+                           sizeof("multipart/x-mixed-replace") - 1)
+           == 0)
+    {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "image filter: multipart/x-mixed-replace response");
+
+        return NGX_ERROR;
+    }
+
+    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_image_filter_ctx_t));
+    if (ctx == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_set_ctx(r, ctx, ngx_http_image_filter_module);
+
+    len = r->headers_out.content_length_n;
+
+    if (len != -1 && len > (off_t) conf->buffer_size) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "image filter: too big response: %O", len);
+
+        return NGX_ERROR;
+    }
+
+    if (len == -1) {
+        ctx->length = conf->buffer_size;
+
+    } else {
+        ctx->length = (size_t) len;
+    }
+
+    if (r->headers_out.refresh) {
+        r->headers_out.refresh->hash = 0;
+    }
+
+    r->main_filter_need_in_memory = 1;
+    r->allow_ranges = 0;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_image_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+    ngx_int_t                      rc;
+    ngx_str_t                     *ct;
+    ngx_chain_t                    out;
+    ngx_http_image_filter_ctx_t   *ctx;
+    ngx_http_image_filter_conf_t  *conf;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "image filter");
+
+    if (in == NULL) {
+        return ngx_http_next_body_filter(r, in);
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module);
+
+    if (ctx == NULL) {
+        return ngx_http_next_body_filter(r, in);
+    }
+
+    switch (ctx->phase) {
+
+    case NGX_HTTP_IMAGE_START:
+
+        ctx->type = ngx_http_image_test(r, in);
+
+        conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
+
+        if (ctx->type == NGX_HTTP_IMAGE_NONE) {
+
+            if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
+                out.buf = ngx_http_image_json(r, NULL);
+
+                if (out.buf) {
+                    out.next = NULL;
+                    ctx->phase = NGX_HTTP_IMAGE_DONE;
+
+                    return ngx_http_image_send(r, ctx, &out);
+                }
+            }
+
+            return ngx_http_filter_finalize_request(r,
+                                              &ngx_http_image_filter_module,
+                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
+        }
+
+        /* override content type */
+
+        ct = &ngx_http_image_types[ctx->type - 1];
+        r->headers_out.content_type_len = ct->len;
+        r->headers_out.content_type = *ct;
+        r->headers_out.content_type_lowcase = NULL;
+
+        if (conf->filter == NGX_HTTP_IMAGE_TEST) {
+            ctx->phase = NGX_HTTP_IMAGE_PASS;
+
+            return ngx_http_image_send(r, ctx, in);
+        }
+
+        ctx->phase = NGX_HTTP_IMAGE_READ;
+
+        /* fall through */
+
+    case NGX_HTTP_IMAGE_READ:
+
+        rc = ngx_http_image_read(r, in);
+
+        if (rc == NGX_AGAIN) {
+            return NGX_OK;
+        }
+
+        if (rc == NGX_ERROR) {
+            return ngx_http_filter_finalize_request(r,
+                                              &ngx_http_image_filter_module,
+                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
+        }
+
+        /* fall through */
+
+    case NGX_HTTP_IMAGE_PROCESS:
+
+        out.buf = ngx_http_image_process(r);
+
+        if (out.buf == NULL) {
+            return ngx_http_filter_finalize_request(r,
+                                              &ngx_http_image_filter_module,
+                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
+        }
+
+        out.next = NULL;
+        ctx->phase = NGX_HTTP_IMAGE_PASS;
+
+        return ngx_http_image_send(r, ctx, &out);
+
+    case NGX_HTTP_IMAGE_PASS:
+
+        return ngx_http_next_body_filter(r, in);
+
+    default: /* NGX_HTTP_IMAGE_DONE */
+
+        rc = ngx_http_next_body_filter(r, NULL);
+
+        /* NGX_ERROR resets any pending data */
+        return (rc == NGX_OK) ? NGX_ERROR : rc;
+    }
+}
+
+
+static ngx_int_t
+ngx_http_image_send(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx,
+    ngx_chain_t *in)
+{
+    ngx_int_t  rc;
+
+    rc = ngx_http_next_header_filter(r);
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return NGX_ERROR;
+    }
+
+    rc = ngx_http_next_body_filter(r, in);
+
+    if (ctx->phase == NGX_HTTP_IMAGE_DONE) {
+        /* NGX_ERROR resets any pending data */
+        return (rc == NGX_OK) ? NGX_ERROR : rc;
+    }
+
+    return rc;
+}
+
+
+static ngx_uint_t
+ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in)
+{
+    u_char  *p;
+
+    p = in->buf->pos;
+
+    if (in->buf->last - p < 16) {
+        return NGX_HTTP_IMAGE_NONE;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "image filter: \"%c%c\"", p[0], p[1]);
+
+    if (p[0] == 0xff && p[1] == 0xd8) {
+
+        /* JPEG */
+
+        return NGX_HTTP_IMAGE_JPEG;
+
+    } else if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F' && p[3] == '8'
+               && p[5] == 'a')
+    {
+        if (p[4] == '9' || p[4] == '7') {
+            /* GIF */
+            return NGX_HTTP_IMAGE_GIF;
+        }
+
+    } else if (p[0] == 0x89 && p[1] == 'P' && p[2] == 'N' && p[3] == 'G'
+               && p[4] == 0x0d && p[5] == 0x0a && p[6] == 0x1a && p[7] == 0x0a)
+    {
+        /* PNG */
+
+        return NGX_HTTP_IMAGE_PNG;
+    }
+
+    return NGX_HTTP_IMAGE_NONE;
+}
+
+
+static ngx_int_t
+ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in)
+{
+    u_char                       *p;
+    size_t                        size, rest;
+    ngx_buf_t                    *b;
+    ngx_chain_t                  *cl;
+    ngx_http_image_filter_ctx_t  *ctx;
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module);
+
+    if (ctx->image == NULL) {
+        ctx->image = ngx_palloc(r->pool, ctx->length);
+        if (ctx->image == NULL) {
+            return NGX_ERROR;
+        }
+
+        ctx->last = ctx->image;
+    }
+
+    p = ctx->last;
+
+    for (cl = in; cl; cl = cl->next) {
+
+        b = cl->buf;
+        size = b->last - b->pos;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "image buf: %uz", size);
+
+        rest = ctx->image + ctx->length - p;
+        size = (rest < size) ? rest : size;
+
+        p = ngx_cpymem(p, b->pos, size);
+        b->pos += size;
+
+        if (b->last_buf) {
+            ctx->last = p;
+            return NGX_OK;
+        }
+    }
+
+    ctx->last = p;
+    r->connection->buffered |= NGX_HTTP_IMAGE_BUFFERED;
+
+    return NGX_AGAIN;
+}
+
+
+static ngx_buf_t *
+ngx_http_image_process(ngx_http_request_t *r)
+{
+    ngx_int_t                      rc;
+    ngx_http_image_filter_ctx_t   *ctx;
+    ngx_http_image_filter_conf_t  *conf;
+
+    r->connection->buffered &= ~NGX_HTTP_IMAGE_BUFFERED;
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module);
+
+    rc = ngx_http_image_size(r, ctx);
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
+
+    if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
+        return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
+    }
+
+    ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
+    if (ctx->max_width == 0) {
+        return NULL;
+    }
+
+    ctx->max_height = ngx_http_image_filter_get_value(r, conf->hcv,
+                                                      conf->height);
+    if (ctx->max_height == 0) {
+        return NULL;
+    }
+
+    if (rc == NGX_OK
+        && ctx->width <= ctx->max_width
+        && ctx->height <= ctx->max_height)
+    {
+        return ngx_http_image_asis(r, ctx);
+    }
+
+    return ngx_http_image_resize(r, ctx);
+}
+
+
+static ngx_buf_t *
+ngx_http_image_json(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
+{
+    size_t      len;
+    ngx_buf_t  *b;
+
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    if (b == NULL) {
+        return NULL;
+    }
+
+    b->memory = 1;
+    b->last_buf = 1;
+
+    ngx_http_clean_header(r);
+
+    r->headers_out.status = NGX_HTTP_OK;
+    r->headers_out.content_type.len = sizeof("text/plain") - 1;
+    r->headers_out.content_type.data = (u_char *) "text/plain";
+    r->headers_out.content_type_lowcase = NULL;
+
+    if (ctx == NULL) {
+        b->pos = (u_char *) "{}" CRLF;
+        b->last = b->pos + sizeof("{}" CRLF) - 1;
+
+        ngx_http_image_length(r, b);
+
+        return b;
+    }
+
+    len = sizeof("{ \"img\" : "
+                 "{ \"width\": , \"height\": , \"type\": \"jpeg\" } }" CRLF) - 1
+          + 2 * NGX_SIZE_T_LEN;
+
+    b->pos = ngx_pnalloc(r->pool, len);
+    if (b->pos == NULL) {
+        return NULL;
+    }
+
+    b->last = ngx_sprintf(b->pos,
+                          "{ \"img\" : "
+                                       "{ \"width\": %uz,"
+                                        " \"height\": %uz,"
+                                        " \"type\": \"%s\" } }" CRLF,
+                          ctx->width, ctx->height,
+                          ngx_http_image_types[ctx->type - 1].data + 6);
+
+    ngx_http_image_length(r, b);
+
+    return b;
+}
+
+
+static ngx_buf_t *
+ngx_http_image_asis(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
+{
+    ngx_buf_t  *b;
+
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    if (b == NULL) {
+        return NULL;
+    }
+
+    b->pos = ctx->image;
+    b->last = ctx->last;
+    b->memory = 1;
+    b->last_buf = 1;
+
+    ngx_http_image_length(r, b);
+
+    return b;
+}
+
+
+static void
+ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b)
+{
+    r->headers_out.content_length_n = b->last - b->pos;
+
+    if (r->headers_out.content_length) {
+        r->headers_out.content_length->hash = 0;
+    }
+
+    r->headers_out.content_length = NULL;
+}
+
+
+static ngx_int_t
+ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
+{
+    u_char      *p, *last;
+    ngx_uint_t   width, height;
+
+    p = ctx->image;
+
+    switch (ctx->type) {
+
+    case NGX_HTTP_IMAGE_JPEG:
+
+        p += 2;
+        last = ctx->image + ctx->length - 10;
+
+        while (p < last) {
+
+            if (p[0] == 0xff && p[1] != 0xff) {
+
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "JPEG: %02xd %02xd", *p, *(p + 1));
+
+                p++;
+
+                if (*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3
+                    || *p == 0xc9 || *p == 0xca || *p == 0xcb)
+                {
+                    goto found;
+                }
+
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "JPEG: %02xd %02xd", p[1], p[2]);
+
+                p += p[1] * 256 + p[2];
+
+                continue;
+            }
+
+            p++;
+        }
+
+        return NGX_DECLINED;
+
+    found:
+
+        width = p[6] * 256 + p[7];
+        height = p[4] * 256 + p[5];
+
+        break;
+
+    case NGX_HTTP_IMAGE_GIF:
+
+        if (ctx->length < 10) {
+            return NGX_DECLINED;
+        }
+
+        width = p[7] * 256 + p[6];
+        height = p[9] * 256 + p[8];
+
+        break;
+
+    case NGX_HTTP_IMAGE_PNG:
+
+        if (ctx->length < 24) {
+            return NGX_DECLINED;
+        }
+
+        width = p[18] * 256 + p[19];
+        height = p[22] * 256 + p[23];
+
+        break;
+
+    default:
+
+        return NGX_DECLINED;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "image size: %d x %d", width, height);
+
+    ctx->width = width;
+    ctx->height = height;
+
+    return NGX_OK;
+}
+
+
+static ngx_buf_t *
+ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
+{
+    int                            sx, sy, dx, dy, ox, oy, size,
+                                   colors, palette, transparent,
+                                   red, green, blue;
+    u_char                        *out;
+    ngx_buf_t                     *b;
+    ngx_uint_t                     resize;
+    gdImagePtr                     src, dst;
+    ngx_pool_cleanup_t            *cln;
+    ngx_http_image_filter_conf_t  *conf;
+
+    src = ngx_http_image_source(r, ctx);
+
+    if (src == NULL) {
+        return NULL;
+    }
+
+    sx = gdImageSX(src);
+    sy = gdImageSY(src);
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
+
+    if ((ngx_uint_t) sx <= ctx->max_width
+        && (ngx_uint_t) sy <= ctx->max_height)
+    {
+        gdImageDestroy(src);
+        return ngx_http_image_asis(r, ctx);
+    }
+
+    colors = gdImageColorsTotal(src);
+
+    if (colors && conf->transparency) {
+        transparent = gdImageGetTransparent(src);
+
+        if (transparent != -1) {
+            palette = colors;
+            red = gdImageRed(src, transparent);
+            green = gdImageGreen(src, transparent);
+            blue = gdImageBlue(src, transparent);
+
+            goto transparent;
+        }
+    }
+
+    palette = 0;
+    transparent = -1;
+    red = 0;
+    green = 0;
+    blue = 0;
+
+transparent:
+
+    gdImageColorTransparent(src, -1);
+
+    dx = sx;
+    dy = sy;
+
+    if (conf->filter == NGX_HTTP_IMAGE_RESIZE) {
+
+        if ((ngx_uint_t) dx > ctx->max_width) {
+            dy = dy * ctx->max_width / dx;
+            dy = dy ? dy : 1;
+            dx = ctx->max_width;
+        }
+
+        if ((ngx_uint_t) dy > ctx->max_height) {
+            dx = dx * ctx->max_height / dy;
+            dx = dx ? dx : 1;
+            dy = ctx->max_height;
+        }
+
+        resize = 1;
+
+    } else { /* NGX_HTTP_IMAGE_CROP */
+
+        resize = 0;
+
+        if ((ngx_uint_t) (dx * 100 / dy)
+            < ctx->max_width * 100 / ctx->max_height)
+        {
+            if ((ngx_uint_t) dx > ctx->max_width) {
+                dy = dy * ctx->max_width / dx;
+                dy = dy ? dy : 1;
+                dx = ctx->max_width;
+                resize = 1;
+            }
+
+        } else {
+            if ((ngx_uint_t) dy > ctx->max_height) {
+                dx = dx * ctx->max_height / dy;
+                dx = dx ? dx : 1;
+                dy = ctx->max_height;
+                resize = 1;
+            }
+        }
+    }
+
+    if (resize) {
+        dst = ngx_http_image_new(r, dx, dy, palette);
+        if (dst == NULL) {
+            gdImageDestroy(src);
+            return NULL;
+        }
+
+        if (colors == 0) {
+            gdImageSaveAlpha(dst, 1);
+            gdImageAlphaBlending(dst, 0);
+        }
+
+        gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);
+
+        if (colors) {
+            gdImageTrueColorToPalette(dst, 1, 256);
+        }
+
+        gdImageDestroy(src);
+
+    } else {
+        dst = src;
+    }
+
+    if (conf->filter == NGX_HTTP_IMAGE_CROP) {
+
+        src = dst;
+
+        if ((ngx_uint_t) dx > ctx->max_width) {
+            ox = dx - ctx->max_width;
+
+        } else {
+            ox = 0;
+        }
+
+        if ((ngx_uint_t) dy > ctx->max_height) {
+            oy = dy - ctx->max_height;
+
+        } else {
+            oy = 0;
+        }
+
+        if (ox || oy) {
+
+            dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);
+
+            if (dst == NULL) {
+                gdImageDestroy(src);
+                return NULL;
+            }
+
+            ox /= 2;
+            oy /= 2;
+
+            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "image crop: %d x %d @ %d x %d",
+                           dx, dy, ox, oy);
+
+            if (colors == 0) {
+                gdImageSaveAlpha(dst, 1);
+                gdImageAlphaBlending(dst, 0);
+            }
+
+            gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);
+
+            if (colors) {
+                gdImageTrueColorToPalette(dst, 1, 256);
+            }
+
+            gdImageDestroy(src);
+        }
+    }
+
+    if (transparent != -1 && colors) {
+        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
+    }
+
+    out = ngx_http_image_out(r, ctx->type, dst, &size);
+
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "image: %d x %d %d", sx, sy, colors);
+
+    gdImageDestroy(dst);
+    ngx_pfree(r->pool, ctx->image);
+
+    if (out == NULL) {
+        return NULL;
+    }
+
+    cln = ngx_pool_cleanup_add(r->pool, 0);
+    if (cln == NULL) {
+        gdFree(out);
+        return NULL;
+    }
+
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    if (b == NULL) {
+        gdFree(out);
+        return NULL;
+    }
+
+    cln->handler = ngx_http_image_cleanup;
+    cln->data = out;
+
+    b->pos = out;
+    b->last = out + size;
+    b->memory = 1;
+    b->last_buf = 1;
+
+    ngx_http_image_length(r, b);
+
+    return b;
+}
+
+
+static gdImagePtr
+ngx_http_image_source(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
+{
+    char        *failed;
+    gdImagePtr   img;
+
+    img = NULL;
+
+    switch (ctx->type) {
+
+    case NGX_HTTP_IMAGE_JPEG:
+        img = gdImageCreateFromJpegPtr(ctx->length, ctx->image);
+        failed = "gdImageCreateFromJpegPtr() failed";
+        break;
+
+    case NGX_HTTP_IMAGE_GIF:
+        img = gdImageCreateFromGifPtr(ctx->length, ctx->image);
+        failed = "gdImageCreateFromGifPtr() failed";
+        break;
+
+    case NGX_HTTP_IMAGE_PNG:
+        img = gdImageCreateFromPngPtr(ctx->length, ctx->image);
+        failed = "gdImageCreateFromPngPtr() failed";
+        break;
+
+    default:
+        failed = "unknown image type";
+        break;
+    }
+
+    if (img == NULL) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, failed);
+    }
+
+    return img;
+}
+
+
+static gdImagePtr
+ngx_http_image_new(ngx_http_request_t *r, int w, int h, int colors)
+{
+    gdImagePtr  img;
+
+    if (colors == 0) {
+        img = gdImageCreateTrueColor(w, h);
+
+        if (img == NULL) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "gdImageCreateTrueColor() failed");
+            return NULL;
+        }
+
+    } else {
+        img = gdImageCreate(w, h);
+
+        if (img == NULL) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "gdImageCreate() failed");
+            return NULL;
+        }
+    }
+
+    return img;
+}
+
+
+static u_char *
+ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img,
+    int *size)
+{
+    char                          *failed;
+    u_char                        *out;
+    ngx_http_image_filter_conf_t  *conf;
+
+    out = NULL;
+
+    switch (type) {
+
+    case NGX_HTTP_IMAGE_JPEG:
+        conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
+        out = gdImageJpegPtr(img, size, conf->jpeg_quality);
+        failed = "gdImageJpegPtr() failed";
+        break;
+
+    case NGX_HTTP_IMAGE_GIF:
+        out = gdImageGifPtr(img, size);
+        failed = "gdImageGifPtr() failed";
+        break;
+
+    case NGX_HTTP_IMAGE_PNG:
+        out = gdImagePngPtr(img, size);
+        failed = "gdImagePngPtr() failed";
+        break;
+
+    default:
+        failed = "unknown image type";
+        break;
+    }
+
+    if (out == NULL) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, failed);
+    }
+
+    return out;
+}
+
+
+static void
+ngx_http_image_cleanup(void *data)
+{
+    gdFree(data);
+}
+
+
+static ngx_uint_t
+ngx_http_image_filter_get_value(ngx_http_request_t *r,
+    ngx_http_complex_value_t *cv, ngx_uint_t v)
+{
+    ngx_str_t  val;
+
+    if (cv == NULL) {
+        return v;
+    }
+
+    if (ngx_http_complex_value(r, cv, &val) != NGX_OK) {
+        return 0;
+    }
+
+    return ngx_http_image_filter_value(&val);
+}
+
+
+static ngx_uint_t
+ngx_http_image_filter_value(ngx_str_t *value)
+{
+    ngx_int_t  n;
+
+    if (value->len == 1 && value->data[0] == '-') {
+        return (ngx_uint_t) -1;
+    }
+
+    n = ngx_atoi(value->data, value->len);
+
+    if (n > 0) {
+        return (ngx_uint_t) n;
+    }
+
+    return 0;
+}
+
+
+static void *
+ngx_http_image_filter_create_conf(ngx_conf_t *cf)
+{
+    ngx_http_image_filter_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_image_filter_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    conf->filter = NGX_CONF_UNSET_UINT;
+    conf->jpeg_quality = NGX_CONF_UNSET;
+    conf->transparency = NGX_CONF_UNSET;
+    conf->buffer_size = NGX_CONF_UNSET_SIZE;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_image_filter_conf_t *prev = parent;
+    ngx_http_image_filter_conf_t *conf = child;
+
+    if (conf->filter == NGX_CONF_UNSET_UINT) {
+
+        if (prev->filter == NGX_CONF_UNSET_UINT) {
+            conf->filter = NGX_HTTP_IMAGE_OFF;
+
+        } else {
+            conf->filter = prev->filter;
+            conf->width = prev->width;
+            conf->height = prev->height;
+            conf->wcv = prev->wcv;
+            conf->hcv = prev->hcv;
+        }
+    }
+
+    /* 75 is libjpeg default quality */
+    ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75);
+
+    ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
+
+    ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
+                              1 * 1024 * 1024);
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_image_filter_conf_t *imcf = conf;
+
+    ngx_str_t                         *value;
+    ngx_int_t                          n;
+    ngx_uint_t                         i;
+    ngx_http_complex_value_t           cv;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    i = 1;
+
+    if (cf->args->nelts == 2) {
+        if (ngx_strcmp(value[i].data, "off") == 0) {
+            imcf->filter = NGX_HTTP_IMAGE_OFF;
+
+        } else if (ngx_strcmp(value[i].data, "test") == 0) {
+            imcf->filter = NGX_HTTP_IMAGE_TEST;
+
+        } else if (ngx_strcmp(value[i].data, "size") == 0) {
+            imcf->filter = NGX_HTTP_IMAGE_SIZE;
+
+        } else {
+            goto failed;
+        }
+
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_strcmp(value[i].data, "resize") == 0) {
+        imcf->filter = NGX_HTTP_IMAGE_RESIZE;
+
+    } else if (ngx_strcmp(value[i].data, "crop") == 0) {
+        imcf->filter = NGX_HTTP_IMAGE_CROP;
+
+    } else {
+        goto failed;
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[++i];
+    ccv.complex_value = &cv;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (cv.lengths == NULL) {
+        n = ngx_http_image_filter_value(&value[i]);
+
+        if (n == 0) {
+            goto failed;
+        }
+
+        imcf->width = (ngx_uint_t) n;
+
+    } else {
+        imcf->wcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->wcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->wcv = cv;
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[++i];
+    ccv.complex_value = &cv;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (cv.lengths == NULL) {
+        n = ngx_http_image_filter_value(&value[i]);
+
+        if (n == 0) {
+            goto failed;
+        }
+
+        imcf->height = (ngx_uint_t) n;
+
+    } else {
+        imcf->hcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->hcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->hcv = cv;
+    }
+
+    return NGX_CONF_OK;
+
+failed:
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
+                       &value[i]);
+
+    return NGX_CONF_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_image_filter_init(ngx_conf_t *cf)
+{
+    ngx_http_next_header_filter = ngx_http_top_header_filter;
+    ngx_http_top_header_filter = ngx_http_image_header_filter;
+
+    ngx_http_next_body_filter = ngx_http_top_body_filter;
+    ngx_http_top_body_filter = ngx_http_image_body_filter;
+
+    return NGX_OK;
+}
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -83,13 +83,13 @@ ngx_module_t  ngx_http_index_module = {
 
 
 /*
- * Try to open the first index file before the test of the directory existence
- * because the valid requests should be many more than invalid ones.
- * If open() would fail, then stat() should be more quickly because some data
- * is already cached in the kernel.
- * Besides, Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR).
- * Unix has ENOTDIR error, although it less helpfull - it points only
- * that path contains the usual file in place of the directory.
+ * Try to open/test the first index file before the test of directory
+ * existence because valid requests should be much more than invalid ones.
+ * If the file open()/stat() would fail, then the directory stat() should
+ * be more quickly because some data is already cached in the kernel.
+ * Besides, Win32 may return ERROR_PATH_NOT_FOUND (NGX_ENOTDIR) at once.
+ * Unix has ENOTDIR error, however, it's less helpful than Win32's one:
+ * it only indicates that path contains an usual file in place of directory.
  */
 
 static ngx_int_t
@@ -116,7 +116,6 @@ ngx_http_index_handler(ngx_http_request_
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
@@ -209,14 +208,15 @@ ngx_http_index_handler(ngx_http_request_
         of.directio = clcf->directio;
         of.valid = clcf->open_file_cache_valid;
         of.min_uses = clcf->open_file_cache_min_uses;
+        of.test_only = 1;
         of.errors = clcf->open_file_cache_errors;
         of.events = clcf->open_file_cache_events;
 
         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
             != NGX_OK)
         {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err,
-                           ngx_open_file_n " \"%s\" failed", path.data);
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err,
+                           "%s \"%s\" failed", of.failed, path.data);
 
             if (of.err == 0) {
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -240,8 +240,8 @@ ngx_http_index_handler(ngx_http_request_
                 continue;
             }
 
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
-                          ngx_open_file_n " \"%s\" failed", path.data);
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
+                          "%s \"%s\" failed", of.failed, path.data);
 
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
@@ -292,6 +292,7 @@ ngx_http_index_test_dir(ngx_http_request
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
     of.test_dir = 1;
+    of.test_only = 1;
     of.valid = clcf->open_file_cache_valid;
     of.errors = clcf->open_file_cache_errors;
 
@@ -319,7 +320,7 @@ ngx_http_index_test_dir(ngx_http_request
             }
 
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
-                          ngx_open_file_n " \"%s\" failed", dir.data);
+                          "%s \"%s\" failed", of.failed, dir.data);
         }
 
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -365,7 +366,7 @@ ngx_http_index_create_loc_conf(ngx_conf_
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->indices = NULL;
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -10,30 +10,39 @@
 
 
 typedef struct {
-    u_char              color;
-    u_char              dummy;
-    u_short             len;
-    ngx_queue_t         queue;
-    ngx_msec_t          last;
-    ngx_uint_t          excess; /* integer value, 1 corresponds to 0.001 r/s */
-    u_char              data[1];
+    u_char                       color;
+    u_char                       dummy;
+    u_short                      len;
+    ngx_queue_t                  queue;
+    ngx_msec_t                   last;
+    /* integer value, 1 corresponds to 0.001 r/s */
+    ngx_uint_t                   excess;
+    u_char                       data[1];
 } ngx_http_limit_req_node_t;
 
 
 typedef struct {
-    ngx_rbtree_t       *rbtree;
-    ngx_queue_t        *queue;
-    ngx_slab_pool_t    *shpool;
-    ngx_uint_t          rate;   /* integer value, 1 corresponds to 0.001 r/s */
-    ngx_int_t           index;
-    ngx_str_t           var;
+    ngx_rbtree_t                  rbtree;
+    ngx_rbtree_node_t             sentinel;
+    ngx_queue_t                   queue;
+} ngx_http_limit_req_shctx_t;
+
+
+typedef struct {
+    ngx_http_limit_req_shctx_t  *sh;
+    ngx_slab_pool_t             *shpool;
+    /* integer value, 1 corresponds to 0.001 r/s */
+    ngx_uint_t                   rate;
+    ngx_int_t                    index;
+    ngx_str_t                    var;
 } ngx_http_limit_req_ctx_t;
 
 
 typedef struct {
-    ngx_shm_zone_t     *shm_zone;
-    ngx_uint_t          burst;  /* integer value, 1 corresponds to 0.001 r/s */
-    ngx_uint_t          nodelay;/* unsigned  nodelay:1 */
+    ngx_shm_zone_t              *shm_zone;
+    /* integer value, 1 corresponds to 0.001 r/s */
+    ngx_uint_t                   burst;
+    ngx_uint_t                   nodelay;/* unsigned  nodelay:1 */
 } ngx_http_limit_req_conf_t;
 
 
@@ -163,7 +172,7 @@ ngx_http_limit_req_handler(ngx_http_requ
     if (lr) {
         ngx_queue_remove(&lr->queue);
 
-        ngx_queue_insert_head(ctx->queue, &lr->queue);
+        ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
 
         excess = lr->excess;
 
@@ -172,14 +181,14 @@ ngx_http_limit_req_handler(ngx_http_requ
     }
 
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                  "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
+                   "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
 
     if (rc == NGX_BUSY) {
         ngx_shmtx_unlock(&ctx->shpool->mutex);
 
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "limiting requests, excess: %ui.%03ui by zone \"%V\"",
-                      excess / 1000, excess % 1000, &lrcf->shm_zone->name);
+                      excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
 
         return NGX_HTTP_SERVICE_UNAVAILABLE;
     }
@@ -193,7 +202,7 @@ ngx_http_limit_req_handler(ngx_http_requ
 
         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
                       "delaying request, excess: %ui.%03ui, by zone \"%V\"",
-                      excess / 1000, excess % 1000, &lrcf->shm_zone->name);
+                      excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
 
         if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -239,9 +248,9 @@ ngx_http_limit_req_handler(ngx_http_requ
     lr->excess = 0;
     ngx_memcpy(lr->data, vv->data, len);
 
-    ngx_rbtree_insert(ctx->rbtree, node);
+    ngx_rbtree_insert(&ctx->sh->rbtree, node);
 
-    ngx_queue_insert_head(ctx->queue, &lr->queue);
+    ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
 
 done:
 
@@ -254,8 +263,23 @@ done:
 static void
 ngx_http_limit_req_delay(ngx_http_request_t *r)
 {
+    ngx_event_t  *wev;
+
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                  "limit_req delay");
+                   "limit_req delay");
+
+    wev = r->connection->write;
+
+    if (!wev->timedout) {
+
+        if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        }
+
+        return;
+    }
+
+    wev->timedout = 0;
 
     if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -324,8 +348,8 @@ ngx_http_limit_req_lookup(ngx_http_limit
 
     ctx = lrcf->shm_zone->data;
 
-    node = ctx->rbtree->root;
-    sentinel = ctx->rbtree->sentinel;
+    node = ctx->sh->rbtree.root;
+    sentinel = ctx->sh->rbtree.sentinel;
 
     while (node != sentinel) {
 
@@ -411,11 +435,11 @@ ngx_http_limit_req_expire(ngx_http_limit
 
     while (n < 3) {
 
-        if (ngx_queue_empty(ctx->queue)) {
+        if (ngx_queue_empty(&ctx->sh->queue)) {
             return;
         }
 
-        q = ngx_queue_last(ctx->queue);
+        q = ngx_queue_last(&ctx->sh->queue);
 
         lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue);
 
@@ -440,7 +464,7 @@ ngx_http_limit_req_expire(ngx_http_limit
         node = (ngx_rbtree_node_t *)
                    ((u_char *) lr - offsetof(ngx_rbtree_node_t, color));
 
-        ngx_rbtree_delete(ctx->rbtree, node);
+        ngx_rbtree_delete(&ctx->sh->rbtree, node);
 
         ngx_slab_free_locked(ctx->shpool, node);
     }
@@ -453,7 +477,6 @@ ngx_http_limit_req_init_zone(ngx_shm_zon
     ngx_http_limit_req_ctx_t  *octx = data;
 
     size_t                     len;
-    ngx_rbtree_node_t         *sentinel;
     ngx_http_limit_req_ctx_t  *ctx;
 
     ctx = shm_zone->data;
@@ -463,12 +486,11 @@ ngx_http_limit_req_init_zone(ngx_shm_zon
             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
                           "limit_req \"%V\" uses the \"%V\" variable "
                           "while previously it used the \"%V\" variable",
-                          &shm_zone->name, &ctx->var, &octx->var);
+                          &shm_zone->shm.name, &ctx->var, &octx->var);
             return NGX_ERROR;
         }
 
-        ctx->rbtree = octx->rbtree;
-        ctx->queue = octx->queue;
+        ctx->sh = octx->sh;
         ctx->shpool = octx->shpool;
 
         return NGX_OK;
@@ -476,27 +498,25 @@ ngx_http_limit_req_init_zone(ngx_shm_zon
 
     ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
-    ctx->rbtree = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_t));
-    if (ctx->rbtree == NULL) {
-        return NGX_ERROR;
+    if (shm_zone->shm.exists) {
+        ctx->sh = ctx->shpool->data;
+
+        return NGX_OK;
     }
 
-    sentinel = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
+    ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t));
+    if (ctx->sh == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_rbtree_init(ctx->rbtree, sentinel,
+    ctx->shpool->data = ctx->sh;
+
+    ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
                     ngx_http_limit_req_rbtree_insert_value);
 
-    ctx->queue = ngx_slab_alloc(ctx->shpool, sizeof(ngx_queue_t));
-    if (ctx->queue == NULL) {
-        return NGX_ERROR;
-    }
+    ngx_queue_init(&ctx->sh->queue);
 
-    ngx_queue_init(ctx->queue);
-
-    len = sizeof(" in limit_req zone \"\"") + shm_zone->name.len;
+    len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len;
 
     ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
     if (ctx->shpool->log_ctx == NULL) {
@@ -504,7 +524,7 @@ ngx_http_limit_req_init_zone(ngx_shm_zon
     }
 
     ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z",
-                &shm_zone->name);
+                &shm_zone->shm.name);
 
     return NGX_OK;
 }
@@ -517,7 +537,7 @@ ngx_http_limit_req_create_conf(ngx_conf_
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -574,6 +594,8 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, 
             p = (u_char *) ngx_strchr(name.data, ':');
 
             if (p) {
+                *p = '\0';
+
                 name.len = p - name.data;
 
                 p++;
@@ -744,7 +766,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c
     if (lrcf->shm_zone->data == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "unknown limit_req_zone \"%V\"",
-                           &lrcf->shm_zone->name);
+                           &lrcf->shm_zone->shm.name);
         return NGX_CONF_ERROR;
     }
 
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -191,7 +191,7 @@ ngx_http_limit_zone_handler(ngx_http_req
 
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                               "limiting connections by zone \"%V\"",
-                              &lzcf->shm_zone->name);
+                              &lzcf->shm_zone->shm.name);
 
                 return NGX_HTTP_SERVICE_UNAVAILABLE;
             }
@@ -328,7 +328,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
                           "limit_zone \"%V\" uses the \"%V\" variable "
                           "while previously it used the \"%V\" variable",
-                          &shm_zone->name, &ctx->var, &octx->var);
+                          &shm_zone->shm.name, &ctx->var, &octx->var);
             return NGX_ERROR;
         }
 
@@ -339,11 +339,19 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
+    if (shm_zone->shm.exists) {
+        ctx->rbtree = shpool->data;
+
+        return NGX_OK;
+    }
+
     ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
     if (ctx->rbtree == NULL) {
         return NGX_ERROR;
     }
 
+    shpool->data = ctx->rbtree;
+
     sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
     if (sentinel == NULL) {
         return NGX_ERROR;
@@ -352,14 +360,15 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
     ngx_rbtree_init(ctx->rbtree, sentinel,
                     ngx_http_limit_zone_rbtree_insert_value);
 
-    len = sizeof(" in limit_zone \"\"") + shm_zone->name.len;
+    len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len;
 
     shpool->log_ctx = ngx_slab_alloc(shpool, len);
     if (shpool->log_ctx == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", &shm_zone->name);
+    ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z",
+                &shm_zone->shm.name);
 
     return NGX_OK;
 }
@@ -372,7 +381,7 @@ ngx_http_limit_zone_create_conf(ngx_conf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -385,6 +385,8 @@ ngx_http_log_script_write(ngx_http_reque
 
         of.valid = clcf->open_file_cache_valid;
         of.min_uses = clcf->open_file_cache_min_uses;
+        of.test_dir = 1;
+        of.test_only = 1;
         of.errors = clcf->open_file_cache_errors;
         of.events = clcf->open_file_cache_events;
 
@@ -439,7 +441,7 @@ ngx_http_log_script_write(ngx_http_reque
         != NGX_OK)
     {
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                      ngx_open_file_n " \"%s\" failed", log.data);
+                      "%s \"%s\" failed", of.failed, log.data);
         /* simulate successfull logging */
         return len;
     }
@@ -674,7 +676,7 @@ ngx_http_log_escape(u_char *dst, u_char 
 
         /* find the number of the characters to be escaped */
 
-        n  = 0;
+        n = 0;
 
         for (i = 0; i < size; i++) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
@@ -712,18 +714,18 @@ ngx_http_log_create_main_conf(ngx_conf_t
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     fmt = ngx_array_push(&conf->formats);
     if (fmt == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     fmt->name.len = sizeof("combined") - 1;
@@ -733,7 +735,7 @@ ngx_http_log_create_main_conf(ngx_conf_t
 
     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
     if (fmt->ops == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return conf;
@@ -747,7 +749,7 @@ ngx_http_log_create_loc_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->open_file_cache = NGX_CONF_UNSET_PTR;
@@ -835,7 +837,13 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
 
     if (ngx_strcmp(value[1].data, "off") == 0) {
         llcf->off = 1;
-        return NGX_CONF_OK;
+        if (cf->args->nelts == 2) {
+            return NGX_CONF_OK;
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid parameter \"%V\"", &value[2]);
+        return NGX_CONF_ERROR;
     }
 
     if (llcf->logs == NULL) {
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -160,7 +160,7 @@ ngx_http_map_create_conf(ngx_conf_t *cf)
 
     mcf = ngx_palloc(cf->pool, sizeof(ngx_http_map_conf_t));
     if (mcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     mcf->hash_max_size = NGX_CONF_UNSET_UINT;
@@ -337,7 +337,7 @@ ngx_http_map_cmp_dns_wildcards(const voi
     first = (ngx_hash_key_t *) one;
     second = (ngx_hash_key_t *) two;
 
-    return ngx_strcmp(first->key.data, second->key.data);
+    return ngx_dns_strcmp(first->key.data, second->key.data);
 }
 
 
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -176,23 +176,18 @@ ngx_http_memcached_handler(ngx_http_requ
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
-
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
-    if (u == NULL) {
+    if (ngx_http_upstream_create(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    u = r->upstream;
+
     u->schema.len = sizeof("memcached://") - 1;
     u->schema.data = (u_char *) "memcached://";
 
-    u->peer.log = r->connection->log;
-    u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
+    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
 
-    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
+    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
 
     u->conf = &mlcf->upstream;
 
@@ -202,8 +197,6 @@ ngx_http_memcached_handler(ngx_http_requ
     u->abort_request = ngx_http_memcached_abort_request;
     u->finalize_request = ngx_http_memcached_finalize_request;
 
-    r->upstream = u;
-
     ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
     if (ctx == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -218,6 +211,8 @@ ngx_http_memcached_handler(ngx_http_requ
     u->input_filter = ngx_http_memcached_filter;
     u->input_filter_ctx = ctx;
 
+    r->main->count++;
+
     ngx_http_upstream_init(r);
 
     return NGX_DONE;
@@ -513,7 +508,7 @@ ngx_http_memcached_create_loc_conf(ngx_c
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -47,8 +47,8 @@ ngx_module_t  ngx_http_not_modified_filt
 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
 
 
-static
-ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r)
+static ngx_int_t
+ngx_http_not_modified_header_filter(ngx_http_request_t *r)
 {
     time_t                     ims;
     ngx_http_core_loc_conf_t  *clcf;
@@ -92,8 +92,8 @@ ngx_int_t ngx_http_not_modified_header_f
 }
 
 
-static
-ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf)
+static ngx_int_t
+ngx_http_not_modified_filter_init(ngx_conf_t *cf)
 {
     ngx_http_next_header_filter = ngx_http_top_header_filter;
     ngx_http_top_header_filter = ngx_http_not_modified_header_filter;
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -64,6 +64,10 @@ typedef struct {
     ngx_str_t                      location;
     ngx_str_t                      url;
 
+#if (NGX_HTTP_CACHE)
+    ngx_http_complex_value_t       cache_key;
+#endif
+
     ngx_http_proxy_vars_t          vars;
 
     ngx_flag_t                     redirect;
@@ -132,6 +136,8 @@ static char *ngx_http_proxy_store(ngx_co
 #if (NGX_HTTP_CACHE)
 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 #endif
 
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
@@ -161,11 +167,21 @@ static ngx_conf_bitmask_t  ngx_http_prox
     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+    { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
     { ngx_null_string, 0 }
 };
 
 
+static ngx_conf_bitmask_t  ngx_http_proxy_ignore_headers_masks[] = {
+    { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT },
+    { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES },
+    { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES },
+    { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL },
+    { ngx_null_string, 0 }
+};
+
+
 ngx_module_t  ngx_http_proxy_module;
 
 
@@ -327,6 +343,13 @@ static ngx_command_t  ngx_http_proxy_com
       0,
       NULL },
 
+    { ngx_string("proxy_cache_key"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_http_proxy_cache_key,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("proxy_cache_path"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
       ngx_http_file_cache_set_slot,
@@ -355,6 +378,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
       &ngx_http_proxy_next_upstream_masks },
 
+    { ngx_string("proxy_cache_methods"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
+      &ngx_http_upstream_cache_method_mask },
+
 #endif
 
     { ngx_string("proxy_temp_path"),
@@ -413,6 +443,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
       NULL },
 
+    { ngx_string("proxy_ignore_headers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
+      &ngx_http_proxy_ignore_headers_masks },
+
 #if (NGX_HTTP_SSL)
 
     { ngx_string("proxy_ssl_session_reuse"),
@@ -484,6 +521,40 @@ static ngx_str_t  ngx_http_proxy_hide_he
 };
 
 
+#if (NGX_HTTP_CACHE)
+
+static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
+    { ngx_string("Host"), ngx_string("$proxy_host") },
+    { ngx_string("Connection"), ngx_string("close") },
+    { ngx_string("Keep-Alive"), ngx_string("") },
+    { ngx_string("Expect"), ngx_string("") },
+    { ngx_string("If-Modified-Since"), ngx_string("") },
+    { ngx_string("If-Unmodified-Since"), ngx_string("") },
+    { ngx_string("If-Match-None"), ngx_string("") },
+    { ngx_string("If-Match"), ngx_string("") },
+    { ngx_string("Range"), ngx_string("") },
+    { ngx_string("If-Range"), ngx_string("") },
+    { ngx_null_string, ngx_null_string }
+};
+
+
+static ngx_str_t  ngx_http_proxy_hide_cache_headers[] = {
+    ngx_string("Date"),
+    ngx_string("Server"),
+    ngx_string("X-Pad"),
+    ngx_string("X-Accel-Expires"),
+    ngx_string("X-Accel-Redirect"),
+    ngx_string("X-Accel-Limit-Rate"),
+    ngx_string("X-Accel-Buffering"),
+    ngx_string("X-Accel-Charset"),
+    ngx_string("Set-Cookie"),
+    ngx_string("P3P"),
+    ngx_null_string
+};
+
+#endif
+
+
 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
 
     { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
@@ -519,13 +590,10 @@ ngx_http_proxy_handler(ngx_http_request_
     ngx_http_proxy_ctx_t       *ctx;
     ngx_http_proxy_loc_conf_t  *plcf;
 
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
-    if (u == NULL) {
+    if (ngx_http_upstream_create(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->upstream = u;
-
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
@@ -535,6 +603,8 @@ ngx_http_proxy_handler(ngx_http_request_
 
     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
 
+    u = r->upstream;
+
     if (plcf->proxy_lengths == 0) {
         ctx->vars = plcf->vars;
         u->schema = plcf->vars.schema;
@@ -548,12 +618,6 @@ ngx_http_proxy_handler(ngx_http_request_
         }
     }
 
-    u->peer.log = r->connection->log;
-    u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
-
     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
 
     u->conf = &plcf->upstream;
@@ -715,6 +779,15 @@ ngx_http_proxy_create_key(ngx_http_reque
         return NGX_ERROR;
     }
 
+    if (plcf->cache_key.value.len) {
+
+        if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        return NGX_OK;
+    }
+
     *key = ctx->vars.key_start;
 
     key = ngx_array_push(&r->cache->keys);
@@ -1804,15 +1877,17 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
      * set by ngx_pcalloc():
      *
      *     conf->upstream.bufs.num = 0;
+     *     conf->upstream.ignore_headers = 0;
      *     conf->upstream.next_upstream = 0;
-     *     conf->upstream.use_stale_cache = 0;
+     *     conf->upstream.cache_use_stale = 0;
+     *     conf->upstream.cache_methods = 0;
      *     conf->upstream.temp_path = NULL;
      *     conf->upstream.hide_headers_hash = { NULL, 0 };
      *     conf->upstream.uri = { 0, NULL };
@@ -1884,6 +1959,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_http_proxy_loc_conf_t *conf = child;
 
     size_t                      size;
+    ngx_str_t                  *h;
     ngx_keyval_t               *s;
     ngx_hash_init_t             hash;
     ngx_http_proxy_redirect_t  *pr;
@@ -1891,7 +1967,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
     if (conf->upstream.store != 0) {
         ngx_conf_merge_value(conf->upstream.store,
-                                  prev->upstream.store, 0);
+                              prev->upstream.store, 0);
 
         if (conf->upstream.store_lengths == NULL) {
             conf->upstream.store_lengths = prev->upstream.store_lengths;
@@ -2015,6 +2091,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     }
 
 
+    ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
+                              prev->upstream.ignore_headers,
+                              NGX_CONF_BITMASK_SET);
+
+
     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
                               prev->upstream.next_upstream,
                               (NGX_CONF_BITMASK_SET
@@ -2047,7 +2128,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "\"proxy_cache\" zone \"%V\" is unknown",
-                           &shm_zone->name);
+                           &shm_zone->shm.name);
 
         return NGX_CONF_ERROR;
     }
@@ -2060,6 +2141,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
                               (NGX_CONF_BITMASK_SET
                                |NGX_HTTP_UPSTREAM_FT_OFF));
 
+    if (conf->upstream.cache_methods == 0) {
+        conf->upstream.cache_methods = prev->upstream.cache_methods;
+    }
+
+    conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
+
     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
                                          |NGX_HTTP_UPSTREAM_FT_OFF;
@@ -2068,6 +2155,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                              prev->upstream.cache_valid, NULL);
 
+    if (conf->cache_key.value.data == NULL) {
+        conf->cache_key = prev->cache_key;
+    }
+
 #endif
 
     if (conf->method.len == 0) {
@@ -2131,6 +2222,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
         conf->proxy_values = prev->proxy_values;
     }
 
+#if (NGX_HTTP_SSL)
+    if (conf->upstream.ssl == NULL) {
+        conf->upstream.ssl = prev->upstream.ssl;
+    }
+#endif
+
     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
                               prev->headers_hash_max_size, 512);
 
@@ -2144,9 +2241,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     hash.bucket_size = conf->headers_hash_bucket_size;
     hash.name = "proxy_headers_hash";
 
+#if (NGX_HTTP_CACHE)
+
+    h = conf->upstream.cache ? ngx_http_proxy_hide_cache_headers:
+                               ngx_http_proxy_hide_headers;
+#else
+
+    h = ngx_http_proxy_hide_headers;
+
+#endif
+
     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
-                                            &prev->upstream,
-                                            ngx_http_proxy_hide_headers, &hash)
+                                            &prev->upstream, h, &hash)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -2229,7 +2335,12 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
         conf->headers_source = prev->headers_source;
     }
 
-    if (conf->headers_set_hash.buckets) {
+    if (conf->headers_set_hash.buckets
+#if (NGX_HTTP_CACHE)
+        && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+#endif
+       )
+    {
         return NGX_OK;
     }
 
@@ -2260,7 +2371,17 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
 
     src = conf->headers_source->elts;
 
-    for (h = ngx_http_proxy_headers; h->key.len; h++) {
+#if (NGX_HTTP_CACHE)
+
+    h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
+                               ngx_http_proxy_headers;
+#else
+
+    h = ngx_http_proxy_headers;
+
+#endif
+
+    while (h->key.len) {
 
         for (i = 0; i < conf->headers_source->nelts; i++) {
             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
@@ -2279,7 +2400,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
 
     next:
 
-        continue;
+        h++;
     }
 
 
@@ -2464,6 +2585,12 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
 
+    clcf->handler = ngx_http_proxy_handler;
+
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
     value = cf->args->elts;
 
     url = &value[1];
@@ -2492,8 +2619,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
         }
 #endif
 
-        clcf->handler = ngx_http_proxy_handler;
-
         return NGX_CONF_OK;
     }
 
@@ -2540,8 +2665,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
     ngx_http_proxy_set_vars(&u, &plcf->vars);
 
-    clcf->handler = ngx_http_proxy_handler;
-
     plcf->location = clcf->name;
 
     if (clcf->named
@@ -2565,10 +2688,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
     plcf->url = *url;
 
-    if (clcf->name.data[clcf->name.len - 1] == '/') {
-        clcf->auto_redirect = 1;
-    }
-
     return NGX_CONF_OK;
 }
 
@@ -2589,10 +2708,26 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, 
 
     value = cf->args->elts;
 
-    if (ngx_strcmp(value[1].data, "off") == 0) {
-        plcf->redirect = 0;
-        plcf->redirects = NULL;
-        return NGX_CONF_OK;
+    if (cf->args->nelts == 2) {
+        if (ngx_strcmp(value[1].data, "off") == 0) {
+            plcf->redirect = 0;
+            plcf->redirects = NULL;
+            return NGX_CONF_OK;
+        }
+
+        if (ngx_strcmp(value[1].data, "false") == 0) {
+            ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
+                           "invalid parameter \"false\", use \"off\" instead");
+            plcf->redirect = 0;
+            plcf->redirects = NULL;
+            return NGX_CONF_OK;
+        }
+
+        if (ngx_strcmp(value[1].data, "default") != 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
     }
 
     if (plcf->redirects == NULL) {
@@ -2608,7 +2743,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, 
         return NGX_CONF_ERROR;
     }
 
-    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) {
+    if (ngx_strcmp(value[1].data, "default") == 0) {
         if (plcf->url.data == NULL) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"proxy_rewrite_location default\" must go "
@@ -2671,20 +2806,31 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx
     ngx_str_t                  *value;
     ngx_http_script_compile_t   sc;
 
-    if (plcf->upstream.store != NGX_CONF_UNSET || plcf->upstream.store_lengths)
+    if (plcf->upstream.store != NGX_CONF_UNSET
+        || plcf->upstream.store_lengths)
     {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    if (ngx_strcmp(value[1].data, "on") == 0) {
-        plcf->upstream.store = 1;
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        plcf->upstream.store = 0;
         return NGX_CONF_OK;
     }
 
-    if (ngx_strcmp(value[1].data, "off") == 0) {
-        plcf->upstream.store = 0;
+#if (NGX_HTTP_CACHE)
+
+    if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
+        && plcf->upstream.cache != NULL)
+    {
+        return "is incompatible with \"proxy_cache\"";
+    }
+
+#endif
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        plcf->upstream.store = 1;
         return NGX_CONF_OK;
     }
 
@@ -2729,6 +2875,10 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx
         return NGX_CONF_OK;
     }
 
+    if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
+        return "is incompatible with \"proxy_store\"";
+    }
+
     plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
                                                  &ngx_http_proxy_module);
     if (plcf->upstream.cache == NULL) {
@@ -2738,6 +2888,34 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx
     return NGX_CONF_OK;
 }
 
+
+static char *
+ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_proxy_loc_conf_t *plcf = conf;
+
+    ngx_str_t                         *value;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    if (plcf->cache_key.value.len) {
+        return "is duplicate";
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = &plcf->cache_key;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
 #endif
 
 
--- a/src/http/modules/ngx_http_random_index_module.c
+++ b/src/http/modules/ngx_http_random_index_module.c
@@ -86,7 +86,6 @@ ngx_http_random_index_handler(ngx_http_r
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
@@ -281,7 +280,7 @@ ngx_http_random_index_create_loc_conf(ng
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -456,6 +456,8 @@ ngx_http_range_multipart_header(ngx_http
         return NGX_ERROR;
     }
 
+    r->headers_out.content_type_lowcase = NULL;
+
     /* "Content-Type: multipart/byteranges; boundary=0123456789" */
 
     r->headers_out.content_type.len =
@@ -464,6 +466,7 @@ ngx_http_range_multipart_header(ngx_http
                                        boundary)
                            - r->headers_out.content_type.data;
 
+    r->headers_out.content_type_len = r->headers_out.content_type.len;
 
     /* the size of the last boundary CRLF "--0123456789--" CRLF */
 
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -360,7 +360,7 @@ ngx_http_realip_create_loc_conf(ngx_conf
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -221,7 +221,7 @@ ngx_http_referer_create_conf(ngx_conf_t 
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
 #if (NGX_PCRE)
@@ -506,6 +506,11 @@ ngx_http_add_regex_referer(ngx_conf_t *c
     ngx_regex_elt_t  *re;
     u_char            errstr[NGX_MAX_CONF_ERRSTR];
 
+    if (name->len == 1) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name);
+        return NGX_CONF_ERROR;
+    }
+
     if (rlcf->regex == NGX_CONF_UNSET_PTR) {
         rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t));
         if (rlcf->regex == NULL) {
@@ -562,5 +567,5 @@ ngx_http_cmp_referer_wildcards(const voi
     first = (ngx_hash_key_t *) one;
     second = (ngx_hash_key_t *) two;
 
-    return ngx_strcmp(first->key.data, second->key.data);
+    return ngx_dns_strcmp(first->key.data, second->key.data);
 }
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -220,7 +220,7 @@ ngx_http_rewrite_create_loc_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     conf->stack_size = NGX_CONF_UNSET_UINT;
@@ -568,7 +568,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
 
     if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
     if (if_code == NULL) {
-        return NULL;
+        return NGX_CONF_ERROR;
     }
 
     if_code->code = ngx_http_script_if_code;
--- a/src/http/modules/ngx_http_secure_link_module.c
+++ b/src/http/modules/ngx_http_secure_link_module.c
@@ -152,7 +152,7 @@ ngx_http_secure_link_create_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -360,6 +360,7 @@ ngx_http_ssi_header_filter(ngx_http_requ
     if (r == r->main) {
         ngx_http_clear_content_length(r);
         ngx_http_clear_last_modified(r);
+        ngx_http_clear_accept_ranges(r);
     }
 
     return ngx_http_next_header_filter(r);
@@ -2689,14 +2690,14 @@ ngx_http_ssi_create_main_conf(ngx_conf_t
 
     smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_main_conf_t));
     if (smcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     smcf->commands.pool = cf->pool;
     smcf->commands.temp_pool = cf->temp_pool;
 
     if (ngx_hash_keys_array_init(&smcf->commands, NGX_HASH_SMALL) != NGX_OK) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return smcf;
@@ -2736,7 +2737,7 @@ ngx_http_ssi_create_loc_conf(ngx_conf_t 
 
     slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_loc_conf_t));
     if (slcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -31,15 +31,6 @@ static char *ngx_http_ssl_enable(ngx_con
 static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-
-static char  ngx_http_ssl_openssl097[] = "OpenSSL 0.9.7 and higher";
-
-#endif
-
 
 static ngx_conf_bitmask_t  ngx_http_ssl_protocols[] = {
     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
@@ -52,7 +43,7 @@ static ngx_conf_bitmask_t  ngx_http_ssl_
 static ngx_conf_enum_t  ngx_http_ssl_verify[] = {
     { ngx_string("off"), 0 },
     { ngx_string("on"), 1 },
-    { ngx_string("ask"), 2 },
+    { ngx_string("optional"), 2 },
     { ngx_null_string, 0 }
 };
 
@@ -124,14 +115,10 @@ static ngx_command_t  ngx_http_ssl_comma
 
     { ngx_string("ssl_prefer_server_ciphers"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
       ngx_conf_set_flag_slot,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers),
       NULL },
-#else
-      ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 },
-#endif
 
     { ngx_string("ssl_session_cache"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
@@ -147,6 +134,13 @@ static ngx_command_t  ngx_http_ssl_comma
       offsetof(ngx_http_ssl_srv_conf_t, session_timeout),
       NULL },
 
+    { ngx_string("ssl_crl"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_ssl_srv_conf_t, crl),
+      NULL },
+
       ngx_null_command
 };
 
@@ -206,6 +200,9 @@ static ngx_http_variable_t  ngx_http_ssl
     { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
@@ -302,7 +299,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
 
     sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
     if (sscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -313,6 +310,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
      *     sscf->certificate_key = { 0, NULL };
      *     sscf->dhparam = { 0, NULL };
      *     sscf->client_certificate = { 0, NULL };
+     *     sscf->crl = { 0, NULL };
      *     sscf->ciphers.len = 0;
      *     sscf->ciphers.data = NULL;
      *     sscf->shm_zone = NULL;
@@ -320,8 +318,8 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
 
     sscf->enable = NGX_CONF_UNSET;
     sscf->prefer_server_ciphers = NGX_CONF_UNSET;
-    sscf->verify = NGX_CONF_UNSET;
-    sscf->verify_depth = NGX_CONF_UNSET;
+    sscf->verify = NGX_CONF_UNSET_UINT;
+    sscf->verify_depth = NGX_CONF_UNSET_UINT;
     sscf->builtin_session_cache = NGX_CONF_UNSET;
     sscf->session_timeout = NGX_CONF_UNSET;
 
@@ -359,6 +357,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 
     ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
                          "");
+    ngx_conf_merge_str_value(conf->crl, prev->crl, "");
 
     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
 
@@ -407,9 +406,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
                                                ngx_http_ssl_servername)
         == 0)
     {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_set_tlsext_servername_callback() failed");
-        return NGX_CONF_ERROR;
+        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+            "nginx was build with SNI support, however, now it is linked "
+            "dynamically to an OpenSSL library which has no tlsext support, "
+            "therefore SNI is not available");
     }
 
 #endif
@@ -453,16 +453,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         {
             return NGX_CONF_ERROR;
         }
+
+        if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
     }
 
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
-
     if (conf->prefer_server_ciphers) {
         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
     }
 
-#endif
-
     /* a temporary 512-bit RSA key is required for export versions of MSIE */
     if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
         return NGX_CONF_ERROR;
@@ -564,6 +564,7 @@ ngx_http_ssl_session_cache(ngx_conf_t *c
 
             for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
                 if (value[i].data[j] == ':') {
+                    value[i].data[j] = '\0';
                     break;
                 }
 
@@ -619,18 +620,3 @@ invalid:
 
     return NGX_CONF_ERROR;
 }
-
-
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *
-ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"%V\" directive is available only in %s,",
-                       &cmd->name, cmd->post);
-
-    return NGX_CONF_ERROR;
-}
-
-#endif
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -33,6 +33,7 @@ typedef struct {
     ngx_str_t                       certificate_key;
     ngx_str_t                       dhparam;
     ngx_str_t                       client_certificate;
+    ngx_str_t                       crl;
 
     ngx_str_t                       ciphers;
 
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -66,7 +66,6 @@ ngx_http_static_handler(ngx_http_request
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
@@ -129,7 +128,7 @@ ngx_http_static_handler(ngx_http_request
 
         if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
             ngx_log_error(level, log, of.err,
-                          ngx_open_file_n " \"%s\" failed", path.data);
+                          "%s \"%s\" failed", of.failed, path.data);
         }
 
         return rc;
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -638,7 +638,7 @@ ngx_http_sub_create_conf(ngx_conf_t *cf)
 
     slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t));
     if (slcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -390,12 +390,13 @@ ngx_http_userid_set_uid(ngx_http_request
 
         } else {
             if (conf->service == NGX_CONF_UNSET) {
-                if (ngx_http_server_addr(r, NULL) != NGX_OK) {
+
+                c = r->connection;
+
+                if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
                     return NGX_ERROR;
                 }
 
-                c = r->connection;
-
                 switch (c->local_sockaddr->sa_family) {
 
 #if (NGX_HAVE_INET6)
@@ -569,7 +570,7 @@ ngx_http_userid_create_conf(ngx_conf_t *
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -64,7 +64,6 @@ typedef struct {
 
 static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r,
     ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
-static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r);
 static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r,
     ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
 
@@ -195,7 +194,7 @@ ngx_module_t  ngx_http_xslt_filter_modul
     NULL,                                  /* init process */
     NULL,                                  /* init thread */
     NULL,                                  /* exit thread */
-    ngx_http_xslt_filter_exit,            /* exit process */
+    ngx_http_xslt_filter_exit,             /* exit process */
     ngx_http_xslt_filter_exit,             /* exit master */
     NGX_MODULE_V1_PADDING
 };
@@ -248,6 +247,7 @@ ngx_http_xslt_header_filter(ngx_http_req
 static ngx_int_t
 ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
+    int                          wellFormed;
     ngx_chain_t                 *cl;
     ngx_http_xslt_filter_ctx_t  *ctx;
 
@@ -281,7 +281,7 @@ ngx_http_xslt_body_filter(ngx_http_reque
             return ngx_http_xslt_send(r, ctx, NULL);
         }
 
-        if (cl->buf->last_buf) {
+        if (cl->buf->last_buf || cl->buf->last_in_chain) {
 
             ctx->doc = ctx->ctxt->myDoc;
 
@@ -289,9 +289,11 @@ ngx_http_xslt_body_filter(ngx_http_reque
             ctx->doc->extSubset = NULL;
 #endif
 
+            wellFormed = ctx->ctxt->wellFormed;
+
             xmlFreeParserCtxt(ctx->ctxt);
 
-            if (ctx->ctxt->wellFormed) {
+            if (wellFormed) {
                 return ngx_http_xslt_send(r, ctx,
                                        ngx_http_xslt_apply_stylesheet(r, ctx));
             }
@@ -320,14 +322,15 @@ ngx_http_xslt_send(ngx_http_request_t *r
     ctx->done = 1;
 
     if (b == NULL) {
-        return ngx_http_xslt_filter_internal_error(r);
+        return ngx_http_filter_finalize_request(r, NULL,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
     }
 
     cln = ngx_pool_cleanup_add(r->pool, 0);
 
     if (cln == NULL) {
         ngx_free(b->pos);
-        return ngx_http_special_response_handler(r,
+        return ngx_http_filter_finalize_request(r, NULL,
                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
     }
 
@@ -360,22 +363,6 @@ ngx_http_xslt_send(ngx_http_request_t *r
 
 
 static ngx_int_t
-ngx_http_xslt_filter_internal_error(ngx_http_request_t *r)
-{
-    ngx_int_t  rc;
-
-    /* clear the modules contexts */
-    ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
-
-    rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-
-    /* NGX_ERROR resets any pending data */
-
-    return (rc == NGX_OK) ? NGX_ERROR : rc;
-}
-
-
-static ngx_int_t
 ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
     ngx_buf_t *b)
 {
@@ -417,7 +404,7 @@ ngx_http_xslt_add_chunk(ngx_http_request
         sax->endElementNs = ngx_http_xslt_sax_end_element;
 
         sax->characters = ngx_http_xslt_sax_characters;
-        sax->ignorableWhitespace  = ngx_http_xslt_sax_characters;
+        sax->ignorableWhitespace = ngx_http_xslt_sax_characters;
         sax->cdataBlock = ngx_http_xslt_sax_cdata_block;
         sax->getEntity = ngx_http_xslt_sax_get_entity;
         sax->resolveEntity = ngx_http_xslt_sax_resolve_entity;
@@ -443,8 +430,8 @@ ngx_http_xslt_add_chunk(ngx_http_request
         ctx->request = r;
     }
 
-    err = xmlParseChunk(ctx->ctxt, (char *) b->pos,
-                        (int) (b->last - b->pos), b->last_buf);
+    err = xmlParseChunk(ctx->ctxt, (char *) b->pos, (int) (b->last - b->pos),
+                        (b->last_buf) || (b->last_in_chain));
 
     if (err == 0) {
         b->pos = b->last;
@@ -733,7 +720,7 @@ ngx_http_xslt_sax_error(void *data, cons
     while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ }
 
     ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
-                  "libxml2 error: \"%*s\"", n, buf);
+                  "libxml2 error: \"%*s\"", n + 1, buf);
 }
 
 
@@ -828,7 +815,6 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
     b->pos = buf;
     b->last = buf + len;
     b->memory = 1;
-    b->last_buf = 1;
 
     if (encoding) {
         r->headers_out.charset.len = ngx_strlen(encoding);
@@ -839,6 +825,8 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
         return b;
     }
 
+    b->last_buf = 1;
+
     if (type) {
         len = ngx_strlen(type);
 
@@ -853,6 +841,8 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
         r->headers_out.content_type.data = (u_char *) "text/html";
     }
 
+    r->headers_out.content_type_lowcase = NULL;
+
     return b;
 }
 
@@ -1182,7 +1172,7 @@ ngx_http_xslt_filter_create_main_conf(ng
 
     conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&conf->dtd_files, cf->pool, 1,
@@ -1210,7 +1200,7 @@ ngx_http_xslt_filter_create_conf(ngx_con
 
     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t));
     if (conf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.7.47';
+our $VERSION = '0.8.16';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -607,7 +607,7 @@ sendfile(r, filename, offset = -1, bytes
 
     ngx_http_request_t        *r;
     char                      *filename;
-    int                        offset;
+    off_t                      offset;
     size_t                     bytes;
     ngx_str_t                  path;
     ngx_buf_t                 *b;
@@ -662,7 +662,7 @@ sendfile(r, filename, offset = -1, bytes
         }
 
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                      ngx_open_file_n " \"%s\" failed", filename);
+                      "%s \"%s\" failed", of.failed, filename);
         XSRETURN_EMPTY;
     }
 
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -154,10 +154,14 @@ static ngx_http_ssi_command_t  ngx_http_
 #endif
 
 
-static ngx_str_t  ngx_null_name = ngx_null_string;
+static ngx_str_t    ngx_null_name = ngx_null_string;
+
+static HV          *nginx_stash;
 
+#if (NGX_HAVE_PERL_MULTIPLICITY)
+static ngx_uint_t   ngx_perl_term;
+#endif
 
-static HV  *nginx_stash;
 
 static void
 ngx_http_perl_xs_init(pTHX)
@@ -171,11 +175,12 @@ ngx_http_perl_xs_init(pTHX)
 static ngx_int_t
 ngx_http_perl_handler(ngx_http_request_t *r)
 {
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_HTTP_NOT_FOUND;
     }
 
+    r->main->count++;
+
     ngx_http_perl_handle_request(r);
 
     return NGX_DONE;
@@ -229,7 +234,11 @@ ngx_http_perl_handle_request(ngx_http_re
 
     }
 
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "perl handler done: %i", rc);
+
     if (rc == NGX_DONE) {
+        ngx_http_finalize_request(r, rc);
         return;
     }
 
@@ -237,9 +246,6 @@ ngx_http_perl_handle_request(ngx_http_re
         rc = NGX_OK;
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "perl handler done: %i", rc);
-
     if (ctx->redirect_uri.len) {
         uri = ctx->redirect_uri;
         args = ctx->redirect_args;
@@ -252,11 +258,13 @@ ngx_http_perl_handle_request(ngx_http_re
     ctx->redirect_uri.len = 0;
 
     if (ctx->done || ctx->next) {
+        ngx_http_finalize_request(r, NGX_DONE);
         return;
     }
 
     if (uri.len) {
         ngx_http_internal_redirect(r, &uri, &args);
+        ngx_http_finalize_request(r, NGX_DONE);
         return;
     }
 
@@ -683,15 +691,6 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
 
     SPAGAIN;
 
-    if (c->destroyed) {
-        PUTBACK;
-
-        FREETMPS;
-        LEAVE;
-
-        return NGX_DONE;
-    }
-
     if (n) {
         if (rv == NULL) {
             status = POPi;
@@ -762,7 +761,10 @@ ngx_http_perl_eval_anon_sub(pTHX_ ngx_st
         }
     }
 
-    if (ngx_strncmp(p, "sub ", 4) == 0 || ngx_strncmp(p, "use ", 4) == 0) {
+    if (ngx_strncmp(p, "sub ", 4) == 0
+        || ngx_strncmp(p, "sub{", 4) == 0
+        || ngx_strncmp(p, "use ", 4) == 0)
+    {
         *sv = eval_pv((char *) p, FALSE);
 
         /* eval_pv() does not set ERRSV on failure */
@@ -781,7 +783,7 @@ ngx_http_perl_create_main_conf(ngx_conf_
 
     pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t));
     if (pmcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *))
@@ -821,6 +823,12 @@ ngx_http_perl_cleanup_perl(void *data)
     (void) perl_destruct(perl);
 
     perl_free(perl);
+
+    if (ngx_perl_term) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "perl term");
+
+        PERL_SYS_TERM();
+    }
 }
 
 #endif
@@ -860,7 +868,7 @@ ngx_http_perl_create_loc_conf(ngx_conf_t
 
     plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t));
     if (plcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -1041,15 +1049,13 @@ ngx_http_perl_init_worker(ngx_cycle_t *c
 
     pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module);
 
-    {
-
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
+    if (pmcf) {
+        dTHXa(pmcf->perl);
+        PERL_SET_CONTEXT(pmcf->perl);
 
-    /* set worker's $$ */
+        /* set worker's $$ */
 
-    sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid);
-
+        sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid);
     }
 
     return NGX_OK;
@@ -1059,16 +1065,24 @@ ngx_http_perl_init_worker(ngx_cycle_t *c
 static void
 ngx_http_perl_exit(ngx_cycle_t *cycle)
 {
+#if (NGX_HAVE_PERL_MULTIPLICITY)
+
+    ngx_perl_term = 1;
+
+#else
     ngx_http_perl_main_conf_t  *pmcf;
 
     pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module);
 
-    {
+    if (pmcf && nginx_stash) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term");
 
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
+        (void) perl_destruct(pmcf->perl);
 
-    PERL_SYS_TERM();
+        perl_free(pmcf->perl);
 
+        PERL_SYS_TERM();
     }
+
+#endif
 }
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -18,7 +18,7 @@ static ngx_int_t ngx_http_init_phase_han
     ngx_http_core_main_conf_t *cmcf);
 
 static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf,
-    ngx_array_t *servers, ngx_array_t *in_ports);
+    ngx_array_t *servers, ngx_array_t *ports);
 static ngx_int_t ngx_http_add_ports(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_array_t *ports,
     ngx_http_listen_t *listen);
@@ -122,7 +122,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     char                        *rv;
     ngx_uint_t                   mi, m, s;
     ngx_conf_t                   pcf;
-    ngx_array_t                  in_ports;
+    ngx_array_t                  ports;
     ngx_http_module_t           *module;
     ngx_http_conf_ctx_t         *ctx;
     ngx_http_core_loc_conf_t    *clcf;
@@ -367,14 +367,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
      * to find quickly the server core module configuration at run-time
      */
 
-    if (ngx_http_init_server_lists(cf, &cmcf->servers, &in_ports) != NGX_OK) {
+    if (ngx_http_init_server_lists(cf, &cmcf->servers, &ports) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
 
     /* optimize the lists of ports, addresses and server names */
 
-    if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) {
+    if (ngx_http_optimize_servers(cf, cmcf, &ports) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
@@ -1180,12 +1180,12 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h
             continue;
         }
 
-        /* a port is already in the in_port list */
+        /* a port is already in the port list */
 
         return ngx_http_add_addresses(cf, cscf, &port[i], listen);
     }
 
-    /* add a port to the in_port list */
+    /* add a port to the port list */
 
     port = ngx_array_push(ports);
     if (port == NULL) {
@@ -1279,7 +1279,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 
 /*
  * add the server address, the server names and the server core module
- * configurations to the port (in_port)
+ * configurations to the port list
  */
 
 static ngx_int_t
@@ -1373,10 +1373,10 @@ static ngx_int_t
 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_array_t *ports)
 {
-    ngx_uint_t                s, p, a;
-    ngx_http_conf_port_t     *port;
-    ngx_http_conf_addr_t     *addr;
-    ngx_http_server_name_t   *name;
+    ngx_uint_t               s, p, a;
+    ngx_http_conf_port_t    *port;
+    ngx_http_conf_addr_t    *addr;
+    ngx_http_server_name_t  *name;
 
     port = ports->elts;
     for (p = 0; p < ports->nelts; p++) {
@@ -1425,13 +1425,13 @@ static ngx_int_t
 ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_http_conf_addr_t *addr)
 {
-    ngx_int_t                  rc;
-    ngx_uint_t                 s;
-    ngx_hash_init_t            hash;
-    ngx_http_server_name_t    *name;
-    ngx_hash_keys_arrays_t     ha;
+    ngx_int_t                rc;
+    ngx_uint_t               s;
+    ngx_hash_init_t          hash;
+    ngx_hash_keys_arrays_t   ha;
+    ngx_http_server_name_t  *name;
 #if (NGX_PCRE)
-    ngx_uint_t                 regex, i;
+    ngx_uint_t               regex, i;
 
     regex = 0;
 #endif
@@ -1601,7 +1601,7 @@ ngx_http_cmp_dns_wildcards(const void *o
     first = (ngx_hash_key_t *) one;
     second = (ngx_hash_key_t *) two;
 
-    return ngx_strcmp(first->key.data, second->key.data);
+    return ngx_dns_strcmp(first->key.data, second->key.data);
 }
 
 
@@ -1688,54 +1688,14 @@ static ngx_listening_t *
 ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
 {
     ngx_listening_t           *ls;
-    struct sockaddr           *sa;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
-    u_char                     text[NGX_SOCKADDR_STRLEN];
 
-    ls = ngx_array_push(&cf->cycle->listening);
+    ls = ngx_create_listening(cf, addr->sockaddr, addr->socklen);
     if (ls == NULL) {
         return NULL;
     }
 
-    ngx_memzero(ls, sizeof(ngx_listening_t));
-
-    sa = ngx_palloc(cf->pool, addr->socklen);
-    if (sa == NULL) {
-        return NULL;
-    }
-
-    ngx_memcpy(sa, addr->sockaddr, addr->socklen);
-
-    ls->sockaddr = sa;
-    ls->socklen = addr->socklen;
-
-    ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
-
-    ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len);
-    if (ls->addr_text.data == NULL) {
-        return NULL;
-    }
-
-    ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len);
-
-    ls->fd = (ngx_socket_t) -1;
-    ls->type = SOCK_STREAM;
-
-    switch (ls->sockaddr->sa_family) {
-#if (NGX_HAVE_INET6)
-    case AF_INET6:
-         ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
-         break;
-#endif
-    case AF_INET:
-         ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
-         break;
-    default:
-         ls->addr_text_max_len = NGX_SOCKADDR_STRLEN;
-         break;
-    }
-
     ls->addr_ntop = 1;
 
     ls->handler = ngx_http_init_connection;
@@ -1746,7 +1706,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n
 
     clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
 
-    ls->log = *clcf->err_log;
+    ls->logp = clcf->error_log;
     ls->log.data = &ls->addr_text;
     ls->log.handler = ngx_accept_log_error;
 
@@ -1825,7 +1785,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h
             return NGX_ERROR;
         }
 
-        addrs[i].conf.core_srv_conf->virtual_names = vn;
+        addrs[i].conf.virtual_names = vn;
 
         vn->names.hash = addr[i].hash;
         vn->names.wc_head = addr[i].wc_head;
@@ -1882,7 +1842,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_
             return NGX_ERROR;
         }
 
-        addrs6[i].conf.core_srv_conf->virtual_names = vn;
+        addrs6[i].conf.virtual_names = vn;
 
         vn->names.hash = addr[i].hash;
         vn->names.wc_head = addr[i].wc_head;
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -84,13 +84,17 @@ ngx_int_t ngx_http_find_server_conf(ngx_
 void ngx_http_update_location_config(ngx_http_request_t *r);
 void ngx_http_handler(ngx_http_request_t *r);
 void ngx_http_run_posted_requests(ngx_connection_t *c);
-ngx_int_t ngx_http_post_request(ngx_http_request_t *r);
+ngx_int_t ngx_http_post_request(ngx_http_request_t *r,
+    ngx_http_posted_request_t *pr);
 void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
 
 void ngx_http_empty_handler(ngx_event_t *wev);
 void ngx_http_request_empty_handler(ngx_http_request_t *r);
 
 
+#define ngx_http_ephemeral(r)  (ngx_http_ephemeral_t *) (&r->uri_start)
+
+
 #define NGX_HTTP_LAST   1
 #define NGX_HTTP_FLUSH  2
 
@@ -103,6 +107,9 @@ ngx_int_t ngx_http_read_client_request_b
 ngx_int_t ngx_http_send_header(ngx_http_request_t *r);
 ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r,
     ngx_int_t error);
+ngx_int_t ngx_http_filter_finalize_request(ngx_http_request_t *r,
+    ngx_module_t *m, ngx_int_t error);
+void ngx_http_clean_header(ngx_http_request_t *r);
 
 
 time_t ngx_http_parse_time(u_char *value, size_t len);
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -13,11 +13,12 @@
 #include <ngx_http.h>
 
 
-/**/
-#define NGX_HTTP_CACHE_STALE         1
-#define NGX_HTTP_CACHE_AGED          2
-#define NGX_HTTP_CACHE_THE_SAME      3
-/**/
+#define NGX_HTTP_CACHE_MISS          1
+#define NGX_HTTP_CACHE_EXPIRED       2
+#define NGX_HTTP_CACHE_STALE         3
+#define NGX_HTTP_CACHE_UPDATING      4
+#define NGX_HTTP_CACHE_HIT           5
+#define NGX_HTTP_CACHE_SCARCE        6
 
 #define NGX_HTTP_CACHE_KEY_LEN       16
 
@@ -28,8 +29,6 @@ typedef struct {
 } ngx_http_cache_valid_t;
 
 
-/* ngx_http_file_cache_node_t takes exactly 64 bytes on FreeBSD/i386 */
-
 typedef struct {
     ngx_rbtree_node_t                node;
     ngx_queue_t                      queue;
@@ -41,8 +40,9 @@ typedef struct {
     unsigned                         uses:10;
     unsigned                         valid_msec:10;
     unsigned                         error:10;
-                                     /* 7 unused bits */
     unsigned                         exists:1;
+    unsigned                         updating:1;
+                                     /* 12 unused bits */
 
     ngx_file_uniq_t                  uniq;
     time_t                           expire;
@@ -68,7 +68,6 @@ struct ngx_http_cache_s {
     off_t                            length;
 
     ngx_uint_t                       min_uses;
-    ngx_uint_t                       uses;
     ngx_uint_t                       error;
     ngx_uint_t                       valid_msec;
 
@@ -94,16 +93,22 @@ typedef struct {
 } ngx_http_file_cache_header_t;
 
 
+typedef struct {
+    ngx_rbtree_t                     rbtree;
+    ngx_rbtree_node_t                sentinel;
+    ngx_queue_t                      queue;
+    ngx_atomic_t                     cold;
+    ngx_atomic_t                     loading;
+    off_t                            size;
+} ngx_http_file_cache_sh_t;
+
+
 struct ngx_http_file_cache_s {
-    ngx_rbtree_t                    *rbtree;
-    ngx_queue_t                     *queue;
+    ngx_http_file_cache_sh_t        *sh;
     ngx_slab_pool_t                 *shpool;
 
     ngx_path_t                      *path;
 
-    ngx_atomic_t                    *cold;
-    off_t                           *size;
-
     off_t                            max_size;
     size_t                           bsize;
 
@@ -124,11 +129,12 @@ ngx_int_t ngx_http_cache_send(ngx_http_r
 void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf);
 time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
 
-
 char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
+extern ngx_str_t  ngx_http_cache_status[];
+
 
 #endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -69,8 +69,10 @@ typedef struct {
     ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index]
 
 #define ngx_http_cycle_get_module_main_conf(cycle, module)                    \
-    ((ngx_http_conf_ctx_t *)                                                  \
-         cycle->conf_ctx[ngx_http_module.index])->main_conf[module.ctx_index]
+    (cycle->conf_ctx[ngx_http_module.index] ?                                 \
+        ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index])      \
+            ->main_conf[module.ctx_index]:                                    \
+        NULL)
 
 
 #endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -14,6 +14,15 @@ typedef struct {
 } ngx_http_copy_filter_conf_t;
 
 
+#if (NGX_HAVE_FILE_AIO)
+static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx,
+    ngx_file_t *file);
+static void ngx_http_copy_aio_event_handler(ngx_event_t *ev);
+#if (NGX_HAVE_AIO_SENDFILE)
+static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev);
+#endif
+#endif
+
 static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
 static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -73,18 +82,17 @@ ngx_http_copy_filter(ngx_http_request_t 
     ngx_int_t                     rc;
     ngx_connection_t             *c;
     ngx_output_chain_ctx_t       *ctx;
+    ngx_http_core_loc_conf_t     *clcf;
     ngx_http_copy_filter_conf_t  *conf;
 
     c = r->connection;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "copy filter: \"%V?%V\"", &r->uri, &r->args);
+                   "http copy filter: \"%V?%V\"", &r->uri, &r->args);
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
 
     if (ctx == NULL) {
-        conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
-
         ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
         if (ctx == NULL) {
             return NGX_ERROR;
@@ -92,11 +100,16 @@ ngx_http_copy_filter(ngx_http_request_t 
 
         ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);
 
+        conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
         ctx->sendfile = c->sendfile;
         ctx->need_in_memory = r->main_filter_need_in_memory
                               || r->filter_need_in_memory;
         ctx->need_in_temp = r->filter_need_temporary;
 
+        ctx->alignment = clcf->directio_alignment;
+
         ctx->pool = r->pool;
         ctx->bufs = conf->bufs;
         ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module;
@@ -104,27 +117,139 @@ ngx_http_copy_filter(ngx_http_request_t 
         ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
         ctx->filter_ctx = r;
 
+#if (NGX_HAVE_FILE_AIO)
+        if (clcf->aio) {
+            ctx->aio_handler = ngx_http_copy_aio_handler;
+#if (NGX_HAVE_AIO_SENDFILE)
+            c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE);
+#endif
+        }
+#endif
+
         r->request_output = 1;
     }
 
-    rc = ngx_output_chain(ctx, in);
+#if (NGX_HAVE_FILE_AIO)
+    ctx->aio = r->aio;
+#endif
 
-    if (!c->destroyed) {
+    for ( ;; ) {
+        rc = ngx_output_chain(ctx, in);
 
         if (ctx->in == NULL) {
             r->buffered &= ~NGX_HTTP_COPY_BUFFERED;
+
         } else {
             r->buffered |= NGX_HTTP_COPY_BUFFERED;
         }
 
-        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
+
+#if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE)
+
+        if (c->busy_sendfile) {
+            ssize_t                n;
+            off_t                  offset;
+            ngx_file_t            *file;
+            ngx_http_ephemeral_t  *e;
+
+            file = c->busy_sendfile->file;
+            offset = c->busy_sendfile->file_pos;
+
+            if (file->aio) {
+                c->aio_sendfile = (offset != file->aio->last_offset);
+                file->aio->last_offset = offset;
+
+                if (c->aio_sendfile == 0) {
+                    ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+                                  "sendfile(%V) returned busy again",
+                                  &file->name);
+                }
+            }
+
+            c->busy_sendfile = NULL;
+            e = (ngx_http_ephemeral_t *) &r->uri_start;
+
+            n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool);
+
+            if (n > 0) {
+                in = NULL;
+                continue;
+            }
+
+            rc = n;
+
+            if (file->aio) {
+                file->aio->data = r;
+                file->aio->handler = ngx_http_copy_aio_sendfile_event_handler;
+
+                r->main->blocked++;
+                r->aio = 1;
+            }
+        }
+#endif
+
+        return rc;
     }
+}
 
-    return rc;
+
+#if (NGX_HAVE_FILE_AIO)
+
+static void
+ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
+{
+    ngx_http_request_t *r;
+
+    r = ctx->filter_ctx;
+
+    file->aio->data = r;
+    file->aio->handler = ngx_http_copy_aio_event_handler;
+
+    r->main->blocked++;
+    r->aio = 1;
 }
 
 
+static void
+ngx_http_copy_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t     *aio;
+    ngx_http_request_t  *r;
+
+    aio = ev->data;
+    r = aio->data;
+
+    r->main->blocked--;
+    r->aio = 0;
+
+    r->connection->write->handler(r->connection->write);
+}
+
+
+#if (NGX_HAVE_AIO_SENDFILE)
+
+static void
+ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t     *aio;
+    ngx_http_request_t  *r;
+
+    aio = ev->data;
+    r = aio->data;
+
+    r->main->blocked--;
+    r->aio = 0;
+    ev->complete = 0;
+
+    r->connection->write->handler(r->connection->write);
+}
+
+#endif
+#endif
+
+
 static void *
 ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
 {
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -104,6 +104,20 @@ static ngx_conf_enum_t  ngx_http_core_re
 };
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+static ngx_conf_enum_t  ngx_http_core_aio[] = {
+    { ngx_string("off"), NGX_HTTP_AIO_OFF  },
+    { ngx_string("on"), NGX_HTTP_AIO_ON },
+#if (NGX_HAVE_AIO_SENDFILE)
+    { ngx_string("sendfile"), NGX_HTTP_AIO_SENDFILE },
+#endif
+    { ngx_null_string, 0 }
+};
+
+#endif
+
+
 static ngx_conf_enum_t  ngx_http_core_satisfy[] = {
     { ngx_string("all"), NGX_HTTP_SATISFY_ALL },
     { ngx_string("any"), NGX_HTTP_SATISFY_ANY },
@@ -355,12 +369,19 @@ static ngx_command_t  ngx_http_core_comm
       NULL },
 
     { ngx_string("client_body_in_file_only"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_enum_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, client_body_in_file_only),
       &ngx_http_core_request_body_in_file },
 
+    { ngx_string("client_body_in_single_buffer"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, client_body_in_single_buffer),
+      NULL },
+
     { ngx_string("sendfile"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                         |NGX_CONF_TAKE1,
@@ -376,6 +397,17 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
       NULL },
 
+#if (NGX_HAVE_FILE_AIO)
+
+    { ngx_string("aio"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, aio),
+      &ngx_http_core_aio },
+
+#endif
+
     { ngx_string("directio"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_http_core_directio,
@@ -383,6 +415,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("directio_alignment"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_off_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, directio_alignment),
+      NULL },
+
     { ngx_string("tcp_nopush"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -426,6 +465,14 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, limit_rate),
       NULL },
 
+    { ngx_string("limit_rate_after"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, limit_rate_after),
+      NULL },
+
     { ngx_string("keepalive_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
       ngx_http_core_keepalive,
@@ -433,6 +480,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("keepalive_requests"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, keepalive_requests),
+      NULL },
+
     { ngx_string("satisfy"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_enum_slot,
@@ -691,7 +745,7 @@ ngx_module_t  ngx_http_core_module = {
 };
 
 
-static ngx_str_t  ngx_http_core_get_method = { 3, (u_char *) "GET " };
+ngx_str_t  ngx_http_core_get_method = { 3, (u_char *) "GET " };
 
 
 void
@@ -863,6 +917,7 @@ ngx_http_core_find_config_phase(ngx_http
                       "client intended to send too large body: %O bytes",
                       r->headers_in.content_length_n);
 
+        (void) ngx_http_discard_request_body(r);
         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
         return NGX_OK;
     }
@@ -939,6 +994,7 @@ ngx_http_core_post_rewrite_phase(ngx_htt
                       "rewrite or internal redirection cycle "
                       "while processing \"%V\"", &r->uri);
 
+        r->main->count++;
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return NGX_OK;
     }
@@ -1144,6 +1200,11 @@ ngx_http_core_try_files_phase(ngx_http_r
 
         if (tf->lengths == NULL && tf->name.len == 0) {
 
+            if (tf->code) {
+                ngx_http_finalize_request(r, tf->code);
+                return NGX_OK;
+            }
+
             path.len -= root;
             path.data += root;
 
@@ -1156,6 +1217,7 @@ ngx_http_core_try_files_phase(ngx_http_r
                 (void) ngx_http_internal_redirect(r, &path, &args);
             }
 
+            ngx_http_finalize_request(r, NGX_DONE);
             return NGX_OK;
         }
 
@@ -1164,6 +1226,7 @@ ngx_http_core_try_files_phase(ngx_http_r
         of.directio = clcf->directio;
         of.valid = clcf->open_file_cache_valid;
         of.min_uses = clcf->open_file_cache_min_uses;
+        of.test_only = 1;
         of.errors = clcf->open_file_cache_errors;
         of.events = clcf->open_file_cache_events;
 
@@ -1172,7 +1235,7 @@ ngx_http_core_try_files_phase(ngx_http_r
         {
             if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
                 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
-                              ngx_open_file_n " \"%s\" failed", path.data);
+                              "%s \"%s\" failed", of.failed, path.data);
             }
 
             continue;
@@ -1200,10 +1263,7 @@ ngx_http_core_try_files_phase(ngx_http_r
             ngx_memcpy(p, name, path.len);
         }
 
-        if (ngx_http_set_exten(r) != NGX_OK) {
-            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return NGX_OK;
-        }
+        ngx_http_set_exten(r);
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "try file uri: \"%V\"", &r->uri);
@@ -1235,10 +1295,6 @@ ngx_http_core_content_phase(ngx_http_req
 
     rc = ph->handler(r);
 
-    if (rc == NGX_DONE) {
-        return NGX_OK;
-    }
-
     if (rc != NGX_DECLINED) {
         ngx_http_finalize_request(r, rc);
         return NGX_OK;
@@ -1286,10 +1342,10 @@ ngx_http_update_location_config(ngx_http
     }
 
     if (r == r->main) {
-        r->connection->log->file = clcf->err_log->file;
+        r->connection->log->file = clcf->error_log->file;
 
         if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
-            r->connection->log->log_level = clcf->err_log->log_level;
+            r->connection->log->log_level = clcf->error_log->log_level;
         }
     }
 
@@ -1311,8 +1367,15 @@ ngx_http_update_location_config(ngx_http
         r->request_body_file_log_level = NGX_LOG_WARN;
     }
 
-    if (r->keepalive && clcf->keepalive_timeout == 0) {
-        r->keepalive = 0;
+    r->request_body_in_single_buf = clcf->client_body_in_single_buffer;
+
+    if (r->keepalive) {
+        if (clcf->keepalive_timeout == 0) {
+            r->keepalive = 0;
+
+        } else if (r->connection->requests >= clcf->keepalive_requests) {
+            r->keepalive = 0;
+        }
     }
 
     if (!clcf->tcp_nopush) {
@@ -1515,38 +1578,38 @@ ngx_http_core_find_static_location(ngx_h
 void *
 ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash)
 {
-    u_char       c, *p;
-    ngx_uint_t   i, hash;
+    u_char      c, *lowcase;
+    size_t      len;
+    ngx_uint_t  i, hash;
 
     if (r->headers_out.content_type.len == 0) {
         return NULL;
     }
 
+    len = r->headers_out.content_type_len;
+
     if (r->headers_out.content_type_lowcase == NULL) {
 
-        p = ngx_pnalloc(r->pool, r->headers_out.content_type_len);
-
-        if (p == NULL) {
+        lowcase = ngx_pnalloc(r->pool, len);
+        if (lowcase == NULL) {
             return NULL;
         }
 
-        r->headers_out.content_type_lowcase = p;
+        r->headers_out.content_type_lowcase = lowcase;
 
         hash = 0;
 
-        for (i = 0; i < r->headers_out.content_type_len; i++) {
+        for (i = 0; i < len; i++) {
             c = ngx_tolower(r->headers_out.content_type.data[i]);
             hash = ngx_hash(hash, c);
-            *p++ = c;
+            lowcase[i] = c;
         }
 
         r->headers_out.content_type_hash = hash;
     }
 
-    return ngx_hash_find(types_hash,
-                         r->headers_out.content_type_hash,
-                         r->headers_out.content_type_lowcase,
-                         r->headers_out.content_type_len);
+    return ngx_hash_find(types_hash, r->headers_out.content_type_hash,
+                         r->headers_out.content_type_lowcase, len);
 }
 
 
@@ -1606,7 +1669,7 @@ ngx_http_set_content_type(ngx_http_reque
 }
 
 
-ngx_int_t
+void
 ngx_http_set_exten(ngx_http_request_t *r)
 {
     ngx_int_t  i;
@@ -1620,14 +1683,14 @@ ngx_http_set_exten(ngx_http_request_t *r
             r->exten.len = r->uri.len - i - 1;
             r->exten.data = &r->uri.data[i + 1];
 
-            break;
+            return;
 
         } else if (r->uri.data[i] == '/') {
-            break;
+            return;
         }
     }
 
-    return NGX_OK;
+    return;
 }
 
 
@@ -1646,16 +1709,19 @@ ngx_http_send_header(ngx_http_request_t 
 ngx_int_t
 ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
-    ngx_int_t  rc;
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+    ngx_int_t          rc;
+    ngx_connection_t  *c;
+
+    c = r->connection;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http output filter \"%V?%V\"", &r->uri, &r->args);
 
     rc = ngx_http_top_body_filter(r, in);
 
     if (rc == NGX_ERROR) {
         /* NGX_ERROR may be returned by any filter */
-        r->connection->error = 1;
+        c->error = 1;
     }
 
     return rc;
@@ -1805,68 +1871,6 @@ ngx_http_auth_basic_user(ngx_http_reques
 }
 
 
-ngx_int_t
-ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s)
-{
-    socklen_t             len;
-    ngx_uint_t            addr;
-    ngx_connection_t     *c;
-    u_char                sa[NGX_SOCKADDRLEN];
-    struct sockaddr_in   *sin;
-#if (NGX_HAVE_INET6)
-    ngx_uint_t            i;
-    struct sockaddr_in6  *sin6;
-#endif
-
-    c = r->connection;
-
-    switch (c->local_sockaddr->sa_family) {
-
-#if (NGX_HAVE_INET6)
-    case AF_INET6:
-        sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
-
-        for (addr = 0, i = 0; addr == 0 && i < 16; i++) {
-            addr |= sin6->sin6_addr.s6_addr[i];
-        }
-
-        break;
-#endif
-
-    default: /* AF_INET */
-        sin = (struct sockaddr_in *) c->local_sockaddr;
-        addr = sin->sin_addr.s_addr;
-        break;
-    }
-
-    if (addr == 0) {
-
-        len = NGX_SOCKADDRLEN;
-
-        if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) {
-            ngx_connection_error(c, ngx_socket_errno, "getsockname() failed");
-            return NGX_ERROR;
-        }
-
-        c->local_sockaddr = ngx_palloc(r->connection->pool, len);
-        if (c->local_sockaddr == NULL) {
-            return NGX_ERROR;
-        }
-
-        c->local_socklen = len;
-        ngx_memcpy(c->local_sockaddr, &sa, len);
-    }
-
-    if (s == NULL) {
-        return NGX_OK;
-    }
-
-    s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, 0);
-
-    return NGX_OK;
-}
-
-
 #if (NGX_HTTP_GZIP)
 
 ngx_int_t
@@ -2106,9 +2110,7 @@ ngx_http_subrequest(ngx_http_request_t *
     sr->method_name = ngx_http_core_get_method;
     sr->http_protocol = r->http_protocol;
 
-    if (ngx_http_set_exten(sr) != NGX_OK) {
-        return NGX_ERROR;
-    }
+    ngx_http_set_exten(sr);
 
     sr->main = r->main;
     sr->parent = r;
@@ -2150,10 +2152,11 @@ ngx_http_subrequest(ngx_http_request_t *
     sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
 
     r->main->subrequests++;
+    r->main->count++;
 
     *psr = sr;
 
-    return ngx_http_post_request(sr);
+    return ngx_http_post_request(sr, NULL);
 }
 
 
@@ -2170,6 +2173,7 @@ ngx_http_internal_redirect(ngx_http_requ
                       "rewrite or internal redirection cycle "
                       "while internal redirect to \"%V\"", uri);
 
+        r->main->count++;
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return NGX_DONE;
     }
@@ -2187,10 +2191,7 @@ ngx_http_internal_redirect(ngx_http_requ
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "internal redirect: \"%V?%V\"", uri, &r->args);
 
-    if (ngx_http_set_exten(r) != NGX_OK) {
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return NGX_DONE;
-    }
+    ngx_http_set_exten(r);
 
     /* clear the modules contexts */
     ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
@@ -2205,6 +2206,7 @@ ngx_http_internal_redirect(ngx_http_requ
 #endif
 
     r->internal = 1;
+    r->main->count++;
 
     ngx_http_handler(r);
 
@@ -2219,6 +2221,8 @@ ngx_http_named_location(ngx_http_request
     ngx_http_core_loc_conf_t   **clcfp;
     ngx_http_core_main_conf_t   *cmcf;
 
+    r->main->count++;
+
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
     if (cscf->named_locations) {
@@ -2593,6 +2597,10 @@ ngx_http_core_regex_location(ngx_conf_t 
     err.len = NGX_MAX_CONF_ERRSTR;
     err.data = errstr;
 
+#if (NGX_HAVE_CASELESS_FILESYSTEM)
+    caseless = 1;
+#endif
+
     clcf->regex = ngx_regex_compile(regex, caseless ? NGX_REGEX_CASELESS: 0,
                                     cf->pool, &err);
 
@@ -2722,14 +2730,14 @@ ngx_http_core_create_main_conf(ngx_conf_
 
     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t));
     if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
                        sizeof(ngx_http_core_srv_conf_t *))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
@@ -2781,7 +2789,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t
 
     cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t));
     if (cscf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -2794,14 +2802,14 @@ ngx_http_core_create_srv_conf(ngx_conf_t
                        sizeof(ngx_http_listen_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
                        sizeof(ngx_http_server_name_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     cscf->connection_pool_size = NGX_CONF_UNSET_SIZE;
@@ -2912,7 +2920,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
 
     lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
     if (lcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -2923,7 +2931,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
      *     lcf->post_action = { 0, NULL };
      *     lcf->types = NULL;
      *     lcf->default_type = { 0, NULL };
-     *     lcf->err_log = NULL;
+     *     lcf->error_log = NULL;
      *     lcf->error_pages = NULL;
      *     lcf->try_files = NULL;
      *     lcf->client_body_path = NULL;
@@ -2939,19 +2947,26 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
     lcf->satisfy = NGX_CONF_UNSET_UINT;
     lcf->if_modified_since = NGX_CONF_UNSET_UINT;
+    lcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
+    lcf->client_body_in_single_buffer = NGX_CONF_UNSET;
     lcf->internal = NGX_CONF_UNSET;
-    lcf->client_body_in_file_only = NGX_CONF_UNSET;
     lcf->sendfile = NGX_CONF_UNSET;
     lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
+#if (NGX_HAVE_FILE_AIO)
+    lcf->aio = NGX_CONF_UNSET;
+#endif
     lcf->directio = NGX_CONF_UNSET;
+    lcf->directio_alignment = NGX_CONF_UNSET;
     lcf->tcp_nopush = NGX_CONF_UNSET;
     lcf->tcp_nodelay = NGX_CONF_UNSET;
     lcf->send_timeout = NGX_CONF_UNSET_MSEC;
     lcf->send_lowat = NGX_CONF_UNSET_SIZE;
     lcf->postpone_output = NGX_CONF_UNSET_SIZE;
     lcf->limit_rate = NGX_CONF_UNSET_SIZE;
+    lcf->limit_rate_after = NGX_CONF_UNSET_SIZE;
     lcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
     lcf->keepalive_header = NGX_CONF_UNSET;
+    lcf->keepalive_requests = NGX_CONF_UNSET_UINT;
     lcf->lingering_time = NGX_CONF_UNSET_MSEC;
     lcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
     lcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
@@ -3103,11 +3118,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
         }
     }
 
-    if (conf->err_log == NULL) {
-        if (prev->err_log) {
-            conf->err_log = prev->err_log;
+    if (conf->error_log == NULL) {
+        if (prev->error_log) {
+            conf->error_log = prev->error_log;
         } else {
-            conf->err_log = cf->cycle->new_log;
+            conf->error_log = &cf->cycle->new_log;
         }
     }
 
@@ -3130,14 +3145,21 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
                               NGX_HTTP_SATISFY_ALL);
     ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
                               NGX_HTTP_IMS_EXACT);
+    ngx_conf_merge_uint_value(conf->client_body_in_file_only,
+                              prev->client_body_in_file_only, 0);
+    ngx_conf_merge_value(conf->client_body_in_single_buffer,
+                              prev->client_body_in_single_buffer, 0);
     ngx_conf_merge_value(conf->internal, prev->internal, 0);
-    ngx_conf_merge_value(conf->client_body_in_file_only,
-                              prev->client_body_in_file_only, 0);
     ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
     ngx_conf_merge_size_value(conf->sendfile_max_chunk,
                               prev->sendfile_max_chunk, 0);
+#if (NGX_HAVE_FILE_AIO)
+    ngx_conf_merge_value(conf->aio, prev->aio, 0);
+#endif
     ngx_conf_merge_off_value(conf->directio, prev->directio,
                               NGX_MAX_OFF_T_VALUE);
+    ngx_conf_merge_off_value(conf->directio_alignment, prev->directio_alignment,
+                              512);
     ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
     ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1);
 
@@ -3146,10 +3168,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
                               1460);
     ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
+    ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after,
+                              0);
     ngx_conf_merge_msec_value(conf->keepalive_timeout,
                               prev->keepalive_timeout, 75000);
     ngx_conf_merge_sec_value(conf->keepalive_header,
                               prev->keepalive_header, 0);
+    ngx_conf_merge_uint_value(conf->keepalive_requests,
+                              prev->keepalive_requests, 100);
     ngx_conf_merge_msec_value(conf->lingering_time,
                               prev->lingering_time, 30000);
     ngx_conf_merge_msec_value(conf->lingering_timeout,
@@ -3525,6 +3551,12 @@ ngx_http_core_server_name(ngx_conf_t *cf
         ngx_str_t  err;
         u_char     errstr[NGX_MAX_CONF_ERRSTR];
 
+        if (value[i].len == 1) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "empty regex in server name \"%V\"", &value[i]);
+            return NGX_CONF_ERROR;
+        }
+
         err.len = NGX_MAX_CONF_ERRSTR;
         err.data = errstr;
 
@@ -3875,7 +3907,7 @@ ngx_http_core_error_page(ngx_conf_t *cf,
     args.len = 0;
     args.data = NULL;
 
-    if (cv.lengths == NULL) {
+    if (cv.lengths == NULL && uri.data[0] == '/') {
         p = (u_char *) ngx_strchr(uri.data, '?');
 
         if (p) {
@@ -3939,6 +3971,7 @@ ngx_http_core_try_files(ngx_conf_t *cf, 
     ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t                  *value;
+    ngx_int_t                   code;
     ngx_uint_t                  i, n;
     ngx_http_try_file_t        *tf;
     ngx_http_script_compile_t   sc;
@@ -3994,6 +4027,20 @@ ngx_http_core_try_files(ngx_conf_t *cf, 
         }
     }
 
+    if (tf[i - 1].name.data[0] == '=') {
+
+        code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2);
+
+        if (code == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid code \"%*s\"",
+                               tf[i - 1].name.len - 1, tf[i - 1].name.data);
+            return NGX_CONF_ERROR;
+        }
+
+        tf[i].code = code;
+    }
+
     return NGX_CONF_OK;
 }
 
@@ -4081,12 +4128,25 @@ ngx_http_core_error_log(ngx_conf_t *cf, 
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
-    lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args);
-    if (lcf->err_log == NULL) {
+    ngx_str_t  *value;
+
+    if (lcf->error_log) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    lcf->error_log = ngx_log_create(cf->cycle, &value[1]);
+    if (lcf->error_log == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    return ngx_set_error_log_levels(cf, lcf->err_log);
+    if (cf->args->nelts == 2) {
+        lcf->error_log->log_level = NGX_LOG_ERR;
+        return NGX_CONF_OK;
+    }
+
+    return ngx_log_set_levels(cf, lcf->error_log);
 }
 
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -24,6 +24,11 @@
 #define NGX_HTTP_GZIP_PROXIED_ANY       0x0200
 
 
+#define NGX_HTTP_AIO_OFF                0
+#define NGX_HTTP_AIO_ON                 1
+#define NGX_HTTP_AIO_SENDFILE           2
+
+
 #define NGX_HTTP_SATISFY_ALL            0
 #define NGX_HTTP_SATISFY_ANY            1
 
@@ -153,8 +158,6 @@ typedef struct {
     /* server ctx */
     ngx_http_conf_ctx_t        *ctx;
 
-    ngx_http_virtual_names_t   *virtual_names;
-
     ngx_str_t                   server_name;
 
     size_t                      connection_pool_size;
@@ -180,6 +183,8 @@ typedef struct {
     /* the default server configuration for this address:port */
     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
@@ -267,7 +272,9 @@ typedef struct {
     ngx_array_t               *lengths;
     ngx_array_t               *values;
     ngx_str_t                  name;
-    ngx_uint_t                 test_dir;   /* unsigned  test_dir:1; */
+
+    unsigned                   code:10;
+    unsigned                   test_dir:1;
 } ngx_http_try_file_t;
 
 
@@ -317,11 +324,13 @@ struct ngx_http_core_loc_conf_s {
 
     off_t         client_max_body_size;    /* client_max_body_size */
     off_t         directio;                /* directio */
+    off_t         directio_alignment;      /* directio_alignment */
 
     size_t        client_body_buffer_size; /* client_body_buffer_size */
     size_t        send_lowat;              /* send_lowat */
     size_t        postpone_output;         /* postpone_output */
     size_t        limit_rate;              /* limit_rate */
+    size_t        limit_rate_after;        /* limit_rate_after */
     size_t        sendfile_max_chunk;      /* sendfile_max_chunk */
 
     ngx_msec_t    client_body_timeout;     /* client_body_timeout */
@@ -335,12 +344,18 @@ struct ngx_http_core_loc_conf_s {
 
     time_t        keepalive_header;        /* keepalive_timeout */
 
+    ngx_uint_t    keepalive_requests;      /* keepalive_requests */
     ngx_uint_t    satisfy;                 /* satisfy */
     ngx_uint_t    if_modified_since;       /* if_modified_since */
+    ngx_uint_t    client_body_in_file_only; /* client_body_in_file_only */
 
+    ngx_flag_t    client_body_in_single_buffer;
+                                           /* client_body_in_singe_buffer */
     ngx_flag_t    internal;                /* internal */
-    ngx_flag_t    client_body_in_file_only; /* client_body_in_file_only */
     ngx_flag_t    sendfile;                /* sendfile */
+#if (NGX_HAVE_FILE_AIO)
+    ngx_flag_t    aio;                     /* aio */
+#endif
     ngx_flag_t    tcp_nopush;              /* tcp_nopush */
     ngx_flag_t    tcp_nodelay;             /* tcp_nodelay */
     ngx_flag_t    reset_timedout_connection; /* reset_timedout_connection */
@@ -375,7 +390,7 @@ struct ngx_http_core_loc_conf_s {
     ngx_flag_t    open_file_cache_errors;
     ngx_flag_t    open_file_cache_events;
 
-    ngx_log_t    *err_log;
+    ngx_log_t    *error_log;
 
     ngx_uint_t    types_hash_max_size;
     ngx_uint_t    types_hash_bucket_size;
@@ -432,11 +447,10 @@ ngx_int_t ngx_http_core_content_phase(ng
 
 void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash);
 ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
-ngx_int_t ngx_http_set_exten(ngx_http_request_t *r);
+void ngx_http_set_exten(ngx_http_request_t *r);
 u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name,
     size_t *root_length, size_t reserved);
 ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r);
-ngx_int_t ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s);
 #if (NGX_HTTP_GZIP)
 ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r);
 #endif
@@ -466,6 +480,8 @@ extern ngx_module_t  ngx_http_core_modul
 
 extern ngx_uint_t ngx_http_max_module;
 
+extern ngx_str_t  ngx_http_core_get_method;
+
 
 #define ngx_http_clear_content_length(r)                                      \
                                                                               \
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -10,6 +10,11 @@
 #include <ngx_md5.h>
 
 
+static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
+    ngx_http_cache_t *c);
+#if (NGX_HAVE_FILE_AIO)
+static void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
+#endif
 static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
     ngx_http_cache_t *c);
 static ngx_http_file_cache_node_t *
@@ -35,6 +40,15 @@ static ngx_int_t ngx_http_file_cache_del
     ngx_str_t *path);
 
 
+ngx_str_t  ngx_http_cache_status[] = {
+    ngx_string("MISS"),
+    ngx_string("EXPIRED"),
+    ngx_string("STALE"),
+    ngx_string("UPDATING"),
+    ngx_string("HIT")
+};
+
+
 static u_char  ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
 
 
@@ -44,7 +58,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
     ngx_http_file_cache_t  *ocache = data;
 
     size_t                  len;
-    ngx_rbtree_node_t      *sentinel;
+    ngx_uint_t              n;
     ngx_http_file_cache_t  *cache;
 
     cache = shm_zone->data;
@@ -54,65 +68,65 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
                           "cache \"%V\" uses the \"%V\" cache path "
                           "while previously it used the \"%V\" cache path",
-                          &shm_zone->name, &cache->path->name,
+                          &shm_zone->shm.name, &cache->path->name,
                           &ocache->path->name);
 
             return NGX_ERROR;
         }
 
-        cache->rbtree = ocache->rbtree;
-        cache->queue = ocache->queue;
+        for (n = 0; n < 3; n++) {
+            if (cache->path->level[n] != ocache->path->level[n]) {
+                ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
+                              "cache \"%V\" had previously different levels",
+                              &shm_zone->shm.name);
+                return NGX_ERROR;
+            }
+        }
+
+        cache->sh = ocache->sh;
+
         cache->shpool = ocache->shpool;
-        cache->cold = ocache->cold;
-        cache->size = ocache->size;
         cache->bsize = ocache->bsize;
 
         cache->max_size /= cache->bsize;
 
+        if (!cache->sh->cold || cache->sh->loading) {
+            cache->path->loader = NULL;
+        }
+
         return NGX_OK;
     }
 
     cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
-    cache->rbtree = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_t));
-    if (cache->rbtree == NULL) {
-        return NGX_ERROR;
+    if (shm_zone->shm.exists) {
+        cache->sh = cache->shpool->data;
+        cache->bsize = ngx_fs_bsize(cache->path->name.data);
+
+        return NGX_OK;
     }
 
-    sentinel = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
+    cache->sh = ngx_slab_alloc(cache->shpool, sizeof(ngx_http_file_cache_sh_t));
+    if (cache->sh == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_rbtree_init(cache->rbtree, sentinel,
+    cache->shpool->data = cache->sh;
+
+    ngx_rbtree_init(&cache->sh->rbtree, &cache->sh->sentinel,
                     ngx_http_file_cache_rbtree_insert_value);
 
-    cache->queue = ngx_slab_alloc(cache->shpool, sizeof(ngx_queue_t));
-    if (cache->queue == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_queue_init(cache->queue);
+    ngx_queue_init(&cache->sh->queue);
 
-    cache->cold = ngx_slab_alloc(cache->shpool, sizeof(ngx_atomic_t));
-    if (cache->cold == NULL) {
-        return NGX_ERROR;
-    }
-
-    *cache->cold = 1;
-
-    cache->size = ngx_slab_alloc(cache->shpool, sizeof(off_t));
-    if (cache->size == NULL) {
-        return NGX_ERROR;
-    }
-
-    *cache->size = 0;
+    cache->sh->cold = 1;
+    cache->sh->loading = 0;
+    cache->sh->size = 0;
 
     cache->bsize = ngx_fs_bsize(cache->path->name.data);
 
     cache->max_size /= cache->bsize;
 
-    len = sizeof(" in cache keys zone \"\"") + shm_zone->name.len;
+    len = sizeof(" in cache keys zone \"\"") + shm_zone->shm.name.len;
 
     cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len);
     if (cache->shpool->log_ctx == NULL) {
@@ -120,7 +134,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
     }
 
     ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z",
-                &shm_zone->name);
+                &shm_zone->shm.name);
 
     return NGX_OK;
 }
@@ -164,20 +178,22 @@ ngx_http_file_cache_create_key(ngx_http_
 ngx_int_t
 ngx_http_file_cache_open(ngx_http_request_t *r)
 {
-    u_char                        *p;
-    time_t                         now;
-    ssize_t                        n;
-    ngx_int_t                      rc, rv;
-    ngx_uint_t                     cold, test;
-    ngx_path_t                    *path;
-    ngx_http_cache_t              *c;
-    ngx_pool_cleanup_t            *cln;
-    ngx_open_file_info_t           of;
-    ngx_http_file_cache_t         *cache;
-    ngx_http_core_loc_conf_t      *clcf;
-    ngx_http_file_cache_header_t  *h;
+    u_char                    *p;
+    ngx_int_t                  rc, rv;
+    ngx_uint_t                 cold, test;
+    ngx_path_t                *path;
+    ngx_http_cache_t          *c;
+    ngx_pool_cleanup_t        *cln;
+    ngx_open_file_info_t       of;
+    ngx_http_file_cache_t     *cache;
+    ngx_http_core_loc_conf_t  *clcf;
 
     c = r->cache;
+
+    if (c->buf) {
+        return ngx_http_file_cache_read(r, c);
+    }
+
     cache = c->file_cache;
 
     cln = ngx_pool_cleanup_add(r->pool, 0);
@@ -187,9 +203,8 @@ ngx_http_file_cache_open(ngx_http_reques
 
     rc = ngx_http_file_cache_exists(cache, c);
 
-    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http file cache exists: %i u:%ui e:%d",
-                   rc, c->uses, c->exists);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http file cache exists: %i e:%d", rc, c->exists);
 
     if (rc == NGX_ERROR) {
         return rc;
@@ -199,10 +214,10 @@ ngx_http_file_cache_open(ngx_http_reques
     cln->data = c;
 
     if (rc == NGX_AGAIN) {
-        return rc;
+        return NGX_HTTP_CACHE_SCARCE;
     }
 
-    cold = *cache->cold;
+    cold = cache->sh->cold;
 
     if (rc == NGX_OK) {
 
@@ -219,11 +234,11 @@ ngx_http_file_cache_open(ngx_http_reques
         if (c->min_uses > 1) {
 
             if (!cold) {
-                return NGX_AGAIN;
+                return NGX_HTTP_CACHE_SCARCE;
             }
 
             test = 1;
-            rv = NGX_AGAIN;
+            rv = NGX_HTTP_CACHE_SCARCE;
 
         } else {
             c->temp_file = 1;
@@ -291,14 +306,58 @@ ngx_http_file_cache_open(ngx_http_reques
 
     c->file.fd = of.fd;
     c->file.log = r->connection->log;
+    c->uniq = of.uniq;
+    c->length = of.size;
 
     c->buf = ngx_create_temp_buf(r->pool, c->body_start);
     if (c->buf == NULL) {
         return NGX_ERROR;
     }
 
+    return ngx_http_file_cache_read(r, c);
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
+    time_t                         now;
+    ssize_t                        n;
+    ngx_int_t                      rc;
+    ngx_http_file_cache_t         *cache;
+    ngx_http_file_cache_header_t  *h;
+
+    c = r->cache;
+
+#if (NGX_HAVE_FILE_AIO)
+    {
+    ngx_http_core_loc_conf_t      *clcf;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->aio) {
+        n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
+
+        if (n == NGX_AGAIN) {
+            c->file.aio->data = r;
+            c->file.aio->handler = ngx_http_cache_aio_event_handler;
+
+            r->main->blocked++;
+            r->aio = 1;
+
+            return NGX_AGAIN;
+        }
+
+    } else {
+        n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
+    }
+    }
+#else
+
     n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
 
+#endif
+
     if (n == NGX_ERROR) {
         return n;
     }
@@ -323,12 +382,13 @@ ngx_http_file_cache_open(ngx_http_reques
     c->last_modified = h->last_modified;
     c->date = h->date;
     c->valid_msec = h->valid_msec;
-    c->length = of.size;
     c->body_start = h->body_start;
 
     r->cached = 1;
 
-    if (cold) {
+    cache = c->file_cache;
+
+    if (cache->sh->cold) {
 
         ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -336,8 +396,9 @@ ngx_http_file_cache_open(ngx_http_reques
             c->node->uses = 1;
             c->node->body_start = c->body_start;
             c->node->exists = 1;
+            c->node->uniq = c->uniq;
 
-            *cache->size += (c->length + cache->bsize - 1) / cache->bsize;
+            cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
         }
 
         ngx_shmtx_unlock(&cache->shpool->mutex);
@@ -347,20 +408,50 @@ ngx_http_file_cache_open(ngx_http_reques
 
     if (c->valid_sec < now) {
 
-        c->uses = c->min_uses;
+        ngx_shmtx_lock(&cache->shpool->mutex);
 
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http file cache expired: %T %T", c->valid_sec, now);
+        if (c->node->updating) {
+            rc = NGX_HTTP_CACHE_UPDATING;
 
-        return NGX_HTTP_CACHE_STALE;
+        } else {
+            c->node->updating = 1;
+            rc = NGX_HTTP_CACHE_STALE;
+        }
+
+        ngx_shmtx_unlock(&cache->shpool->mutex);
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http file cache expired: %i %T %T",
+                       rc, c->valid_sec, now);
+
+        return rc;
     }
 
-    /* TODO: NGX_HTTP_CACHE_AGED */
-
     return NGX_OK;
 }
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+
+static void
+ngx_http_cache_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t     *aio;
+    ngx_http_request_t  *r;
+
+    aio = ev->data;
+    r = aio->data;
+
+    r->main->blocked--;
+    r->aio = 0;
+
+    r->connection->write->handler(r->connection->write);
+}
+
+#endif
+
+
 static ngx_int_t
 ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
 {
@@ -417,7 +508,7 @@ ngx_http_file_cache_exists(ngx_http_file
     if (fcn == NULL) {
         ngx_shmtx_unlock(&cache->shpool->mutex);
 
-        ngx_http_file_cache_forced_expire(cache);
+        (void) ngx_http_file_cache_forced_expire(cache);
 
         ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -434,7 +525,7 @@ ngx_http_file_cache_exists(ngx_http_file
     ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
 
-    ngx_rbtree_insert(cache->rbtree, &fcn->node);
+    ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
 
 renew:
 
@@ -454,10 +545,9 @@ done:
 
     fcn->expire = ngx_time() + cache->inactive;
 
-    ngx_queue_insert_head(cache->queue, &fcn->queue);
+    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
 
     c->uniq = fcn->uniq;
-    c->uses = fcn->uses;
     c->error = fcn->error;
     c->node = fcn;
 
@@ -479,8 +569,8 @@ ngx_http_file_cache_lookup(ngx_http_file
 
     ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t));
 
-    node = cache->rbtree->root;
-    sentinel = cache->rbtree->sentinel;
+    node = cache->sh->rbtree.root;
+    sentinel = cache->sh->rbtree.sentinel;
 
     while (node != sentinel) {
 
@@ -633,7 +723,6 @@ ngx_http_file_cache_update(ngx_http_requ
     ext.time = -1;
     ext.create_path = 1;
     ext.delete_file = 1;
-    ext.log_rename_error = 1;
     ext.log = r->connection->log;
 
     rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
@@ -663,12 +752,14 @@ ngx_http_file_cache_update(ngx_http_requ
 
     c->node->length = c->length;
 
-    *cache->size += size;
+    cache->sh->size += size;
 
     if (rc == NGX_OK) {
         c->node->exists = 1;
     }
 
+    c->node->updating = 0;
+
     ngx_shmtx_unlock(&cache->shpool->mutex);
 }
 
@@ -676,6 +767,7 @@ ngx_http_file_cache_update(ngx_http_requ
 ngx_int_t
 ngx_http_cache_send(ngx_http_request_t *r)
 {
+    off_t              size;
     ngx_int_t          rc;
     ngx_buf_t         *b;
     ngx_chain_t        out;
@@ -704,10 +796,15 @@ ngx_http_cache_send(ngx_http_request_t *
         return rc;
     }
 
+    size = c->length - c->body_start;
+    if (size == 0) {
+        return rc;
+    }
+
     b->file_pos = c->body_start;
     b->file_last = c->length;
 
-    b->in_file = (c->length - c->body_start) ? 1: 0;
+    b->in_file = size ? 1: 0;
     b->last_buf = (r == r->main) ? 1: 0;
     b->last_in_chain = 1;
 
@@ -751,6 +848,8 @@ ngx_http_file_cache_free(ngx_http_reques
         c->node->error = c->error;
     }
 
+    c->node->updating = 0;
+
     ngx_shmtx_unlock(&cache->shpool->mutex);
 
     if (c->temp_file) {
@@ -818,18 +917,18 @@ ngx_http_file_cache_forced_expire(ngx_ht
 
     name = ngx_alloc(len + 1, ngx_cycle->log);
     if (name == NULL) {
-        return 60;
+        return 10;
     }
 
     ngx_memcpy(name, path->name.data, path->name.len);
 
-    wait = 60;
+    wait = 10;
     tries = 0;
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
-    for (q = ngx_queue_last(cache->queue);
-         q != ngx_queue_sentinel(cache->queue);
+    for (q = ngx_queue_last(&cache->sh->queue);
+         q != ngx_queue_sentinel(&cache->sh->queue);
          q = ngx_queue_prev(q))
     {
         fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
@@ -853,7 +952,7 @@ ngx_http_file_cache_forced_expire(ngx_ht
         if (!fcn->exists) {
 
             ngx_queue_remove(q);
-            ngx_rbtree_delete(cache->rbtree, &fcn->node);
+            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
             ngx_slab_free_locked(cache->shpool, fcn);
 
             break;
@@ -891,7 +990,7 @@ ngx_http_file_cache_expire(ngx_http_file
 
     name = ngx_alloc(len + 1, ngx_cycle->log);
     if (name == NULL) {
-        return 60;
+        return 10;
     }
 
     ngx_memcpy(name, path->name.data, path->name.len);
@@ -902,19 +1001,19 @@ ngx_http_file_cache_expire(ngx_http_file
 
     for ( ;; ) {
 
-        if (ngx_queue_empty(cache->queue)) {
-            wait = 60;
+        if (ngx_queue_empty(&cache->sh->queue)) {
+            wait = 10;
             break;
         }
 
-        q = ngx_queue_last(cache->queue);
+        q = ngx_queue_last(&cache->sh->queue);
 
         fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
 
         wait = fcn->expire - now;
 
         if (wait > 0) {
-            wait = wait > 60 ? 60 : wait;
+            wait = wait > 10 ? 10 : wait;
             break;
         }
 
@@ -939,7 +1038,7 @@ ngx_http_file_cache_expire(ngx_http_file
              */
 
             ngx_queue_remove(q);
-            ngx_rbtree_delete(cache->rbtree, &fcn->node);
+            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
 
             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                        "ignore long locked inactive cache entry %*s, count:%d",
@@ -951,7 +1050,7 @@ ngx_http_file_cache_expire(ngx_http_file
         if (!fcn->exists) {
 
             ngx_queue_remove(q);
-            ngx_rbtree_delete(cache->rbtree, &fcn->node);
+            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
             ngx_slab_free_locked(cache->shpool, fcn);
 
             continue;
@@ -979,7 +1078,7 @@ ngx_http_file_cache_delete(ngx_http_file
 
     fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
 
-    *cache->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
+    cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
 
     path = cache->path;
 
@@ -993,7 +1092,7 @@ ngx_http_file_cache_delete(ngx_http_file
 
     ngx_queue_remove(q);
 
-    ngx_rbtree_delete(cache->rbtree, &fcn->node);
+    ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
 
     ngx_slab_free_locked(cache->shpool, fcn);
 
@@ -1020,39 +1119,8 @@ ngx_http_file_cache_manager(void *data)
 {
     ngx_http_file_cache_t  *cache = data;
 
-    off_t           size;
-    time_t          next;
-    ngx_tree_ctx_t  tree;
-
-    if (*cache->cold) {
-
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
-                       "http file cache manager update");
-
-        tree.init_handler = NULL;
-        tree.file_handler = ngx_http_file_cache_manage_file;
-        tree.pre_tree_handler = ngx_http_file_cache_noop;
-        tree.post_tree_handler = ngx_http_file_cache_noop;
-        tree.spec_handler = ngx_http_file_cache_delete_file;
-        tree.data = cache;
-        tree.alloc = 0;
-        tree.log = ngx_cycle->log;
-
-        cache->last = ngx_current_msec;
-        cache->files = 0;
-
-        if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
-            return 60;
-        }
-
-        *cache->cold = 0;
-
-        ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
-                      "http file cache: %V %.3fM, bsize: %uz",
-                      &cache->path->name,
-                      ((double) *cache->size * cache->bsize) / (1024 * 1024),
-                      cache->bsize);
-    }
+    off_t   size;
+    time_t  next;
 
     next = ngx_http_file_cache_expire(cache);
 
@@ -1062,7 +1130,7 @@ ngx_http_file_cache_manager(void *data)
     for ( ;; ) {
         ngx_shmtx_lock(&cache->shpool->mutex);
 
-        size = *cache->size;
+        size = cache->sh->size;
 
         ngx_shmtx_unlock(&cache->shpool->mutex);
 
@@ -1082,6 +1150,52 @@ ngx_http_file_cache_manager(void *data)
 }
 
 
+static void
+ngx_http_file_cache_loader(void *data)
+{
+    ngx_http_file_cache_t  *cache = data;
+
+    ngx_tree_ctx_t  tree;
+
+    if (!cache->sh->cold || cache->sh->loading) {
+        return;
+    }
+
+    if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) {
+        return;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+                   "http file cache loader");
+
+    tree.init_handler = NULL;
+    tree.file_handler = ngx_http_file_cache_manage_file;
+    tree.pre_tree_handler = ngx_http_file_cache_noop;
+    tree.post_tree_handler = ngx_http_file_cache_noop;
+    tree.spec_handler = ngx_http_file_cache_delete_file;
+    tree.data = cache;
+    tree.alloc = 0;
+    tree.log = ngx_cycle->log;
+
+    cache->last = ngx_current_msec;
+    cache->files = 0;
+
+    if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
+        cache->sh->loading = 0;
+        return;
+    }
+
+    cache->sh->cold = 0;
+    cache->sh->loading = 0;
+
+    ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+                  "http file cache: %V %.3fM, bsize: %uz",
+                  &cache->path->name,
+                  ((double) cache->sh->size * cache->bsize) / (1024 * 1024),
+                  cache->bsize);
+}
+
+
 static ngx_int_t
 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache)
 {
@@ -1245,7 +1359,7 @@ ngx_http_file_cache_add(ngx_http_file_ca
         ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                    NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
 
-        ngx_rbtree_insert(cache->rbtree, &fcn->node);
+        ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
 
         fcn->uses = 1;
         fcn->count = 0;
@@ -1257,7 +1371,7 @@ ngx_http_file_cache_add(ngx_http_file_ca
         fcn->body_start = c->body_start;
         fcn->length = c->length;
 
-        *cache->size += (c->length + cache->bsize - 1) / cache->bsize;
+        cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
 
     } else {
         ngx_queue_remove(&fcn->queue);
@@ -1265,7 +1379,7 @@ ngx_http_file_cache_add(ngx_http_file_ca
 
     fcn->expire = ngx_time() + cache->inactive;
 
-    ngx_queue_insert_head(cache->queue, &fcn->queue);
+    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
 
     ngx_shmtx_unlock(&cache->shpool->mutex);
 
@@ -1357,13 +1471,12 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
 
         if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {
 
-            n = 0;
             p = value[i].data + 7;
             last = value[i].data + value[i].len;
 
-            while (p < last) {
+            for (n = 0; n < 3 && p < last; n++) {
 
-                if (*p > '0' && *p < '6') {
+                if (*p > '0' && *p < '3') {
 
                     cache->path->level[n] = *p++ - '0';
                     cache->path->len += cache->path->level[n] + 1;
@@ -1372,20 +1485,11 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
                         break;
                     }
 
-                    if (*p++ == ':') {
-
-                        if (n > 2) {
-                            goto invalid_levels;
-                        }
-
-                        if (cache->path->level[n] == 0) {
-                            goto invalid_levels;
-                        }
-
-                        n++;
-
+                    if (*p++ == ':' && n < 2 && p != last) {
                         continue;
                     }
+
+                    goto invalid_levels;
                 }
 
                 goto invalid_levels;
@@ -1409,6 +1513,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
             p = (u_char *) ngx_strchr(name.data, ':');
 
             if (p) {
+                *p = '\0';
+
                 name.len = p - name.data;
 
                 p++;
@@ -1470,6 +1576,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
     }
 
     cache->path->manager = ngx_http_file_cache_manager;
+    cache->path->loader = ngx_http_file_cache_loader;
     cache->path->data = cache;
 
     if (ngx_add_path(cf, &cache->path) != NGX_OK) {
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -61,7 +61,8 @@ static ngx_str_t ngx_http_status_lines[]
 
     /* ngx_null_string, */  /* "207 Multi-Status" */
 
-#define NGX_HTTP_LEVEL_200  7
+#define NGX_HTTP_LAST_LEVEL_200  207
+#define NGX_HTTP_LEVEL_200       (NGX_HTTP_LAST_LEVEL_200 - 200)
 
     /* ngx_null_string, */  /* "300 Multiple Choices" */
 
@@ -74,7 +75,8 @@ static ngx_str_t ngx_http_status_lines[]
     /* ngx_null_string, */  /* "306 unused" */
     /* ngx_null_string, */  /* "307 Temporary Redirect" */
 
-#define NGX_HTTP_LEVEL_300  4
+#define NGX_HTTP_LAST_LEVEL_300  305
+#define NGX_HTTP_LEVEL_300       (NGX_HTTP_LAST_LEVEL_300 - 301)
 
     ngx_string("400 Bad Request"),
     ngx_string("401 Unauthorized"),
@@ -106,7 +108,8 @@ static ngx_str_t ngx_http_status_lines[]
     /* ngx_null_string, */  /* "423 Locked" */
     /* ngx_null_string, */  /* "424 Failed Dependency" */
 
-#define NGX_HTTP_LEVEL_400  17
+#define NGX_HTTP_LAST_LEVEL_400  417
+#define NGX_HTTP_LEVEL_400       (NGX_HTTP_LAST_LEVEL_400 - 400)
 
     ngx_string("500 Internal Server Error"),
     ngx_string("501 Method Not Implemented"),
@@ -120,6 +123,9 @@ static ngx_str_t ngx_http_status_lines[]
     /* ngx_null_string, */  /* "508 unused" */
     /* ngx_null_string, */  /* "509 unused" */
     /* ngx_null_string, */  /* "510 Not Extended" */
+
+#define NGX_HTTP_LAST_LEVEL_500  508
+
 };
 
 
@@ -153,12 +159,13 @@ ngx_http_header_filter(ngx_http_request_
 {
     u_char                    *p;
     size_t                     len;
-    ngx_str_t                  host;
+    ngx_str_t                  host, *status_line;
     ngx_buf_t                 *b;
     ngx_uint_t                 status, i, port;
     ngx_chain_t                out;
     ngx_list_part_t           *part;
     ngx_table_elt_t           *header;
+    ngx_connection_t          *c;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
     struct sockaddr_in        *sin;
@@ -199,17 +206,21 @@ ngx_http_header_filter(ngx_http_request_
 
     if (r->headers_out.status_line.len) {
         len += r->headers_out.status_line.len;
+        status_line = &r->headers_out.status_line;
 #if (NGX_SUPPRESS_WARN)
-        status = NGX_INVALID_ARRAY_INDEX;
+        status = 0;
 #endif
 
     } else {
 
-        if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY) {
+        status = r->headers_out.status;
+
+        if (status >= NGX_HTTP_OK
+            && status < NGX_HTTP_LAST_LEVEL_200)
+        {
             /* 2XX */
-            status = r->headers_out.status - NGX_HTTP_OK;
 
-            if (r->headers_out.status == NGX_HTTP_NO_CONTENT) {
+            if (status == NGX_HTTP_NO_CONTENT) {
                 r->header_only = 1;
                 r->headers_out.content_type.len = 0;
                 r->headers_out.content_type.data = NULL;
@@ -219,30 +230,50 @@ ngx_http_header_filter(ngx_http_request_
                 r->headers_out.content_length_n = -1;
             }
 
-        } else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST) {
+            status -= NGX_HTTP_OK;
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
+
+        } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
+                   && status < NGX_HTTP_LAST_LEVEL_300)
+        {
             /* 3XX */
-            status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY
-                                           + NGX_HTTP_LEVEL_200;
 
-            if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
+            if (status == NGX_HTTP_NOT_MODIFIED) {
                 r->header_only = 1;
             }
 
-        } else if (r->headers_out.status < NGX_HTTP_INTERNAL_SERVER_ERROR) {
+            status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
+
+        } else if (status >= NGX_HTTP_BAD_REQUEST
+                   && status < NGX_HTTP_LAST_LEVEL_400)
+        {
             /* 4XX */
-            status = r->headers_out.status - NGX_HTTP_BAD_REQUEST
-                                           + NGX_HTTP_LEVEL_200
-                                           + NGX_HTTP_LEVEL_300;
+            status = status - NGX_HTTP_BAD_REQUEST
+                            + NGX_HTTP_LEVEL_200
+                            + NGX_HTTP_LEVEL_300;
+
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
+
+        } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
+                   && status < NGX_HTTP_LAST_LEVEL_500)
+        {
+            /* 5XX */
+            status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
+                            + NGX_HTTP_LEVEL_200
+                            + NGX_HTTP_LEVEL_300
+                            + NGX_HTTP_LEVEL_400;
+
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
 
         } else {
-            /* 5XX */
-            status = r->headers_out.status - NGX_HTTP_INTERNAL_SERVER_ERROR
-                                           + NGX_HTTP_LEVEL_200
-                                           + NGX_HTTP_LEVEL_300
-                                           + NGX_HTTP_LEVEL_400;
+            len += NGX_INT_T_LEN;
+            status_line = NULL;
         }
-
-        len += ngx_http_status_lines[status].len;
     }
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -279,6 +310,8 @@ ngx_http_header_filter(ngx_http_request_
         len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
     }
 
+    c = r->connection;
+
     if (r->headers_out.location
         && r->headers_out.location->value.len
         && r->headers_out.location->value.data[0] == '/')
@@ -296,21 +329,21 @@ ngx_http_header_filter(ngx_http_request_
             host.len = NGX_SOCKADDR_STRLEN;
             host.data = addr;
 
-            if (ngx_http_server_addr(r, &host) != NGX_OK) {
+            if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
                 return NGX_ERROR;
             }
         }
 
-        switch (r->connection->local_sockaddr->sa_family) {
+        switch (c->local_sockaddr->sa_family) {
 
 #if (NGX_HAVE_INET6)
         case AF_INET6:
-            sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr;
+            sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
             port = ntohs(sin6->sin6_port);
             break;
 #endif
         default: /* AF_INET */
-            sin = (struct sockaddr_in *) r->connection->local_sockaddr;
+            sin = (struct sockaddr_in *) c->local_sockaddr;
             port = ntohs(sin->sin_port);
             break;
         }
@@ -322,11 +355,14 @@ ngx_http_header_filter(ngx_http_request_
         if (clcf->port_in_redirect) {
 
 #if (NGX_HTTP_SSL)
-            if (r->connection->ssl)
+            if (c->ssl)
                 port = (port == 443) ? 0 : port;
             else
 #endif
                 port = (port == 80) ? 0 : port;
+
+        } else {
+            port = 0;
         }
 
         if (port) {
@@ -400,13 +436,11 @@ ngx_http_header_filter(ngx_http_request_
     b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
 
     /* status line */
-    if (r->headers_out.status_line.len) {
-        b->last = ngx_copy(b->last, r->headers_out.status_line.data,
-                           r->headers_out.status_line.len);
+    if (status_line) {
+        b->last = ngx_copy(b->last, status_line->data, status_line->len);
 
     } else {
-        b->last = ngx_copy(b->last, ngx_http_status_lines[status].data,
-                           ngx_http_status_lines[status].len);
+        b->last = ngx_sprintf(b->last, "%ui", status);
     }
     *b->last++ = CR; *b->last++ = LF;
 
@@ -480,7 +514,7 @@ ngx_http_header_filter(ngx_http_request_
                              sizeof("Location: http") - 1);
 
 #if (NGX_HTTP_SSL)
-        if (r->connection->ssl) {
+        if (c->ssl) {
             *b->last++ ='s';
         }
 #endif
@@ -557,8 +591,8 @@ ngx_http_header_filter(ngx_http_request_
         *b->last++ = CR; *b->last++ = LF;
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "%*s\n", (size_t) (b->last - b->pos), b->pos);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "%*s", (size_t) (b->last - b->pos), b->pos);
 
     /* the end of HTTP header */
     *b->last++ = CR; *b->last++ = LF;
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -143,7 +143,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             }
 
-            if (ch < 'A' || ch > 'Z') {
+            if ((ch < 'A' || ch > 'Z') && ch != '_') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
 
@@ -257,7 +257,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             }
 
-            if (ch < 'A' || ch > 'Z') {
+            if ((ch < 'A' || ch > 'Z') && ch != '_') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
 
@@ -739,6 +739,7 @@ ngx_http_parse_header_line(ngx_http_requ
 
         /* first char */
         case sw_start:
+            r->header_name_start = p;
             r->invalid_header = 0;
 
             switch (ch) {
@@ -751,7 +752,6 @@ ngx_http_parse_header_line(ngx_http_requ
                 goto header_done;
             default:
                 state = sw_name;
-                r->header_name_start = p;
 
                 c = lowcase[ch];
 
@@ -950,9 +950,6 @@ ngx_http_parse_complex_uri(ngx_http_requ
         sw_slash,
         sw_dot,
         sw_dot_dot,
-#if (NGX_WIN32)
-        sw_dot_dot_dot,
-#endif
         sw_quoted,
         sw_quoted_second
     } state, quoted_state;
@@ -1137,65 +1134,15 @@ ngx_http_parse_complex_uri(ngx_http_requ
 #endif
             case '/':
                 state = sw_slash;
-                u -= 4;
-                if (u < r->uri.data) {
-                    return NGX_HTTP_PARSE_INVALID_REQUEST;
-                }
-                while (*(u - 1) != '/') {
-                    u--;
-                }
-                break;
-            case '%':
-                quoted_state = state;
-                state = sw_quoted;
-                break;
-            case '?':
-                r->args_start = p;
-                goto args;
-            case '#':
-                goto done;
-#if (NGX_WIN32)
-            case '.':
-                state = sw_dot_dot_dot;
-                *u++ = ch;
-                break;
-#endif
-            case '+':
-                r->plus_in_uri = 1;
-            default:
-                state = sw_usual;
-                *u++ = ch;
-                break;
-            }
-
-            ch = *p++;
-            break;
-
-#if (NGX_WIN32)
-        case sw_dot_dot_dot:
-
-            if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
-                state = sw_usual;
-                *u++ = ch;
-                ch = *p++;
-                break;
-            }
-
-            switch(ch) {
-            case '\\':
-            case '/':
-                state = sw_slash;
                 u -= 5;
-                if (u < r->uri.data) {
-                    return NGX_HTTP_PARSE_INVALID_REQUEST;
-                }
-                while (*u != '/') {
-                    u--;
-                }
-                if (u < r->uri.data) {
-                    return NGX_HTTP_PARSE_INVALID_REQUEST;
-                }
-                while (*(u - 1) != '/') {
+                for ( ;; ) {
+                    if (u < r->uri.data) {
+                        return NGX_HTTP_PARSE_INVALID_REQUEST;
+                    }
+                    if (*u == '/') {
+                        u++;
+                        break;
+                    }
                     u--;
                 }
                 break;
@@ -1218,7 +1165,6 @@ ngx_http_parse_complex_uri(ngx_http_requ
 
             ch = *p++;
             break;
-#endif
 
         case sw_quoted:
             r->quoted_uri = 1;
@@ -1337,12 +1283,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
         goto unsafe;
     }
 
-    if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/'
-#if (NGX_WIN32)
-                                                   || p[2] == '\\'
-#endif
-        ))
-    {
+    if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
         goto unsafe;
     }
 
@@ -1367,35 +1308,13 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
             continue;
         }
 
-        if ((ch == '/'
-#if (NGX_WIN32)
-             || ch == '\\'
-#endif
-            ) && len > 2)
-        {
+        if (ngx_path_separator(ch) && len > 2) {
+
             /* detect "/../" */
 
-            if (p[0] == '.' && p[1] == '.' && p[2] == '/') {
+            if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
                 goto unsafe;
             }
-
-#if (NGX_WIN32)
-
-            if (p[2] == '\\') {
-                goto unsafe;
-            }
-
-            if (len > 3) {
-
-                /* detect "/.../" */
-
-                if (p[0] == '.' && p[1] == '.' && p[2] == '.'
-                    && (p[3] == '/' || p[3] == '\\'))
-                {
-                    goto unsafe;
-                }
-            }
-#endif
         }
     }
 
@@ -1486,20 +1405,20 @@ ngx_http_parse_multi_header_lines(ngx_ar
 ngx_int_t
 ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
 {
-    u_char  *p;
+    u_char  *p, *last;
 
     if (r->args.len == 0) {
         return NGX_DECLINED;
     }
 
-    for (p = r->args.data; *p && *p != ' '; p++) {
+    p = r->args.data;
+    last = p + r->args.len;
 
-        /*
-         * although r->args.data is not null-terminated by itself,
-         * however, there is null in the end of request line
-         */
+    for ( /* void */ ; p < last; p++) {
 
-        p = ngx_strcasestrn(p, (char *) name, len - 1);
+        /* we need '=' after name, so drop one char from last */
+
+        p = ngx_strlcasestrn(p, last - 1, name, len - 1);
 
         if (p == NULL) {
             return NGX_DECLINED;
@@ -1509,7 +1428,7 @@ ngx_http_arg(ngx_http_request_t *r, u_ch
 
             value->data = p + len + 1;
 
-            p = (u_char *) ngx_strchr(p, '&');
+            p = ngx_strlchr(p, last, '&');
 
             if (p == NULL) {
                 p = r->args.data + r->args.len;
--- a/src/http/ngx_http_postpone_filter_module.c
+++ b/src/http/ngx_http_postpone_filter_module.c
@@ -102,7 +102,7 @@ ngx_http_postpone_filter(ngx_http_reques
 
             c->data = pr->request;
 
-            return ngx_http_post_request(pr->request);
+            return ngx_http_post_request(pr->request, NULL);
         }
 
         if (pr->out == NULL) {
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -36,6 +36,9 @@ static ngx_int_t ngx_http_find_virtual_s
     u_char *host, size_t len);
 
 static void ngx_http_request_handler(ngx_event_t *ev);
+static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc);
+static void ngx_http_terminate_handler(ngx_http_request_t *r);
+static void ngx_http_finalize_connection(ngx_http_request_t *r);
 static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r);
 static void ngx_http_writer(ngx_http_request_t *r);
 static void ngx_http_request_finalizer(ngx_http_request_t *r);
@@ -46,7 +49,7 @@ static void ngx_http_set_lingering_close
 static void ngx_http_lingering_close_handler(ngx_event_t *ev);
 static ngx_int_t ngx_http_post_action(ngx_http_request_t *r);
 static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error);
-static void ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error);
+static void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t error);
 static void ngx_http_log_request(ngx_http_request_t *r);
 static void ngx_http_close_connection(ngx_connection_t *c);
 
@@ -129,7 +132,7 @@ ngx_http_header_t  ngx_http_headers_in[]
     { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive),
                  ngx_http_process_header_line },
 
-#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
+#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)
     { ngx_string("X-Forwarded-For"),
                  offsetof(ngx_http_headers_in_t, x_forwarded_for),
                  ngx_http_process_header_line },
@@ -198,7 +201,7 @@ ngx_http_init_connection(ngx_connection_
     c->write->handler = ngx_http_empty_handler;
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_reading, 1);
+    (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
 #endif
 
     if (rev->ready) {
@@ -217,7 +220,7 @@ ngx_http_init_connection(ngx_connection_
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
 #if (NGX_STAT_STUB)
-        ngx_atomic_fetch_add(ngx_stat_reading, -1);
+        (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
 #endif
         ngx_http_close_connection(c);
         return;
@@ -247,7 +250,7 @@ ngx_http_init_request(ngx_event_t *rev)
 #endif
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_reading, -1);
+    (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
 #endif
 
     c = rev->data;
@@ -259,6 +262,8 @@ ngx_http_init_request(ngx_event_t *rev)
         return;
     }
 
+    c->requests++;
+
     hc = c->data;
 
     if (hc == NULL) {
@@ -310,7 +315,7 @@ ngx_http_init_request(ngx_event_t *rev)
          * is required to determine a server address
          */
 
-        if (ngx_http_server_addr(r, NULL) != NGX_OK) {
+        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
             ngx_http_close_connection(c);
             return;
         }
@@ -321,7 +326,7 @@ ngx_http_init_request(ngx_event_t *rev)
         case AF_INET6:
             sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
 
-            addr6 = (ngx_http_in6_addr_t *) port->addrs;
+            addr6 = port->addrs;
 
             /* the last address is "*" */
 
@@ -360,7 +365,7 @@ ngx_http_init_request(ngx_event_t *rev)
 
 #if (NGX_HAVE_INET6)
         case AF_INET6:
-            addr6 = (ngx_http_in6_addr_t *) port->addrs;
+            addr6 = port->addrs;
             addr_conf = &addr6[0].conf;
             break;
 #endif
@@ -372,6 +377,8 @@ ngx_http_init_request(ngx_event_t *rev)
         }
     }
 
+    r->virtual_names = addr_conf->virtual_names;
+
     /* the default server configuration for the address:port */
     cscf = addr_conf->core_srv_conf;
 
@@ -380,6 +387,7 @@ ngx_http_init_request(ngx_event_t *rev)
     r->loc_conf = cscf->ctx->loc_conf;
 
     rev->handler = ngx_http_process_request_line;
+    r->read_event_handler = ngx_http_block_reading;
 
 #if (NGX_HTTP_SSL)
 
@@ -418,9 +426,9 @@ ngx_http_init_request(ngx_event_t *rev)
 #endif
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-    c->log->file = clcf->err_log->file;
+    c->log->file = clcf->error_log->file;
     if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
-        c->log->log_level = clcf->err_log->log_level;
+        c->log->log_level = clcf->error_log->log_level;
     }
 
     if (c->buffer == NULL) {
@@ -447,13 +455,15 @@ ngx_http_init_request(ngx_event_t *rev)
                       sizeof(ngx_table_elt_t))
         != NGX_OK)
     {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_destroy_pool(r->pool);
+        ngx_http_close_connection(c);
         return;
     }
 
     r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
     if (r->ctx == NULL) {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_destroy_pool(r->pool);
+        ngx_http_close_connection(c);
         return;
     }
 
@@ -462,7 +472,8 @@ ngx_http_init_request(ngx_event_t *rev)
     r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
                                         * sizeof(ngx_http_variable_value_t));
     if (r->variables == NULL) {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_destroy_pool(r->pool);
+        ngx_http_close_connection(c);
         return;
     }
 
@@ -470,6 +481,7 @@ ngx_http_init_request(ngx_event_t *rev)
     c->destroyed = 0;
 
     r->main = r;
+    r->count = 1;
 
     tp = ngx_timeofday();
     r->start_sec = tp->sec;
@@ -493,9 +505,9 @@ ngx_http_init_request(ngx_event_t *rev)
     r->log_handler = ngx_http_log_error_handler;
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_reading, 1);
+    (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
     r->stat_reading = 1;
-    ngx_atomic_fetch_add(ngx_stat_requests, 1);
+    (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
 #endif
 
     rev->handler(rev);
@@ -697,7 +709,6 @@ ngx_http_process_request_line(ngx_event_
 
             r->request_line.len = r->request_end - r->request_start;
             r->request_line.data = r->request_start;
-            *r->request_end = '\0';
 
 
             if (r->args_start) {
@@ -760,6 +771,22 @@ ngx_http_process_request_line(ngx_event_
                 r->args.data = r->args_start;
             }
 
+#if (NGX_WIN32)
+            {
+            u_char  *p;
+
+            p = r->uri.data + r->uri.len - 1;
+
+            if (*p == '.') {
+
+                while (--p > r->uri.data && *p == '.') { /* void */ }
+
+                r->uri.len = p + 1 - r->uri.data;
+
+                ngx_http_set_exten(r);
+            }
+            }
+#endif
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                            "http request line: \"%V\"", &r->request_line);
@@ -866,9 +893,10 @@ ngx_http_process_request_line(ngx_event_
 static void
 ngx_http_process_request_headers(ngx_event_t *rev)
 {
+    u_char                     *p;
+    size_t                      len;
     ssize_t                     n;
     ngx_int_t                   rc, rv;
-    ngx_str_t                   header;
     ngx_table_elt_t            *h;
     ngx_connection_t           *c;
     ngx_http_header_t          *hh;
@@ -908,19 +936,17 @@ ngx_http_process_request_headers(ngx_eve
                 }
 
                 if (rv == NGX_DECLINED) {
-                    header.len = r->header_in->end - r->header_name_start;
-                    header.data = r->header_name_start;
-
-                    if (header.len > NGX_MAX_ERROR_STR - 300) {
-                        header.len = NGX_MAX_ERROR_STR - 300;
-                        header.data[header.len++] = '.';
-                        header.data[header.len++] = '.';
-                        header.data[header.len++] = '.';
+                    len = r->header_in->end - r->header_name_start;
+                    p = r->header_name_start;
+
+                    if (len > NGX_MAX_ERROR_STR - 300) {
+                        len = NGX_MAX_ERROR_STR - 300;
+                        p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
                     }
 
                     ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                                  "client sent too long header line: \"%V\"",
-                                  &header);
+                                  "client sent too long header line: \"%*s\"",
+                                  len, r->header_name_start);
                     ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                     return;
                 }
@@ -942,12 +968,10 @@ ngx_http_process_request_headers(ngx_eve
 
                 /* there was error while a header line parsing */
 
-                header.len = r->header_end - r->header_name_start;
-                header.data = r->header_name_start;
-
                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client sent invalid header line: \"%V\"",
-                              &header);
+                              "client sent invalid header line: \"%*s\"",
+                              r->header_end - r->header_name_start,
+                              r->header_name_start);
                 continue;
             }
 
@@ -1027,11 +1051,10 @@ ngx_http_process_request_headers(ngx_eve
 
         /* rc == NGX_HTTP_PARSE_INVALID_HEADER: "\r" is not followed by "\n" */
 
-        header.len = r->header_end - r->header_name_start;
-        header.data = r->header_name_start;
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                      "client sent invalid header line: \"%V\\r...\"",
-                      &header);
+                      "client sent invalid header line: \"%*s\\r...\"",
+                      r->header_end - r->header_name_start,
+                      r->header_name_start);
         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
         return;
     }
@@ -1359,8 +1382,13 @@ ngx_http_process_user_agent(ngx_http_req
                 r->headers_in.msie4 = 1;
                 /* fall through */
             case '5':
+                r->headers_in.msie6 = 1;
+                break;
             case '6':
-                r->headers_in.msie6 = 1;
+                if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) {
+                    r->headers_in.msie6 = 1;
+                }
+                break;
             }
         }
 
@@ -1502,7 +1530,7 @@ ngx_http_process_request(ngx_http_reques
 
         sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
 
-        if (sscf->verify == 1) {
+        if (sscf->verify) {
             rc = SSL_get_verify_result(c->ssl->connection);
 
             if (rc != X509_V_OK) {
@@ -1517,20 +1545,22 @@ ngx_http_process_request(ngx_http_reques
                 return;
             }
 
-            cert = SSL_get_peer_certificate(c->ssl->connection);
-
-            if (cert == NULL) {
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client sent no required SSL certificate");
-
-                ngx_ssl_remove_cached_session(sscf->ssl.ctx,
+            if (sscf->verify == 1) {
+                cert = SSL_get_peer_certificate(c->ssl->connection);
+
+                if (cert == NULL) {
+                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                                  "client sent no required SSL certificate");
+
+                    ngx_ssl_remove_cached_session(sscf->ssl.ctx,
                                        (SSL_get0_session(c->ssl->connection)));
 
-                ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
-                return;
+                    ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
+                    return;
+                }
+
+                X509_free(cert);
             }
-
-            X509_free(cert);
         }
     }
 
@@ -1541,9 +1571,9 @@ ngx_http_process_request(ngx_http_reques
     }
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_reading, -1);
+    (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
     r->stat_reading = 0;
-    ngx_atomic_fetch_add(ngx_stat_writing, 1);
+    (void) ngx_atomic_fetch_add(ngx_stat_writing, 1);
     r->stat_writing = 1;
 #endif
 
@@ -1586,15 +1616,9 @@ ngx_http_validate_host(u_char *host, siz
             continue;
         }
 
-        if (ch == '/' || ch == '\0') {
+        if (ngx_path_separator(ch) || ch == '\0') {
             return -1;
         }
-
-#if (NGX_WIN32)
-        if (ch == '\\') {
-            return -1;
-        }
-#endif
     }
 
     if (dot) {
@@ -1610,15 +1634,11 @@ ngx_http_find_virtual_server(ngx_http_re
 {
     u_char                    *server;
     ngx_uint_t                 hash;
-    ngx_http_virtual_names_t  *vn;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
     u_char                     buf[32];
 
-    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
-    vn = cscf->virtual_names;
-
-    if (vn == NULL) {
+    if (r->virtual_names == NULL) {
         return NGX_DECLINED;
     }
 
@@ -1634,7 +1654,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
     hash = ngx_hash_strlow(server, host, len);
 
-    cscf = ngx_hash_find_combined(&vn->names, hash, server, len);
+    cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len);
 
     if (cscf) {
         goto found;
@@ -1642,7 +1662,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
 #if (NGX_PCRE)
 
-    if (vn->nregex) {
+    if (r->virtual_names->nregex) {
         size_t                   ncaptures;
         ngx_int_t                n;
         ngx_uint_t               i;
@@ -1654,9 +1674,9 @@ ngx_http_find_virtual_server(ngx_http_re
 
         ncaptures = 0;
 
-        sn = vn->regex;
-
-        for (i = 0; i < vn->nregex; i++) {
+        sn = r->virtual_names->regex;
+
+        for (i = 0; i < r->virtual_names->nregex; i++) {
 
             if (sn[i].captures && r->captures == NULL) {
 
@@ -1713,10 +1733,10 @@ found:
     r->loc_conf = cscf->ctx->loc_conf;
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-    r->connection->log->file = clcf->err_log->file;
+    r->connection->log->file = clcf->error_log->file;
 
     if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
-        r->connection->log->log_level = clcf->err_log->log_level;
+        r->connection->log->log_level = clcf->error_log->log_level;
     }
 
     return NGX_OK;
@@ -1786,13 +1806,15 @@ ngx_http_run_posted_requests(ngx_connect
 
 
 ngx_int_t
-ngx_http_post_request(ngx_http_request_t *r)
+ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr)
 {
-    ngx_http_posted_request_t  *pr, **p;
-
-    pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
+    ngx_http_posted_request_t  **p;
+
     if (pr == NULL) {
-        return NGX_ERROR;
+        pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
+        if (pr == NULL) {
+            return NGX_ERROR;
+        }
     }
 
     pr->request = r;
@@ -1813,16 +1835,21 @@ ngx_http_finalize_request(ngx_http_reque
     ngx_http_request_t        *pr;
     ngx_http_core_loc_conf_t  *clcf;
 
+    c = r->connection;
+
+    ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http finalize request: %d, \"%V?%V\" a:%d, c:%d",
+                   rc, &r->uri, &r->args, r == c->data, r->main->count);
+
     if (rc == NGX_DONE) {
-        /* the request pool may be already destroyed */
+        ngx_http_finalize_connection(r);
         return;
     }
 
-    c = r->connection;
-
-    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http finalize request: %d, \"%V?%V\" %d",
-                   rc, &r->uri, &r->args, r == c->data);
+    if (rc == NGX_OK && r->filter_finalize) {
+        c->error = 1;
+        return;
+    }
 
     if (rc == NGX_DECLINED) {
         r->content_handler = NULL;
@@ -1840,15 +1867,15 @@ ngx_http_finalize_request(ngx_http_reque
         || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
         || c->error)
     {
-        if (rc > 0 && r->headers_out.status == 0) {
-            r->headers_out.status = rc;
-        }
-
         if (ngx_http_post_action(r) == NGX_OK) {
             return;
         }
 
-        ngx_http_close_request(r, 0);
+        if (r->main->blocked) {
+            r->write_event_handler = ngx_http_request_finalizer;
+        }
+
+        ngx_http_terminate_request(r, rc);
         return;
     }
 
@@ -1857,7 +1884,7 @@ ngx_http_finalize_request(ngx_http_reque
         || rc == NGX_HTTP_NO_CONTENT)
     {
         if (rc == NGX_HTTP_CLOSE) {
-            ngx_http_close_request(r, rc);
+            ngx_http_terminate_request(r, rc);
             return;
         }
 
@@ -1883,7 +1910,7 @@ ngx_http_finalize_request(ngx_http_reque
         if (r->buffered || r->postponed) {
 
             if (ngx_http_set_write_handler(r) != NGX_OK) {
-                ngx_http_close_request(r->main, 0);
+                ngx_http_terminate_request(r, 0);
             }
 
             return;
@@ -1901,6 +1928,8 @@ ngx_http_finalize_request(ngx_http_reque
 
         if (r == c->data) {
 
+            r->main->count--;
+
             if (!r->logged) {
 
                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -1934,8 +1963,9 @@ ngx_http_finalize_request(ngx_http_reque
             }
         }
 
-        if (ngx_http_post_request(pr) != NGX_OK) {
-            ngx_http_close_request(r->main, 0);
+        if (ngx_http_post_request(pr, NULL) != NGX_OK) {
+            r->main->count++;
+            ngx_http_terminate_request(r, 0);
             return;
         }
 
@@ -1946,10 +1976,10 @@ ngx_http_finalize_request(ngx_http_reque
         return;
     }
 
-    if (r->buffered || c->buffered || r->postponed) {
+    if (r->buffered || c->buffered || r->postponed || r->blocked) {
 
         if (ngx_http_set_write_handler(r) != NGX_OK) {
-            ngx_http_close_request(r, 0);
+            ngx_http_terminate_request(r, 0);
         }
 
         return;
@@ -1981,11 +2011,77 @@ ngx_http_finalize_request(ngx_http_reque
         ngx_del_timer(c->write);
     }
 
-    if (c->destroyed) {
+    if (c->read->eof) {
+        ngx_http_close_request(r, 0);
         return;
     }
 
-    if (c->read->eof) {
+    ngx_http_finalize_connection(r);
+}
+
+
+static void
+ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc)
+{
+    ngx_http_cleanup_t    *cln;
+    ngx_http_request_t    *mr;
+    ngx_http_ephemeral_t  *e;
+
+    mr = r->main;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http terminate request count:%d", mr->count);
+
+    cln = mr->cleanup;
+    mr->cleanup = NULL;
+
+    while (cln) {
+        if (cln->handler) {
+            cln->handler(cln->data);
+        }
+
+        cln = cln->next;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http terminate cleanup count:%d blk:%d",
+                   mr->count, mr->blocked);
+
+    if (mr->write_event_handler) {
+
+        if (mr->blocked) {
+            return;
+        }
+
+        e = ngx_http_ephemeral(mr);
+        mr->posted_requests = NULL;
+        mr->write_event_handler = ngx_http_terminate_handler;
+        (void) ngx_http_post_request(mr, &e->terminal_posted_request);
+        return;
+    }
+
+    ngx_http_close_request(mr, rc);
+}
+
+
+static void
+ngx_http_terminate_handler(ngx_http_request_t *r)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http terminate handler count:%d", r->count);
+
+    r->count = 1;
+
+    ngx_http_close_request(r, 0);
+}
+
+
+static void
+ngx_http_finalize_connection(ngx_http_request_t *r)
+{
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (r->main->count != 1) {
         ngx_http_close_request(r, 0);
         return;
     }
@@ -2080,7 +2176,7 @@ ngx_http_writer(ngx_http_request_t *r)
         }
 
     } else {
-        if (wev->delayed) {
+        if (wev->delayed || r->aio) {
             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
                            "http writer delayed");
 
@@ -2094,14 +2190,15 @@ ngx_http_writer(ngx_http_request_t *r)
 
     rc = ngx_http_output_filter(r, NULL);
 
-    if (c->destroyed) {
-        return;
-    }
-
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http writer output filter: %d, \"%V?%V\"",
                    rc, &r->uri, &r->args);
 
+    if (rc == NGX_ERROR) {
+        ngx_http_finalize_request(r, rc);
+        return;
+    }
+
     if (r->buffered || r->postponed || (r == r->main && c->buffered)) {
 
         if (!wev->ready && !wev->delayed) {
@@ -2294,7 +2391,7 @@ ngx_http_set_keepalive(ngx_http_request_
         }
     }
 
-    ngx_http_request_done(r, 0);
+    ngx_http_free_request(r, 0);
 
     c->data = hc;
 
@@ -2313,7 +2410,7 @@ ngx_http_set_keepalive(ngx_http_request_
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request");
 
 #if (NGX_STAT_STUB)
-        ngx_atomic_fetch_add(ngx_stat_reading, 1);
+        (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
 #endif
 
         hc->pipeline = 1;
@@ -2543,7 +2640,7 @@ ngx_http_keepalive_handler(ngx_event_t *
     b->last += n;
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_reading, 1);
+    (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
 #endif
 
     c->log->handler = ngx_http_log_error;
@@ -2688,7 +2785,14 @@ ngx_http_send_special(ngx_http_request_t
     }
 
     if (flags & NGX_HTTP_LAST) {
-        b->last_buf = 1;
+
+        if (r == r->main && !r->post_action) {
+            b->last_buf = 1;
+
+        } else {
+            b->sync = 1;
+            b->last_in_chain = 1;
+        }
     }
 
     if (flags & NGX_HTTP_FLUSH) {
@@ -2716,6 +2820,8 @@ ngx_http_post_action(ngx_http_request_t 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "post action: \"%V\"", &clcf->post_action);
 
+    r->main->count--;
+
     r->http_version = NGX_HTTP_VERSION_9;
     r->header_only = 1;
     r->post_action = 1;
@@ -2734,19 +2840,33 @@ ngx_http_post_action(ngx_http_request_t 
 
 
 static void
-ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error)
+ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
 {
     ngx_connection_t  *c;
 
+    r = r->main;
     c = r->connection;
 
-    ngx_http_request_done(r->main, error);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http request count:%d blk:%d", r->count, r->blocked);
+
+    if (r->count == 0) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero");
+    }
+
+    r->count--;
+
+    if (r->count || r->blocked) {
+        return;
+    }
+
+    ngx_http_free_request(r, rc);
     ngx_http_close_connection(c);
 }
 
 
 static void
-ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error)
+ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc)
 {
     ngx_log_t                 *log;
     struct linger              linger;
@@ -2772,17 +2892,17 @@ ngx_http_request_done(ngx_http_request_t
 #if (NGX_STAT_STUB)
 
     if (r->stat_reading) {
-        ngx_atomic_fetch_add(ngx_stat_reading, -1);
+        (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
     }
 
     if (r->stat_writing) {
-        ngx_atomic_fetch_add(ngx_stat_writing, -1);
+        (void) ngx_atomic_fetch_add(ngx_stat_writing, -1);
     }
 
 #endif
 
-    if (error && r->headers_out.status == 0) {
-        r->headers_out.status = error;
+    if (rc > 0 && (r->headers_out.status == 0 || r->connection->sent == 0)) {
+        r->headers_out.status = rc;
     }
 
     log->action = "logging request";
@@ -2857,7 +2977,7 @@ ngx_http_close_connection(ngx_connection
 #endif
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_active, -1);
+    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
 #endif
 
     c->destroyed = 1;
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -184,7 +184,7 @@ typedef struct {
 
     ngx_table_elt_t                  *keep_alive;
 
-#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
+#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)
     ngx_table_elt_t                  *x_forwarded_for;
 #endif
 
@@ -387,6 +387,8 @@ struct ngx_http_request_s {
     ngx_http_post_subrequest_t       *post_subrequest;
     ngx_http_posted_request_t        *posted_requests;
 
+    ngx_http_virtual_names_t         *virtual_names;
+
     ngx_int_t                         phase_handler;
     ngx_http_handler_pt               content_handler;
     ngx_uint_t                        access_code;
@@ -414,6 +416,12 @@ struct ngx_http_request_s {
 
     ngx_http_cleanup_t               *cleanup;
 
+    unsigned                          subrequests:8;
+    unsigned                          count:8;
+    unsigned                          blocked:8;
+
+    unsigned                          aio:1;
+
     unsigned                          http_state:4;
 
     /* URI with "/." and on Win32 with "//" */
@@ -476,6 +484,8 @@ struct ngx_http_request_s {
     unsigned                          discard_body:1;
     unsigned                          internal:1;
     unsigned                          error_page:1;
+    unsigned                          ignore_content_encoding:1;
+    unsigned                          filter_finalize:1;
     unsigned                          post_action:1;
     unsigned                          request_complete:1;
     unsigned                          request_output:1;
@@ -484,7 +494,6 @@ struct ngx_http_request_s {
     unsigned                          root_tested:1;
     unsigned                          done:1;
     unsigned                          logged:1;
-    unsigned                          utf8:1;
 
     unsigned                          buffered:4;
 
@@ -498,11 +507,24 @@ struct ngx_http_request_s {
     unsigned                          stat_writing:1;
 #endif
 
-    unsigned                          subrequests:8;
-
     /* used to parse HTTP headers */
 
     ngx_uint_t                        state;
+
+    ngx_uint_t                        header_hash;
+    ngx_uint_t                        lowcase_index;
+    u_char                            lowcase_header[NGX_HTTP_LC_HEADER_LEN];
+
+    u_char                           *header_name_start;
+    u_char                           *header_name_end;
+    u_char                           *header_start;
+    u_char                           *header_end;
+
+    /*
+     * a memory that can be reused after parsing a request line
+     * via ngx_http_ephemeral_t
+     */
+
     u_char                           *uri_start;
     u_char                           *uri_end;
     u_char                           *uri_ext;
@@ -516,18 +538,18 @@ struct ngx_http_request_s {
     u_char                           *host_end;
     u_char                           *port_start;
     u_char                           *port_end;
-    u_char                           *header_name_start;
-    u_char                           *header_name_end;
-    u_char                           *header_start;
-    u_char                           *header_end;
 
     unsigned                          http_minor:16;
     unsigned                          http_major:16;
+};
 
-    ngx_uint_t                        header_hash;
-    ngx_uint_t                        lowcase_index;
-    u_char                            lowcase_header[NGX_HTTP_LC_HEADER_LEN];
-};
+
+typedef struct {
+    ngx_http_posted_request_t         terminal_posted_request;
+#if (NGX_HAVE_AIO_SENDFILE)
+    u_char                            aio_preload;
+#endif
+} ngx_http_ephemeral_t;
 
 
 extern ngx_http_header_t       ngx_http_headers_in[];
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -37,6 +37,8 @@ ngx_http_read_client_request_body(ngx_ht
     ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
 
+    r->main->count++;
+
     if (r->request_body || r->discard_body) {
         post_handler(r);
         return NGX_OK;
@@ -475,6 +477,7 @@ ngx_http_discard_request_body(ngx_http_r
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    r->count++;
     (void) ngx_http_read_discarded_request_body(r);
 
     return NGX_OK;
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -561,7 +561,7 @@ ngx_http_script_add_code(ngx_array_t *co
 
     new = ngx_array_push_n(codes, size);
     if (new == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (code) {
@@ -1074,11 +1074,7 @@ ngx_http_script_regex_end_code(ngx_http_
             return;
         }
 
-        if (ngx_http_set_exten(r) != NGX_OK) {
-            e->ip = ngx_http_script_exit;
-            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            return;
-        }
+        ngx_http_set_exten(r);
     }
 
     e->ip += sizeof(ngx_http_script_regex_end_code_t);
@@ -1213,7 +1209,7 @@ ngx_http_script_add_full_name_code(ngx_h
     }
 
     code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code;
-    code->prefix = sc->conf_prefix;
+    code->conf_prefix = sc->conf_prefix;
 
     code = ngx_http_script_add_code(*sc->values,
                                     sizeof(ngx_http_script_full_name_code_t),
@@ -1223,7 +1219,7 @@ ngx_http_script_add_full_name_code(ngx_h
     }
 
     code->code = ngx_http_script_full_name_code;
-    code->prefix = sc->conf_prefix;
+    code->conf_prefix = sc->conf_prefix;
 
     return NGX_OK;
 }
@@ -1238,7 +1234,8 @@ ngx_http_script_full_name_len_code(ngx_h
 
     e->ip += sizeof(ngx_http_script_full_name_code_t);
 
-    return code->prefix ? sizeof(NGX_CONF_PREFIX) : ngx_cycle->root.len;
+    return code->conf_prefix ? ngx_cycle->conf_prefix.len:
+                               ngx_cycle->prefix.len;
 }
 
 
@@ -1254,7 +1251,7 @@ ngx_http_script_full_name_code(ngx_http_
     value.data = e->buf.data;
     value.len = e->pos - e->buf.data;
 
-    if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->prefix)
+    if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix)
         != NGX_OK)
     {
         e->ip = ngx_http_script_exit;
@@ -1413,6 +1410,7 @@ ngx_http_script_file_code(ngx_http_scrip
     of.directio = clcf->directio;
     of.valid = clcf->open_file_cache_valid;
     of.min_uses = clcf->open_file_cache_min_uses;
+    of.test_only = 1;
     of.errors = clcf->open_file_cache_errors;
     of.events = clcf->open_file_cache_events;
 
@@ -1421,7 +1419,7 @@ ngx_http_script_file_code(ngx_http_scrip
     {
         if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
-                          ngx_file_info_n " \"%s\" failed", value->data);
+                          "%s \"%s\" failed", of.failed, value->data);
         }
 
         switch (code->op) {
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -153,7 +153,7 @@ typedef struct {
 
 typedef struct {
     ngx_http_script_code_pt     code;
-    uintptr_t                   prefix;
+    uintptr_t                   conf_prefix;
 } ngx_http_script_full_name_code_t;
 
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -275,14 +275,16 @@ static ngx_str_t ngx_http_error_pages[] 
 
     ngx_null_string,                     /* 201, 204 */
 
-#define NGX_HTTP_LEVEL_200  1
+#define NGX_HTTP_LAST_LEVEL_200  202
+#define NGX_HTTP_LEVEL_200       (NGX_HTTP_LAST_LEVEL_200 - 201)
 
     /* ngx_null_string, */               /* 300 */
     ngx_string(ngx_http_error_301_page),
     ngx_string(ngx_http_error_302_page),
     ngx_null_string,                     /* 303 */
 
-#define NGX_HTTP_LEVEL_300  3
+#define NGX_HTTP_LAST_LEVEL_300  304
+#define NGX_HTTP_LEVEL_300       (NGX_HTTP_LAST_LEVEL_300 - 301)
 
     ngx_string(ngx_http_error_400_page),
     ngx_string(ngx_http_error_401_page),
@@ -302,7 +304,8 @@ static ngx_str_t ngx_http_error_pages[] 
     ngx_string(ngx_http_error_415_page),
     ngx_string(ngx_http_error_416_page),
 
-#define NGX_HTTP_LEVEL_400  17
+#define NGX_HTTP_LAST_LEVEL_400  417
+#define NGX_HTTP_LEVEL_400       (NGX_HTTP_LAST_LEVEL_400 - 400)
 
     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
@@ -318,6 +321,9 @@ static ngx_str_t ngx_http_error_pages[] 
     ngx_null_string,                     /* 505 */
     ngx_null_string,                     /* 506 */
     ngx_string(ngx_http_error_507_page)
+
+#define NGX_HTTP_LAST_LEVEL_500  508
+
 };
 
 
@@ -402,16 +408,22 @@ ngx_http_special_response_handler(ngx_ht
         /* 204 */
         err = 0;
 
-    } else if (error < NGX_HTTP_BAD_REQUEST) {
+    } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
+               && error < NGX_HTTP_LAST_LEVEL_300)
+    {
         /* 3XX */
         err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
 
-    } else if (error < NGX_HTTP_OWN_CODES) {
+    } else if (error >= NGX_HTTP_BAD_REQUEST
+               && error < NGX_HTTP_LAST_LEVEL_400)
+    {
         /* 4XX */
         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200
                                            + NGX_HTTP_LEVEL_300;
 
-    } else {
+    } else if (error >= NGX_HTTP_OWN_CODES
+               && error < NGX_HTTP_LAST_LEVEL_500)
+    {
         /* 49X, 5XX */
         err = error - NGX_HTTP_OWN_CODES + NGX_HTTP_LEVEL_200
                                          + NGX_HTTP_LEVEL_300
@@ -423,12 +435,72 @@ ngx_http_special_response_handler(ngx_ht
                 r->err_status = NGX_HTTP_BAD_REQUEST;
                 break;
         }
+
+    } else {
+        /* unknown code, zero body */
+        err = 0;
     }
 
     return ngx_http_send_special_response(r, clcf, err);
 }
 
 
+ngx_int_t
+ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
+    ngx_int_t error)
+{
+    void       *ctx;
+    ngx_int_t   rc;
+
+    ngx_http_clean_header(r);
+
+    ctx = NULL;
+
+    if (m) {
+        ctx = r->ctx[m->ctx_index];
+    }
+
+    /* clear the modules contexts */
+    ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
+
+    if (m) {
+        r->ctx[m->ctx_index] = ctx;
+    }
+
+    r->filter_finalize = 1;
+
+    rc = ngx_http_special_response_handler(r, error);
+
+    /* NGX_ERROR resets any pending data */
+
+    switch (rc) {
+
+    case NGX_OK:
+    case NGX_DONE:
+        return NGX_ERROR;
+
+    default:
+        return rc;
+    }
+}
+
+
+void
+ngx_http_clean_header(ngx_http_request_t *r)
+{
+    ngx_memzero(&r->headers_out.status,
+                sizeof(ngx_http_headers_out_t)
+                    - offsetof(ngx_http_headers_out_t, status));
+
+    r->headers_out.headers.part.nelts = 0;
+    r->headers_out.headers.part.next = NULL;
+    r->headers_out.headers.last = &r->headers_out.headers.part;
+
+    r->headers_out.content_length_n = -1;
+    r->headers_out.last_modified_time = -1;
+}
+
+
 static ngx_int_t
 ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
 {
@@ -451,14 +523,14 @@ ngx_http_send_error_page(ngx_http_reques
         return NGX_ERROR;
     }
 
-    if (err_page->value.lengths) {
-        ngx_http_split_args(r, &uri, &args);
+    if (uri.data[0] == '/') {
 
-    } else {
-        args = err_page->args;
-    }
+        if (err_page->value.lengths) {
+            ngx_http_split_args(r, &uri, &args);
 
-    if (uri.data[0] == '/') {
+        } else {
+            args = err_page->args;
+        }
 
         if (r->method != NGX_HTTP_HEAD) {
             r->method = NGX_HTTP_GET;
@@ -538,6 +610,7 @@ ngx_http_send_special_response(ngx_http_
             r->headers_out.content_type_len = sizeof("text/html") - 1;
             r->headers_out.content_type.len = sizeof("text/html") - 1;
             r->headers_out.content_type.data = (u_char *) "text/html";
+            r->headers_out.content_type_lowcase = NULL;
 
         } else {
             r->headers_out.content_length_n = -1;
@@ -640,6 +713,7 @@ ngx_http_send_refresh(ngx_http_request_t
     r->headers_out.content_type_len = sizeof("text/html") - 1;
     r->headers_out.content_type.len = sizeof("text/html") - 1;
     r->headers_out.content_type.data = (u_char *) "text/html";
+    r->headers_out.content_type_lowcase = NULL;
 
     r->headers_out.location->hash = 0;
     r->headers_out.location = NULL;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -14,8 +14,11 @@ static ngx_int_t ngx_http_upstream_cache
     ngx_http_upstream_t *u);
 static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
     ngx_http_upstream_t *u);
+static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 #endif
 
+static void ngx_http_upstream_init_request(ngx_http_request_t *r);
 static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
 static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
 static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
@@ -70,10 +73,14 @@ static void ngx_http_upstream_finalize_r
 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t
-    ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
+    ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
@@ -155,6 +162,12 @@ ngx_http_upstream_header_t  ngx_http_ups
                  offsetof(ngx_http_upstream_headers_in_t, last_modified),
                  ngx_http_upstream_copy_last_modified, 0, 0 },
 
+    { ngx_string("ETag"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, etag),
+                 ngx_http_upstream_copy_header_line,
+                 offsetof(ngx_http_headers_out_t, etag), 0 },
+
     { ngx_string("Server"),
                  ngx_http_upstream_process_header_line,
                  offsetof(ngx_http_upstream_headers_in_t, server),
@@ -184,14 +197,12 @@ ngx_http_upstream_header_t  ngx_http_ups
                  ngx_http_upstream_copy_header_line, 0, 1 },
 
     { ngx_string("Cache-Control"),
-                 ngx_http_upstream_process_multi_header_lines,
-                 offsetof(ngx_http_upstream_headers_in_t, cache_control),
+                 ngx_http_upstream_process_cache_control, 0,
                  ngx_http_upstream_copy_multi_header_lines,
                  offsetof(ngx_http_headers_out_t, cache_control), 1 },
 
     { ngx_string("Expires"),
-                 ngx_http_upstream_process_header_line,
-                 offsetof(ngx_http_upstream_headers_in_t, expires),
+                 ngx_http_upstream_process_expires, 0,
                  ngx_http_upstream_copy_header_line,
                  offsetof(ngx_http_headers_out_t, expires), 1 },
 
@@ -214,26 +225,25 @@ ngx_http_upstream_header_t  ngx_http_ups
                  ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Expires"),
-                 ngx_http_upstream_process_header_line,
-                 offsetof(ngx_http_upstream_headers_in_t, x_accel_expires),
+                 ngx_http_upstream_process_accel_expires, 0,
                  ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Redirect"),
                  ngx_http_upstream_process_header_line,
                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Limit-Rate"),
                  ngx_http_upstream_process_limit_rate, 0,
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Buffering"),
                  ngx_http_upstream_process_buffering, 0,
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("X-Accel-Charset"),
                  ngx_http_upstream_process_charset, 0,
-                 ngx_http_upstream_ignore_header_line, 0, 0 },
+                 ngx_http_upstream_copy_header_line, 0, 0 },
 
 #if (NGX_HTTP_GZIP)
     { ngx_string("Content-Encoding"),
@@ -315,6 +325,14 @@ static ngx_http_variable_t  ngx_http_ups
       ngx_http_upstream_response_length_variable, 0,
       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
+#if (NGX_HTTP_CACHE)
+
+    { ngx_string("upstream_cache_status"), NULL,
+      ngx_http_upstream_cache_status, 0,
+      NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
+#endif
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
@@ -328,18 +346,53 @@ static ngx_http_upstream_next_t  ngx_htt
     { 0, 0 }
 };
 
+
+ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[] = {
+   { ngx_string("GET"),  NGX_HTTP_GET},
+   { ngx_string("HEAD"), NGX_HTTP_HEAD },
+   { ngx_string("POST"), NGX_HTTP_POST },
+   { ngx_null_string, 0 }
+};
+
+
+ngx_int_t
+ngx_http_upstream_create(ngx_http_request_t *r)
+{
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+
+    if (u && u->cleanup) {
+        r->main->count++;
+        ngx_http_upstream_cleanup(r);
+        *u->cleanup = NULL;
+    }
+
+    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
+    if (u == NULL) {
+        return NGX_ERROR;
+    }
+
+    r->upstream = u;
+
+    u->peer.log = r->connection->log;
+    u->peer.log_error = NGX_ERROR_ERR;
+#if (NGX_THREADS)
+    u->peer.lock = &r->connection->lock;
+#endif
+
+#if (NGX_HTTP_CACHE)
+    r->cache = NULL;
+#endif
+
+    return NGX_OK;
+}
+
+
 void
 ngx_http_upstream_init(ngx_http_request_t *r)
 {
-    ngx_str_t                      *host;
-    ngx_uint_t                      i;
-    ngx_connection_t               *c;
-    ngx_resolver_ctx_t             *ctx, temp;
-    ngx_http_cleanup_t             *cln;
-    ngx_http_upstream_t            *u;
-    ngx_http_core_loc_conf_t       *clcf;
-    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
-    ngx_http_upstream_main_conf_t  *umcf;
+    ngx_connection_t     *c;
 
     c = r->connection;
 
@@ -350,13 +403,6 @@ ngx_http_upstream_init(ngx_http_request_
         ngx_del_timer(c->read);
     }
 
-    u = r->upstream;
-
-    if (!r->post_action && !u->conf->ignore_client_abort) {
-        r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
-        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
-    }
-
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
 
         if (!c->write->active) {
@@ -369,10 +415,28 @@ ngx_http_upstream_init(ngx_http_request_
         }
     }
 
-    if (r->request_body) {
-        u->request_bufs = r->request_body->bufs;
+    ngx_http_upstream_init_request(r);
+}
+
+
+static void
+ngx_http_upstream_init_request(ngx_http_request_t *r)
+{
+    ngx_str_t                      *host;
+    ngx_uint_t                      i;
+    ngx_resolver_ctx_t             *ctx, temp;
+    ngx_http_cleanup_t             *cln;
+    ngx_http_upstream_t            *u;
+    ngx_http_core_loc_conf_t       *clcf;
+    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    if (r->aio) {
+        return;
     }
 
+    u = r->upstream;
+
 #if (NGX_HTTP_CACHE)
 
     if (u->conf->cache) {
@@ -380,6 +444,13 @@ ngx_http_upstream_init(ngx_http_request_
 
         rc = ngx_http_upstream_cache(r, u);
 
+        if (rc == NGX_BUSY) {
+            r->write_event_handler = ngx_http_upstream_init_request;
+            return;
+        }
+
+        r->write_event_handler = ngx_http_request_empty_handler;
+
         if (rc == NGX_DONE) {
             return;
         }
@@ -392,6 +463,17 @@ ngx_http_upstream_init(ngx_http_request_
 
 #endif
 
+    u->store = (u->conf->store || u->conf->store_lengths);
+
+    if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
+        r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
+        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
+    }
+
+    if (r->request_body) {
+        u->request_bufs = r->request_body->bufs;
+    }
+
     if (u->create_request(r) != NGX_OK) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
@@ -399,6 +481,7 @@ ngx_http_upstream_init(ngx_http_request_
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
+    u->output.alignment = clcf->directio_alignment;
     u->output.pool = r->pool;
     u->output.bufs.num = 1;
     u->output.bufs.size = clcf->client_body_buffer_size;
@@ -438,8 +521,6 @@ ngx_http_upstream_init(ngx_http_request_
     cln->data = r;
     u->cleanup = &cln->handler;
 
-    u->store = (u->conf->store || u->conf->store_lengths);
-
     if (u->resolved == NULL) {
 
         uscf = u->conf->upstream;
@@ -488,7 +569,7 @@ ngx_http_upstream_init(ngx_http_request_
         }
 
         if (ctx == NGX_NO_RESOLVER) {
-            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                           "no resolver defined to resolve %V", host);
 
             ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
@@ -531,38 +612,73 @@ ngx_http_upstream_cache(ngx_http_request
     ngx_int_t          rc;
     ngx_http_cache_t  *c;
 
-    c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
+    c = r->cache;
+
     if (c == NULL) {
-        return NGX_ERROR;
-    }
-
-    if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
-        return NGX_ERROR;
+
+        if (!(r->method & u->conf->cache_methods)) {
+            return NGX_DECLINED;
+        }
+
+        if (r->method & NGX_HTTP_HEAD) {
+            u->method = ngx_http_core_get_method;
+        }
+
+        c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
+        if (c == NULL) {
+            return NGX_ERROR;
+        }
+
+        if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        r->cache = c;
+        c->file.log = r->connection->log;
+
+        if (u->create_key(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        /* TODO: add keys */
+
+        ngx_http_file_cache_create_key(r);
+
+        u->cacheable = 1;
+
+        c->min_uses = u->conf->cache_min_uses;
+        c->body_start = u->conf->buffer_size;
+        c->file_cache = u->conf->cache->data;
+
+        u->cache_status = NGX_HTTP_CACHE_MISS;
     }
 
-    r->cache = c;
-    c->file.log = r->connection->log;
-
-    if (u->create_key(r) != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-    /* TODO: add keys */
-
-    ngx_http_file_cache_create_key(r);
-
-    u->cacheable = 1;
-
-    c->min_uses = r->upstream->conf->cache_min_uses;
-    c->body_start = r->upstream->conf->buffer_size;
-    c->file_cache = u->conf->cache->data;
-
     rc = ngx_http_file_cache_open(r);
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http upstream cache: %i u:%ui", rc, c->uses);
-
-    if (rc == NGX_OK) {
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http upstream cache: %i", rc);
+
+    switch (rc) {
+
+    case NGX_HTTP_CACHE_UPDATING:
+
+        if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) {
+            u->cache_status = rc;
+            rc = NGX_OK;
+
+        } else {
+            rc = NGX_HTTP_CACHE_STALE;
+        }
+
+        break;
+
+    case NGX_OK:
+        u->cache_status = NGX_HTTP_CACHE_HIT;
+    }
+
+    switch (rc) {
+
+    case NGX_OK:
 
         rc = ngx_http_upstream_cache_send(r, u);
 
@@ -570,16 +686,17 @@ ngx_http_upstream_cache(ngx_http_request
             return rc;
         }
 
-    } else if (rc == NGX_ERROR) {
-
-        return NGX_ERROR;
-
-    } else if (rc == NGX_HTTP_CACHE_STALE) {
-
-        u->stale_cache = 1;
+        break;
+
+    case NGX_HTTP_CACHE_STALE:
+
+        c->valid_sec = 0;
         u->buffer.start = NULL;
-
-    } else if (rc == NGX_DECLINED) {
+        u->cache_status = NGX_HTTP_CACHE_EXPIRED;
+
+        break;
+
+    case NGX_DECLINED:
 
         if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
             u->buffer.start = NULL;
@@ -589,14 +706,28 @@ ngx_http_upstream_cache(ngx_http_request
             u->buffer.last = u->buffer.pos;
         }
 
-    } else if (rc == NGX_AGAIN) {
+        break;
+
+    case NGX_HTTP_CACHE_SCARCE:
 
         u->cacheable = 0;
 
-    } else {
+        break;
+
+    case NGX_AGAIN:
+
+        return NGX_BUSY;
+
+    case NGX_ERROR:
+
+        return NGX_ERROR;
+
+    default:
 
         /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
 
+        u->cache_status = NGX_HTTP_CACHE_HIT;
+
         return rc;
     }
 
@@ -612,6 +743,7 @@ ngx_http_upstream_cache_send(ngx_http_re
     ngx_int_t          rc;
     ngx_http_cache_t  *c;
 
+    r->cached = 1;
     c = r->cache;
 
     /* TODO: cache stack */
@@ -758,6 +890,7 @@ ngx_http_upstream_check_broken_connectio
     int                  n;
     char                 buf[1];
     ngx_err_t            err;
+    ngx_int_t            event;
     ngx_connection_t     *c;
     ngx_http_upstream_t  *u;
 
@@ -769,8 +902,22 @@ ngx_http_upstream_check_broken_connectio
     u = r->upstream;
 
     if (c->error) {
-        ngx_http_upstream_finalize_request(r, u,
-                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
+        if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
+
+            event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
+
+            if (ngx_del_event(ev, event, 0) != NGX_OK) {
+                ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return;
+            }
+        }
+
+        if (!u->cacheable) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
+        }
+
         return;
     }
 
@@ -793,7 +940,7 @@ ngx_http_upstream_check_broken_connectio
             ev->error = 1;
         }
 
-        if (!u->cacheable && !u->store && u->peer.connection) {
+        if (!u->cacheable && u->peer.connection) {
             ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
                           "kevent() reported that client closed prematurely "
                           "connection, so upstream connection is closed too");
@@ -824,17 +971,15 @@ ngx_http_upstream_check_broken_connectio
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
                    "http upstream recv(): %d", n);
 
-    /*
-     * we do not need to disable the write event because
-     * that event has NGX_USE_CLEAR_EVENT type
-     */
-
     if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
         return;
     }
 
     if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
-        if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+
+        event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
+
+        if (ngx_del_event(ev, event, 0) != NGX_OK) {
             ngx_http_upstream_finalize_request(r, u,
                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
@@ -859,7 +1004,7 @@ ngx_http_upstream_check_broken_connectio
     ev->eof = 1;
     c->error = 1;
 
-    if (!u->cacheable && !u->store && u->peer.connection) {
+    if (!u->cacheable && u->peer.connection) {
         ngx_log_error(NGX_LOG_INFO, ev->log, err,
                       "client closed prematurely connection, "
                       "so upstream connection is closed too");
@@ -949,7 +1094,9 @@ ngx_http_upstream_connect(ngx_http_reque
     u->output.sendfile = c->sendfile;
 
     c->pool = r->pool;
-    c->read->log = c->write->log = c->log = r->connection->log;
+    c->log = r->connection->log;
+    c->read->log = c->log;
+    c->write->log = c->log;
 
     /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
 
@@ -1463,10 +1610,6 @@ ngx_http_upstream_test_next(ngx_http_req
     ngx_uint_t                 status;
     ngx_http_upstream_next_t  *un;
 
-    if (!(u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_STATUS)) {
-        return NGX_DECLINED;
-    }
-
     status = u->headers_in.status_n;
 
     for (un = ngx_http_upstream_next_errors; un->status; un++) {
@@ -1482,12 +1625,19 @@ ngx_http_upstream_test_next(ngx_http_req
 
 #if (NGX_HTTP_CACHE)
 
-        if (u->peer.tries == 0
-            && u->stale_cache
+        if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
             && (u->conf->cache_use_stale & un->mask))
         {
-            ngx_http_upstream_finalize_request(r, u,
-                                           ngx_http_upstream_cache_send(r, u));
+            ngx_int_t  rc;
+
+            rc = u->reinit_request(r);
+
+            if (rc == NGX_OK) {
+                u->cache_status = NGX_HTTP_CACHE_STALE;
+                rc = ngx_http_upstream_cache_send(r, u);
+            }
+
+            ngx_http_upstream_finalize_request(r, u, rc);
             return NGX_OK;
         }
 
@@ -1530,8 +1680,9 @@ ngx_http_upstream_intercept_errors(ngx_h
 
         if (err_page[i].status == status) {
 
-            if (status == NGX_HTTP_UNAUTHORIZED) {
-
+            if (status == NGX_HTTP_UNAUTHORIZED
+                && u->headers_in.www_authenticate)
+            {
                 h = ngx_list_push(&r->headers_out.headers);
 
                 if (h == NULL) {
@@ -1611,8 +1762,9 @@ ngx_http_upstream_process_headers(ngx_ht
 
     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
 
-    if (u->headers_in.x_accel_redirect) {
-
+    if (u->headers_in.x_accel_redirect
+        && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
+    {
         ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
 
         part = &u->headers_in.headers.part;
@@ -1663,6 +1815,7 @@ ngx_http_upstream_process_headers(ngx_ht
         r->valid_unparsed_uri = 0;
 
         ngx_http_internal_redirect(r, uri, &args);
+        ngx_http_finalize_request(r, NGX_DONE);
         return NGX_DONE;
     }
 
@@ -1815,11 +1968,32 @@ ngx_http_upstream_send_response(ngx_http
 
     rc = ngx_http_send_header(r);
 
-    if (rc == NGX_ERROR || rc > NGX_OK || r->post_action || r->header_only) {
+    if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
         ngx_http_upstream_finalize_request(r, u, rc);
         return;
     }
 
+    c = r->connection;
+
+    if (r->header_only) {
+
+        if (u->cacheable || u->store) {
+
+            if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
+                ngx_connection_error(c, ngx_socket_errno,
+                                     ngx_shutdown_socket_n " failed");
+            }
+
+            r->read_event_handler = ngx_http_request_empty_handler;
+            r->write_event_handler = ngx_http_request_empty_handler;
+            c->error = 1;
+
+        } else {
+            ngx_http_upstream_finalize_request(r, u, rc);
+            return;
+        }
+    }
+
     u->header_sent = 1;
 
     if (r->request_body && r->request_body->temp_file) {
@@ -1827,8 +2001,6 @@ ngx_http_upstream_send_response(ngx_http
         r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
     }
 
-    c = r->connection;
-
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (!u->buffering) {
@@ -1910,14 +2082,19 @@ ngx_http_upstream_send_response(ngx_http
     if (u->cacheable) {
         time_t  now, valid;
 
-        valid = ngx_http_file_cache_valid(u->conf->cache_valid,
-                                          u->headers_in.status_n);
+        now = ngx_time();
+
+        valid = r->cache->valid_sec;
+
+        if (valid == 0) {
+            valid = ngx_http_file_cache_valid(u->conf->cache_valid,
+                                              u->headers_in.status_n);
+            if (valid) {
+                r->cache->valid_sec = now + valid;
+            }
+        }
+
         if (valid) {
-
-            now = ngx_time();
-
-            r->cache->valid_sec = now + valid;
-
             r->cache->last_modified = r->headers_out.last_modified_time;
             r->cache->date = now;
             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
@@ -1931,9 +2108,17 @@ ngx_http_upstream_send_response(ngx_http
 
         } else {
             u->cacheable = 0;
+            r->headers_out.last_modified_time = -1;
         }
     }
 
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http cacheable: %d", u->cacheable);
+
+    if (u->cacheable == 0 && r->cache) {
+        ngx_http_file_cache_free(r, u->pipe->temp_file);
+    }
+
 #endif
 
     p = u->pipe;
@@ -2115,10 +2300,6 @@ ngx_http_upstream_process_non_buffered_r
             if (u->out_bufs || u->busy_bufs) {
                 rc = ngx_http_output_filter(r, u->out_bufs);
 
-                if (downstream->destroyed) {
-                    return;
-                }
-
                 if (rc == NGX_ERROR) {
                     ngx_http_upstream_finalize_request(r, u, 0);
                     return;
@@ -2291,11 +2472,6 @@ ngx_http_upstream_process_downstream(ngx
             }
 
             if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
-
-                if (c->destroyed) {
-                    return;
-                }
-
                 ngx_http_upstream_finalize_request(r, u, 0);
                 return;
             }
@@ -2321,11 +2497,6 @@ ngx_http_upstream_process_downstream(ngx
         }
 
         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
-
-            if (c->destroyed) {
-                return;
-            }
-
             ngx_http_upstream_finalize_request(r, u, 0);
             return;
         }
@@ -2353,14 +2524,7 @@ ngx_http_upstream_process_upstream(ngx_h
         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
 
     } else {
-        c = r->connection;
-
         if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
-
-            if (c->destroyed) {
-                return;
-            }
-
             ngx_http_upstream_finalize_request(r, u, 0);
             return;
         }
@@ -2448,7 +2612,7 @@ ngx_http_upstream_process_request(ngx_ht
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "http upstream downstream error");
 
-        if (!u->cacheable && u->peer.connection) {
+        if (!u->cacheable && !u->store && u->peer.connection) {
             ngx_http_upstream_finalize_request(r, u, 0);
         }
     }
@@ -2496,7 +2660,6 @@ ngx_http_upstream_store(ngx_http_request
     ext.time = -1;
     ext.create_path = 1;
     ext.delete_file = 1;
-    ext.log_rename_error = 1;
     ext.log = r->connection->log;
 
     if (u->headers_in.last_modified) {
@@ -2523,6 +2686,8 @@ ngx_http_upstream_store(ngx_http_request
         }
     }
 
+    path.len--;
+
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "upstream stores \"%s\" to \"%s\"",
                    tf->file.name.data, path.data);
@@ -2608,10 +2773,19 @@ ngx_http_upstream_next(ngx_http_request_
 
 #if (NGX_HTTP_CACHE)
 
-            if (u->stale_cache && (u->conf->cache_use_stale & ft_type)) {
-
-                ngx_http_upstream_finalize_request(r, u,
-                                           ngx_http_upstream_cache_send(r, u));
+            if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
+                && (u->conf->cache_use_stale & ft_type))
+            {
+                ngx_int_t  rc;
+
+                rc = u->reinit_request(r);
+
+                if (rc == NGX_OK) {
+                    u->cache_status = NGX_HTTP_CACHE_STALE;
+                    rc = ngx_http_upstream_cache_send(r, u);
+                }
+
+                ngx_http_upstream_finalize_request(r, u, rc);
                 return;
             }
 #endif
@@ -2735,7 +2909,7 @@ ngx_http_upstream_finalize_request(ngx_h
 
 #if (NGX_HTTP_CACHE)
 
-    if (r->cache) {
+    if (u->cacheable && r->cache) {
         time_t  valid;
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -2757,7 +2931,8 @@ ngx_http_upstream_finalize_request(ngx_h
 
 #endif
 
-    if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
+    if (u->header_sent
+        && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
     {
         rc = 0;
     }
@@ -2768,7 +2943,7 @@ ngx_http_upstream_finalize_request(ngx_h
 
     r->connection->log->action = "sending to client";
 
-    if (rc == 0 && r == r->main && !r->post_action) {
+    if (rc == 0) {
         rc = ngx_http_send_special(r, NGX_HTTP_LAST);
     }
 
@@ -2793,13 +2968,23 @@ ngx_http_upstream_process_header_line(ng
 
 
 static ngx_int_t
-ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
+ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset)
 {
-    ngx_array_t       *pa;
-    ngx_table_elt_t  **ph;
-
-    pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset);
+    ngx_array_t          *pa;
+    ngx_table_elt_t     **ph;
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+    pa = &u->headers_in.cache_control;
 
     if (pa->elts == NULL) {
        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
@@ -2815,14 +3000,159 @@ ngx_http_upstream_process_multi_header_l
 
     *ph = h;
 
+#if (NGX_HTTP_CACHE)
+    {
+    u_char     *p, *last;
+    ngx_int_t   n;
+
+    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) {
+        return NGX_OK;
+    }
+
+    if (r->cache == NULL) {
+        return NGX_OK;
+    }
+
+    if (r->cache->valid_sec != 0) {
+        return NGX_OK;
+    }
+
+    last = h->value.data + h->value.len;
+
+    if (ngx_strlcasestrn(h->value.data, last, (u_char *) "no-cache", 8 - 1)
+        != NULL)
+    {
+        u->cacheable = 0;
+        return NGX_OK;
+    }
+
+    p = ngx_strlcasestrn(h->value.data, last, (u_char *) "max-age=", 8 - 1);
+
+    if (p == NULL) {
+        return NGX_OK;
+    }
+
+    n = 0;
+
+    for (p += 8; p < last; p++) {
+        if (*p == ';' || *p == ' ') {
+            break;
+        }
+
+        if (*p >= '0' && *p <= '9') {
+            n = n * 10 + *p - '0';
+            continue;
+        }
+
+        u->cacheable = 0;
+        return NGX_OK;
+    }
+
+    if (n == 0) {
+        u->cacheable = 0;
+        return NGX_OK;
+    }
+
+    r->cache->valid_sec = ngx_time() + n;
+    }
+#endif
+
     return NGX_OK;
 }
 
 
 static ngx_int_t
-ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
+ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+    u->headers_in.expires = h;
+
+#if (NGX_HTTP_CACHE)
+    {
+    time_t  expires;
+
+    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) {
+        return NGX_OK;
+    }
+
+    if (r->cache == NULL) {
+        return NGX_OK;
+    }
+
+    if (r->cache->valid_sec != 0) {
+        return NGX_OK;
+    }
+
+    expires = ngx_http_parse_time(h->value.data, h->value.len);
+
+    if (expires == NGX_ERROR || expires < ngx_time()) {
+        u->cacheable = 0;
+        return NGX_OK;
+    }
+
+    r->cache->valid_sec = expires;
+    }
+#endif
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset)
+{
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+    u->headers_in.x_accel_expires = h;
+
+#if (NGX_HTTP_CACHE)
+    {
+    u_char     *p;
+    size_t      len;
+    ngx_int_t   n;
+
+    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) {
+        return NGX_OK;
+    }
+
+    if (r->cache == NULL) {
+        return NGX_OK;
+    }
+
+    len = h->value.len;
+    p = h->value.data;
+
+    if (p[0] != '@') {
+        n = ngx_atoi(p, len);
+
+        switch (n) {
+        case 0:
+            u->cacheable = 0;
+        case NGX_ERROR:
+            return NGX_OK;
+
+        default:
+            r->cache->valid_sec = ngx_time() + n;
+            return NGX_OK;
+        }
+    }
+
+    p++;
+    len--;
+
+    n = ngx_atoi(p, len);
+
+    if (n != NGX_ERROR) {
+        r->cache->valid_sec = n;
+    }
+    }
+#endif
+
     return NGX_OK;
 }
 
@@ -2949,6 +3279,7 @@ ngx_http_upstream_copy_content_type(ngx_
 
     r->headers_out.content_type_len = h->value.len;
     r->headers_out.content_type = h->value;
+    r->headers_out.content_type_lowcase = NULL;
 
     for (p = h->value.data; *p; p++) {
 
@@ -3025,10 +3356,11 @@ ngx_http_upstream_copy_last_modified(ngx
 
     *ho = *h;
 
+    r->headers_out.last_modified = ho;
+
 #if (NGX_HTTP_CACHE)
 
-    if (r->cached) {
-        r->headers_out.last_modified = ho;
+    if (r->upstream->cacheable) {
         r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data,
                                                                 h->value.len);
     }
@@ -3152,6 +3484,8 @@ ngx_http_upstream_copy_allow_ranges(ngx_
 
     *ho = *h;
 
+    r->headers_out.accept_ranges = ho;
+
     return NGX_OK;
 }
 
@@ -3478,6 +3812,33 @@ ngx_http_upstream_header_variable(ngx_ht
 }
 
 
+#if (NGX_HTTP_CACHE)
+
+ngx_int_t
+ngx_http_upstream_cache_status(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_uint_t  n;
+
+    if (r->upstream == NULL || r->upstream->cache_status == 0) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    n = r->upstream->cache_status - 1;
+
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->len = ngx_http_cache_status[n].len;
+    v->data = ngx_http_cache_status[n].data;
+
+    return NGX_OK;
+}
+
+#endif
+
+
 static char *
 ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
 {
@@ -3850,7 +4211,12 @@ ngx_http_upstream_hide_headers_hash(ngx_
     {
         conf->hide_headers_hash = prev->hide_headers_hash;
 
-        if (conf->hide_headers_hash.buckets) {
+        if (conf->hide_headers_hash.buckets
+#if (NGX_HTTP_CACHE)
+            && ((conf->cache == NULL) == (prev->cache == NULL))
+#endif
+           )
+        {
             return NGX_OK;
         }
 
@@ -3956,7 +4322,7 @@ ngx_http_upstream_create_main_conf(ngx_c
                        sizeof(ngx_http_upstream_srv_conf_t *))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return umcf;
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -24,8 +24,9 @@
 #define NGX_HTTP_UPSTREAM_FT_HTTP_503        0x00000040
 #define NGX_HTTP_UPSTREAM_FT_HTTP_504        0x00000080
 #define NGX_HTTP_UPSTREAM_FT_HTTP_404        0x00000100
-#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK       0x00000200
-#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING     0x00000400
+#define NGX_HTTP_UPSTREAM_FT_UPDATING        0x00000200
+#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK       0x00000400
+#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING     0x00000800
 #define NGX_HTTP_UPSTREAM_FT_NOLIVE          0x40000000
 #define NGX_HTTP_UPSTREAM_FT_OFF             0x80000000
 
@@ -38,6 +39,12 @@
 #define NGX_HTTP_UPSTREAM_INVALID_HEADER     40
 
 
+#define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT    0x00000002
+#define NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES     0x00000004
+#define NGX_HTTP_UPSTREAM_IGN_EXPIRES        0x00000008
+#define NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL  0x00000010
+
+
 typedef struct {
     ngx_msec_t                       bl_time;
     ngx_uint_t                       bl_state;
@@ -128,6 +135,7 @@ typedef struct {
 
     ngx_bufs_t                       bufs;
 
+    ngx_uint_t                       ignore_headers;
     ngx_uint_t                       next_upstream;
     ngx_uint_t                       store_access;
     ngx_flag_t                       buffering;
@@ -149,6 +157,7 @@ typedef struct {
 
     ngx_uint_t                       cache_min_uses;
     ngx_uint_t                       cache_use_stale;
+    ngx_uint_t                       cache_methods;
 
     ngx_array_t                     *cache_valid;
 #endif
@@ -162,7 +171,7 @@ typedef struct {
 
 #if (NGX_HTTP_SSL)
     ngx_ssl_t                       *ssl;
-    ngx_flag_t                      ssl_session_reuse;
+    ngx_flag_t                       ssl_session_reuse;
 #endif
 
 } ngx_http_upstream_conf_t;
@@ -289,7 +298,7 @@ struct ngx_http_upstream_s {
     unsigned                         accel:1;
     unsigned                         ssl:1;
 #if (NGX_HTTP_CACHE)
-    unsigned                         stale_cache:1;
+    unsigned                         cache_status:3;
 #endif
 
     unsigned                         buffering:1;
@@ -308,6 +317,7 @@ typedef struct {
 ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 
+ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r);
 void ngx_http_upstream_init(ngx_http_request_t *r);
 ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
     ngx_url_t *u, ngx_uint_t flags);
@@ -320,7 +330,9 @@ ngx_int_t ngx_http_upstream_hide_headers
     uscf->srv_conf[module.ctx_index]
 
 
-extern ngx_module_t  ngx_http_upstream_module;
+extern ngx_module_t        ngx_http_upstream_module;
+extern ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[];
+
 
 
 #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -25,6 +25,8 @@ static ngx_int_t ngx_http_variable_unkno
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
@@ -62,6 +64,8 @@ static ngx_int_t ngx_http_variable_body_
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_request_body(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 
@@ -162,8 +166,7 @@ static ngx_http_variable_t  ngx_http_cor
       offsetof(ngx_http_request_t, uri),
       NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
-    { ngx_string("request"), NULL, ngx_http_variable_request,
-      offsetof(ngx_http_request_t, request_line), 0, 0 },
+    { ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 },
 
     { ngx_string("document_root"), NULL,
       ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
@@ -202,6 +205,10 @@ static ngx_http_variable_t  ngx_http_cor
       ngx_http_variable_request_completion,
       0, 0, 0 },
 
+    { ngx_string("request_body"), NULL,
+      ngx_http_variable_request_body,
+      0, 0, 0 },
+
     { ngx_string("request_body_file"), NULL,
       ngx_http_variable_request_body_file,
       0, 0, 0 },
@@ -745,6 +752,42 @@ ngx_http_variable_unknown_header(ngx_htt
 
 
 static ngx_int_t
+ngx_http_variable_request_line(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_char  *p, *s;
+
+    s = r->request_line.data;
+
+    if (s == NULL) {
+        s = r->request_start;
+
+        if (s == NULL) {
+            v->not_found = 1;
+            return NGX_OK;
+        }
+
+        for (p = s; p < r->header_in->last; p++) {
+            if (*p == CR || *p == LF) {
+                break;
+            }
+        }
+
+        r->request_line.len = p - s;
+        r->request_line.data = s;
+    }
+
+    v->len = r->request_line.len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = s;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
 {
@@ -932,7 +975,7 @@ ngx_http_variable_server_addr(ngx_http_r
     s.len = NGX_SOCKADDR_STRLEN;
     s.data = addr;
 
-    if (ngx_http_server_addr(r, &s) != NGX_OK) {
+    if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -968,7 +1011,7 @@ ngx_http_variable_server_port(ngx_http_r
     v->no_cacheable = 0;
     v->not_found = 0;
 
-    if (ngx_http_server_addr(r, NULL) != NGX_OK) {
+    if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -1478,6 +1521,59 @@ ngx_http_variable_request_completion(ngx
 
 
 static ngx_int_t
+ngx_http_variable_request_body(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_char       *p;
+    size_t        len;
+    ngx_buf_t    *buf, *next;
+    ngx_chain_t  *cl;
+
+    if (r->request_body == NULL
+        || r->request_body->bufs == NULL
+        || r->request_body->temp_file)
+    {
+        v->not_found = 1;
+
+        return NGX_OK;
+    }
+
+    cl = r->request_body->bufs;
+    buf = cl->buf;
+
+    if (cl->next == NULL) {
+        v->len = buf->last - buf->pos;
+        v->valid = 1;
+        v->no_cacheable = 0;
+        v->not_found = 0;
+        v->data = buf->pos;
+
+        return NGX_OK;
+    }
+
+    next = cl->next->buf;
+    len = (buf->last - buf->pos) + (next->last - next->pos);
+
+    p = ngx_pnalloc(r->pool, len);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->data = p;
+
+    p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
+    ngx_memcpy(p, next->pos, next->last - next->pos);
+
+    v->len = len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_variable_request_body_file(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -46,7 +46,7 @@ ngx_module_t  ngx_http_write_filter_modu
 ngx_int_t
 ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
-    off_t                      size, sent, limit;
+    off_t                      size, sent, nsent, limit;
     ngx_uint_t                 last, flush;
     ngx_msec_t                 delay;
     ngx_chain_t               *cl, *ln, **ll, *chain;
@@ -210,7 +210,8 @@ ngx_http_write_filter(ngx_http_request_t
     }
 
     if (r->limit_rate) {
-        limit = r->limit_rate * (ngx_time() - r->start_sec + 1) - c->sent;
+        limit = r->limit_rate * (ngx_time() - r->start_sec + 1)
+                - (c->sent - clcf->limit_rate_after);
 
         if (limit <= 0) {
             c->write->delayed = 1;
@@ -245,7 +246,23 @@ ngx_http_write_filter(ngx_http_request_t
     }
 
     if (r->limit_rate) {
-        delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1);
+
+        nsent = c->sent;
+
+        if (clcf->limit_rate_after) {
+
+            sent -= clcf->limit_rate_after;
+            if (sent < 0) {
+                sent = 0;
+            }
+
+            nsent -= clcf->limit_rate_after;
+            if (nsent < 0) {
+                nsent = 0;
+            }
+        }
+
+        delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1);
 
         if (delay > 0) {
             c->write->delayed = 1;
--- a/src/mail/ngx_mail.c
+++ b/src/mail/ngx_mail.c
@@ -11,7 +11,16 @@
 
 
 static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two);
+static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
+    ngx_mail_listen_t *listen);
+static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports);
+static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
+    ngx_mail_conf_addr_t *addr);
+#if (NGX_HAVE_INET6)
+static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
+    ngx_mail_conf_addr_t *addr);
+#endif
+static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two);
 
 
 ngx_uint_t  ngx_mail_max_module;
@@ -64,18 +73,12 @@ static char *
 ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char                        *rv;
-    u_char                      *text;
-    size_t                       len;
-    ngx_uint_t                   i, a, l, m, mi, s, p, last, bind_all, done;
+    ngx_uint_t                   i, m, mi, s;
     ngx_conf_t                   pcf;
-    ngx_array_t                  in_ports;
-    ngx_listening_t             *ls;
-    ngx_mail_listen_t           *imls;
+    ngx_array_t                  ports;
+    ngx_mail_listen_t           *listen;
     ngx_mail_module_t           *module;
-    ngx_mail_in_port_t          *imip;
     ngx_mail_conf_ctx_t         *ctx;
-    ngx_mail_conf_in_port_t     *in_port;
-    ngx_mail_conf_in_addr_t     *in_addr;
     ngx_mail_core_srv_conf_t   **cscfp;
     ngx_mail_core_main_conf_t   *cmcf;
 
@@ -216,178 +219,196 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
     *cf = pcf;
 
 
-    if (ngx_array_init(&in_ports, cf->temp_pool, 4,
-                       sizeof(ngx_mail_conf_in_port_t))
+    if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
     }
 
-    imls = cmcf->listen.elts;
-
-    for (l = 0; l < cmcf->listen.nelts; l++) {
-
-        /* AF_INET only */
+    listen = cmcf->listen.elts;
 
-        in_port = in_ports.elts;
-        for (p = 0; p < in_ports.nelts; p++) {
-            if (in_port[p].port == imls[l].port) {
-                in_port = &in_port[p];
-                goto found;
-            }
-        }
-
-        in_port = ngx_array_push(&in_ports);
-        if (in_port == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        in_port->port = imls[l].port;
-
-        if (ngx_array_init(&in_port->addrs, cf->temp_pool, 2,
-                           sizeof(ngx_mail_conf_in_addr_t))
-            != NGX_OK)
-        {
+    for (i = 0; i < cmcf->listen.nelts; i++) {
+        if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
+    }
 
-    found:
+    return ngx_mail_optimize_servers(cf, &ports);
+}
+
+
+static ngx_int_t
+ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
+    ngx_mail_listen_t *listen)
+{
+    in_port_t              p;
+    ngx_uint_t             i;
+    struct sockaddr       *sa;
+    struct sockaddr_in    *sin;
+    ngx_mail_conf_port_t  *port;
+    ngx_mail_conf_addr_t  *addr;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6   *sin6;
+#endif
+
+    sa = (struct sockaddr *) &listen->sockaddr;
 
-        in_addr = ngx_array_push(&in_port->addrs);
-        if (in_addr == NULL) {
-            return NGX_CONF_ERROR;
+    switch (sa->sa_family) {
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *) sa;
+        p = sin6->sin6_port;
+        break;
+#endif
+
+    default: /* AF_INET */
+        sin = (struct sockaddr_in *) sa;
+        p = sin->sin_port;
+        break;
+    }
+
+    port = ports->elts;
+    for (i = 0; i < ports->nelts; i++) {
+        if (p == port[i].port && sa->sa_family == port[i].family) {
+
+            /* a port is already in the port list */
+
+            port = &port[i];
+            goto found;
         }
-
-        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 */
+    /* add a port to the port list */
+
+    port = ngx_array_push(ports);
+    if (port == NULL) {
+        return NGX_ERROR;
+    }
+
+    port->family = sa->sa_family;
+    port->port = p;
 
-    /* AF_INET only */
+    if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
+                       sizeof(ngx_mail_conf_addr_t))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+found:
+
+    addr = ngx_array_push(&port->addrs);
+    if (addr == NULL) {
+        return NGX_ERROR;
+    }
 
-    in_port = in_ports.elts;
-    for (p = 0; p < in_ports.nelts; p++) {
+    addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
+    addr->socklen = listen->socklen;
+    addr->ctx = listen->ctx;
+    addr->bind = listen->bind;
+    addr->wildcard = listen->wildcard;
+#if (NGX_MAIL_SSL)
+    addr->ssl = listen->ssl;
+#endif
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+    addr->ipv6only = listen->ipv6only;
+#endif
+
+    return NGX_OK;
+}
+
 
-        ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts,
-                 sizeof(ngx_mail_conf_in_addr_t), ngx_mail_cmp_conf_in_addrs);
+static char *
+ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
+{
+    ngx_uint_t             i, p, last, bind_wildcard;
+    ngx_listening_t       *ls;
+    ngx_mail_port_t       *mport;
+    ngx_mail_conf_port_t  *port;
+    ngx_mail_conf_addr_t  *addr;
 
-        in_addr = in_port[p].addrs.elts;
-        last = in_port[p].addrs.nelts;
+    port = ports->elts;
+    for (p = 0; p < ports->nelts; p++) {
+
+        ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
+                 sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs);
+
+        addr = port[p].addrs.elts;
+        last = port[p].addrs.nelts;
 
         /*
          * if there is the binding to the "*:port" then we need to bind()
          * to the "*:port" only and ignore the other bindings
          */
 
-        if (in_addr[last - 1].addr == INADDR_ANY) {
-            in_addr[last - 1].bind = 1;
-            bind_all = 0;
+        if (addr[last - 1].wildcard) {
+            addr[last - 1].bind = 1;
+            bind_wildcard = 1;
 
         } else {
-            bind_all = 1;
+            bind_wildcard = 0;
         }
 
-        for (a = 0; a < last; /* void */ ) {
+        i = 0;
 
-            if (!bind_all && !in_addr[a].bind) {
-                a++;
+        while (i < last) {
+
+            if (bind_wildcard && !addr[i].bind) {
+                i++;
                 continue;
             }
 
-            ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
-                                                  in_port[p].port);
+            ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
             if (ls == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            ls->backlog = NGX_LISTEN_BACKLOG;
-            ls->rcvbuf = -1;
-            ls->sndbuf = -1;
-
             ls->addr_ntop = 1;
             ls->handler = ngx_mail_init_connection;
             ls->pool_size = 256;
 
-            /* STUB */
-            ls->log = *cf->cycle->new_log;
+            /* TODO: error_log directive */
+            ls->logp = &cf->cycle->new_log;
             ls->log.data = &ls->addr_text;
             ls->log.handler = ngx_accept_log_error;
-            /**/
 
-            imip = ngx_palloc(cf->pool, sizeof(ngx_mail_in_port_t));
-            if (imip == NULL) {
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+            ls->ipv6only = addr[i].ipv6only;
+#endif
+
+            mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
+            if (mport == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            ls->servers = imip;
-
-            in_addr = in_port[p].addrs.elts;
+            ls->servers = mport;
 
-            if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
-                imip->naddrs = 1;
-                done = 0;
-
-            } else if (in_port[p].addrs.nelts > 1
-                       && in_addr[last - 1].addr == INADDR_ANY)
-            {
-                imip->naddrs = last;
-                done = 1;
+            if (i == last - 1) {
+                mport->naddrs = last;
 
             } else {
-                imip->naddrs = 1;
-                done = 0;
+                mport->naddrs = 1;
+                i = 0;
             }
 
-#if 0
-            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
-                          "%ui: %V %d %ui %ui",
-                          a, &ls->addr_text, in_addr[a].bind,
-                          imip->naddrs, last);
-#endif
-
-            imip->addrs = ngx_pcalloc(cf->pool,
-                                    imip->naddrs * sizeof(ngx_mail_in_addr_t));
-            if (imip->addrs == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            for (i = 0; i < imip->naddrs; i++) {
-                imip->addrs[i].addr = in_addr[i].addr;
-                imip->addrs[i].ctx = in_addr[i].ctx;
-
-                text = ngx_pnalloc(cf->pool,
-                                   NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1);
-                if (text == NULL) {
+            switch (ls->sockaddr->sa_family) {
+#if (NGX_HAVE_INET6)
+            case AF_INET6:
+                if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
                     return NGX_CONF_ERROR;
                 }
-
-                len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text,
-                                    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;
+                break;
 #endif
-            }
-
-            if (done) {
+            default: /* AF_INET */
+                if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
+                    return NGX_CONF_ERROR;
+                }
                 break;
             }
 
-            in_addr++;
-            in_port[p].addrs.elts = in_addr;
+            addr++;
             last--;
-
-            a = 0;
         }
     }
 
@@ -396,15 +417,111 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
 
 
 static ngx_int_t
-ngx_mail_cmp_conf_in_addrs(const void *one, const void *two)
+ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
+    ngx_mail_conf_addr_t *addr)
 {
-    ngx_mail_conf_in_addr_t  *first, *second;
+    u_char              *p;
+    size_t               len;
+    ngx_uint_t           i;
+    ngx_mail_in_addr_t  *addrs;
+    struct sockaddr_in  *sin;
+    u_char               buf[NGX_SOCKADDR_STRLEN];
+
+    mport->addrs = ngx_pcalloc(cf->pool,
+                               mport->naddrs * sizeof(ngx_mail_in_addr_t));
+    if (mport->addrs == NULL) {
+        return NGX_ERROR;
+    }
+
+    addrs = mport->addrs;
+
+    for (i = 0; i < mport->naddrs; i++) {
+
+        sin = (struct sockaddr_in *) addr[i].sockaddr;
+        addrs[i].addr = sin->sin_addr.s_addr;
+
+        addrs[i].conf.ctx = addr[i].ctx;
+#if (NGX_MAIL_SSL)
+        addrs[i].conf.ssl = addr[i].ssl;
+#endif
+
+        len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
+
+        p = ngx_pnalloc(cf->pool, len);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_memcpy(p, buf, len);
+
+        addrs[i].conf.addr_text.len = len;
+        addrs[i].conf.addr_text.data = p;
+    }
+
+    return NGX_OK;
+}
+
+
+#if (NGX_HAVE_INET6)
 
-    first = (ngx_mail_conf_in_addr_t *) one;
-    second = (ngx_mail_conf_in_addr_t *) two;
+static ngx_int_t
+ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
+    ngx_mail_conf_addr_t *addr)
+{
+    u_char               *p;
+    size_t                len;
+    ngx_uint_t            i;
+    ngx_mail_in6_addr_t  *addrs6;
+    struct sockaddr_in6  *sin6;
+    u_char                buf[NGX_SOCKADDR_STRLEN];
+
+    mport->addrs = ngx_pcalloc(cf->pool,
+                               mport->naddrs * sizeof(ngx_mail_in6_addr_t));
+    if (mport->addrs == NULL) {
+        return NGX_ERROR;
+    }
+
+    addrs6 = mport->addrs;
+
+    for (i = 0; i < mport->naddrs; i++) {
+
+        sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
+        addrs6[i].addr6 = sin6->sin6_addr;
+
+        addrs6[i].conf.ctx = addr[i].ctx;
+#if (NGX_MAIL_SSL)
+        addrs6[i].conf.ssl = addr[i].ssl;
+#endif
 
-    if (first->addr == INADDR_ANY) {
-        /* the INADDR_ANY must be the last resort, shift it to the end */
+        len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
+
+        p = ngx_pnalloc(cf->pool, len);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_memcpy(p, buf, len);
+
+        addrs6[i].conf.addr_text.len = len;
+        addrs6[i].conf.addr_text.data = p;
+    }
+
+    return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_mail_cmp_conf_addrs(const void *one, const void *two)
+{
+    ngx_mail_conf_addr_t  *first, *second;
+
+    first = (ngx_mail_conf_addr_t *) one;
+    second = (ngx_mail_conf_addr_t *) two;
+
+    if (first->wildcard) {
+        /* a wildcard must be the last resort, shift it to the end */
         return 1;
     }
 
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -26,50 +26,76 @@ typedef struct {
 
 
 typedef struct {
-    in_addr_t               addr;
-    in_port_t               port;
-    int                     family;
+    u_char                  sockaddr[NGX_SOCKADDRLEN];
+    socklen_t               socklen;
 
     /* server ctx */
     ngx_mail_conf_ctx_t    *ctx;
 
     unsigned                bind:1;
+    unsigned                wildcard:1;
 #if (NGX_MAIL_SSL)
     unsigned                ssl:1;
 #endif
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+    unsigned                ipv6only:2;
+#endif
 } ngx_mail_listen_t;
 
 
 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_addr_conf_t;
+
+typedef struct {
+    in_addr_t               addr;
+    ngx_mail_addr_conf_t    conf;
 } ngx_mail_in_addr_t;
 
 
+#if (NGX_HAVE_INET6)
+
 typedef struct {
-    ngx_mail_in_addr_t     *addrs;       /* array of ngx_mail_in_addr_t */
-    ngx_uint_t              naddrs;
-} ngx_mail_in_port_t;
+    struct in6_addr         addr6;
+    ngx_mail_addr_conf_t    conf;
+} ngx_mail_in6_addr_t;
+
+#endif
 
 
 typedef struct {
+    /* ngx_mail_in_addr_t or ngx_mail_in6_addr_t */
+    void                   *addrs;
+    ngx_uint_t              naddrs;
+} ngx_mail_port_t;
+
+
+typedef struct {
+    int                     family;
     in_port_t               port;
-    ngx_array_t             addrs;       /* array of ngx_mail_conf_in_addr_t */
-} ngx_mail_conf_in_port_t;
+    ngx_array_t             addrs;       /* array of ngx_mail_conf_addr_t */
+} ngx_mail_conf_port_t;
 
 
 typedef struct {
-    in_addr_t               addr;
+    struct sockaddr        *sockaddr;
+    socklen_t               socklen;
+
     ngx_mail_conf_ctx_t    *ctx;
+
     unsigned                bind:1;
+    unsigned                wildcard:1;
 #if (NGX_MAIL_SSL)
     unsigned                ssl:1;
 #endif
-} ngx_mail_conf_in_addr_t;
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+    unsigned                ipv6only:2;
+#endif
+} ngx_mail_conf_addr_t;
 
 
 typedef struct {
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -139,6 +139,7 @@ ngx_module_t  ngx_mail_auth_http_module 
 static ngx_str_t   ngx_mail_auth_http_method[] = {
     ngx_string("plain"),
     ngx_string("plain"),
+    ngx_string("plain"),
     ngx_string("apop"),
     ngx_string("cram-md5"),
     ngx_string("none")
@@ -770,6 +771,8 @@ ngx_mail_auth_http_process_headers(ngx_m
                 return;
             }
 
+            /* AF_INET only */
+
             sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
             if (sin == NULL) {
                 ngx_destroy_pool(ctx->pool);
@@ -1299,7 +1302,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_
 
     ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t));
     if (ahcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     ahcf->timeout = NGX_CONF_UNSET_MSEC;
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -120,20 +120,20 @@ ngx_mail_core_create_main_conf(ngx_conf_
 
     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
     if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
                        sizeof(ngx_mail_core_srv_conf_t *))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     return cmcf;
@@ -274,19 +274,24 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx
 }
 
 
-/* AF_INET only */
-
 static char *
 ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_mail_core_srv_conf_t  *cscf = conf;
 
+    size_t                      len, off;
+    in_port_t                   port;
     ngx_str_t                  *value;
     ngx_url_t                   u;
     ngx_uint_t                  i, m;
-    ngx_mail_listen_t          *imls;
+    struct sockaddr            *sa;
+    ngx_mail_listen_t          *ls;
     ngx_mail_module_t          *module;
+    struct sockaddr_in         *sin;
     ngx_mail_core_main_conf_t  *cmcf;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6        *sin6;
+#endif
 
     value = cf->args->elts;
 
@@ -305,18 +310,42 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    if (u.family != AF_INET) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "listen supports IPv4 only");
-        return NGX_CONF_ERROR;
-    }
-
     cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
 
-    imls = cmcf->listen.elts;
+    ls = cmcf->listen.elts;
 
     for (i = 0; i < cmcf->listen.nelts; i++) {
 
-        if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
+        sa = (struct sockaddr *) ls[i].sockaddr;
+
+        if (sa->sa_family != u.family) {
+            continue;
+        }
+
+        switch (sa->sa_family) {
+
+#if (NGX_HAVE_INET6)
+        case AF_INET6:
+            off = offsetof(struct sockaddr_in6, sin6_addr);
+            len = 16;
+            sin6 = (struct sockaddr_in6 *) sa;
+            port = sin6->sin6_port;
+            break;
+#endif
+
+        default: /* AF_INET */
+            off = offsetof(struct sockaddr_in, sin_addr);
+            len = 4;
+            sin = (struct sockaddr_in *) sa;
+            port = sin->sin_port;
+            break;
+        }
+
+        if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) {
+            continue;
+        }
+
+        if (port != u.port) {
             continue;
         }
 
@@ -325,17 +354,18 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    imls = ngx_array_push(&cmcf->listen);
-    if (imls == NULL) {
+    ls = ngx_array_push(&cmcf->listen);
+    if (ls == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    ngx_memzero(imls, sizeof(ngx_mail_listen_t));
+    ngx_memzero(ls, sizeof(ngx_mail_listen_t));
+
+    ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);
 
-    imls->addr = u.addr.in_addr;
-    imls->port = u.port;
-    imls->family = u.family;
-    imls->ctx = cf->ctx;
+    ls->socklen = u.socklen;
+    ls->wildcard = u.wildcard;
+    ls->ctx = cf->ctx;
 
     for (m = 0; ngx_modules[m]; m++) {
         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
@@ -359,13 +389,54 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
     for (i = 2; i < cf->args->nelts; i++) {
 
         if (ngx_strcmp(value[i].data, "bind") == 0) {
-            imls->bind = 1;
+            ls->bind = 1;
             continue;
         }
 
+        if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+            struct sockaddr  *sa;
+            u_char            buf[NGX_SOCKADDR_STRLEN];
+
+            sa = (struct sockaddr *) ls->sockaddr;
+
+            if (sa->sa_family == AF_INET6) {
+
+                if (ngx_strcmp(&value[i].data[10], "n") == 0) {
+                    ls->ipv6only = 1;
+
+                } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
+                    ls->ipv6only = 2;
+
+                } else {
+                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                       "invalid ipv6only flags \"%s\"",
+                                       &value[i].data[9]);
+                    return NGX_CONF_ERROR;
+                }
+
+                ls->bind = 1;
+
+            } else {
+                len = ngx_sock_ntop(sa, buf, NGX_SOCKADDR_STRLEN, 1);
+
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "ipv6only is not supported "
+                                   "on addr \"%*s\", ignored", len, buf);
+            }
+
+            continue;
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "bind ipv6only is not supported "
+                               "on this platform");
+            return NGX_CONF_ERROR;
+#endif
+        }
+
         if (ngx_strcmp(value[i].data, "ssl") == 0) {
 #if (NGX_MAIL_SSL)
-            imls->ssl = 1;
+            ls->ssl = 1;
             continue;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -21,25 +21,27 @@ static void ngx_mail_ssl_handshake_handl
 void
 ngx_mail_init_connection(ngx_connection_t *c)
 {
-    in_addr_t             in_addr;
-    socklen_t             len;
-    ngx_uint_t            i;
-    struct sockaddr_in    sin;
-    ngx_mail_log_ctx_t   *ctx;
-    ngx_mail_in_port_t   *imip;
-    ngx_mail_in_addr_t   *imia;
-    ngx_mail_session_t   *s;
+    ngx_uint_t             i;
+    ngx_mail_port_t       *port;
+    struct sockaddr       *sa;
+    struct sockaddr_in    *sin;
+    ngx_mail_log_ctx_t    *ctx;
+    ngx_mail_in_addr_t    *addr;
+    ngx_mail_session_t    *s;
+    ngx_mail_addr_conf_t  *addr_conf;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6   *sin6;
+    ngx_mail_in6_addr_t   *addr6;
+#endif
+
 
     /* find the server configuration for the address:port */
 
     /* AF_INET only */
 
-    imip = c->listening->servers;
-    imia = imip->addrs;
+    port = c->listening->servers;
 
-    i = 0;
-
-    if (imip->naddrs > 1) {
+    if (port->naddrs > 1) {
 
         /*
          * There are several addresses on this port and one of them
@@ -49,45 +51,79 @@ ngx_mail_init_connection(ngx_connection_
          * AcceptEx() already gave this address.
          */
 
-#if (NGX_WIN32)
-        if (c->local_sockaddr) {
-            in_addr =
-                   ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
+        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
+            ngx_mail_close_connection(c);
+            return;
+        }
+
+        sa = c->local_sockaddr;
+
+        switch (sa->sa_family) {
 
-        } else
-#endif
-        {
-            len = sizeof(struct sockaddr_in);
-            if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
-                ngx_connection_error(c, ngx_socket_errno,
-                                     "getsockname() failed");
-                ngx_mail_close_connection(c);
-                return;
+#if (NGX_HAVE_INET6)
+        case AF_INET6:
+            sin6 = (struct sockaddr_in6 *) sa;
+
+            addr6 = port->addrs;
+
+            /* the last address is "*" */
+
+            for (i = 0; i < port->naddrs - 1; i++) {
+                if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
+                    break;
+                }
             }
 
-            in_addr = sin.sin_addr.s_addr;
+            addr_conf = &addr6[i].conf;
+
+            break;
+#endif
+
+        default: /* AF_INET */
+            sin = (struct sockaddr_in *) sa;
+
+            addr = port->addrs;
+
+            /* the last address is "*" */
+
+            for (i = 0; i < port->naddrs - 1; i++) {
+                if (addr[i].addr == sin->sin_addr.s_addr) {
+                    break;
+                }
+            }
+
+            addr_conf = &addr[i].conf;
+
+            break;
         }
 
-        /* the last address is "*" */
+    } else {
+        switch (c->local_sockaddr->sa_family) {
 
-        for ( /* void */ ; i < imip->naddrs - 1; i++) {
-            if (in_addr == imia[i].addr) {
-                break;
-            }
+#if (NGX_HAVE_INET6)
+        case AF_INET6:
+            addr6 = port->addrs;
+            addr_conf = &addr6[0].conf;
+            break;
+#endif
+
+        default: /* AF_INET */
+            addr = port->addrs;
+            addr_conf = &addr[0].conf;
+            break;
         }
     }
 
-
     s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t));
     if (s == NULL) {
         ngx_mail_close_connection(c);
         return;
     }
 
-    s->main_conf = imia[i].ctx->main_conf;
-    s->srv_conf = imia[i].ctx->srv_conf;
+    s->main_conf = addr_conf->ctx->main_conf;
+    s->srv_conf = addr_conf->ctx->srv_conf;
 
-    s->addr_text = &imia[i].addr_text;
+    s->addr_text = &addr_conf->addr_text;
 
     c->data = s;
     s->connection = c;
@@ -124,7 +160,7 @@ ngx_mail_init_connection(ngx_connection_
         return;
     }
 
-    if (imia[i].ssl) {
+    if (addr_conf->ssl) {
 
         c->log->action = "SSL handshaking";
 
@@ -680,7 +716,7 @@ ngx_mail_close_connection(ngx_connection
 #endif
 
 #if (NGX_STAT_STUB)
-    ngx_atomic_fetch_add(ngx_stat_active, -1);
+    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
 #endif
 
     c->destroyed = 1;
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -1066,7 +1066,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *c
 
     pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t));
     if (pcf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     pcf->enable = NGX_CONF_UNSET;
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -66,6 +66,12 @@ ngx_mail_smtp_init_session(ngx_mail_sess
         return;
     }
 
+    if (c->sockaddr->sa_family != AF_INET) {
+        s->host = smtp_tempunavail;
+        ngx_mail_smtp_greeting(s, c);
+        return;
+    }
+
     c->log->action = "in resolving client address";
 
     ctx = ngx_resolve_start(cscf->resolver, NULL);
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -22,15 +22,6 @@ static char *ngx_mail_ssl_starttls(ngx_c
 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-
-static char  ngx_mail_ssl_openssl097[] = "OpenSSL 0.9.7 and higher";
-
-#endif
-
 
 static ngx_conf_enum_t  ngx_http_starttls_state[] = {
     { ngx_string("off"), NGX_MAIL_STARTTLS_OFF },
@@ -102,14 +93,10 @@ static ngx_command_t  ngx_mail_ssl_comma
 
     { ngx_string("ssl_prefer_server_ciphers"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
       ngx_conf_set_flag_slot,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers),
       NULL },
-#else
-      ngx_mail_ssl_nosupported, 0, 0, ngx_mail_ssl_openssl097 },
-#endif
 
     { ngx_string("ssl_session_cache"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
@@ -166,7 +153,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
 
     scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t));
     if (scf == NULL) {
-        return NGX_CONF_ERROR;
+        return NULL;
     }
 
     /*
@@ -182,7 +169,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
      */
 
     scf->enable = NGX_CONF_UNSET;
-    scf->starttls = NGX_CONF_UNSET;
+    scf->starttls = NGX_CONF_UNSET_UINT;
     scf->prefer_server_ciphers = NGX_CONF_UNSET;
     scf->builtin_session_cache = NGX_CONF_UNSET;
     scf->session_timeout = NGX_CONF_UNSET;
@@ -297,14 +284,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
         }
     }
 
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
-
     if (conf->prefer_server_ciphers) {
         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
     }
 
-#endif
-
     if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
@@ -492,18 +475,3 @@ invalid:
 
     return NGX_CONF_ERROR;
 }
-
-
-#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
-
-static char *
-ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "\"%V\" directive is available only in %s,",
-                       &cmd->name, cmd->post);
-
-    return NGX_CONF_ERROR;
-}
-
-#endif
deleted file mode 100644
--- a/src/os/unix/ngx_aio.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_AIO_H_INCLUDED_
-#define _NGX_AIO_H_INCLUDED_
-
-
-#include <ngx_core.h>
-
-
-ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size);
-ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl);
-ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size);
-ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
-                                 off_t limit);
-
-
-#endif /* _NGX_AIO_H_INCLUDED_ */
--- a/src/os/unix/ngx_aio_read.c
+++ b/src/os/unix/ngx_aio_read.c
@@ -7,20 +7,10 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
-
-#if (NGX_HAVE_KQUEUE)
-#include <ngx_kqueue_module.h>
-#endif
 
 
-/*
- * the ready data requires 3 syscalls:
- *     aio_write(), aio_error(), aio_return()
- * the non-ready data requires 4 (kqueue) or 5 syscalls:
- *     aio_write(), aio_error(), notifiction, aio_error(), aio_return()
- *                               timeout, aio_cancel(), aio_error()
- */
+extern int  ngx_kqueue;
+
 
 ssize_t
 ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size)
--- a/src/os/unix/ngx_aio_read_chain.c
+++ b/src/os/unix/ngx_aio_read_chain.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
 
 
 ssize_t
--- a/src/os/unix/ngx_aio_write.c
+++ b/src/os/unix/ngx_aio_write.c
@@ -7,20 +7,10 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
-
-#if (NGX_HAVE_KQUEUE)
-#include <ngx_kqueue_module.h>
-#endif
 
 
-/*
- * the ready data requires 3 syscalls:
- *     aio_write(), aio_error(), aio_return()
- * the non-ready data requires 4 (kqueue) or 5 syscalls:
- *     aio_write(), aio_error(), notifiction, aio_error(), aio_return()
- *                               timeout, aio_cancel(), aio_error()
- */
+extern int  ngx_kqueue;
+
 
 ssize_t
 ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size)
--- a/src/os/unix/ngx_aio_write_chain.c
+++ b/src/os/unix/ngx_aio_write_chain.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
 
 
 ngx_chain_t *
--- a/src/os/unix/ngx_darwin_sendfile_chain.c
+++ b/src/os/unix/ngx_darwin_sendfile_chain.c
@@ -42,7 +42,7 @@ ngx_darwin_sendfile_chain(ngx_connection
     u_char          *prev;
     off_t            size, send, prev_send, aligned, sent, fprev;
     off_t            header_size, file_size;
-    ngx_uint_t       eintr, eagain, complete;
+    ngx_uint_t       eintr, complete;
     ngx_err_t        err;
     ngx_buf_t       *file;
     ngx_array_t      header, trailer;
@@ -75,7 +75,6 @@ ngx_darwin_sendfile_chain(ngx_connection
     }
 
     send = 0;
-    eagain = 0;
 
     header.elts = headers;
     header.size = sizeof(struct iovec);
@@ -238,22 +237,22 @@ ngx_darwin_sendfile_chain(ngx_connection
             if (rc == -1) {
                 err = ngx_errno;
 
-                if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                    if (err == NGX_EINTR) {
-                        eintr = 1;
+                switch (err) {
+                case NGX_EAGAIN:
+                    break;
 
-                    } else {
-                        eagain = 1;
-                    }
+                case NGX_EINTR:
+                    eintr = 1;
+                    break;
 
-                    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "sendfile() sent only %O bytes", sent);
-
-                } else {
+                default:
                     wev->error = 1;
                     (void) ngx_connection_error(c, err, "sendfile() failed");
                     return NGX_CHAIN_ERROR;
                 }
+
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "sendfile() sent only %O bytes", sent);
             }
 
             if (rc == 0 && sent == 0) {
@@ -284,19 +283,22 @@ ngx_darwin_sendfile_chain(ngx_connection
             if (rc == -1) {
                 err = ngx_errno;
 
-                if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                    if (err == NGX_EINTR) {
-                        eintr = 1;
-                    }
+                switch (err) {
+                case NGX_EAGAIN:
+                    break;
 
-                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "writev() not ready");
+                case NGX_EINTR:
+                    eintr = 1;
+                    break;
 
-                } else {
+                default:
                     wev->error = 1;
                     ngx_connection_error(c, err, "writev() failed");
                     return NGX_CHAIN_ERROR;
                 }
+
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "writev() not ready");
             }
 
             sent = rc > 0 ? rc : 0;
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -16,6 +16,7 @@ typedef int               ngx_err_t;
 
 #define NGX_EPERM         EPERM
 #define NGX_ENOENT        ENOENT
+#define NGX_ENOPATH       ENOENT
 #define NGX_ESRCH         ESRCH
 #define NGX_EINTR         EINTR
 #define NGX_ECHILD        ECHILD
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_file_aio_read.c
@@ -0,0 +1,214 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * FreeBSD file AIO features and quirks:
+ *
+ *    if an asked data are already in VM cache, then aio_error() returns 0,
+ *    and the data are already copied in buffer;
+ *
+ *    aio_read() preread in VM cache as minimum 16K (probably BKVASIZE);
+ *    the first AIO preload may be up to 128K;
+ *
+ *    aio_read/aio_error() may return EINPROGRESS for just written data;
+ *
+ *    kqueue EVFILT_AIO filter is level triggered only: an event repeats
+ *    until aio_return() will be called;
+ *
+ *    aio_cancel() can not cancel file AIO: it returns AIO_NOTCANCELED always.
+ */
+
+
+extern int  ngx_kqueue;
+
+
+static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
+    ngx_event_t *ev);
+static void ngx_file_aio_event_handler(ngx_event_t *ev);
+
+
+ssize_t
+ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+    ngx_pool_t *pool)
+{
+    int                 n;
+    ngx_event_t        *ev;
+    ngx_event_aio_t    *aio;
+    static ngx_uint_t   enosys = 0;
+
+    if (enosys) {
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    aio = file->aio;
+
+    if (aio == NULL) {
+        aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+        if (aio == NULL) {
+            return NGX_ERROR;
+        }
+
+        aio->file = file;
+        aio->fd = file->fd;
+        aio->event.data = aio;
+        aio->event.ready = 1;
+        aio->event.log = file->log;
+#if (NGX_HAVE_AIO_SENDFILE)
+        aio->last_offset = -1;
+#endif
+        file->aio = aio;
+    }
+
+    ev = &aio->event;
+
+    if (!ev->ready) {
+        ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+                      "second aio post for \"%V\"", &file->name);
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio complete:%d @%O:%z %V",
+                   ev->complete, offset, size, &file->name);
+
+    if (ev->complete) {
+        ev->complete = 0;
+        ngx_set_errno(aio->err);
+
+        if (aio->err == 0) {
+            return aio->nbytes;
+        }
+
+        return NGX_ERROR;
+    }
+
+    ngx_memzero(&aio->aiocb, sizeof(struct aiocb));
+
+    aio->aiocb.aio_fildes = file->fd;
+    aio->aiocb.aio_offset = offset;
+    aio->aiocb.aio_buf = buf;
+    aio->aiocb.aio_nbytes = size;
+#if (NGX_HAVE_KQUEUE)
+    aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
+    aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+    aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
+#endif
+    ev->handler = ngx_file_aio_event_handler;
+
+    n = aio_read(&aio->aiocb);
+
+    if (n == -1) {
+        n = ngx_errno;
+
+        if (n == NGX_EAGAIN) {
+            return ngx_read_file(file, buf, size, offset);
+        }
+
+        ngx_log_error(NGX_LOG_CRIT, file->log, n,
+                      "aio_read(\"%V\") failed", &file->name);
+
+        if (n == NGX_ENOSYS) {
+            enosys = 1;
+            return ngx_read_file(file, buf, size, offset);
+        }
+
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio_read: fd:%d %d", file->fd, n);
+
+    ev->active = 1;
+    ev->ready = 0;
+    ev->complete = 0;
+
+    return ngx_file_aio_result(aio->file, aio, ev);
+}
+
+
+static ssize_t
+ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev)
+{
+    int        n;
+    ngx_err_t  err;
+
+    n = aio_error(&aio->aiocb);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio_error: fd:%d %d", file->fd, n);
+
+    if (n == -1) {
+        err = ngx_errno;
+        aio->err = err;
+
+        ngx_log_error(NGX_LOG_ALERT, file->log, err,
+                      "aio_error(\"%V\") failed", &file->name);
+        return NGX_ERROR;
+    }
+
+    if (n != 0) {
+        if (n == NGX_EINPROGRESS) {
+            if (ev->ready) {
+                ev->ready = 0;
+                ngx_log_error(NGX_LOG_ALERT, file->log, n,
+                              "aio_read(\"%V\") still in progress",
+                              &file->name);
+            }
+
+            return NGX_AGAIN;
+        }
+
+        aio->err = n;
+        ev->ready = 0;
+
+        ngx_log_error(NGX_LOG_CRIT, file->log, n,
+                      "aio_read(\"%V\") failed", &file->name);
+        return NGX_ERROR;
+    }
+
+    n = aio_return(&aio->aiocb);
+
+    if (n == -1) {
+        err = ngx_errno;
+        aio->err = err;
+        ev->ready = 0;
+
+        ngx_log_error(NGX_LOG_ALERT, file->log, err,
+                      "aio_return(\"%V\") failed", &file->name);
+        return NGX_ERROR;
+    }
+
+    aio->err = 0;
+    aio->nbytes = n;
+    ev->ready = 1;
+    ev->active = 0;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio_return: fd:%d %d", file->fd, n);
+
+    return n;
+}
+
+
+static void
+ngx_file_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t  *aio;
+
+    aio = ev->data;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                   "aio event handler fd:%d %V", aio->fd, &aio->file->name);
+
+    if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) {
+        aio->handler(ev);
+    }
+}
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -18,13 +18,13 @@ typedef ino_t                    ngx_fil
 
 
 typedef struct {
-    DIR                        *dir;
-    struct dirent              *de;
-    struct stat                 info;
+    DIR                         *dir;
+    struct dirent               *de;
+    struct stat                  info;
 
-    unsigned                    type:8;
-    unsigned                    valid_info:1;
-    unsigned                    valid_type:1;
+    unsigned                     type:8;
+    unsigned                     valid_info:1;
+    unsigned                     valid_type:1;
 } ngx_dir_t;
 
 
@@ -63,7 +63,7 @@ typedef struct {
 #define NGX_FILE_RDWR            O_RDWR
 #define NGX_FILE_CREATE_OR_OPEN  O_CREAT
 #define NGX_FILE_OPEN            0
-#define NGX_FILE_TRUNCATE        O_TRUNC
+#define NGX_FILE_TRUNCATE        O_CREAT|O_TRUNC
 #define NGX_FILE_APPEND          O_WRONLY|O_APPEND
 
 #define NGX_FILE_DEFAULT_ACCESS  0644
@@ -113,6 +113,10 @@ ngx_write_fd(ngx_fd_t fd, void *buf, siz
 
 #define ngx_write_fd_n           "write()"
 
+
+#define ngx_write_console        ngx_write_fd
+
+
 #define ngx_linefeed(p)          *p++ = LF;
 #define NGX_LINEFEED_SIZE        1
 
@@ -158,8 +162,10 @@ ngx_int_t ngx_set_file_time(u_char *name
 
 #define ngx_realpath(p, r)       realpath((char *) p, (char *) r)
 #define ngx_realpath_n           "realpath()"
-#define ngx_getcwd(buf, size)    (getcwd(buf, size) != NULL)
+#define ngx_getcwd(buf, size)    (getcwd((char *) buf, size) != NULL)
 #define ngx_getcwd_n             "getcwd()"
+#define ngx_path_separator(c)    ((c) == '/')
+
 #define NGX_MAX_PATH             PATH_MAX
 
 #define NGX_DIR_MASK_LEN         0
@@ -273,8 +279,20 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
 
 #endif
 
-
 size_t ngx_fs_bsize(u_char *name);
 
 
+#define ngx_stderr               STDERR_FILENO
+#define ngx_set_stderr(fd)       dup2(fd, STDERR_FILENO)
+#define ngx_set_stderr_n         "dup2(STDERR_FILENO)"
+
+
+#if (NGX_HAVE_FILE_AIO)
+
+ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
+    off_t offset, ngx_pool_t *pool);
+
+#endif
+
+
 #endif /* _NGX_FILES_H_INCLUDED_ */
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -73,13 +73,14 @@
 #endif
 
 
-#if (NGX_HAVE_AIO)
-#include <aio.h>
+#if (NGX_HAVE_KQUEUE)
+#include <sys/event.h>
 #endif
 
 
-#if (NGX_HAVE_KQUEUE)
-#include <sys/event.h>
+#if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO)
+#include <aio.h>
+typedef struct aiocb  ngx_aiocb_t;
 #endif
 
 
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -40,7 +40,7 @@
 ngx_chain_t *
 ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
 {
-    int              rc;
+    int              rc, flags;
     u_char          *prev;
     off_t            size, send, prev_send, aligned, sent, fprev;
     size_t           header_size, file_size;
@@ -78,6 +78,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio
 
     send = 0;
     eagain = 0;
+    flags = 0;
 
     header.elts = headers;
     header.size = sizeof(struct iovec);
@@ -261,36 +262,46 @@ ngx_freebsd_sendfile_chain(ngx_connectio
 
             sent = 0;
 
+#if (NGX_HAVE_AIO_SENDFILE)
+            flags = c->aio_sendfile ? SF_NODISKIO : 0;
+#endif
+
             rc = sendfile(file->file->fd, c->fd, file->file_pos,
-                          file_size + header_size, &hdtr, &sent, 0);
+                          file_size + header_size, &hdtr, &sent, flags);
 
             if (rc == -1) {
                 err = ngx_errno;
 
-                if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                    if (err == NGX_EINTR) {
-                        eintr = 1;
+                switch (err) {
+                case NGX_EAGAIN:
+                    eagain = 1;
+                    break;
 
-                    } else {
-                        eagain = 1;
-                    }
+                case NGX_EINTR:
+                    eintr = 1;
+                    break;
 
-                    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "sendfile() sent only %O bytes", sent);
+#if (NGX_HAVE_AIO_SENDFILE)
+                case NGX_EBUSY:
+                    c->busy_sendfile = file;
+                    break;
+#endif
 
-                } else {
+                default:
                     wev->error = 1;
                     (void) ngx_connection_error(c, err, "sendfile() failed");
                     return NGX_CHAIN_ERROR;
                 }
-            }
+
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "sendfile() sent only %O bytes", sent);
 
             /*
              * sendfile() in FreeBSD 3.x-4.x may return value >= 0
              * on success, although only 0 is documented
              */
 
-            if (rc >= 0 && sent == 0) {
+            } else if (rc >= 0 && sent == 0) {
 
                 /*
                  * if rc is OK and sent equal to zero, then someone
@@ -299,8 +310,8 @@ ngx_freebsd_sendfile_chain(ngx_connectio
                  */
 
                 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
-                              "sendfile() reported that \"%s\" was truncated",
-                              file->file->name.data);
+                         "sendfile() reported that \"%s\" was truncated at %O",
+                         file->file->name.data, file->file_pos);
 
                 return NGX_CHAIN_ERROR;
             }
@@ -318,19 +329,22 @@ ngx_freebsd_sendfile_chain(ngx_connectio
             if (rc == -1) {
                 err = ngx_errno;
 
-                if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                    if (err == NGX_EINTR) {
-                        eintr = 1;
-                    }
+                switch (err) {
+                case NGX_EAGAIN:
+                    break;
 
-                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "writev() not ready");
+                case NGX_EINTR:
+                    eintr = 1;
+                    break;
 
-                } else {
+                default:
                     wev->error = 1;
                     ngx_connection_error(c, err, "writev() failed");
                     return NGX_CHAIN_ERROR;
                 }
+
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "writev() not ready");
             }
 
             sent = rc > 0 ? rc : 0;
@@ -379,6 +393,12 @@ ngx_freebsd_sendfile_chain(ngx_connectio
             break;
         }
 
+#if (NGX_HAVE_AIO_SENDFILE)
+        if (c->busy_sendfile) {
+            return cl;
+        }
+#endif
+
         if (eagain) {
 
             /*
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_linux_aio_read.c
@@ -0,0 +1,131 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+extern int            ngx_eventfd;
+extern aio_context_t  ngx_aio_ctx;
+
+
+static void ngx_file_aio_event_handler(ngx_event_t *ev);
+
+
+static long
+io_submit(aio_context_t ctx, long n, struct iocb **paiocb)
+{
+    return syscall(SYS_io_submit, ctx, n, paiocb);
+}
+
+
+ssize_t
+ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+    ngx_pool_t *pool)
+{
+    long                n;
+    struct iocb        *piocb[1];
+    ngx_event_t        *ev;
+    ngx_event_aio_t    *aio;
+    static ngx_uint_t   enosys = 0;
+
+    if (enosys) {
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    aio = file->aio;
+
+    if (aio == NULL) {
+        aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+        if (aio == NULL) {
+            return NGX_ERROR;
+        }
+
+        aio->file = file;
+        aio->fd = file->fd;
+        aio->event.data = aio;
+        aio->event.ready = 1;
+        aio->event.log = file->log;
+        file->aio = aio;
+    }
+
+    ev = &aio->event;
+
+    if (!ev->ready) {
+        ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+                      "second aio post for \"%V\"", &file->name);
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio complete:%d @%O:%z %V",
+                   ev->complete, offset, size, &file->name);
+
+    if (ev->complete) {
+        ev->active = 0;
+        ev->complete = 0;
+
+        if (aio->res >= 0) {
+            ngx_set_errno(0);
+            return aio->res;
+        }
+
+        ngx_set_errno(-aio->res);
+        return NGX_ERROR;
+    }
+
+    ngx_memzero(&aio->aiocb, sizeof(struct iocb));
+
+    aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev;
+    aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD;
+    aio->aiocb.aio_fildes = file->fd;
+    aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf;
+    aio->aiocb.aio_nbytes = size;
+    aio->aiocb.aio_offset = offset;
+    aio->aiocb.aio_flags = IOCB_FLAG_RESFD;
+    aio->aiocb.aio_resfd = ngx_eventfd;
+
+    ev->handler = ngx_file_aio_event_handler;
+
+    piocb[0] = &aio->aiocb;
+
+    n = io_submit(ngx_aio_ctx, 1, piocb);
+
+    if (n == 1) {
+        return NGX_AGAIN;
+    }
+
+    n = -n;
+
+    if (n == NGX_EAGAIN) {
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    ngx_log_error(NGX_LOG_CRIT, file->log, n,
+                  "io_submit(\"%V\") failed", &file->name);
+
+    if (n == NGX_ENOSYS) {
+        enosys = 1;
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    return NGX_ERROR;
+}
+
+
+static void
+ngx_file_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t  *aio;
+
+    aio = ev->data;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                   "aio event handler fd:%d %V", aio->fd, &aio->file->name);
+
+    aio->handler(ev);
+}
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -81,6 +81,13 @@ extern ssize_t sendfile(int s, int fd, i
 #endif
 
 
+#if (NGX_HAVE_FILE_AIO)
+#include <sys/syscall.h>
+#include <linux/aio_abi.h>
+typedef struct iocb  ngx_aiocb_t;
+#endif
+
+
 #define NGX_LISTEN_BACKLOG        511
 
 
@@ -95,11 +102,6 @@ extern ssize_t sendfile(int s, int fd, i
 #endif
 
 
-#ifndef NGX_HAVE_GNU_CRYPT_R
-#define NGX_HAVE_GNU_CRYPT_R         1
-#endif
-
-
 #ifndef NGX_HAVE_INHERITED_NONBLOCK
 #define NGX_HAVE_INHERITED_NONBLOCK  0
 #endif
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -263,19 +263,22 @@ ngx_linux_sendfile_chain(ngx_connection_
             if (rc == -1) {
                 err = ngx_errno;
 
-                if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                    if (err == NGX_EINTR) {
-                        eintr = 1;
-                    }
+                switch (err) {
+                case NGX_EAGAIN:
+                    break;
 
-                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "sendfile() is not ready");
+                case NGX_EINTR:
+                    eintr = 1;
+                    break;
 
-                } else {
+                default:
                     wev->error = 1;
                     ngx_connection_error(c, err, "sendfile() failed");
                     return NGX_CHAIN_ERROR;
                 }
+
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "sendfile() is not ready");
             }
 
             sent = rc > 0 ? rc : 0;
@@ -290,19 +293,22 @@ ngx_linux_sendfile_chain(ngx_connection_
             if (rc == -1) {
                 err = ngx_errno;
 
-                if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                    if (err == NGX_EINTR) {
-                        eintr = 1;
-                    }
+                switch (err) {
+                case NGX_EAGAIN:
+                    break;
 
-                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "writev() not ready");
+                case NGX_EINTR:
+                    eintr = 1;
+                    break;
 
-                } else {
+                default:
                     wev->error = 1;
                     ngx_connection_error(c, err, "writev() failed");
                     return NGX_CHAIN_ERROR;
                 }
+
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "writev() not ready");
             }
 
             sent = rc > 0 ? rc : 0;
--- a/src/os/unix/ngx_os.h
+++ b/src/os/unix/ngx_os.h
@@ -37,6 +37,7 @@ void ngx_os_status(ngx_log_t *log);
 ngx_int_t ngx_os_specific_init(ngx_log_t *log);
 void ngx_os_specific_status(ngx_log_t *log);
 ngx_int_t ngx_daemon(ngx_log_t *log);
+ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid);
 
 
 ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size);
@@ -46,6 +47,14 @@ ssize_t ngx_unix_send(ngx_connection_t *
 ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in,
     off_t limit);
 
+#if (NGX_HAVE_AIO)
+ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl);
+ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size);
+ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
+    off_t limit);
+#endif
+
 
 extern ngx_os_io_t  ngx_os_io;
 extern ngx_int_t    ngx_ncpu;
@@ -53,7 +62,6 @@ extern ngx_int_t    ngx_max_sockets;
 extern ngx_uint_t   ngx_inherited_nonblocking;
 extern ngx_uint_t   ngx_tcp_nodelay_and_tcp_nopush;
 
-#define ngx_stderr_fileno  STDERR_FILENO
 
 #if (NGX_FREEBSD)
 #include <ngx_freebsd.h>
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -44,6 +44,9 @@
 #include <grp.h>
 #include <dirent.h>
 #include <glob.h>
+#if (NGX_HAVE_SYS_PARAM_H)
+#include <sys/param.h>          /* statfs() */
+#endif
 #if (NGX_HAVE_SYS_MOUNT_H)
 #include <sys/mount.h>          /* statfs() */
 #endif
@@ -109,6 +112,12 @@
 #endif
 
 
+#if (NGX_HAVE_FILE_AIO)
+#include <aio.h>
+typedef struct aiocb  ngx_aiocb_t;
+#endif
+
+
 #define NGX_LISTEN_BACKLOG  511
 
 
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -13,6 +13,7 @@
 typedef struct {
      int     signo;
      char   *signame;
+     char   *name;
      void  (*handler)(int signo);
 } ngx_signal_t;
 
@@ -36,39 +37,47 @@ ngx_process_t    ngx_processes[NGX_MAX_P
 ngx_signal_t  signals[] = {
     { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
       "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
+      "reload",
       ngx_signal_handler },
 
     { ngx_signal_value(NGX_REOPEN_SIGNAL),
       "SIG" ngx_value(NGX_REOPEN_SIGNAL),
+      "reopen",
       ngx_signal_handler },
 
     { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
       "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
+      "",
       ngx_signal_handler },
 
     { ngx_signal_value(NGX_TERMINATE_SIGNAL),
       "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
+      "stop",
       ngx_signal_handler },
 
     { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
       "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
+      "quit",
       ngx_signal_handler },
 
     { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
       "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
+      "",
       ngx_signal_handler },
 
-    { SIGALRM, "SIGALRM", ngx_signal_handler },
+    { SIGALRM, "SIGALRM", "", ngx_signal_handler },
 
-    { SIGINT, "SIGINT", ngx_signal_handler },
+    { SIGINT, "SIGINT", "", ngx_signal_handler },
 
-    { SIGIO, "SIGIO", ngx_signal_handler },
+    { SIGIO, "SIGIO", "", ngx_signal_handler },
 
-    { SIGCHLD, "SIGCHLD", ngx_signal_handler },
+    { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
+
+    { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
 
-    { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN },
+    { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
 
-    { 0, NULL, NULL }
+    { 0, NULL, "", NULL }
 };
 
 
@@ -207,21 +216,33 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
 
     switch (respawn) {
 
+    case NGX_PROCESS_NORESPAWN:
+        ngx_processes[s].respawn = 0;
+        ngx_processes[s].just_spawn = 0;
+        ngx_processes[s].detached = 0;
+        break;
+
+    case NGX_PROCESS_JUST_SPAWN:
+        ngx_processes[s].respawn = 0;
+        ngx_processes[s].just_spawn = 1;
+        ngx_processes[s].detached = 0;
+        break;
+
     case NGX_PROCESS_RESPAWN:
         ngx_processes[s].respawn = 1;
-        ngx_processes[s].just_respawn = 0;
+        ngx_processes[s].just_spawn = 0;
         ngx_processes[s].detached = 0;
         break;
 
     case NGX_PROCESS_JUST_RESPAWN:
         ngx_processes[s].respawn = 1;
-        ngx_processes[s].just_respawn = 1;
+        ngx_processes[s].just_spawn = 1;
         ngx_processes[s].detached = 0;
         break;
 
     case NGX_PROCESS_DETACHED:
         ngx_processes[s].respawn = 0;
-        ngx_processes[s].just_respawn = 0;
+        ngx_processes[s].just_spawn = 0;
         ngx_processes[s].detached = 1;
         break;
     }
@@ -352,6 +373,7 @@ ngx_signal_handler(int signo)
             break;
 
         case SIGALRM:
+            ngx_sigalrm = 1;
             break;
 
         case SIGIO:
@@ -540,3 +562,23 @@ ngx_debug_point(void)
         ngx_abort();
     }
 }
+
+
+ngx_int_t
+ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid)
+{
+    ngx_signal_t  *sig;
+
+    for (sig = signals; sig->signo != 0; sig++) {
+        if (ngx_strcmp(name, sig->name) == 0) {
+            if (kill(pid, sig->signo) != -1) {
+                return 0;
+            }
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          "kill(%P, %d) failed", pid, sig->signo);
+        }
+    }
+
+    return 1;
+}
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -27,7 +27,7 @@ typedef struct {
     char               *name;
 
     unsigned            respawn:1;
-    unsigned            just_respawn:1;
+    unsigned            just_spawn:1;
     unsigned            detached:1;
     unsigned            exiting:1;
     unsigned            exited:1;
@@ -45,9 +45,10 @@ typedef struct {
 #define NGX_MAX_PROCESSES         1024
 
 #define NGX_PROCESS_NORESPAWN     -1
-#define NGX_PROCESS_RESPAWN       -2
-#define NGX_PROCESS_JUST_RESPAWN  -3
-#define NGX_PROCESS_DETACHED      -4
+#define NGX_PROCESS_JUST_SPAWN    -2
+#define NGX_PROCESS_RESPAWN       -3
+#define NGX_PROCESS_JUST_RESPAWN  -4
+#define NGX_PROCESS_DETACHED      -5
 
 
 #define ngx_getpid   getpid
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -12,7 +12,9 @@
 
 static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n,
     ngx_int_t type);
-static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type);
+static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle,
+    ngx_uint_t respawn);
+static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch);
 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
 static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle);
 static void ngx_master_process_exit(ngx_cycle_t *cycle);
@@ -26,6 +28,7 @@ static ngx_thread_value_t ngx_worker_thr
 #endif
 static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data);
 static void ngx_cache_manager_process_handler(ngx_event_t *ev);
+static void ngx_cache_loader_process_handler(ngx_event_t *ev);
 
 
 ngx_uint_t    ngx_process;
@@ -34,6 +37,7 @@ ngx_uint_t    ngx_threaded;
 
 sig_atomic_t  ngx_reap;
 sig_atomic_t  ngx_sigio;
+sig_atomic_t  ngx_sigalrm;
 sig_atomic_t  ngx_terminate;
 sig_atomic_t  ngx_quit;
 sig_atomic_t  ngx_debug_quit;
@@ -61,6 +65,15 @@ u_long         cpu_affinity;
 static u_char  master_process[] = "master process";
 
 
+static ngx_cache_manager_ctx_t  ngx_cache_manager_ctx = {
+    ngx_cache_manager_process_handler, "cache manager process", 0
+};
+
+static ngx_cache_manager_ctx_t  ngx_cache_loader_ctx = {
+    ngx_cache_loader_process_handler, "cache loader process", 60000
+};
+
+
 static ngx_cycle_t      ngx_exit_cycle;
 static ngx_log_t        ngx_exit_log;
 static ngx_open_file_t  ngx_exit_log_file;
@@ -122,7 +135,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
     ngx_start_worker_processes(cycle, ccf->worker_processes,
                                NGX_PROCESS_RESPAWN);
-    ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
+    ngx_start_cache_manager_processes(cycle, 0);
 
     ngx_new_binary = 0;
     delay = 0;
@@ -130,10 +143,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
     for ( ;; ) {
         if (delay) {
-            delay *= 2;
+            if (ngx_sigalrm) {
+                delay *= 2;
+                ngx_sigalrm = 0;
+            }
 
             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                           "temination cycle: %d", delay);
+                           "termination cycle: %d", delay);
 
             itv.it_interval.tv_sec = 0;
             itv.it_interval.tv_usec = 0;
@@ -203,7 +219,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
             if (ngx_new_binary) {
                 ngx_start_worker_processes(cycle, ccf->worker_processes,
                                            NGX_PROCESS_RESPAWN);
-                ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
+                ngx_start_cache_manager_processes(cycle, 0);
                 ngx_noaccepting = 0;
 
                 continue;
@@ -222,7 +238,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
                                                    ngx_core_module);
             ngx_start_worker_processes(cycle, ccf->worker_processes,
                                        NGX_PROCESS_JUST_RESPAWN);
-            ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN);
+            ngx_start_cache_manager_processes(cycle, 1);
             live = 1;
             ngx_signal_worker_processes(cycle,
                                         ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
@@ -232,7 +248,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
             ngx_restart = 0;
             ngx_start_worker_processes(cycle, ccf->worker_processes,
                                        NGX_PROCESS_RESPAWN);
-            ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
+            ngx_start_cache_manager_processes(cycle, 0);
             live = 1;
         }
 
@@ -265,8 +281,6 @@ ngx_single_process_cycle(ngx_cycle_t *cy
 {
     ngx_uint_t  i;
 
-    ngx_init_temp_number();
-
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->init_process) {
             if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
@@ -317,7 +331,7 @@ ngx_single_process_cycle(ngx_cycle_t *cy
 static void
 ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
 {
-    ngx_int_t      i, s;
+    ngx_int_t      i;
     ngx_channel_t  ch;
 
     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
@@ -335,58 +349,70 @@ ngx_start_worker_processes(ngx_cycle_t *
         ch.slot = ngx_process_slot;
         ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
-        for (s = 0; s < ngx_last_process; s++) {
-
-            if (s == ngx_process_slot
-                || ngx_processes[s].pid == -1
-                || ngx_processes[s].channel[0] == -1)
-            {
-                continue;
-            }
-
-            ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
-                          "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
-                          ch.slot, ch.pid, ch.fd,
-                          s, ngx_processes[s].pid,
-                          ngx_processes[s].channel[0]);
-
-            /* TODO: NGX_AGAIN */
-
-            ngx_write_channel(ngx_processes[s].channel[0],
-                              &ch, sizeof(ngx_channel_t), cycle->log);
-        }
+        ngx_pass_open_channel(cycle, &ch);
     }
 }
 
 
 static void
-ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type)
+ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn)
 {
-    ngx_int_t        i;
-    ngx_uint_t       n;
+    ngx_uint_t       i, manager, loader;
     ngx_path_t     **path;
     ngx_channel_t    ch;
 
+    manager = 0;
+    loader = 0;
+
     path = ngx_cycle->pathes.elts;
-    for (n = 0; n < ngx_cycle->pathes.nelts; n++) {
-        if (path[n]->manager) {
-            goto start;
+    for (i = 0; i < ngx_cycle->pathes.nelts; i++) {
+
+        if (path[i]->manager) {
+            manager = 1;
+        }
+
+        if (path[i]->loader) {
+            loader = 1;
         }
     }
 
-    return;
+    if (manager == 0) {
+        return;
+    }
 
-start:
+    ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
+                      &ngx_cache_manager_ctx, "cache manager process",
+                      respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);
 
     ch.command = NGX_CMD_OPEN_CHANNEL;
-
-    ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, NULL,
-                      "cache manager process", type);
-
     ch.pid = ngx_processes[ngx_process_slot].pid;
     ch.slot = ngx_process_slot;
     ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
+    ngx_pass_open_channel(cycle, &ch);
+
+    if (loader == 0) {
+        return;
+    }
+
+    ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
+                      &ngx_cache_loader_ctx, "cache loader process",
+                      respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);
+
+    ch.command = NGX_CMD_OPEN_CHANNEL;
+    ch.pid = ngx_processes[ngx_process_slot].pid;
+    ch.slot = ngx_process_slot;
+    ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+    ngx_pass_open_channel(cycle, &ch);
+}
+
+
+static void
+ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch)
+{
+    ngx_int_t  i;
+
     for (i = 0; i < ngx_last_process; i++) {
 
         if (i == ngx_process_slot
@@ -398,14 +424,14 @@ start:
 
         ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                       "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
-                      ch.slot, ch.pid, ch.fd,
+                      ch->slot, ch->pid, ch->fd,
                       i, ngx_processes[i].pid,
                       ngx_processes[i].channel[0]);
 
         /* TODO: NGX_AGAIN */
 
         ngx_write_channel(ngx_processes[i].channel[0],
-                          &ch, sizeof(ngx_channel_t), cycle->log);
+                          ch, sizeof(ngx_channel_t), cycle->log);
     }
 }
 
@@ -456,14 +482,14 @@ ngx_signal_worker_processes(ngx_cycle_t 
                        ngx_processes[i].exited,
                        ngx_processes[i].detached,
                        ngx_processes[i].respawn,
-                       ngx_processes[i].just_respawn);
+                       ngx_processes[i].just_spawn);
 
         if (ngx_processes[i].detached || ngx_processes[i].pid == -1) {
             continue;
         }
 
-        if (ngx_processes[i].just_respawn) {
-            ngx_processes[i].just_respawn = 0;
+        if (ngx_processes[i].just_spawn) {
+            ngx_processes[i].just_spawn = 0;
             continue;
         }
 
@@ -492,8 +518,7 @@ ngx_signal_worker_processes(ngx_cycle_t 
         if (kill(ngx_processes[i].pid, signo) == -1) {
             err = ngx_errno;
             ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
-                          "kill(%P, %d) failed",
-                          ngx_processes[i].pid, signo);
+                          "kill(%P, %d) failed", ngx_processes[i].pid, signo);
 
             if (err == NGX_ESRCH) {
                 ngx_processes[i].exited = 1;
@@ -533,7 +558,7 @@ ngx_reap_children(ngx_cycle_t *cycle)
                        ngx_processes[i].exited,
                        ngx_processes[i].detached,
                        ngx_processes[i].respawn,
-                       ngx_processes[i].just_respawn);
+                       ngx_processes[i].just_spawn);
 
         if (ngx_processes[i].pid == -1) {
             continue;
@@ -590,26 +615,7 @@ ngx_reap_children(ngx_cycle_t *cycle)
                 ch.slot = ngx_process_slot;
                 ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
-                for (n = 0; n < ngx_last_process; n++) {
-
-                    if (n == ngx_process_slot
-                        || ngx_processes[n].pid == -1
-                        || ngx_processes[n].channel[0] == -1)
-                    {
-                        continue;
-                    }
-
-                    ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
-                          "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
-                          ch.slot, ch.pid, ch.fd,
-                          n, ngx_processes[n].pid,
-                          ngx_processes[n].channel[0]);
-
-                    /* TODO: NGX_AGAIN */
-
-                    ngx_write_channel(ngx_processes[n].channel[0],
-                                      &ch, sizeof(ngx_channel_t), cycle->log);
-                }
+                ngx_pass_open_channel(cycle, &ch);
 
                 live = 1;
 
@@ -925,8 +931,6 @@ ngx_worker_process_init(ngx_cycle_t *cyc
                       "sigprocmask() failed");
     }
 
-    ngx_init_temp_number();
-
     /*
      * disable deleting previous events for the listening sockets because
      * in the worker processes there are no events at all at this point
@@ -1012,13 +1016,14 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
                 && !c[i].read->resolver)
             {
                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
-                              "open socket #%d left in connection %ui%s",
-                              c[i].fd, i, ngx_debug_quit ? ", aborting" : "");
-                ngx_debug_point();
+                              "open socket #%d left in connection %ui",
+                              c[i].fd, i);
+                ngx_debug_quit = 1;
             }
         }
 
         if (ngx_debug_quit) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
             ngx_debug_point();
         }
     }
@@ -1265,6 +1270,8 @@ ngx_worker_thread_cycle(void *data)
 static void
 ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
 {
+    ngx_cache_manager_ctx_t *ctx = data;
+
     void         *ident[4];
     ngx_event_t   ev;
 
@@ -1275,16 +1282,16 @@ ngx_cache_manager_process_cycle(ngx_cycl
     ngx_close_listening_sockets(cycle);
 
     ngx_memzero(&ev, sizeof(ngx_event_t));
-    ev.handler = ngx_cache_manager_process_handler;
+    ev.handler = ctx->handler;
     ev.data = ident;
     ev.log = cycle->log;
     ident[3] = (void *) -1;
 
     ngx_use_accept_mutex = 0;
 
-    ngx_setproctitle("cache manager process");
+    ngx_setproctitle(ctx->name);
 
-    ngx_add_timer(&ev, 0);
+    ngx_add_timer(&ev, ctx->delay);
 
     for ( ;; ) {
 
@@ -1331,3 +1338,29 @@ ngx_cache_manager_process_handler(ngx_ev
 
     ngx_add_timer(ev, next * 1000);
 }
+
+
+static void
+ngx_cache_loader_process_handler(ngx_event_t *ev)
+{
+    ngx_uint_t     i;
+    ngx_path_t   **path;
+    ngx_cycle_t   *cycle;
+
+    cycle = (ngx_cycle_t *) ngx_cycle;
+
+    path = cycle->pathes.elts;
+    for (i = 0; i < cycle->pathes.nelts; i++) {
+
+        if (ngx_terminate || ngx_quit) {
+            break;
+        }
+
+        if (path[i]->loader) {
+            path[i]->loader(path[i]->data);
+            ngx_time_update(0, 0);
+        }
+    }
+
+    exit(0);
+}
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -19,9 +19,17 @@
 #define NGX_CMD_REOPEN         5
 
 
-#define NGX_PROCESS_SINGLE   0
-#define NGX_PROCESS_MASTER   1
-#define NGX_PROCESS_WORKER   2
+#define NGX_PROCESS_SINGLE     0
+#define NGX_PROCESS_MASTER     1
+#define NGX_PROCESS_WORKER     2
+#define NGX_PROCESS_SIGNALLER  3
+
+
+typedef struct {
+    ngx_event_handler_pt       handler;
+    char                      *name;
+    ngx_msec_t                 delay;
+} ngx_cache_manager_ctx_t;
 
 
 void ngx_master_process_cycle(ngx_cycle_t *cycle);
@@ -38,6 +46,7 @@ extern ngx_uint_t      ngx_exiting;
 
 extern sig_atomic_t    ngx_reap;
 extern sig_atomic_t    ngx_sigio;
+extern sig_atomic_t    ngx_sigalrm;
 extern sig_atomic_t    ngx_quit;
 extern sig_atomic_t    ngx_debug_quit;
 extern sig_atomic_t    ngx_terminate;
--- a/src/os/unix/ngx_send.c
+++ b/src/os/unix/ngx_send.c
@@ -40,6 +40,8 @@ ngx_unix_send(ngx_connection_t *c, u_cha
                 wev->ready = 0;
             }
 
+            c->sent += n;
+
             return n;
         }
 
--- a/src/os/unix/ngx_shmem.h
+++ b/src/os/unix/ngx_shmem.h
@@ -15,7 +15,9 @@
 typedef struct {
     u_char      *addr;
     size_t       size;
+    ngx_str_t    name;
     ngx_log_t   *log;
+    ngx_uint_t   exists;   /* unsigned  exists:1;  */
 } ngx_shm_t;
 
 
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -62,16 +62,6 @@
 #endif
 
 
-#if (NGX_HAVE_SENDFILE)
-#include <sys/sendfile.h>
-#endif
-
-
-#if (NGX_HAVE_AIO)
-#include <aio.h>
-#endif
-
-
 #if (NGX_HAVE_DEVPOLL)
 #include <sys/ioctl.h>
 #include <sys/devpoll.h>
@@ -83,6 +73,11 @@
 #endif
 
 
+#if (NGX_HAVE_SENDFILE)
+#include <sys/sendfile.h>
+#endif
+
+
 #define NGX_LISTEN_BACKLOG           511
 
 
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -168,19 +168,22 @@ ngx_solaris_sendfilev_chain(ngx_connecti
         if (n == -1) {
             err = ngx_errno;
 
-            if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                if (err == NGX_EINTR) {
-                    eintr = 1;
-                }
+            switch (err) {
+            case NGX_EAGAIN:
+                break;
 
-                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
-                              "sendfilev() sent only %uz bytes", sent);
+            case NGX_EINTR:
+                eintr = 1;
+                break;
 
-            } else {
+            default:
                 wev->error = 1;
                 ngx_connection_error(c, err, "sendfilev() failed");
                 return NGX_CHAIN_ERROR;
             }
+
+            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
+                          "sendfilev() sent only %uz bytes", sent);
         }
 
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
--- a/src/os/unix/ngx_sunpro_x86.il
+++ b/src/os/unix/ngx_sunpro_x86.il
@@ -5,7 +5,7 @@
 / ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock,
 /     ngx_atomic_uint_t old, ngx_atomic_uint_t set);
 /
-/ the arguments are passed on the stack (%esp), 4(%esp), 8(%esp)
+/ the arguments are passed on stack (%esp), 4(%esp), 8(%esp)
 
         .inline ngx_atomic_cmp_set,0
         movl      (%esp), %ecx
@@ -21,7 +21,7 @@
 / ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value,
 /     ngx_atomic_int_t add);
 /
-/ the arguments are passed on the stack (%esp), 4(%esp)
+/ the arguments are passed on stack (%esp), 4(%esp)
 
         .inline ngx_atomic_fetch_add,0
         movl      (%esp), %ecx
@@ -32,7 +32,12 @@
 
 
 / ngx_cpu_pause()
+/
+/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware
+/ capability added by linker because Solaris/i386 does not know about it:
+/
+/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000  [ PAUSE ]
 
        .inline ngx_cpu_pause,0
-       pause
+       rep; nop
        .end
deleted file mode 100644
--- a/src/os/unix/ngx_sunpro_x86.map
+++ /dev/null
@@ -1,2 +0,0 @@
-# disable { PAUSE ] hwcap for Sun Studio 11
-hwcap_1 = OVERRIDE;
--- a/src/os/unix/ngx_writev_chain.c
+++ b/src/os/unix/ngx_writev_chain.c
@@ -110,19 +110,22 @@ ngx_writev_chain(ngx_connection_t *c, ng
         if (n == -1) {
             err = ngx_errno;
 
-            if (err == NGX_EAGAIN || err == NGX_EINTR) {
-                if (err == NGX_EINTR) {
-                    eintr = 1;
-                }
+            switch (err) {
+            case NGX_EAGAIN:
+                break;
 
-                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
-                               "writev() not ready");
+            case NGX_EINTR:
+                eintr = 1;
+                break;
 
-            } else {
+            default:
                 wev->error = 1;
                 (void) ngx_connection_error(c, err, "writev() failed");
                 return NGX_CHAIN_ERROR;
             }
+
+            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                           "writev() not ready");
         }
 
         sent = n > 0 ? n : 0;