changeset 665:0b460e61bdcd default tip

Merge with nginx 1.0.0.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 25 Apr 2011 04:22:17 +0400
parents 06419a2298a9 (current diff) 00d13b6d4ebd (diff)
children
files .hgtags auto/modules src/mail/ngx_mail.h src/mail/ngx_mail_auth_http_module.c src/mail/ngx_mail_handler.c src/mail/ngx_mail_imap_handler.c src/mail/ngx_mail_pop3_handler.c src/mail/ngx_mail_proxy_module.c src/mail/ngx_mail_smtp_handler.c
diffstat 175 files changed, 13302 insertions(+), 4167 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -271,3 +271,49 @@ 80f7156c296569546cf57fa286749d84e0cc8b9d
 0161f31978175e258b8bb4989262b2ccb5fa9207 NGINX_0_8_15
 005a70f9573bc6bcf760786cb0573a62f1e570f3 NGINX_0_8_16
 5938746e70c2ae3e83fb402c030635f5ab459251 PATCH_NGINX_MAIL_0_8
+4c5d2c627a6c0ad577b5e930782128fc7b082599 NGINX_0_8_17
+f7ec98e3caeb844c9401027b092837eee63dccab NGINX_0_8_18
+a52c99698e7f7001336116600d8bb40bdfdc59e0 NGINX_0_8_19
+0dc162a5f3e89e9d967f4aa30b2add942d895083 NGINX_0_8_20
+1dcf6adad48485e10aec666e0774634c318a9d76 NGINX_0_8_21
+c04fa65fe604240cbf3b29f4dddfc7683514fa5a NGINX_0_8_22
+2b9e388c61f18f47f2a26639c1bdf836db7ef41e NGINX_0_8_23
+40c366b3535c1c7c93baedb2ee910c1de0180e62 NGINX_0_8_24
+e19e5f54287869c93f4dc51035231772e5dca61c NGINX_0_8_25
+ab7d265273edb2eb721cb032870c23ffeda0ce60 NGINX_0_8_26
+697030d79811b68a1541986a16d39b8a9bd705c9 NGINX_0_8_27
+43e02819c5cf4e5124486eed8a338cfc2e868f18 NGINX_0_8_28
+5c576ea5dbd969cb73e9c6672723eeb11ddda2ac NGINX_0_8_29
+25255878df91eae733aead855caa35aaf8275671 NGINX_0_8_30
+2da4537168f879f528f09d0e0ce80abe68adf05e NGINX_0_8_31
+daf4847b43ff5f01a6cd52111fc8d747e2db0d72 NGINX_0_8_32
+7fa8dc2315bd08cb5329d94763ea7475d8c4d46d NGINX_0_8_33
+da3c99095432591583f4fde189906f6b860002f7 NGINX_0_8_34
+be4f34123024c582d06401144a678ed96f7963bc NGINX_0_8_35
+566e105a89f11e96c34277df2e12de7583dafc56 NGINX_0_8_36
+8246d8a2c2be92f925435369b414899f0db45492 NGINX_0_8_37
+ff463db0be31226ba236423b24e3d6d58cc78d7e NGINX_0_8_38
+7858d4f8dec4ba84e9448c5dd9c24aca7b371707 NGINX_0_8_39
+01f2313e34f1b0a22a7c7395e687ec3846b31b8a NGINX_0_8_40
+bc110f60c0de90e5a56424c85286e46321e0b884 NGINX_0_8_41
+4d3e880ce86c7593d874a5ea75b415bf52fa78ff NGINX_0_8_42
+c456a023113cfb4ce0dd5acede9b77b8277abb3c NGINX_0_8_43
+016632f0fb18481572e637dba5a82d0431b6fd80 NGINX_0_8_44
+53f5f04a64b8ff12526d81276be859efce6b9abc NGINX_0_8_45
+b6a5942a4e6a372aea8083d8d714748f02482cdd NGINX_0_8_46
+cde3626b2d0d4a784d9d33b41640672fa66ae24d NGINX_0_8_47
+09d5f308901fa05a6031c104b0ea8f8c19c1b2b1 NGINX_0_8_48
+3436cf38d59e5d8a3ac57414535a6bd7effa5936 NGINX_0_8_49
+6c96fdd2dfc3419755a0337ab50dd32123745ace NGINX_0_8_50
+be70f83b184f95fb120e072d0ab320507edc9d50 NGINX_0_8_51
+5dc296c4372ab4049b1a17259c894ad4f2a78e73 NGINX_0_8_52
+c5122335e41d714c25792bcd57a6c42396d04c35 NGINX_0_8_53
+428c6e58046a618a6edd6bc9fdc96f72c6ef6ae8 NGINX_0_9_0
+9ad199846233b1c040ba06934bfc104839917a01 NGINX_0_9_1
+3036c1836a244c5ba1ac6d43d88bd5ab685eb925 NGINX_0_9_2
+7ea1bba9a4f6fedf1df77201fa15abc0ef07639d NGINX_0_9_3
+ce857f6b74a730b814b13b64f205017721d2ff24 NGINX_0_9_4
+bb20316269e40c4aec209f67934ecac111fddeeb NGINX_0_9_5
+8214eaef3530da4aff945052fc2e99b0c097e21e NGINX_0_9_6
+b9763778e212fc338790a00c19a41fd0e68e1923 NGINX_0_9_7
+b4dcae568a2a9b258146c6dbd9c7f72fe1f3059c NGINX_1_0_0
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,796 @@
 
+Changes with nginx 1.0.0                                         12 Apr 2011
+
+    *) Bugfix: a cache manager might hog CPU after reload.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: an "image_filter crop" directive worked incorrectly coupled 
+       with an "image_filter rotate 180" directive.
+
+    *) Bugfix: a "satisfy any" directive disabled custom 401 error page.
+
+
+Changes with nginx 0.9.7                                         04 Apr 2011
+
+    *) Feature: now keepalive connections may be closed premature, if there 
+       are no free worker connections.
+       Thanks to Maxim Dounin.
+
+    *) Feature: the "rotate" parameter of the "image_filter" directive.
+       Thanks to Adam Bocim.
+
+    *) Bugfix: a case when a backend in "fastcgi_pass", "scgi_pass", or 
+       "uwsgi_pass" directives is given by expression and refers to a 
+       defined upstream.
+
+
+Changes with nginx 0.9.6                                         21 Mar 2011
+
+    *) Feature: the "map" directive supports regular expressions as value 
+       of the first parameter.
+
+    *) Feature: $time_iso8601 access_log variable.
+       Thanks to Michael Lustfield.
+
+
+Changes with nginx 0.9.5                                         21 Feb 2011
+
+    *) Change: now nginx uses a default listen backlog value -1 on 
+       Linux.
+       Thanks to Andrei Nigmatulin.
+
+    *) Feature: the "utf8" parameter of "geoip_country" and "geoip_city" 
+       directives.
+       Thanks to Denis F. Latypoff.
+
+    *) Bugfix: in a default "proxy_redirect" directive if "proxy_pass" 
+       directive has no URI part.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: an "error_page" directive did not work with nonstandard 
+       error codes; the bug had appeared in 0.8.53.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.9.4                                         21 Jan 2011
+
+    *) Feature: the "server_name" directive supports the $hostname variable.
+
+    *) Feature: 494 code for "Request Header Too Large" error.
+
+
+Changes with nginx 0.9.3                                         13 Dec 2010
+
+    *) Bugfix: if there was a single server for given IPv6 address:port 
+       pair, then captures in regular expressions in a "server_name" 
+       directive did not work.
+
+    *) Bugfix: nginx could not be built on Solaris; the bug had appeared in 
+       0.9.0.
+
+
+Changes with nginx 0.9.2                                         06 Dec 2010
+
+    *) Feature: the "If-Unmodified-Since" client request header line 
+       support.
+
+    *) Workaround: fallback to accept() syscall if accept4() was not 
+       implemented; the issue had appeared in 0.9.0.
+
+    *) Bugfix: nginx could not be built on Cygwin; the bug had appeared in 
+       0.9.0.
+
+    *) Bugfix: for OpenSSL vulnerability CVE-2010-4180.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.9.1                                         30 Nov 2010
+
+    *) Bugfix: "return CODE message" directives did not work; the bug had 
+       appeared in 0.9.0.
+
+
+Changes with nginx 0.9.0                                         29 Nov 2010
+
+    *) Feature: the "keepalive_disable" directive.
+
+    *) Feature: the "map" directive supports variables as value of a 
+       defined variable.
+
+    *) Feature: the "map" directive supports empty strings as value of the 
+       first parameter.
+
+    *) Feature: the "map" directive supports expressions as the first 
+       parameter.
+
+    *) Feature: nginx(8) manual page.
+       Thanks to Sergey Osokin.
+
+    *) Feature: Linux accept4() support.
+       Thanks to Simon Liu.
+
+    *) Workaround: elimination of Linux linker warning about "sys_errlist" 
+       and "sys_nerr"; the warning had appeared in 0.8.35.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, if the 
+       "auth_basic" directive was used.
+       Thanks to Michail Laletin.
+
+    *) Bugfix: compatibility with ngx_http_eval_module; the bug had 
+       appeared in 0.8.42.
+
+
+Changes with nginx 0.8.53                                        18 Oct 2010
+
+    *) Feature: now the "error_page" directive allows to change a status 
+       code in a redirect.
+
+    *) Feature: the "gzip_disable" directive supports special "degradation" 
+       mask.
+
+    *) Bugfix: a socket leak might occurred if file AIO was used.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: if the first server had no "listen" directive and there was 
+       no explicit default server, then a next server with a "listen" 
+       directive became the default server; the bug had appeared in 0.8.21.
+
+
+Changes with nginx 0.8.52                                        28 Sep 2010
+
+    *) Bugfix: nginx used SSL mode for a listen socket if any listen option 
+       was set; the bug had appeared in 0.8.51.
+
+
+Changes with nginx 0.8.51                                        27 Sep 2010
+
+    *) Change: the "secure_link_expires" directive has been canceled.
+
+    *) Change: a logging level of resolver errors has been lowered from 
+       "alert" to "error".
+
+    *) Feature: now a listen socket "ssl" parameter may be set several 
+       times.
+
+
+Changes with nginx 0.8.50                                        02 Sep 2010
+
+    *) Feature: the "secure_link", "secure_link_md5", and 
+       "secure_link_expires" directives of the ngx_http_secure_link_module.
+
+    *) Feature: the -q switch.
+       Thanks to Gena Makhomed.
+
+    *) Bugfix: worker processes may got caught in an endless loop during 
+       reconfiguration, if a caching was used; the bug had appeared in 
+       0.8.48.
+
+    *) Bugfix: in the "gzip_disable" directive.
+       Thanks to Derrick Petzold.
+
+    *) Bugfix: nginx/Windows could not send stop, quit, reopen, and reload 
+       signals to a process run in other session.
+
+
+Changes with nginx 0.8.49                                        09 Aug 2010
+
+    *) Feature: the "image_filter_jpeg_quality" directive supports 
+       variables.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, if the 
+       $geoip_region_name variables was used; the bug had appeared in 
+       0.8.48.
+
+    *) Bugfix: errors intercepted by error_page were cached only for next 
+       request; the bug had appeared in 0.8.48.
+
+
+Changes with nginx 0.8.48                                        03 Aug 2010
+
+    *) Change: now the "server_name" directive default value is an empty 
+       name "".
+       Thanks to Gena Makhomed.
+
+    *) Change: now the "server_name_in_redirect" directive default value is 
+       "off".
+
+    *) Feature: the $geoip_dma_code, $geoip_area_code, and 
+       $geoip_region_name variables.
+       Thanks to Christine McGonagle.
+
+    *) Bugfix: the "proxy_pass", "fastcgi_pass", "uwsgi_pass", and 
+       "scgi_pass" directives were not inherited inside "limit_except" 
+       blocks.
+
+    *) Bugfix: the "proxy_cache_min_uses", "fastcgi_cache_min_uses" 
+       "uwsgi_cache_min_uses", and "scgi_cache_min_uses" directives did not 
+       work; the bug had appeared in 0.8.46.
+
+    *) Bugfix: the "fastcgi_split_path_info" directive used incorrectly 
+       captures, if only parts of an URI were captured.
+       Thanks to Yuriy Taraday and Frank Enderle.
+
+    *) Bugfix: the "rewrite" directive did not escape a ";" character 
+       during copying from URI to query string.
+       Thanks to Daisuke Murase.
+
+    *) Bugfix: the ngx_http_image_filter_module closed a connection, if an 
+       image was larger than "image_filter_buffer" size.
+
+
+Changes with nginx 0.8.47                                        28 Jul 2010
+
+    *) Bugfix: $request_time variable had invalid values for subrequests.
+
+    *) Bugfix: errors intercepted by error_page could not be cached.
+
+    *) Bugfix: a cache manager process may got caught in an endless loop, 
+       if max_size parameter was used; the bug had appeared in 0.8.46.
+
+
+Changes with nginx 0.8.46                                        19 Jul 2010
+
+    *) Change: now the "proxy_no_cache", "fastcgi_no_cache", 
+       "uwsgi_no_cache", and "scgi_no_cache" directives affect on a cached 
+       response saving only.
+
+    *) Feature: the "proxy_cache_bypass", "fastcgi_cache_bypass", 
+       "uwsgi_cache_bypass", and "scgi_cache_bypass" directives.
+
+    *) Bugfix: nginx did not free memory in cache keys zones if there was 
+       an error during working with backend: the memory was freed only 
+       after inactivity time or on memory low condition.
+
+
+Changes with nginx 0.8.45                                        13 Jul 2010
+
+    *) Feature: ngx_http_xslt_filter improvements.
+       Thanks to Laurence Rowe.
+
+    *) Bugfix: SSI response might be truncated after include with 
+       wait="yes"; the bug had appeared in 0.7.25.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the "listen" directive did not support the "setfib=0" 
+       parameter.
+
+
+Changes with nginx 0.8.44                                        05 Jul 2010
+
+    *) Change: now nginx does not cache by default backend responses, if 
+       they have a "Set-Cookie" header line.
+
+    *) Feature: the "listen" directive supports the "setfib" parameter.
+       Thanks to Andrew Filonov.
+
+    *) Bugfix: the "sub_filter" directive might change character case on 
+       partial match.
+
+    *) Bugfix: compatibility with HP/UX.
+
+    *) Bugfix: compatibility with AIX xlC_r compiler.
+
+    *) Bugfix: nginx treated large SSLv2 packets as plain requests.
+       Thanks to Miroslaw Jaworski.
+
+
+Changes with nginx 0.8.43                                        30 Jun 2010
+
+    *) Feature: large geo ranges base loading speed-up.
+
+    *) Bugfix: an error_page redirection to "location /zero {return 204;}" 
+       without changing status code kept the error body; the bug had 
+       appeared in 0.8.42.
+
+    *) Bugfix: nginx might close IPv6 listen socket during 
+       reconfiguration.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the $uid_set variable may be used at any request processing 
+       stage.
+
+
+Changes with nginx 0.8.42                                        21 Jun 2010
+
+    *) Change: now nginx tests locations given by regular expressions, if 
+       request was matched exactly by a location given by a prefix string. 
+       The previous behavior has been introduced in 0.7.1.
+
+    *) Feature: the ngx_http_scgi_module.
+       Thanks to Manlio Perillo.
+
+    *) Feature: a text answer may be added to a "return" directive.
+
+
+Changes with nginx 0.8.41                                        15 Jun 2010
+
+    *) Security: nginx/Windows worker might be terminated abnormally if a 
+       requested file name has invalid UTF-8 encoding.
+
+    *) Change: now nginx allows to use spaces in a request line.
+
+    *) Bugfix: the "proxy_redirect" directive changed incorrectly a backend 
+       "Refresh" response header line.
+       Thanks to Andrey Andreew and Max Sogin.
+
+    *) Bugfix: nginx did not support path without host name in 
+       "Destination" request header line.
+
+
+Changes with nginx 0.8.40                                        07 Jun 2010
+
+    *) Security: now nginx/Windows ignores default file stream name.
+       Thanks to Jose Antonio Vazquez Gonzalez.
+
+    *) Feature: the ngx_http_uwsgi_module.
+       Thanks to Roberto De Ioris.
+
+    *) Feature: a "fastcgi_param" directive with value starting with 
+       "HTTP_" overrides a client request header line.
+
+    *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request 
+       header lines were passed to FastCGI-server while caching.
+
+    *) Bugfix: listen unix domain socket could not be changed during 
+       reconfiguration.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.8.39                                        31 May 2010
+
+    *) Bugfix: an inherited "alias" directive worked incorrectly in 
+       inclusive location.
+
+    *) Bugfix: in "alias" with variables and "try_files" directives 
+       combination.
+
+    *) Bugfix: listen unix domain and IPv6 sockets did not inherit while 
+       online upgrade.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.8.38                                        24 May 2010
+
+    *) Feature: the "proxy_no_cache" and "fastcgi_no_cache" directives.
+
+    *) Feature: now the "rewrite" directive does a redirect automatically 
+       if the $scheme variable is used.
+       Thanks to Piotr Sikora.
+
+    *) Bugfix: now "limit_req" delay directive conforms to the described 
+       algorithm.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the $uid_got variable might not be used in the SSI and perl 
+       modules.
+
+
+Changes with nginx 0.8.37                                        17 May 2010
+
+    *) Feature: the ngx_http_split_clients_module.
+
+    *) Feature: the "map" directive supports keys more than 255 characters.
+
+    *) Bugfix: nginx ignored the "private" and "no-store" values in the 
+       "Cache-Control" backend response header line.
+
+    *) Bugfix: a "stub" parameter of an "include" SSI directive was not 
+       used, if empty response has 200 status code.
+
+    *) Bugfix: if a proxied or FastCGI request was internally redirected to 
+       another proxied or FastCGI location, then a segmentation fault might 
+       occur in a worker process; the bug had appeared in 0.8.33.
+       Thanks to Yichun Zhang.
+
+    *) Bugfix: IMAP connections may hang until they timed out while talking 
+       to Zimbra server.
+       Thanks to Alan Batie.
+
+
+Changes with nginx 0.8.36                                        22 Apr 2010
+
+    *) Bugfix: the ngx_http_dav_module handled incorrectly the DELETE, 
+       COPY, and MOVE methods for symlinks.
+
+    *) Bugfix: values of the $query_string, $arg_..., etc. variables cached 
+       in main request were used by the SSI module in subrequests.
+
+    *) Bugfix: a variable value was repeatedly encoded after each an "echo" 
+       SSI-command output; the bug had appeared in 0.6.14.
+
+    *) Bugfix: a worker process hung if a FIFO file was requested.
+       Thanks to Vicente Aguilar and Maxim Dounin.
+
+    *) Bugfix: OpenSSL-1.0.0 compatibility on 64-bit Linux.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: nginx could not be built --without-http-cache; the bug had 
+       appeared in 0.8.35.
+
+
+Changes with nginx 0.8.35                                        01 Apr 2010
+
+    *) Change: now the charset filter runs before the SSI filter.
+
+    *) Feature: the "chunked_transfer_encoding" directive.
+
+    *) Bugfix: an "&" character was not escaped when it was copied in 
+       arguments part in a rewrite rule.
+
+    *) Bugfix: nginx might be terminated abnormally while a signal 
+       processing or if the directive "timer_resolution" was used on 
+       platforms which do not support kqueue or eventport notification 
+       methods.
+       Thanks to George Xie and Maxim Dounin.
+
+    *) Bugfix: if temporary files and permanent storage area resided at 
+       different file systems, then permanent file modification times were 
+       incorrect.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: ngx_http_memcached_module might issue the error message 
+       "memcached sent invalid trailer".
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: nginx could not built zlib-1.2.4 library using the library 
+       sources.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault occurred in a worker process, if there 
+       was large stderr output before FastCGI response; the bug had 
+       appeared in 0.8.34.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.8.34                                        03 Mar 2010
+
+    *) Bugfix: nginx did not support all ciphers and digests used in client 
+       certificates.
+       Thanks to Innocenty Enikeew.
+
+    *) Bugfix: nginx cached incorrectly FastCGI responses if there was 
+       large stderr output before response.
+
+    *) Bugfix: nginx did not support HTTPS referrers.
+
+    *) Bugfix: nginx/Windows might not find file if path in configuration 
+       was given in other character case; the bug had appeared in 0.8.33.
+
+    *) Bugfix: the $date_local variable has an incorrect value, if the "%s" 
+       format was used.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: if ssl_session_cache was not set or was set to "none", then 
+       during client certificate verify the error "session id context 
+       uninitialized" might occur; the bug had appeared in 0.7.1.
+
+    *) Bugfix: a geo range returned default value if the range included two 
+       or more /16 networks and did not begin at /16 network boundary.
+
+    *) Bugfix: a block used in a "stub" parameter of an "include" SSI 
+       directive was output with "text/plain" MIME type.
+
+    *) Bugfix: $r->sleep() did not work; the bug had appeared in 0.8.11.
+
+
+Changes with nginx 0.8.33                                        01 Feb 2010
+
+    *) Security: now nginx/Windows ignores trailing spaces in URI.
+       Thanks to Dan Crowley, Core Security Technologies.
+
+    *) Security: now nginx/Windows ignores short files names.
+       Thanks to Dan Crowley, Core Security Technologies.
+
+    *) Change: now keepalive connections after POST requests are not 
+       disabled for MSIE 7.0+.
+       Thanks to Adam Lounds.
+
+    *) Workaround: now keepalive connections are disabled for Safari.
+       Thanks to Joshua Sierles.
+
+    *) Bugfix: if a proxied or FastCGI request was internally redirected to 
+       another proxied or FastCGI location, then $upstream_response_time 
+       variable may have abnormally large value; the bug had appeared in 
+       0.8.7.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, while 
+       discarding a request body; the bug had appeared in 0.8.11.
+
+
+Changes with nginx 0.8.32                                        11 Jan 2010
+
+    *) Bugfix: UTF-8 encoding usage in the ngx_http_autoindex_module.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: regular expression named captures worked for two names only. 
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: now the "localhost" name is used in the "Host" request 
+       header line, if an unix domain socket is defined in the "auth_http" 
+       directive.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: nginx did not support chunked transfer encoding for 201 
+       responses.
+       Thanks to Julian Reich.
+
+    *) Bugfix: if the "expires modified" set date in the past, then a 
+       negative number was set in the "Cache-Control" response header line. 
+       Thanks to Alex Kapranoff.
+
+
+Changes with nginx 0.8.31                                        23 Dec 2009
+
+    *) Feature: now the "error_page" directive may redirect the 301 and 302 
+       responses.
+
+    *) Feature: the $geoip_city_continent_code, $geoip_latitude, and 
+       $geoip_longitude variables.
+       Thanks to Arvind Sundararajan.
+
+    *) Feature: now the ngx_http_image_filter_module deletes always EXIF 
+       and other application specific data if the data consume more than 5% 
+       of a JPEG file.
+
+    *) Bugfix: nginx closed a connection if a cached response had an empty 
+       body.
+       Thanks to Piotr Sikora.
+
+    *) Bugfix: nginx might not be built by gcc 4.x if the -O2 or higher 
+       optimization option was used.
+       Thanks to Maxim Dounin and Denis F. Latypoff.
+
+    *) Bugfix: regular expressions in location were always tested in 
+       case-sensitive mode; the bug had appeared in 0.8.25.
+
+    *) Bugfix: nginx cached a 304 response if there was the "If-None-Match" 
+       header line in a proxied request.
+       Thanks to Tim Dettrick and David Kostal.
+
+    *) Bugfix: nginx/Windows tried to delete a temporary file twice if the 
+       file should replace an already existent file.
+
+
+Changes with nginx 0.8.30                                        15 Dec 2009
+
+    *) Change: now the default buffer size of the 
+       "large_client_header_buffers" directive is 8K.
+       Thanks to Andrew Cholakian.
+
+    *) Feature: the conf/fastcgi.conf for simple FastCGI configurations.
+
+    *) Bugfix: nginx/Windows tried to rename a temporary file twice if the 
+       file should replace an already existent file.
+
+    *) Bugfix: of "double free or corruption" error issued if host could 
+       not be resolved; the bug had appeared in 0.8.22.
+       Thanks to Konstantin Svist.
+
+    *) Bugfix: in libatomic usage on some platforms.
+       Thanks to W-Mark Kubacki.
+
+
+Changes with nginx 0.8.29                                        30 Nov 2009
+
+    *) Change: now the "009" status code is written to an access log for 
+       proxied HTTP/0.9 responses.
+
+    *) Feature: the "addition_types", "charset_types", "gzip_types", 
+       "ssi_types", "sub_filter_types", and "xslt_types" directives support 
+       an "*" parameter.
+
+    *) Feature: GCC 4.1+ built-in atomic operations usage.
+       Thanks to W-Mark Kubacki.
+
+    *) Feature: the --with-libatomic[=DIR] option in the configure.
+       Thanks to W-Mark Kubacki.
+
+    *) Bugfix: listen unix domain socket had limited access rights.
+
+    *) Bugfix: cached HTTP/0.9 responses were handled incorrectly.
+
+    *) Bugfix: regular expression named captures given by "?P<...>" did not 
+       work in a "server_name" directive.
+       Thanks to Maxim Dounin.
+
+
+Changes with nginx 0.8.28                                        23 Nov 2009
+
+    *) Bugfix: nginx could not be built with the --without-pcre parameter; 
+       the bug had appeared in 0.8.25.
+
+
+Changes with nginx 0.8.27                                        17 Nov 2009
+
+    *) Bugfix: regular expressions did not work in nginx/Windows; the bug 
+       had appeared in 0.8.25.
+
+
+Changes with nginx 0.8.26                                        16 Nov 2009
+
+    *) Bugfix: in captures usage in "rewrite" directive; the bug had 
+       appeared in 0.8.25.
+
+    *) Bugfix: nginx could not be built without the --with-debug option; 
+       the bug had appeared in 0.8.25.
+
+
+Changes with nginx 0.8.25                                        16 Nov 2009
+
+    *) Change: now no message is written in an error log if a variable is 
+       not found by $r->variable() method.
+
+    *) Feature: the ngx_http_degradation_module.
+
+    *) Feature: regular expression named captures.
+
+    *) Feature: now URI part is not required a "proxy_pass" directive if 
+       variables are used.
+
+    *) Feature: now the "msie_padding" directive works for Chrome too.
+
+    *) Bugfix: a segmentation fault occurred in a worker process on low 
+       memory condition; the bug had appeared in 0.8.18.
+
+    *) Bugfix: nginx sent gzipped responses to clients those do not support 
+       gzip, if "gzip_static on" and "gzip_vary off"; the bug had appeared 
+       in 0.8.16.
+
+
+Changes with nginx 0.8.24                                        11 Nov 2009
+
+    *) Bugfix: nginx always added "Content-Encoding: gzip" response header 
+       line in 304 responses sent by ngx_http_gzip_static_module.
+
+    *) Bugfix: nginx could not be built without the --with-debug option; 
+       the bug had appeared in 0.8.23.
+
+    *) Bugfix: the "unix:" parameter of the "set_real_ip_from" directive 
+       inherited incorrectly from previous level.
+
+    *) Bugfix: in resolving empty name.
+
+
+Changes with nginx 0.8.23                                        11 Nov 2009
+
+    *) Security: now SSL/TLS renegotiation is disabled.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: listen unix domain socket did not inherit while online 
+       upgrade.
+
+    *) Bugfix: the "unix:" parameter of the "set_real_ip_from" directive 
+       did not without yet another directive with any IP address.
+
+    *) Bugfix: segmentation fault and infinite looping in resolver.
+
+    *) Bugfix: in resolver.
+       Thanks to Artem Bokhan.
+
+
+Changes with nginx 0.8.22                                        03 Nov 2009
+
+    *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" 
+       directives.
+
+    *) Feature: the "access" and the "deny" directives support IPv6.
+
+    *) Feature: the "set_real_ip_from" directive supports IPv6 addresses in 
+       request headers.
+
+    *) Feature: the "unix:" parameter of the "set_real_ip_from" directive.
+
+    *) Bugfix: nginx did not delete unix domain socket after configuration 
+       testing.
+
+    *) Bugfix: nginx deleted unix domain socket while online upgrade.
+
+    *) Bugfix: the "!-x" operator did not work.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, if 
+       limit_rate was used in HTTPS server.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault might occur in a worker process while 
+       $limit_rate logging.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, if 
+       there was no "listen" directive in "server" block; the bug had 
+       appeared in 0.8.21.
+
+
+Changes with nginx 0.8.21                                        26 Oct 2009
+
+    *) Feature: now the "-V" switch shows TLS SNI support.
+
+    *) Feature: the "listen" directive of the HTTP module supports unix 
+       domain sockets.
+       Thanks to Hongli Lai.
+
+    *) Feature: the "default_server" parameter of the "listen" directive.
+
+    *) Feature: now a "default" parameter is not required to set listen 
+       socket options.
+
+    *) Bugfix: nginx did not support dates in 2038 year on 32-bit platforms;
+
+    *) Bugfix: socket leak; the bug had appeared in 0.8.11.
+
+
+Changes with nginx 0.8.20                                        14 Oct 2009
+
+    *) Change: now default SSL ciphers are "HIGH:!ADH:!MD5".
+
+    *) Bugfix: the ngx_http_autoindex_module did not show the trailing 
+       slash in links to a directory; the bug had appeared in 0.7.15.
+
+    *) Bugfix: nginx did not close a log file set by the --error-log-path 
+       configuration option; the bug had appeared in 0.7.53.
+
+    *) Bugfix: nginx did not treat a comma as separator in the 
+       "Cache-Control" backend response header line.
+
+    *) Bugfix: nginx/Windows might not create temporary file, a cache file, 
+       or "proxy/fastcgi_store"d file if a worker had no enough access 
+       rights for top level directories.
+
+    *) Bugfix: the "Set-Cookie" and "P3P" FastCGI response header lines 
+       were not hidden while caching if no "fastcgi_hide_header" directives 
+       were used with any parameters.
+
+    *) Bugfix: nginx counted incorrectly disk cache size.
+
+
+Changes with nginx 0.8.19                                        06 Oct 2009
+
+    *) Change: now SSLv2 protocol is disabled by default.
+
+    *) Change: now default SSL ciphers are "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM".
+
+    *) Bugfix: a "limit_req" directive did not work; the bug had appeared 
+       in 0.8.18.
+
+
+Changes with nginx 0.8.18                                        06 Oct 2009
+
+    *) Feature: the "read_ahead" directive.
+
+    *) Feature: now several "perl_modules" directives may be used.
+
+    *) Feature: the "limit_req_log_level" and "limit_conn_log_level" 
+       directives.
+
+    *) Bugfix: now "limit_req" directive conforms to the leaky bucket 
+       algorithm.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: nginx did not work on Linux/sparc.
+       Thanks to Marcus Ramberg.
+
+    *) Bugfix: nginx sent '\0' in a "Location" response header line on 
+       MKCOL request.
+       Thanks to Xie Zhenye.
+
+    *) Bugfix: zero status code was logged instead of 499 status code; the 
+       bug had appeared in 0.8.11.
+
+    *) Bugfix: socket leak; the bug had appeared in 0.8.11.
+
+
+Changes with nginx 0.8.17                                        28 Sep 2009
+
+    *) Security: now "/../" are disabled in "Destination" request header 
+       line.
+
+    *) Change: now $host variable value is always low case.
+
+    *) Feature: the $ssl_session_id variable.
+
+    *) Bugfix: socket leak; the bug had appeared in 0.8.11.
+
+
 Changes with nginx 0.8.16                                        22 Sep 2009
 
     *) Feature: the "image_filter_transparency" directive.
@@ -533,7 +1325,7 @@ Changes with nginx 0.7.44               
 
     *) Bugfix: the "try_files" directive might test incorrectly directories.
 
-    *) Bugfix: if there is the single server for given address:port pair, 
+    *) Bugfix: if there was a single server for given address:port pair, 
        then captures in regular expressions in a "server_name" directive 
        did not work.
 
@@ -887,7 +1679,7 @@ Changes with nginx 0.7.18               
     *) Bugfix: the "http_503" parameter of the "proxy_next_upstream" or 
        "fastcgi_next_upstream" directives did not work.
 
-    *) Bugfix: nginx might send a "Transfer-Encoding: chunked" heaer line 
+    *) Bugfix: nginx might send a "Transfer-Encoding: chunked" header line 
        for HEAD requests.
 
     *) Bugfix: now accept threshold depends on worker_connections.
@@ -4296,7 +5088,7 @@ Changes with nginx 0.1.11               
 Changes with nginx 0.1.10                                        26 Nov 2004
 
     *) Bugfix: if the request without arguments contains "//", "/./", 
-       "/../" or "%XX" then the lost character in the request line was 
+       "/../" or "%XX" then the last character in the request line was 
        lost; the bug had appeared in 0.1.9.
 
     *) Bugfix: the fix in 0.1.9 for the files bigger than 2G on Linux did 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,809 @@
 
+éÚÍÅÎÅÎÉÑ × nginx 1.0.0                                           12.04.2011
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: cache manager ÍÏÇ ÎÁÇÒÕÖÁÔØ ÐÒÏÃÅÓÓÏÒ ÐÏÓÌÅ 
+       ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á "image_filter crop" ÎÅÐÒÁ×ÉÌØÎÏ ÒÁÂÏÔÁÌÁ × 
+       ÓÏÞÅÔÁÎÉÉ Ó "image_filter rotate 180".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á "satisfy any" ÚÁÐÒÅÝÁÌÁ ×ÙÄÁÞÕ 
+       ÐÏÌØÚÏ×ÁÔÅÌØÓËÏÊ ÓÔÒÁÎÉÃÙ ÄÌÑ 401 ËÏÄÁ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.7                                           04.04.2011
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÓÏÅÄÉÎÅÎÉÑ × ÓÏÓÔÏÑÎÉÉ keepalive ÍÏÇÕÔ ÂÙÔØ 
+       ÚÁËÒÙÔÙ ÐÒÅÖÄÅ×ÒÅÍÅÎÎÏ, ÅÓÌÉ Õ ×ÏÒËÅÒÁ ÎÅÔ Ó×ÏÂÏÄÎÙÈ ÓÏÅÄÉÎÅÎÉÊ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ rotate ÄÉÒÅËÔÉ×Ù image_filter.
+       óÐÁÓÉÂÏ Adam Bocim.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÉÔÕÁÃÉÉ, ËÏÇÄÁ ÂÜËÅÎÄ × ÄÉÒÅËÔÉ×ÁÈ fastcgi_pass, 
+       scgi_pass ÉÌÉ uwsgi_pass ÚÁÄÁÎ ×ÙÒÁÖÅÎÉÅÍ É ÓÓÙÌÁÅÔÓÑ ÎÁ ÏÐÉÓÁÎÎÙÊ 
+       upstream.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.6                                           21.03.2011
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á map ÐÏÄÄÅÒÖÉ×ÁÅÔ ÒÅÇÕÌÑÒÎÙÅ ×ÙÒÁÖÅÎÉÑ × 
+       ËÁÞÅÓÔ×Å ÚÎÁÞÅÎÉÑ ÐÅÒ×ÏÇÏ ÐÁÒÁÍÅÔÒÁ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $time_iso8601 ÄÌÑ access_log.
+       óÐÁÓÉÂÏ Michael Lustfield.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.5                                           21.02.2011
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ nginx ÉÓÐÏÌØÚÕÅÔ ÚÎÁÞÅÎÉÅ -1 ÄÌÑ 
+       listen backlog ÎÁ Linux.
+       óÐÁÓÉÂÏ áÎÄÒÅÀ îÉÇÍÁÔÕÌÉÎÕ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ utf8 × ÄÉÒÅËÔÉ×ÁÈ geoip_country É 
+       geoip_city.
+       óÐÁÓÉÂÏ äÅÎÉÓÕ ìÁÔÙÐÏ×Õ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÉÓÐÒÁ×ÌÅÎÉÅ × ÕÍÏÌÞÁÔÅÌØÎÏÊ ÄÉÒÅËÔÉ×Å proxy_redirect, 
+       ÅÓÌÉ × ÄÉÒÅËÔÉ×Å proxy_pass ÎÅ ÂÙÌ ÏÐÉÓÁÎ URI.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á error_page ÎÅ ÒÁÂÏÔÁÌÁ Ó ÎÅÓÔÁÎÄÁÒÔÎÙÍÉ 
+       ËÏÄÁÍÉ ÏÛÉÂÏË; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.53.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.4                                           21.01.2011
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á server_name ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÅÒÅÍÅÎÎÕÀ $hostname.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: 494 ËÏÄ ÄÌÑ ÏÛÉÂËÉ "Request Header Too Large".
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.3                                           13.12.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÄÌÑ ÐÁÒÙ IPv6-ÁÄÒÅÓ:ÐÏÒÔ ÏÐÉÓÁÎ ÔÏÌØËÏ ÏÄÉÎ 
+       ÓÅÒ×ÅÒ, ÔÏ ×ÙÄÅÌÅÎÉÑ × ÒÅÇÕÌÑÒÎÙÈ ×ÙÒÁÖÅÎÉÑÈ × ÄÉÒÅËÔÉ×Å server_name 
+       ÎÅ ÒÁÂÏÔÁÌÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÐÏÄ Solaris; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.9.0.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.2                                           06.12.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ ÓÔÒÏËÉ "If-Unmodified-Since" × ÚÁÇÏÌÏ×ËÅ 
+       ÚÁÐÒÏÓÅ ËÌÉÅÎÔÁ.
+
+    *) éÚÍÅÎÅÎÉÅ: ÉÓÐÏÌØÚÏ×ÁÎÉÅ accept(), ÅÓÌÉ accept4() ÎÅ ÒÅÁÌÉÚÏ×ÁÎ; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.9.0.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÐÏÄ Cygwin; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.9.0.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÑÚ×ÉÍÏÓÔÉ × OpenSSL CVE-2010-4180.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.1                                           30.11.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù ×ÉÄÁ "return CODE message" ÎÅ ÒÁÂÏÔÁÌÉ; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.9.0.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.9.0                                           29.11.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á keepalive_disable.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á map ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÅÒÅÍÅÎÎÙÅ × ËÁÞÅÓÔ×Å 
+       ÚÎÁÞÅÎÉÑ ÏÐÒÅÄÅÌÑÅÍÏÊ ÐÅÒÅÍÅÎÎÏÊ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á map ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÕÓÔÙÅ ÓÔÒÏËÉ × ËÁÞÅÓÔ×Å 
+       ÚÎÁÞÅÎÉÑ ÐÅÒ×ÏÇÏ ÐÁÒÁÍÅÔÒÁ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á map ÐÏÄÄÅÒÖÉ×ÁÅÔ ×ÙÒÁÖÅÎÉÑ × ÐÅÒ×ÏÍ ÐÁÒÁÍÅÔÒÅ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÓÔÒÁÎÉÃÁ ÒÕËÏ×ÏÄÓÔ×Á nginx(8).
+       óÐÁÓÉÂÏ óÅÒÇÅÀ ïÓÏËÉÎÕ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ accept4() × Linux.
+       óÐÁÓÉÂÏ Simon Liu.
+
+    *) éÚÍÅÎÅÎÉÅ: ÕÓÔÒÁÎÅÎÉÅ ÐÒÅÄÕÐÒÅÖÄÅÎÉÑ ÌÉÎËÅÒÁ Ï "sys_errlist" É 
+       "sys_nerr" ÐÏÄ Linux; ÐÒÅÄÕÐÒÅÖÄÅÎÉÅ ÐÏÑ×ÉÌÏÓØ × 0.8.35.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù auth_basic × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault.
+       óÐÁÓÉÂÏ íÉÈÁÉÌÕ ìÁÌÅÔÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏ×ÍÅÓÔÉÍÏÓÔØ Ó ÍÏÄÕÌÅÍ ngx_http_eval_module; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.42.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.53                                          18.10.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á error_page ÐÏÚ×ÏÌÑÅÔ ÍÅÎÑÔØ ËÏÄ ÓÔÁÔÕÓÁ 
+       Õ ÒÅÄÉÒÅËÔÁ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á gzip_disable ÐÏÄÄÅÒÖÉ×ÁÅÔ ÓÐÅÃÉÁÌØÎÕÀ ÍÁÓËÕ 
+       degradation.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÆÁÊÌÏ×ÏÇÏ AIO ÍÏÇÌÁ ÐÒÏÉÓÈÏÄÉÔØ 
+       ÕÔÅÞËÁ ÓÏËÅÔÏ×.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ × ÐÅÒ×ÏÍ ÓÅÒ×ÅÒÅ ÎÅ ÂÙÌÁ ÏÐÉÓÁÎÁ ÄÉÒÅËÔÉ×Á listen 
+       É ÎÉÇÄÅ Ñ×ÎÏ ÎÅ ÏÐÉÓÁÎ ÓÅÒ×ÅÒ ÐÏ ÕÍÏÌÞÁÎÉÀ, ÔÏ ÓÅÒ×ÅÒÏÍ ÐÏ ÕÍÏÌÞÁÎÉÀ 
+       ÓÔÁÎÏ×ÉÌÓÑ ÓÌÅÄÕÀÝÉÊ ÓÅÒ×ÅÒ Ó ÄÉÒÅËÔÉ×ÏÊ listen; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.8.21.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.52                                          28.09.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÉÓÐÏÌØÚÏ×ÁÌ ÒÅÖÉÍ SSL ÄÌÑ listen ÓÏËÅÔÁ, ÅÓÌÉ ÄÌÑ 
+       ÎÅÇÏ ÂÙÌ ÕÓÔÁÎÏ×ÌÅÎ ÌÀÂÏÊ listen-ÐÁÒÁÍÅÔÒ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.51.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.51                                          27.09.2010
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á secure_link_expires ÕÐÒÁÚÄÎÅÎÁ.
+
+    *) éÚÍÅÎÅÎÉÅ: ÕÒÏ×ÅÎØ ÌÏÇÇÉÒÏ×ÁÎÉÑ ÏÛÉÂÏË resolver'Á ÐÏÎÉÖÅÎ Ó ÕÒÏ×ÎÑ 
+       alert ÎÁ error.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÁÒÁÍÅÔÒ "ssl" listen-ÓÏËÅÔÁ ÍÏÖÎÏ ÕÓÔÁÎÁ×ÌÉ×ÁÔØ 
+       ÎÅÓËÏÌØËÏ ÒÁÚ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.50                                          02.09.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù secure_link, secure_link_md5 É 
+       secure_link_expires ÍÏÄÕÌÑ ngx_http_secure_link_module.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ËÌÀÞ -q.
+       óÐÁÓÉÂÏ çÅÎÎÁÄÉÀ íÁÈÏÍÅÄÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ËÜÛÉÒÏ×ÁÎÉÑ ÒÁÂÏÞÉÅ ÐÒÏÃÅÓÓÙ É ÍÏÇÌÉ 
+       ÚÁÃÉËÌÉÔØÓÑ ×Ï ×ÒÅÍÑ ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.48.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÄÉÒÅËÔÉ×Å gzip_disable.
+       óÐÁÓÉÂÏ Derrick Petzold.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÎÅ ÍÏÇ ÐÏÓÙÌÁÔØ ÓÉÇÎÁÌÙ stop, quit, 
+       reopen, reload ÐÒÏÃÅÓÓÕ, ÚÁÐÕÝÅÎÎÏÍÕ × ÄÒÕÇÏÊ ÓÅÓÓÉÉ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.49                                          09.08.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á image_filter_jpeg_quality ÐÏÄÄÅÒÖÉ×ÁÅÔ 
+       ÐÅÒÅÍÅÎÎÙÅ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÏÊ $geoip_region_name × 
+       ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.8.48.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ, ÐÅÒÅÈ×ÁÞÅÎÎÙÅ error_page, ËÜÛÉÒÏ×ÁÌÉÓØ ÔÏÌØËÏ 
+       ÄÏ ÓÌÅÄÕÀÝÅÇÏ ÚÁÐÒÏÓÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.48.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.48                                          03.08.2010
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÉÒÅËÔÉ×Á server_name ÉÍÅÅÔ ÚÎÁÞÅÎÉÅ 
+       ÐÕÓÔÏÅ ÉÍÑ "".
+       óÐÁÓÉÂÏ çÅÎÎÁÄÉÀ íÁÈÏÍÅÄÕ.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÉÒÅËÔÉ×Á server_name_in_redirect 
+       ÉÍÅÅÔ ÚÎÁÞÅÎÉÅ off.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÙÅ $geoip_dma_code, $geoip_area_code É 
+       $geoip_region_name.
+       óÐÁÓÉÂÏ Christine McGonagle.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_pass, fastcgi_pass, uwsgi_pass É 
+       scgi_pass ÎÅ ÎÁÓÌÅÄÏ×ÁÌÉÓØ × ÂÌÏËÉ limit_except.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_cache_min_uses, fastcgi_cache_min_uses 
+       uwsgi_cache_min_uses É scgi_cache_min_uses ÎÅ ÒÁÂÏÔÁÌÉ; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.46.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á fastcgi_split_path_info ÎÅ×ÅÒÎÏ ÉÓÐÏÌØÚÏ×ÁÌÁ 
+       ×ÙÄÅÌÅÎÉÑ, ÅÓÌÉ × ×ÙÄÅÌÅÎÉÑ ÐÏÐÁÄÁÌÁ ÔÏÌØËÏ ÞÁÓÔØ URI.
+       óÐÁÓÉÂÏ àÒÉÀ ôÁÒÁÄÁÀ É Frank Enderle.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á rewrite ÎÅ ÜËÒÁÎÉÒÏ×ÁÌÁ ÓÉÍ×ÏÌ ";" ÐÒÉ 
+       ËÏÐÉÒÏ×ÁÎÉÉ ÉÚ URI × ÁÒÇÕÍÅÎÔÙ. 
+       óÐÁÓÉÂÏ Daisuke Murase.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_image_filter_module ÚÁËÒÙ×ÁÌ 
+       ÓÏÅÄÉÎÅÎÉÅ, ÅÓÌÉ ÉÚÏÂÒÁÖÅÎÉÅ ÂÙÌÏ ÂÏÌØÛÅ ÒÁÚÍÅÒÁ image_filter_buffer.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.47                                          28.07.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $request_time ÉÍÅÌÁ ÎÅ×ÅÒÎÙÅ ÚÎÁÞÅÎÉÑ ÄÌÑ 
+       ÐÏÄÚÁÐÒÏÓÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ, ÐÅÒÅÈ×ÁÞÅÎÎÙÅ error_page, ÎÅ ËÜÛÉÒÏ×ÁÌÉÓØ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÐÁÒÁÍÅÔÒ max_size, ÔÏ cache manager 
+       ÍÏÇ ÚÁÃÉËÌÉÔØÓÑ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.46.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.46                                          19.07.2010
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_no_cache, fastcgi_no_cache, 
+       uwsgi_no_cache É scgi_no_cache ÔÅÐÅÒØ ×ÌÉÑÀÔ ÔÏÌØËÏ ÎÁ ÓÏÈÒÁÎÅÎÉÅ 
+       ÚÁËÜÛÉÒÏ×ÁÎÎÏÇÏ ÏÔ×ÅÔÁ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_cache_bypass, fastcgi_cache_bypass, 
+       uwsgi_cache_bypass É scgi_cache_bypass.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÏÓ×ÏÂÏÖÄÁÌ ÐÁÍÑÔØ × keys_zone ËÜÛÅÊ × ÓÌÕÞÁÅ 
+       ÏÛÉÂËÉ ÒÁÂÏÔÙ Ó ÂÜËÅÎÄÏÍ: ÐÁÍÑÔØ ÏÓ×ÏÂÏÖÄÁÌÁÓØ ÔÏÌØËÏ ÐÏ ÉÓÔÅÞÅÎÉÉ 
+       ×ÒÅÍÅÎÉ ÎÅÁËÔÉ×ÎÏÓÔÉ ÉÌÉ ÐÒÉ ÎÅÄÏÓÔÁÔËÅ ÐÁÍÑÔÉ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.45                                          13.07.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÕÌÕÞÛÅÎÉÑ × ÍÏÄÕÌÅ ngx_http_xslt_filter.
+       óÐÁÓÉÂÏ Laurence Rowe.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÔ×ÅÔ SSI ÍÏÄÕÌÑ ÍÏÇ ÐÅÒÅÄÁ×ÁÔØÓÑ ÎÅ ÐÏÌÎÏÓÔØÀ ÐÏÓÌÅ 
+       ËÏÍÁÎÄÙ include Ó ÐÁÒÁÍÅÔÒÏÍ wait="yes"; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.25. 
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á listen ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌÁ ÐÁÒÁÍÅÔÒ setfib=0.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.44                                          05.07.2010
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ nginx ÐÏ ÕÍÏÌÞÁÎÉÀ ÎÅ ËÜÛÉÒÕÅÔ ÏÔ×ÅÔÙ ÂÜËÅÎÄÏ×, × 
+       ÚÁÇÏÌÏ×ËÅ ËÏÔÏÒÙÈ ÅÓÔØ ÓÔÒÏËÁ "Set-Cookie".
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á listen ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÁÒÁÍÅÔÒ setfib.
+       óÐÁÓÉÂÏ áÎÄÒÅÀ æÉÌÏÎÏ×Õ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á sub_filter ÍÏÇÌÁ ÉÚÍÅÎÑÔØ ÒÅÇÉÓÔÒ ÂÕË× ÐÒÉ 
+       ÞÁÓÔÉÞÎÏÍ ÓÏ×ÐÁÄÅÎÉÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏ×ÍÅÓÔÉÍÏÓÔØ Ó HP/UX.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏ×ÍÅÓÔÉÍÏÓÔØ Ó ËÏÍÐÉÌÑÔÏÒÏÍ AIX xlC_r.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÓÞÉÔÁÌ ÂÏÌØÛÉÅ ÐÁËÅÔÙ SSLv2 ËÁË ÏÂÙÞÎÙÅ ÔÅËÓÔÏ×ÙÅ 
+       ÚÁÐÒÏÓÙ.
+       óÐÁÓÉÂÏ Miroslaw Jaworski.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.43                                          30.06.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÕÓËÏÒÅÎÉÅ ÚÁÇÒÕÚËÉ ÂÏÌØÛÉÈ ÂÁÚ geo-ÄÉÁÐÁÚÏÎÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÅ ÏÛÉÂËÉ × "location /zero {return 204;}" 
+       ÂÅÚ ÉÚÍÅÎÅÎÉÑ ËÏÄÁ ÏÔ×ÅÔÁ ÏÓÔÁ×ÌÑÌÏ ÔÅÌÏ ÏÛÉÂËÉ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.8.42.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÍÏÇ ÚÁËÒÙ×ÁÔØ IPv6 listen ÓÏËÅÔ ×Ï ×ÒÅÍÑ 
+       ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÕÀ $uid_set ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÎÁ ÌÀÂÏÊ ÓÔÁÄÉÉ 
+       ÏÂÒÁÂÏÔËÉ ÚÁÐÒÏÓÁ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.42                                          21.06.2010
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ nginx ÐÒÏ×ÅÒÑÅÔ location'Ù, ÚÁÄÁÎÎÙÅ ÒÅÇÕÌÑÒÎÙÍÉ 
+       ×ÙÒÁÖÅÎÉÑÍÉ, ÅÓÌÉ ÚÁÐÒÏÓ ÐÏÌÎÏÓÔØÀ ÓÏ×ÐÁÌ Ó location'ÏÍ, ÚÁÄÁÎÎÙÍ 
+       ÓÔÒÏËÏÊ ÐÒÅÆÉËÓÁ. ðÒÅÄÙÄÕÝÅÅ ÐÏ×ÅÄÅÎÉÅ ÐÏÑ×ÉÌÏÓØ × 0.7.1.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_scgi_module.
+       óÐÁÓÉÂÏ Manlio Perillo.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: × ÄÉÒÅËÔÉ×Å return ÍÏÖÎÏ ÄÏÂÁ×ÌÑÔØ ÔÅËÓÔ ÏÔ×ÅÔÁ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.41                                          15.06.2010
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÒÁÂÏÞÉÊ ÐÒÏÃÅÓÓ nginx/Windows ÍÏÇ ÚÁ×ÅÒÛÁÔØÓÑ Á×ÁÒÉÊÎÏ 
+       ÐÒÉ ÚÁÐÒÏÓÅ ÆÁÊÌÁ Ó ÎÅ×ÅÒÎÏÊ ËÏÄÉÒÏ×ËÏÊ UTF-8.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ nginx ÒÁÚÒÅÛÁÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÐÒÏÂÅÌÙ × ÓÔÒÏËÅ 
+       ÚÁÐÒÏÓÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_redirect ÎÅÐÒÁ×ÉÌØÎÏ ÉÚÍÅÎÑÌÁ ÓÔÒÏËÕ 
+       "Refresh" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ.
+       óÐÁÓÉÂÏ áÎÄÒÅÀ áÎÄÒÅÅ×Õ É íÁËÓÉÍÕ óÏÇÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ÐÕÔØ ÂÅÚ ÉÍÅÎÉ ÈÏÓÔÁ × ÓÔÒÏËÅ 
+       "Destination" × ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.40                                          07.06.2010
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÔÅÐÅÒØ nginx/Windows ÉÇÎÏÒÉÒÕÅÔ ÉÍÑ ÐÏÔÏËÁ ÆÁÊÌÁ ÐÏ 
+       ÕÍÏÌÞÁÎÉÀ.
+       óÐÁÓÉÂÏ Jose Antonio Vazquez Gonzalez.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_uwsgi_module.
+       óÐÁÓÉÂÏ Roberto De Ioris.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á fastcgi_param ÓÏ ÚÎÁÞÅÎÉÅÍ, ÎÁÞÉÎÁÀÝÉÍÓÑ ÓÏ 
+       ÓÔÒÏËÉ "HTTP_", ÉÚÍÅÎÑÅÔ ÓÔÒÏËÕ ÚÁÇÏÌÏ×ËÁ × ÚÁÐÒÏÓÅ ËÌÉÅÎÔÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÔÒÏËÉ "If-Modified-Since", "If-Range" É ÉÍ ÐÏÄÏÂÎÙÅ × 
+       ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ ËÌÉÅÎÔÁ ÐÅÒÅÄÁ×ÁÌÉÓØ FastCGI-ÓÅÒ×ÅÒÕ ÐÒÉ 
+       ËÜÛÉÒÏ×ÁÎÉÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: listen unix domain ÓÏËÅÔ ÎÅÌØÚÑ ÂÙÌÏ ÉÚÍÅÎÉÔØ ×Ï ×ÒÅÍÑ 
+       ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.39                                          31.05.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÎÁÓÌÅÄÕÅÍÁÑ ÄÉÒÅËÔÉ×Á alias ÎÅÐÒÁ×ÉÌØÎÏ ÒÁÂÏÔÁÌÁ ×Ï 
+       ×ÌÏÖÅÎÎÏÍ location'Å.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ËÏÍÂÉÎÁÃÉÉ ÄÉÒÅËÔÉ× alias Ó ÐÅÒÅÍÅÎÎÙÍÉ É try_files;
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: listen unix domain É IPv6 ÓÏËÅÔÙ ÎÅ ÎÁÓÌÅÄÏ×ÁÌÉÓØ ×Ï 
+       ×ÒÅÍÑ ÏÂÎÏ×ÌÅÎÉÑ ÂÅÚ ÐÅÒÅÒÙ×Á.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.38                                          24.05.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_no_cache É fastcgi_no_cache.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÏÊ $scheme × ÄÉÒÅËÔÉ×Å 
+       rewrite Á×ÔÏÍÁÔÉÞÅÓËÉ ÄÅÌÁÅÔÓÑ ÒÅÄÉÒÅËÔ.
+       óÐÁÓÉÂÏ Piotr Sikora.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÚÁÄÅÒÖËÉ × ÄÉÒÅËÔÉ×Å limit_req ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ 
+       ÏÐÉÓÁÎÎÏÍÕ ÁÌÇÏÒÉÔÍÕ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÕÀ $uid_got ÎÅÌØÚÑ ÂÙÌÏ ÉÓÐÏÌØÚÏ×ÁÔØ × SSI É 
+       ÐÅÒÌÏ×ÏÍ ÍÏÄÕÌÑÈ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.37                                          17.05.2010
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_split_clients_module.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á map ÐÏÄÄÅÒÖÉ×ÁÅÔ ËÌÀÞÉ ÂÏÌØÛÅ 255 ÓÉÍ×ÏÌÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÉÇÎÏÒÉÒÏ×ÁÌ ÚÎÁÞÅÎÉÑ "private" É "no-store" × 
+       ÓÔÒÏËÅ "Cache-Control" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ stub × SSI-ÄÉÒÅËÔÉ×Å include ÎÅ ÉÓÐÏÌØÚÏ×ÁÌÓÑ, 
+       ÅÓÌÉ ÐÕÓÔÏÊ ÏÔ×ÅÔ ÉÍÅÌ ËÏÄ 200.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÐÒÏËÓÉÒÏ×ÁÎÎÙÊ ÉÌÉ FastCGI ÚÁÐÒÏÓ ×ÎÕÔÒÅÎÎÅ 
+       ÐÅÒÅÎÁÐÒÁ×ÌÑÌÓÑ × ÄÒÕÇÏÊ ÐÒÏËÓÉÒÏ×ÁÎÎÙÊ ÉÌÉ FastCGI location, ÔÏ × 
+       ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.8.33.
+       óÐÁÓÉÂÏ Yichun Zhang.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏÅÄÉÎÅÎÉÑ IMAP Ë ÓÅÒ×ÅÒÕ Zimbra ÍÏÇÌÏ ÚÁ×ÉÓÎÕÔØ ÄÏ 
+       ÔÁÊÍÁÕÔÁ.
+       óÐÁÓÉÂÏ Alan Batie.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.36                                          22.04.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_dav_module ÎÅÐÒÁ×ÉÌØÎÏ ÏÂÒÁÂÁÔÙ×ÁÌ 
+       ÍÅÔÏÄÙ DELETE, COPY É MOVE ÄÌÑ ÓÉÍÌÉÎËÏ×.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ SSI × ÐÏÄÚÁÐÒÏÓÁÈ ÉÓÐÏÌØÚÏ×ÁÌ ÚÁËÜÛÉÒÏ×ÁÎÎÙÅ × 
+       ÏÓÎÏ×ÎÏÍ ÚÁÐÒÏÓÅ ÚÎÁÞÅÎÉÑ ÐÅÒÅÍÅÎÎÙÈ $query_string, $arg_... É ÉÍ 
+       ÐÏÄÏÂÎÙÈ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ ÐÏ×ÔÏÒÎÏ ÜËÒÁÎÉÒÏ×ÁÌÏÓØ ÐÏÓÌÅ 
+       ËÁÖÄÏÇÏ ×Ù×ÏÄÁ SSI-ËÏÍÁÎÄÙ echo; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.14.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÁÂÏÞÉÊ ÐÒÏÃÅÓÓ ÚÁ×ÉÓÁÌ ÐÒÉ ÚÁÐÒÏÓÅ ÆÁÊÌÁ FIFO.
+       óÐÁÓÉÂÏ Vicente Aguilar É íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏ×ÍÅÓÔÉÍÏÓÔØ Ó OpenSSL-1.0.0 ÎÁ 64-ÂÉÔÎÏÍ Linux.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÐÁÒÁÍÅÔÒÏÍ --without-http-cache; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.35.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.35                                          01.04.2010
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ charset-ÆÉÌØÔÒ ÒÁÂÏÔÁÅÔ ÄÏ SSI-ÆÉÌØÔÒÁ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á chunked_transfer_encoding.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÉÍ×ÏÌ "&" ÐÒÉ ËÏÐÉÒÏ×ÁÎÉÉ × ÁÒÇÕÍÅÎÔÙ × ÐÒÁ×ÉÌÁÈ 
+       rewrite ÎÅ ÜËÒÁÎÉÒÏ×ÁÌÓÑ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÍÏÇ ÚÁ×ÅÒÛÁÔØÓÑ Á×ÁÒÉÊÎÏ ×Ï ×ÒÅÍÑ ÏÂÒÁÂÏÔËÉ 
+       ÓÉÇÎÁÌÁ ÉÌÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù timer_resolution ÎÁ 
+       ÐÌÁÔÆÏÒÍÁÈ, ÎÅ ÐÏÄÄÅÒÖÉ×ÁÀÝÉÈ ÍÅÔÏÄÙ kqueue ÉÌÉ eventport.
+       óÐÁÓÉÂÏ George Xie É íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ×ÒÅÍÅÎÎÙÅ ÆÁÊÌÙ É ÐÏÓÔÏÑÎÎÏÅ ÍÅÓÔÏ ÈÒÁÎÅÎÉÑ 
+       ÒÁÓÐÏÌÁÇÁÌÉÓØ ÎÁ ÒÁÚÎÙÈ ÆÁÊÌÏ×ÙÈ ÓÉÓÔÅÍÁÈ, ÔÏ Õ ÐÏÓÔÏÑÎÎÙÈ ÆÁÊÌÏ× 
+       ×ÒÅÍÑ ÉÚÍÅÎÅÎÉÑ ÂÙÌÏ ÎÅ×ÅÒÎÙÍ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_memcached_module ÍÏÇ ×ÙÄÁ×ÁÔØ ÏÛÉÂËÕ 
+       "memcached sent invalid trailer".
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÍÏÇ ÓÏÂÒÁÔØ ÂÉÂÌÉÏÔÅËÕ zlib-1.2.4 ÉÚ ÉÓÈÏÄÎÙÈ 
+       ÔÅËÓÔÏ×.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault, ÅÓÌÉ 
+       ÐÅÒÅÄ ÏÔ×ÅÔÏÍ FastCGI-ÓÅÒ×ÅÒÁ ÂÙÌÏ ÍÎÏÇÏ ×Ù×ÏÄÁ × stderr; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.34.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.34                                          03.03.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ×ÓÅ ÛÉÆÒÙ, ÉÓÐÏÌØÚÕÅÍÙÅ × 
+       ËÌÉÅÎÔÓËÉÈ ÓÅÒÔÉÆÉËÁÔÁÈ.
+       óÐÁÓÉÂÏ éÎÎÏËÅÎÔÉÀ åÎÉËÅÅ×Õ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅÐÒÁ×ÉÌØÎÏ ËÜÛÉÒÏ×ÁÌ FastCGI-ÏÔ×ÅÔÙ, ÅÓÌÉ ÐÅÒÅÄ 
+       ÏÔ×ÅÔÏÍ ÂÙÌÏ ÍÎÏÇÏ ×Ù×ÏÄÁ × stderr.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ HTTPS-ÒÅÆÅÒÅÒÙ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÍÏÇ ÎÅ ÎÁÈÏÄÉÔØ ÆÁÊÌÙ, ÅÓÌÉ ÐÕÔØ × 
+       ËÏÎÆÉÇÕÒÁÃÉÉ ÂÙÌ ÚÁÄÁÎ × ÄÒÕÇÏÍ ÒÅÇÉÓÔÒÅ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.33.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $date_local ×ÙÄÁ×ÁÌÁ ÎÅ×ÅÒÎÏÅ ×ÒÅÍÑ, ÅÓÌÉ 
+       ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÆÏÒÍÁÔ "%s".
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ssl_session_cache ÎÅ ÂÙÌ ÕÓÔÁÎÏ×ÌÅÎ ÉÌÉ ÕÓÔÁÎÏ×ÌÅÎ 
+       × none, ÔÏ ÐÒÉ ÐÒÏ×ÅÒËÅ ËÌÉÅÎÔÓËÏÇÏ ÓÅÒÔÉÆÉËÁÔÙ ÍÏÇÌÁ ÐÒÏÉÓÈÏÄÉÔØ 
+       ÏÛÉÂËÁ "session id context uninitialized"; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.1.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: geo-ÄÉÁÐÁÚÏÎ ×ÏÚ×ÒÁÝÁÌ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ, ÅÓÌÉ 
+       ÄÉÁÐÁÚÏÎ ×ËÌÀÞÁÌ × ÓÅÂÑ ÏÄÎÕ É ÂÏÌÅÅ ÓÅÔÅÊ ÒÁÚÍÅÒÏÍ /16 É ÎÅ 
+       ÎÁÞÉÎÁÌÓÑ ÎÁ ÇÒÁÎÉÃÅ ÓÅÔÉ ÒÁÚÍÅÒÏÍ /16.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÂÌÏË, ÉÓÐÏÌØÚÕÅÍÙÊ × ÐÁÒÁÍÅÔÒÅ stub × SSI-ÄÉÒÅËÔÉ×Å 
+       include, ×Ù×ÏÄÉÌÓÑ Ó MIME-ÔÉÐÏÍ "text/plain".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: $r->sleep() ÎÅ ÒÁÂÏÔÁÌ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.33                                          01.02.2010
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÔÅÐÅÒØ nginx/Windows ÉÇÎÏÒÉÒÕÅÔ ÐÒÏÂÅÌÙ × ËÏÎÃÅ URI. 
+       óÐÁÓÉÂÏ Dan Crowley, Core Security Technologies.
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÔÅÐÅÒØ nginx/Windows ÉÇÎÏÒÉÒÕÅÔ ËÏÒÏÔËÉÅ ÉÍÅÎÁ ÆÁÊÌÏ×. 
+       óÐÁÓÉÂÏ Dan Crowley, Core Security Technologies.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ keepalive ÓÏÅÄÉÎÅÎÉÑ ÐÏÓÌÅ ÚÁÐÒÏÓÏ× POST ÎÅ 
+       ÚÁÐÒÅÝÁÀÔÓÑ ÄÌÑ MSIE 7.0+.
+       óÐÁÓÉÂÏ Adam Lounds.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ keepalive ÓÏÅÄÉÎÅÎÉÑ ÚÁÐÒÅÝÅÎÙ ÄÌÑ Safari.
+       óÐÁÓÉÂÏ Joshua Sierles.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÐÒÏËÓÉÒÏ×ÁÎÎÙÊ ÉÌÉ FastCGI ÚÁÐÒÏÓ ×ÎÕÔÒÅÎÎÅ 
+       ÐÅÒÅÎÁÐÒÁ×ÌÑÌÓÑ × ÄÒÕÇÏÊ ÐÒÏËÓÉÒÏ×ÁÎÎÙÊ ÉÌÉ FastCGI location, ÔÏ 
+       ÐÅÒÅÍÅÎÎÁÑ $upstream_response_time ÍÏÇÌÁ ÉÍÅÔØ ÎÅÎÏÒÍÁÌØÎÏ ÂÏÌØÛÏÅ 
+       ÚÎÁÞÅÎÉÅ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.7.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault ÐÒÉ 
+       ÏÔÂÒÁÓÙ×ÁÎÉÑ ÔÅÌÁ ÚÁÐÒÏÓÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.32                                          11.01.2010
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ËÏÄÉÒÏ×ËÉ UTF-8 × 
+       ngx_http_autoindex_module.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÉÍÅÎÏ×ÁÎÎÙÅ ×ÙÄÅÌÅÎÉÑ × ÒÅÇÕÌÑÒÎÙÈ ×ÙÒÁÖÅÎÉÑÈ ÒÁÂÏÔÁÌÉ 
+       ÔÏÌØËÏ ÄÌÑ Ä×ÕÈ ÐÅÒÅÍÅÎÎÙÈ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ × ÓÔÒÏËÅ ÚÁÇÏÌÏ×ËÁ ÚÁÐÒÏÓÁ "Host" ÉÓÐÏÌØÚÕÅÔÓÑ 
+       ÉÍÑ "localhost", ÅÓÌÉ × ÄÉÒÅËÔÉ×Å auth_http ÕËÁÚÁÎ unix domain 
+       ÓÏËÅÔ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ÐÅÒÅÄÁÞÕ chunk'ÁÍÉ ÄÌÑ 201-ÙÈ 
+       ÏÔ×ÅÔÏ×.
+       óÐÁÓÉÂÏ Julian Reich.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÄÉÒÅËÔÉ×Á "expires modified" ×ÙÓÔÁ×ÌÑÌÁ ÄÁÔÕ × 
+       ÐÒÏÛÌÏÍ, ÔÏ × ÓÔÒÏËÅ ÚÁÇÏÌÏ×ËÁ ÏÔ×ÅÔÁ "Cache-Control" ×ÙÄÁ×ÁÌÏÓØ 
+       ÏÔÒÉÃÁÔÅÌØÎÏÅ ÞÉÓÌÏ.
+       óÐÁÓÉÂÏ áÌÅËÓÅÀ ëÁÐÒÁÎÏ×Õ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.31                                          23.12.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á error_page ÍÏÖÅÔ ÐÅÒÅÎÁÐÒÁ×ÌÑÔØ ÏÔ×ÅÔÙ 
+       ÓÏ ÓÔÁÔÕÓÏÍ 301 É 302.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÙÅ $geoip_city_continent_code, $geoip_latitude É 
+       $geoip_longitude.
+       óÐÁÓÉÂÏ Arvind Sundararajan.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_image_filter_module ÔÅÐÅÒØ ×ÓÅÇÄÁ 
+       ÕÄÁÌÑÅÔ EXIF É ÄÒÕÇÉÅ ÄÁÎÎÙÅ, ÅÓÌÉ ÏÎÉ ÚÁÎÉÍÁÀÔ ÂÏÌØÛÅ 5% × 
+       JPEG-ÆÁÊÌÅ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÚÁËÒÙ×ÁÌ ÓÏÅÄÉÎÅÎÉÅ ÐÒÉ ÚÁÐÒÏÓÅ ÚÁËÜÛÉÒÏ×ÁÎÎÏÇÏ 
+       ÏÔ×ÅÔÁ Ó ÐÕÓÔÙÍ ÔÅÌÏÍ.
+       óÐÁÓÉÂÏ Piotr Sikora.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÍÏÇ ÎÅ ÓÏÂÉÒÁÔØÓÑ gcc 4.x ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ 
+       ÏÐÔÉÍÉÚÁÃÉÉ -O2 É ×ÙÛÅ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ É äÅÎÉÓÕ ìÁÔÙÐÏ×Õ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÅÇÕÌÑÒÎÙÅ ×ÙÒÁÖÅÎÉÑ × location ×ÓÅÇÄÁ ÔÅÓÔÉÒÏ×ÁÌÉÓØ Ó 
+       ÕÞ£ÔÏÍ ÒÅÇÉÓÔÒÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.25.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ËÜÛÉÒÏ×ÁÌ 304 ÏÔ×ÅÔ, ÅÓÌÉ × ÚÁÇÏÌÏ×ËÅ 
+       ÐÒÏËÓÉÒÕÅÍÏÇÏ ÚÁÐÒÏÓÁ ÂÙÌÁ ÓÔÒÏËÁ "If-None-Match".
+       óÐÁÓÉÂÏ Tim Dettrick É David Kostal.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÐÙÔÁÌÓÑ Ä×ÁÖÄÙ ÕÄÁÌÉÔØ ×ÒÅÍÅÎÎÙÊ ÆÁÊÌ ÐÒÉ 
+       ÐÅÒÅÚÁÐÉÓÉ ÕÖÅ ÓÕÝÅÓÔ×ÕÀÝÅÇÏ ÆÁÊÌÁ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.30                                          15.12.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ÒÁÚÍÅÒ ÂÕÆÅÒÁ ÄÉÒÅËÔÉ×Ù 
+       large_client_header_buffers ÒÁ×ÅÎ 8K.
+       óÐÁÓÉÂÏ Andrew Cholakian.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÆÁÊÌ conf/fastcgi.conf ÄÌÑ ÐÒÏÓÔÙÈ ËÏÎÆÉÇÕÒÁÃÉÊ FastCGI.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÐÙÔÁÌÓÑ Ä×ÁÖÄÙ ÐÅÒÅÉÍÅÎÏ×ÁÔØ ×ÒÅÍÅÎÎÙÊ 
+       ÆÁÊÌ ÐÒÉ ÐÅÒÅÚÁÐÉÓÉ ÕÖÅ ÓÕÝÅÓÔ×ÕÀÝÅÇÏ ÆÁÊÌÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ double free or corruption, ×ÏÚÎÉËÁÀÝÅÊ, ÅÓÌÉ ÉÍÑ 
+       ÈÏÓÔÁ ÎÅ ÂÙÌÏ ÎÁÊÄÅÎÏ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.22.
+       óÐÁÓÉÂÏ ëÏÎÓÔÁÎÔÉÎÕ ó×ÉÓÔÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÉÓÐÏÌØÚÏ×ÁÎÉÉ libatomic ÎÁ ÎÅËÏÔÏÒÙÈ ÐÌÁÔÆÏÒÍÁÈ.
+       óÐÁÓÉÂÏ W-Mark Kubacki.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.29                                          30.11.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÄÌÑ ÐÒÏËÓÉÒÕÅÍÙÈ ÏÔ×ÅÔÏ× HTTP/0.9 × ÌÏÇ ÐÉÛÅÔÓÑ 
+       ËÏÄ ÏÔ×ÅÔÁ "009".
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù addition_types, charset_types, gzip_types, 
+       ssi_types, sub_filter_types É xslt_types ÐÏÄÄÅÒÖÉ×ÁÀÔ ÐÁÒÁÍÅÔÒ "*".
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÉÓÐÏÌØÚÏ×ÁÎÉÅ ×ÓÔÒÏÅÎÎÙÈ ÁÔÏÍÁÒÎÙÈ ÏÐÅÒÁÃÉÊ GCC 4.1+.
+       óÐÁÓÉÂÏ W-Mark Kubacki.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ --with-libatomic[=DIR] × configure.
+       óÐÁÓÉÂÏ W-Mark Kubacki.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: listen unix domain ÓÏËÅÔ ÉÍÅÌÉ ÏÇÒÁÎÉÞÅÎÎÙÅ ÐÒÁ×Á 
+       ÄÏÓÔÕÐÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÚÁËÜÛÉÒÏ×ÁÎÎÙÅ ÏÔ×ÅÔÙ ÏÔ×ÅÔÏ× HTTP/0.9 ÎÅÐÒÁ×ÉÌØÎÏ 
+       ÏÂÒÁÂÁÔÙ×ÁÌÉÓØ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÉÍÅÎÏ×ÁÎÎÙÅ ×ÙÄÅÌÅÎÉÑ × ÒÅÇÕÌÑÒÎÙÈ ×ÙÒÁÖÅÎÉÑÈ, ÚÁÄÁÎÎÙÅ 
+       ËÁË "?P<...>", ÎÅ ÒÁÂÏÔÁÌÉ × ÄÉÒÅËÔÉ×Å server_name.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.28                                          23.11.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÐÁÒÁÍÅÔÒÏÍ --without-pcre; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.25.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.27                                          17.11.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÅÇÕÌÑÒÎÙÅ ×ÙÒÁÖÅÎÉÑ ÎÅ ÒÁÂÏÔÁÌÉ × nginx/Windows; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.25.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.26                                          16.11.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ×ÙÄÅÌÅÎÉÊ × ÄÉÒÅËÔÉ×Å rewrite; 
+       ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.25.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÂÅÚ ÐÁÒÁÍÅÔÒÁ --with-debug; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.25.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.25                                          16.11.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ × ÌÏÇ ÏÛÉÂÏË ÎÅ ÐÉÛÅÔÓÑ ÓÏÏÂÝÅÎÉÅ, ÅÓÌÉ ÐÅÒÅÍÅÎÎÁÑ 
+       ÎÅ ÎÁÊÄÅÎÁ Ó ÐÏÍÏÝØÀ ÍÅÔÏÄÁ $r->variable().
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_degradation_module.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÉÍÅÎÏ×ÁÎÎÙÅ ×ÙÄÅÌÅÎÉÑ × ÒÅÇÕÌÑÒÎÙÈ ×ÙÒÁÖÅÎÉÑÈ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÙÈ × ÄÉÒÅËÔÉ×Å 
+       proxy_pass ÎÅ ÔÒÅÂÕÅÔÓÑ ÚÁÄÁ×ÁÔØ URI.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á msie_padding ÒÁÂÏÔÁÅÔ É ÄÌÑ Chrome.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault ÐÒÉ 
+       ÎÅÄÏÓÔÁÔËÅ ÐÁÍÑÔÉ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.18.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÐÅÒÅÄÁ×ÁÌ ÓÖÁÔÙÅ ÏÔ×ÅÔÙ ËÌÉÅÎÔÁÍ, ÎÅ 
+       ÐÏÄÄÅÒÖÉ×ÁÀÝÉÍ ÓÖÁÔÉÅ, ÐÒÉ ÎÁÓÔÒÏÊËÁÈ gzip_static on É gzip_vary 
+       off; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.16.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.24                                          11.11.2009
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ×ÓÅÇÄÁ ÄÏÂÁ×ÌÑÌ ÓÔÒÏËÕ "Content-Encoding: gzip" × 
+       ÚÁÇÏÌÏ×ÏË 304-ÙÈ ÏÔ×ÅÔÏ× ÍÏÄÕÌÑ ngx_http_gzip_static_module.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÂÅÚ ÐÁÒÁÍÅÔÒÁ --with-debug; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.23.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ "unix:" × ÄÉÒÅËÔÉ×Å set_real_ip_from 
+       ÎÅÐÒÁ×ÉÌØÎÏ ÎÁÓÌÅÄÏ×ÁÌÓÑ Ó ÐÒÅÄÙÄÕÝÅÇÏ ÕÒÏ×ÎÑ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × resolver'Å ÐÒÉ ÏÐÒÅÄÅÌÅÎÉÉ ÐÕÓÔÏÇÏ ÉÍÅÎÉ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.23                                          11.11.2009
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÔÅÐÅÒØ SSL/TLS renegotiation ÚÁÐÒÅÝ£Î.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: listen unix domain ÓÏËÅÔ ÎÅ ÎÁÓÌÅÄÏ×ÁÌÓÑ ×Ï ×ÒÅÍÑ 
+       ÏÂÎÏ×ÌÅÎÉÑ ÂÅÚ ÐÅÒÅÒÙ×Á.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ "unix:" × ÄÉÒÅËÔÉ×Å set_real_ip_from ÎÅ 
+       ÒÁÂÏÔÁÌ ÂÅÚ ÅÝ£ ÏÄÎÏÊ ÄÉÒÅËÔÉ×Ù Ó ÌÀÂÙÍ IP-ÁÄÒÅÓÏÍ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: segmentation fault É ÚÁÃÉËÌÉ×ÁÎÉÑ × resolver'Å.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × resolver'Å.
+       óÐÁÓÉÂÏ áÒÔ£ÍÕ âÏÈÁÎÕ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.22                                          03.11.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_bind, fastcgi_bind É memcached_bind.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù access É deny ÐÏÄÄÅÒÖÉ×ÁÀÔ IPv6.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á set_real_ip_from ÐÏÄÄÅÒÖÉ×ÁÅÔ IPv6 ÁÄÒÅÓÁ × 
+       ÚÁÇÏÌÏ×ËÁÈ ÚÁÐÒÏÓÁ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ "unix:" × ÄÉÒÅËÔÉ×Å set_real_ip_from.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÕÄÁÌÑÌ unix domain ÓÏËÅÔ ÐÏÓÌÅ ÔÅÓÔÉÒÏ×ÁÎÉÑ 
+       ËÏÎÆÉÇÕÒÁÃÉÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÕÄÁÌÑÌ unix domain ÓÏËÅÔ ×Ï ×ÒÅÍÑ ÏÂÎÏ×ÌÅÎÉÑ ÂÅÚ 
+       ÐÅÒÅÒÙ×Á.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÐÅÒÁÔÏÒ "!-x" ÎÅ ÒÁÂÏÔÁÌ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault ÐÒÉ 
+       ÉÓÐÏÌØÚÏ×ÁÎÉÉ limit_rate × HTTPS ÓÅÒ×ÅÒÅ.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÚÁÐÉÓÉ × ÌÏÇ ÐÅÒÅÍÅÎÎÏÊ $limit_rate × ÒÁÂÏÞÅÍ 
+       ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault, 
+       ÅÓÌÉ ×ÎÕÔÒÉ ÂÌÏËÁ server ÎÅ ÂÙÌÏ ÄÉÒÅËÔÉ×Ù listen; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ 
+       × 0.8.21.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.21                                          26.10.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ËÌÀÞ -V ÐÏËÁÚÙ×ÁÅÔ ÓÔÁÔÕÓ ÐÏÄÄÅÒÖËÉ TLS SNI.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á listen ÍÏÄÕÌÑ HTTP ÐÏÄÄÅÒÖÉ×ÁÅÔ unix domain 
+       ÓÏËÅÔÙ.
+       óÐÁÓÉÂÏ Hongli Lai.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ "default_server" × ÄÉÒÅËÔÉ×Å listen.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÁÒÁÍÅÔÒ "default" ÎÅ ÏÂÑÚÁÔÅÌÅÎ ÄÌÑ ÕÓÔÁÎÏ×ËÉ 
+       ÐÁÒÁÍÅÔÒÏ× listen-ÓÏËÅÔÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ÄÁÔÙ × 2038 ÇÏÄÕ ÎÁ 32-ÂÉÔÎÙÈ 
+       ÐÌÁÔÆÏÒÍÁÈ;
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ×; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.20                                          14.10.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ÉÓÐÏÌØÚÕÀÔÓÑ ÓÌÅÄÕÀÝÉÅ ÛÉÆÒÙ SSL: 
+       "HIGH:!ADH:!MD5".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_autoindex_module ÎÅ ÐÏËÁÚÙ×ÁÌ ÐÏÓÌÅÄÎÉÊ 
+       ÓÌÜÛ ÄÌÑ ÌÉÎËÏ× ÎÁ ËÁÔÁÌÏÇÉ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.15.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÚÁËÒÙ×ÁÌ ÌÏÇ, ÚÁÄÁÎÎÙÊ ÐÁÒÁÍÅÔÒÏÍ ËÏÎÆÉÇÕÒÁÃÉÉ 
+       --error-log-path; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.53.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÞÉÔÁÌ ÚÁÐÑÔÕÀ ÒÁÚÄÅÌÉÔÅÌÅÍ × ÓÔÒÏËÅ 
+       "Cache-Control" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÍÏÇ ÎÅ ÓÏÚÄÁÔØ ×ÒÅÍÅÎÎÙÊ ÆÁÊÌ, ÆÁÊÌ × 
+       ËÜÛÅ ÉÌÉ ÆÁÊÌ Ó ÐÏÍÏÝØÀ ÄÉÒÅËÔÉ× proxy/fastcgi_store, ÅÓÌÉ ÒÁÂÏÞÉÊ 
+       ÐÒÏÃÅÓÓ ÎÅ ÉÍÅÌ ÄÏÓÔÁÔÏÞÎÏ ÐÒÁ× ÄÌÑ ÒÁÂÏÔÙ Ó ËÁÔÁÌÏÇÁÍÉ ×ÅÒÈÎÅÇÏ 
+       ÕÒÏ×ÎÑ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÔÒÏËÉ "Set-Cookie" É "P3P" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ 
+       FastCGI-ÓÅÒ×ÅÒÁ ÎÅ ÓËÒÙ×ÁÌÉÓØ ÐÒÉ ËÜÛÉÒÏ×ÁÎÉÉ, ÅÓÌÉ ÎÅ 
+       ÉÓÐÏÌØÚÏ×ÁÌÉÓØ ÄÉÒÅËÔÉ×Ù fastcgi_hide_header Ó ÌÀÂÙÍÉ ÐÁÒÁÍÅÔÒÁÍÉ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ×ÅÒÎÏ ÓÞÉÔÁÌ ÒÁÚÍÅÒ ËÜÛÁ ÎÁ ÄÉÓËÅ.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.19                                          06.10.2009
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÒÏÔÏËÏÌ SSLv2 ÐÏ ÕÍÏÌÞÁÎÉÀ ÚÁÐÒÅÝ£Î.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ÉÓÐÏÌØÚÕÀÔÓÑ ÓÌÅÄÕÀÝÉÅ ÛÉÆÒÙ SSL: 
+       "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á limit_req ÎÅ ÒÁÂÏÔÁÌÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 
+       0.8.18.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.18                                          06.10.2009
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á read_ahead.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÎÅÓËÏÌØËÏ ÄÉÒÅËÔÉ× 
+       perl_modules.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù limit_req_log_level É limit_conn_log_level.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á limit_req ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÁÌÇÏÒÉÔÍÕ 
+       leaky bucket.
+       óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÒÁÂÏÔÁÌ ÎÁ Linux/sparc.
+       óÐÁÓÉÂÏ Marcus Ramberg.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÓÌÁÌ ÓÉÍ×ÏÌ '\0' × ÓÔÒÏËÅ "Location" × ÚÁÇÏÌÏ×ËÅ 
+       × ÏÔ×ÅÔÅ ÎÁ ÚÁÐÒÏÓ MKCOL.
+       óÐÁÓÉÂÏ Xie Zhenye.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ×ÍÅÓÔÏ ËÏÄÁ ÏÔ×ÅÔÁ 499 × ÌÏÇ ÚÁÐÉÓÙ×ÁÌÓÑ ËÏÄ 0; ÏÛÉÂËÁ 
+       ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ×; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+
+éÚÍÅÎÅÎÉÑ × nginx 0.8.17                                          28.09.2009
+
+    *) âÅÚÏÐÁÓÎÏÓÔØ: ÔÅÐÅÒØ ÓÉÍ×ÏÌÙ "/../" ÚÁÐÒÅÝÅÎÙ × ÓÔÒÏËÅ "Destination" 
+       × ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ $host ×ÓÅÇÄÁ × ÎÉÖÎÅÍ ÒÅÇÉÓÔÒÅ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $ssl_session_id.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ×; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.11.
+
+
 éÚÍÅÎÅÎÉÑ × nginx 0.8.16                                          22.09.2009
 
     *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á image_filter_transparency.
@@ -157,7 +962,7 @@
        óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: × ÏÂÒÁÂÏÔËÅ ÓÔÒÏË "Last-Modified" É "Accept-Ranges" × 
-       ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.44
+       ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.44.
        óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ "[alert] zero size buf" ÐÒÉ ÐÏÌÕÞÅÎÉÉ ÐÕÓÔÙÈ 
@@ -1336,7 +2141,7 @@
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ×ÅÒÎÏ ÏÐÒÅÄÅÌÑÌ ÄÌÉÎÕ ÓÔÒÏËÉ ËÜÛÁ ÎÁ 
        Pentium 4.
-       óÐÁÓÉÂÏ Gena Makhomed.
+       óÐÁÓÉÂÏ çÅÎÎÁÄÉÀ íÁÈÏÍÅÄÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÒÏËÓÉÒÏ×ÁÎÎÙÈ ÐÏÄÚÁÐÒÏÓÁÈ É ÐÏÄÚÁÐÒÏÓÁÈ Ë 
        FastCGI-ÓÅÒ×ÅÒÕ ×ÍÅÓÔÏ ÍÅÔÏÄÁ GET ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÏÒÉÇÉÎÁÌØÎÙÊ ÍÅÔÏÄ 
@@ -1604,7 +2409,7 @@
        óÐÁÓÉÂÏ áÎÄÒÅÀ îÉÇÍÁÔÕÌÉÎÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ngx_http_memcached_module ÎÅ ÕÓÔÁÎÁ×ÌÉ×ÁÌ 
-       upstream_response_time.
+       $upstream_response_time.
        óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÁÂÏÞÉÊ ÐÒÏÃÅÓÓ ÍÏÇ ÚÁÃÉËÌÉÔØÓÑ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ 
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2002-2009 Igor Sysoev
+ * Copyright (C) 2002-2011 Igor Sysoev
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/auto/cc/conf
+++ b/auto/cc/conf
@@ -104,7 +104,7 @@ else
 fi
 
 CFLAGS="$CFLAGS $NGX_CC_OPT"
-
+NGX_TEST_LD_OPT="$NGX_LD_OPT"
 
 if [ "$NGX_PLATFORM" != win32 ]; then
 
@@ -125,16 +125,21 @@ if [ "$NGX_PLATFORM" != win32 ]; then
         fi
     fi
 
-    ngx_feature="gcc variadic macros"
-    ngx_feature_name="NGX_HAVE_GCC_VARIADIC_MACROS"
+
+    ngx_feature="gcc builtin atomic operations"
+    ngx_feature_name=NGX_HAVE_GCC_ATOMIC
     ngx_feature_run=yes
-    ngx_feature_incs="#include <stdio.h>
-#define var(dummy, args...)  sprintf(args)"
+    ngx_feature_incs=
     ngx_feature_path=
     ngx_feature_libs=
-    ngx_feature_test="char  buf[30]; buf[0] = '0';
-                      var(0, buf, \"%d\", 1);
-                      if (buf[0] != '1') return 1"
+    ngx_feature_test="long  n = 0;
+                      if (!__sync_bool_compare_and_swap(&n, 0, 1))
+                          return 1;
+                      if (__sync_fetch_and_add(&n, 1) != 1)
+                          return 1;
+                      if (n != 2)
+                          return 1;
+                      __sync_synchronize();"
     . auto/feature
 
 
@@ -155,6 +160,19 @@ if [ "$NGX_PLATFORM" != win32 ]; then
      fi
 
 
+    ngx_feature="gcc variadic macros"
+    ngx_feature_name="NGX_HAVE_GCC_VARIADIC_MACROS"
+    ngx_feature_run=yes
+    ngx_feature_incs="#include <stdio.h>
+#define var(dummy, args...)  sprintf(args)"
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test="char  buf[30]; buf[0] = '0';
+                      var(0, buf, \"%d\", 1);
+                      if (buf[0] != '1') return 1"
+    . auto/feature
+
+
 #    ngx_feature="inline"
 #    ngx_feature_name=
 #    ngx_feature_run=no
--- a/auto/cc/gcc
+++ b/auto/cc/gcc
@@ -51,8 +51,6 @@ esac
 #NGX_GCC_OPT="-Os"
 NGX_GCC_OPT="-O"
 
-CFLAGS="$CFLAGS $NGX_GCC_OPT"
-
 #CFLAGS="$CFLAGS -fomit-frame-pointer"
 
 case $CPU in
@@ -90,7 +88,6 @@ case $CPU in
         # build 32-bit UltraSparc binary
         CPU_OPT="-m32"
         CORE_LINK="$CORE_LINK -m32"
-        CC_AUX_FLAGS="$CC_AUX_FLAGS -m32"
         NGX_CPU_CACHE_LINE=64
     ;;
 
@@ -98,7 +95,6 @@ case $CPU in
         # build 64-bit UltraSparc binary
         CPU_OPT="-m64"
         CORE_LINK="$CORE_LINK -m64"
-        CC_AUX_FLAGS="$CC_AUX_FLAGS -m64"
         NGX_CPU_CACHE_LINE=64
     ;;
 
@@ -108,12 +104,12 @@ case $CPU in
         CPU_OPT="$CPU_OPT -falign-functions=32 -falign-labels=32"
         CPU_OPT="$CPU_OPT -falign-loops=32 -falign-jumps=32"
         CORE_LINK="$CORE_LINK -m64"
-        CC_AUX_FLAGS="$CC_AUX_FLAGS -m64"
         NGX_CPU_CACHE_LINE=128
     ;;
 
 esac
 
+CC_AUX_FLAGS="$CC_AUX_FLAGS $CPU_OPT"
 
 case "$NGX_GCC_VER" in
     2.7*)
--- a/auto/feature
+++ b/auto/feature
@@ -39,7 +39,7 @@ END
 
 
 ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
-          -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
+          -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"
 
 ngx_feature_inc_path=
 
@@ -65,6 +65,24 @@ if [ -x $NGX_AUTOTEST ]; then
             fi
         ;;
 
+        value)
+            # /bin/sh is used to intercept "Killed" or "Abort trap" messages
+            if /bin/sh -c $NGX_AUTOTEST >/dev/null 2>&1; then
+                echo " found"
+                ngx_found=yes
+
+                cat << END >> $NGX_AUTO_CONFIG_H
+
+#ifndef $ngx_feature_name
+#define $ngx_feature_name  `$NGX_AUTOTEST`
+#endif
+
+END
+            else
+                echo " found but is not working"
+            fi
+        ;;
+
         bug)
             # /bin/sh is used to intercept "Killed" or "Abort trap" messages
             if /bin/sh -c $NGX_AUTOTEST >/dev/null 2>&1; then
--- a/auto/install
+++ b/auto/install
@@ -74,6 +74,13 @@ esac
 
 cat << END                                                    >> $NGX_MAKEFILE
 
+manpage:
+	sed -e "s|%%PREFIX%%|$NGX_PREFIX|" \\
+		-e "s|%%PID_PATH%%|$NGX_PID_PATH|" \\
+		-e "s|%%CONF_PATH%%|$NGX_CONF_PATH|" \\
+		-e "s|%%ERROR_LOG_PATH%%|$NGX_ERROR_LOG_PATH|" \\
+		< man/nginx.8 > $NGX_OBJS/nginx.8
+
 install:	$NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \
 		$NGX_INSTALL_PERL_MODULES
 	test -d '\$(DESTDIR)$NGX_PREFIX' || mkdir -p '\$(DESTDIR)$NGX_PREFIX'
@@ -101,6 +108,20 @@ install:	$NGX_OBJS${ngx_dirsep}nginx${ng
 	cp conf/fastcgi_params \
 		'\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default'
 
+	test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \
+		|| cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX'
+	cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default'
+
+	test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \
+		|| cp conf/uwsgi_params '\$(DESTDIR)$NGX_CONF_PREFIX'
+	cp conf/uwsgi_params \
+		'\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params.default'
+
+	test -f '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params' \
+		|| cp conf/scgi_params '\$(DESTDIR)$NGX_CONF_PREFIX'
+	cp conf/scgi_params \
+		'\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params.default'
+
 	test -f '\$(DESTDIR)$NGX_CONF_PATH' \
 		|| cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH'
 	cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default'
@@ -132,6 +153,7 @@ cat << END >> Makefile
 
 build:
 	\$(MAKE) -f $NGX_MAKEFILE
+	\$(MAKE) -f $NGX_MAKEFILE manpage
 
 install:
 	\$(MAKE) -f $NGX_MAKEFILE install
@@ -144,19 +166,4 @@ upgrade:
 	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
@@ -70,6 +70,11 @@ fi
 if [ $HTTP_GEOIP = YES ]; then
     . auto/lib/geoip/conf
 fi
+
 if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then
     . auto/lib/google-perftools/conf
 fi
+
+if [ $NGX_LIBATOMIC != NO ]; then
+    . auto/lib/libatomic/conf
+fi
new file mode 100644
--- /dev/null
+++ b/auto/lib/libatomic/conf
@@ -0,0 +1,42 @@
+
+# Copyright (C) Igor Sysoev
+
+
+if [ $NGX_LIBATOMIC != YES ]; then
+
+    have=NGX_HAVE_LIBATOMIC . auto/have
+    CORE_INCS="$CORE_INCS $NGX_LIBATOMIC/src"
+    LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/src/libatomic_ops.a"
+    CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/src/libatomic_ops.a"
+
+else
+
+    ngx_feature="atomic_ops library"
+    ngx_feature_name=NGX_HAVE_LIBATOMIC
+    ngx_feature_run=yes
+    ngx_feature_incs="#define AO_REQUIRE_CAS
+                      #include <atomic_ops.h>"
+    ngx_feature_path=
+    ngx_feature_libs="-latomic_ops"
+    ngx_feature_test="long  n = 0;
+                      if (!AO_compare_and_swap(&n, 0, 1))
+                          return 1;
+                      if (AO_fetch_and_add(&n, 1) != 1)
+                          return 1;
+                      if (n != 2)
+                          return 1;
+                      AO_nop();"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+    else
+
+cat << END
+
+$0: error: libatomic_ops library was not found.
+
+END
+        exit 1
+    fi
+fi
new file mode 100644
--- /dev/null
+++ b/auto/lib/libatomic/make
@@ -0,0 +1,13 @@
+
+# Copyright (C) Igor Sysoev
+
+
+    cat << END                                            >> $NGX_MAKEFILE
+
+$NGX_LIBATOMIC/src/libatomic_ops.a:	$NGX_LIBATOMIC/Makefile
+	cd $NGX_LIBATOMIC && make
+
+$NGX_LIBATOMIC/Makefile:	$NGX_MAKEFILE
+	cd $NGX_LIBATOMIC && ./configure
+
+END
--- a/auto/lib/make
+++ b/auto/lib/make
@@ -22,6 +22,10 @@ if [ $ZLIB != NONE -a $ZLIB != NO -a $ZL
     . auto/lib/zlib/make
 fi
 
+if [ $NGX_LIBATOMIC != NO -a $NGX_LIBATOMIC != YES ]; then
+    . auto/lib/libatomic/make
+fi
+
 if [ $USE_PERL = YES ]; then
     . auto/lib/perl/make
 fi
--- a/auto/lib/md5/conf
+++ b/auto/lib/md5/conf
@@ -94,8 +94,10 @@ else
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             MD5=YES
             MD5_LIB=$ngx_md5_lib
-        else
+        fi
+    fi
 
+    if [ $MD5 != YES ]; then
 cat << END
 
 $0: error: the HTTP cache module requires md5 functions
@@ -105,9 +107,7 @@ or build the OpenSSL library statically 
 --with-http_ssl_module --with-openssl=<path> options.
 
 END
-            exit 1
-        fi
-
+        exit 1
     fi
 
 fi
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -19,54 +19,45 @@ if [ $OPENSSL != NONE ]; then
 
             # libeay32.lib requires gdi32.lib
             CORE_LIBS="$CORE_LIBS gdi32.lib"
+            # OpenSSL 1.0.0 requires crypt32.lib
+            CORE_LIBS="$CORE_LIBS crypt32.lib"
         ;;
 
         *)
             have=NGX_OPENSSL . auto/have
             have=NGX_SSL . auto/have
 
-            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_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
 
 else
 
-    case "$NGX_PLATFORM" in
-
-        win32)
-            have=NGX_OPENSSL . auto/have
-            have=NGX_SSL . auto/have
-            OPENSSL=YES
+    if [ "$NGX_PLATFORM" != win32 ]; then
 
-            CORE_INCS="$CORE_INCS c:/openssl/include"
-            CORE_LIBS="$CORE_LIBS c:/openssl/ssleay32.lib"
-            CORE_LIBS="$CORE_LIBS c:/openssl/libeay32.lib"
-
-            # libeay32.lib requires gdi32.lib
-            CORE_LIBS="$CORE_LIBS gdi32.lib"
-        ;;
+        OPENSSL=NO
 
-        *)
-            OPENSSL=NO
+        ngx_feature="OpenSSL library"
+        ngx_feature_name="NGX_OPENSSL"
+        ngx_feature_run=no
+        ngx_feature_incs="#include <openssl/ssl.h>"
+        ngx_feature_path=
+        ngx_feature_libs="-lssl -lcrypto"
+        ngx_feature_test="SSL_library_init()"
+        . auto/feature
 
-            ngx_feature="OpenSSL library"
-            ngx_feature_name="NGX_OPENSSL"
-            ngx_feature_run=no
-            ngx_feature_incs="#include <openssl/ssl.h>"
-            ngx_feature_path=
-            ngx_feature_libs="-lssl -lcrypto"
-            ngx_feature_test="SSL_library_init()"
-            . auto/feature
+        if [ $ngx_found = yes ]; then
+            have=NGX_SSL . auto/have
+            CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL"
+            OPENSSL=YES
+        fi
+    fi
 
-            if [ $ngx_found = yes ]; then
-                have=NGX_SSL . auto/have
-                CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL"
-                OPENSSL=YES
-            else
+    if [ $OPENSSL != YES ]; then
 
 cat << END
 
@@ -76,10 +67,7 @@ into the system, or build the OpenSSL li
 with nginx by using --with-openssl=<path> option.
 
 END
-                exit 1
-            fi
-        ;;
-
-    esac
+        exit 1
+    fi
 
 fi
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -46,18 +46,18 @@ END
         esac
 
         case $OPENSSL in
-            /*) ngx_prefix="$OPENSSL/openssl" ;;
-            *)  ngx_prefix="$PWD/$OPENSSL/openssl" ;;
+            /*) ngx_prefix="$OPENSSL/.openssl" ;;
+            *)  ngx_prefix="$PWD/$OPENSSL/.openssl" ;;
         esac
 
         cat << END                                            >> $NGX_MAKEFILE
 
-$OPENSSL/openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
+$OPENSSL/.openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
 	cd $OPENSSL \\
 	&& \$(MAKE) clean \\
 	&& ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\
 	&& \$(MAKE) \\
-	&& \$(MAKE) install
+	&& \$(MAKE) install LIBDIR=lib
 
 END
 
--- a/auto/lib/openssl/makefile.bcc
+++ b/auto/lib/openssl/makefile.bcc
@@ -5,8 +5,7 @@
 all:
 	cd $(OPENSSL)
 
-	perl Configure BC-32 no-shared --prefix=openssl -DNO_SYS_TYPES_H \
-		$(OPENSSL_OPT)
+	perl Configure BC-32 no-shared --prefix=openssl $(OPENSSL_OPT)
 
 	ms\do_nasm
 
--- a/auto/lib/openssl/makefile.msvc
+++ b/auto/lib/openssl/makefile.msvc
@@ -5,8 +5,7 @@
 all:
 	cd $(OPENSSL)
 
-	perl Configure VC-WIN32 no-shared --prefix=openssl -DNO_SYS_TYPES_H \
-		$(OPENSSL_OPT)
+	perl Configure VC-WIN32 no-shared --prefix=openssl $(OPENSSL_OPT)
 
 	ms\do_ms
 
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -161,8 +161,10 @@ else
             CORE_INCS="$CORE_INCS $ngx_feature_path"
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             PCRE=YES
-        else
+        fi
+    fi
 
+    if [ $PCRE != YES ]; then
 cat << END
 
 $0: error: the HTTP rewrite module requires the PCRE library.
@@ -171,9 +173,7 @@ option, or install the PCRE library into
 statically from the source with nginx by using --with-pcre=<path> option.
 
 END
-            exit 1
+        exit 1
+    fi
 
-        fi
-
-    fi
 fi
--- a/auto/lib/zlib/conf
+++ b/auto/lib/zlib/conf
@@ -57,8 +57,10 @@ else
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             ZLIB=YES
             ngx_found=no
-        else
+        fi
+    fi
 
+    if [ $ZLIB != YES ]; then
 cat << END
 
 $0: error: the HTTP gzip module requires the zlib library.
@@ -67,8 +69,7 @@ option, or install the zlib library into
 statically from the source with nginx by using --with-zlib=<path> option.
 
 END
-            exit 1
-        fi
+        exit 1
     fi
 
 fi
--- a/auto/lib/zlib/make
+++ b/auto/lib/zlib/make
@@ -53,7 +53,7 @@ END
 
 $ZLIB/libz.a:	$NGX_MAKEFILE
 	cd $ZLIB \\
-	&& \$(MAKE) clean \\
+	&& \$(MAKE) distclean \\
 	&& cp contrib/asm586/match.S . \\
 	&& CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\
 		./configure \\
@@ -70,7 +70,7 @@ END
 
 $ZLIB/libz.a:	$NGX_MAKEFILE
 	cd $ZLIB \\
-	&& \$(MAKE) clean \\
+	&& \$(MAKE) distclean \\
 	&& cp contrib/asm686/match.S . \\
 	&& CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\
 		./configure \\
@@ -103,7 +103,7 @@ if [ $done = NO ]; then
 
 $ZLIB/libz.a:	$NGX_MAKEFILE
 	cd $ZLIB \\
-	&& \$(MAKE) clean \\
+	&& \$(MAKE) distclean \\
 	&& CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\
 		./configure \\
 	&& \$(MAKE) libz.a
--- a/auto/modules
+++ b/auto/modules
@@ -102,10 +102,10 @@ fi
 #     ngx_http_range_header_filter
 #     ngx_http_gzip_filter
 #     ngx_http_postpone_filter
+#     ngx_http_ssi_filter
 #     ngx_http_charset_filter
-#     ngx_http_ssi_filter
 #         ngx_http_xslt_filter
-#         ngx_http_image_filter_filter
+#         ngx_http_image_filter
 #         ngx_http_sub_filter
 #         ngx_http_addition_filter
 #         ngx_http_userid_filter
@@ -131,12 +131,6 @@ if [ $HTTP_POSTPONE = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS"
 fi
 
-if [ $HTTP_CHARSET = YES ]; then
-    have=NGX_HTTP_CHARSET . auto/have
-    HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_CHARSET_FILTER_MODULE"
-    HTTP_SRCS="$HTTP_SRCS $HTTP_CHARSET_SRCS"
-fi
-
 if [ $HTTP_SSI = YES ]; then
     have=NGX_HTTP_SSI . auto/have
     HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SSI_FILTER_MODULE"
@@ -144,6 +138,11 @@ if [ $HTTP_SSI = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS"
 fi
 
+if [ $HTTP_CHARSET = YES ]; then
+    HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_CHARSET_FILTER_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_CHARSET_SRCS"
+fi
+
 if [ $HTTP_XSLT = YES ]; then
     USE_LIBXSLT=YES
     HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_XSLT_FILTER_MODULE"
@@ -186,7 +185,6 @@ if [ $HTTP_DAV = YES ]; then
 fi
 
 if [ $HTTP_AUTOINDEX = YES ]; then
-    have=NGX_HTTP_AUTOINDEX . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_AUTOINDEX_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_AUTOINDEX_SRCS"
 fi
@@ -194,13 +192,11 @@ fi
 HTTP_MODULES="$HTTP_MODULES $HTTP_INDEX_MODULE"
 
 if [ $HTTP_RANDOM_INDEX = YES ]; then
-    have=NGX_HTTP_RANDOM_INDEX . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_RANDOM_INDEX_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS"
 fi
 
 if [ $HTTP_AUTH_BASIC = YES ]; then
-    have=NGX_HTTP_AUTH_BASIC . auto/have
     have=NGX_CRYPT . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_BASIC_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_BASIC_SRCS"
@@ -208,7 +204,6 @@ if [ $HTTP_AUTH_BASIC = YES ]; then
 fi
 
 if [ $HTTP_ACCESS = YES ]; then
-    have=NGX_HTTP_ACCESS . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_ACCESS_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS"
 fi
@@ -230,7 +225,6 @@ if [ $HTTP_REALIP = YES ]; then
 fi
 
 if [ $HTTP_STATUS = YES ]; then
-    have=NGX_HTTP_STATUS . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_STATUS_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_STATUS_SRCS"
 fi
@@ -242,24 +236,26 @@ if [ $HTTP_GEO = YES ]; then
 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"
     HTTP_SRCS="$HTTP_SRCS $HTTP_MAP_SRCS"
 fi
 
+if [ $HTTP_SPLIT_CLIENTS = YES ]; then
+    HTTP_MODULES="$HTTP_MODULES $HTTP_SPLIT_CLIENTS_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_SPLIT_CLIENTS_SRCS"
+fi
+
 if [ $HTTP_REFERER = YES ]; then
     HTTP_MODULES="$HTTP_MODULES $HTTP_REFERER_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_REFERER_SRCS"
 fi
 
 if [ $HTTP_REWRITE = YES -a $USE_PCRE != DISABLED ]; then
-    have=NGX_HTTP_REWRITE . auto/have
     USE_PCRE=YES
     HTTP_MODULES="$HTTP_MODULES $HTTP_REWRITE_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_REWRITE_SRCS"
@@ -286,9 +282,18 @@ if [ $HTTP_FASTCGI = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_FASTCGI_SRCS"
 fi
 
+if [ $HTTP_UWSGI = YES ]; then
+    HTTP_MODULES="$HTTP_MODULES $HTTP_UWSGI_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_UWSGI_SRCS"
+fi
+
+if [ $HTTP_SCGI = YES ]; then
+    HTTP_MODULES="$HTTP_MODULES $HTTP_SCGI_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_SCGI_SRCS"
+fi
+
 if [ $HTTP_PERL = YES ]; then
     USE_PERL=YES
-    have=NGX_HTTP_PERL . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_PERL_MODULE"
     HTTP_INCS="$HTTP_INCS $HTTP_PERL_INCS"
     HTTP_DEPS="$HTTP_DEPS $HTTP_PERL_DEPS"
@@ -316,6 +321,12 @@ if [ $HTTP_SECURE_LINK = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_SECURE_LINK_SRCS"
 fi
 
+if [ $HTTP_DEGRADATION = YES ]; then
+    have=NGX_HTTP_DEGRADATION . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_DEGRADATION_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_DEGRADATION_SRCS"
+fi
+
 if [ $HTTP_FLV = YES ]; then
     HTTP_MODULES="$HTTP_MODULES $HTTP_FLV_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS"
--- a/auto/options
+++ b/auto/options
@@ -52,6 +52,8 @@ NGX_HTTP_LOG_PATH=
 NGX_HTTP_CLIENT_TEMP_PATH=
 NGX_HTTP_PROXY_TEMP_PATH=
 NGX_HTTP_FASTCGI_TEMP_PATH=
+NGX_HTTP_UWSGI_TEMP_PATH=
+NGX_HTTP_SCGI_TEMP_PATH=
 
 HTTP_CACHE=YES
 HTTP_CHARSET=YES
@@ -74,10 +76,13 @@ HTTP_STATUS=NO
 HTTP_GEO=YES
 HTTP_GEOIP=NO
 HTTP_MAP=YES
+HTTP_SPLIT_CLIENTS=YES
 HTTP_REFERER=YES
 HTTP_REWRITE=YES
 HTTP_PROXY=YES
 HTTP_FASTCGI=YES
+HTTP_UWSGI=YES
+HTTP_SCGI=YES
 HTTP_PERL=NO
 HTTP_MEMCACHED=YES
 HTTP_LIMIT_ZONE=YES
@@ -85,6 +90,7 @@ HTTP_LIMIT_REQ=YES
 HTTP_EMPTY_GIF=YES
 HTTP_BROWSER=YES
 HTTP_SECURE_LINK=NO
+HTTP_DEGRADATION=NO
 HTTP_FLV=NO
 HTTP_GZIP_STATIC=NO
 HTTP_UPSTREAM_IP_HASH=YES
@@ -131,6 +137,8 @@ USE_LIBGD=NO
 NGX_GOOGLE_PERFTOOLS=NO
 NGX_CPP_TEST=NO
 
+NGX_LIBATOMIC=NO
+
 NGX_CPU_CACHE_LINE=
 
 opt=
@@ -181,6 +189,8 @@ do
         --http-client-body-temp-path=*)  NGX_HTTP_CLIENT_TEMP_PATH="$value" ;;
         --http-proxy-temp-path=*)        NGX_HTTP_PROXY_TEMP_PATH="$value" ;;
         --http-fastcgi-temp-path=*)      NGX_HTTP_FASTCGI_TEMP_PATH="$value" ;;
+        --http-uwsgi-temp-path=*)        NGX_HTTP_UWSGI_TEMP_PATH="$value" ;;
+        --http-scgi-temp-path=*)         NGX_HTTP_SCGI_TEMP_PATH="$value" ;;
 
         --with-http_ssl_module)          HTTP_SSL=YES               ;;
         --with-http_realip_module)       HTTP_REALIP=YES            ;;
@@ -194,6 +204,7 @@ do
         --with-http_gzip_static_module)  HTTP_GZIP_STATIC=YES       ;;
         --with-http_random_index_module) HTTP_RANDOM_INDEX=YES      ;;
         --with-http_secure_link_module)  HTTP_SECURE_LINK=YES       ;;
+        --with-http_degradation_module)  HTTP_DEGRADATION=YES       ;;
 
         --without-http_charset_module)   HTTP_CHARSET=NO            ;;
         --without-http_gzip_module)      HTTP_GZIP=NO               ;;
@@ -205,10 +216,13 @@ do
         --without-http_status_module)    HTTP_STATUS=NO             ;;
         --without-http_geo_module)       HTTP_GEO=NO                ;;
         --without-http_map_module)       HTTP_MAP=NO                ;;
+        --without-http_split_clients_module) HTTP_SPLIT_CLIENTS=NO  ;;
         --without-http_referer_module)   HTTP_REFERER=NO            ;;
         --without-http_rewrite_module)   HTTP_REWRITE=NO            ;;
         --without-http_proxy_module)     HTTP_PROXY=NO              ;;
         --without-http_fastcgi_module)   HTTP_FASTCGI=NO            ;;
+        --without-http_uwsgi_module)     HTTP_UWSGI=NO              ;;
+        --without-http_scgi_module)      HTTP_SCGI=NO               ;;
         --without-http_memcached_module) HTTP_MEMCACHED=NO          ;;
         --without-http_limit_zone_module) HTTP_LIMIT_ZONE=NO        ;;
         --without-http_limit_req_module) HTTP_LIMIT_REQ=NO         ;;
@@ -264,6 +278,9 @@ do
         --with-zlib-opt=*)               ZLIB_OPT="$value"          ;;
         --with-zlib-asm=*)               ZLIB_ASM="$value"          ;;
 
+        --with-libatomic)                NGX_LIBATOMIC=YES          ;;
+        --with-libatomic=*)              NGX_LIBATOMIC="$value"     ;;
+
         --test-build-devpoll)            NGX_TEST_BUILD_DEVPOLL=YES ;;
         --test-build-eventport)          NGX_TEST_BUILD_EVENTPORT=YES ;;
         --test-build-epoll)              NGX_TEST_BUILD_EPOLL=YES   ;;
@@ -322,6 +339,7 @@ cat << END
   --with-http_gzip_static_module     enable ngx_http_gzip_static_module
   --with-http_random_index_module    enable ngx_http_random_index_module
   --with-http_secure_link_module     enable ngx_http_secure_link_module
+  --with-http_degradation_module     enable ngx_http_degradation_module
   --with-http_stub_status_module     enable ngx_http_stub_status_module
 
   --without-http_charset_module      disable ngx_http_charset_module
@@ -333,10 +351,13 @@ cat << END
   --without-http_autoindex_module    disable ngx_http_autoindex_module
   --without-http_geo_module          disable ngx_http_geo_module
   --without-http_map_module          disable ngx_http_map_module
+  --without-http_split_clients_module disable ngx_http_split_clients_module
   --without-http_referer_module      disable ngx_http_referer_module
   --without-http_rewrite_module      disable ngx_http_rewrite_module
   --without-http_proxy_module        disable ngx_http_proxy_module
   --without-http_fastcgi_module      disable ngx_http_fastcgi_module
+  --without-http_uwsgi_module        disable ngx_http_uwsgi_module
+  --without-http_scgi_module         disable ngx_http_scgi_module
   --without-http_memcached_module    disable ngx_http_memcached_module
   --without-http_limit_zone_module   disable ngx_http_limit_zone_module
   --without-http_limit_req_module    disable ngx_http_limit_req_module
@@ -355,6 +376,8 @@ cat << END
   --http-proxy-temp-path=PATH        set path to the http proxy temporary files
   --http-fastcgi-temp-path=PATH      set path to the http fastcgi temporary
                                      files
+  --http-uwsgi-temp-path=PATH        set path to the http uwsgi temporary files
+  --http-scgi-temp-path=PATH         set path to the http scgi temporary files
 
   --without-http                     disable HTTP server
   --without-http-cache               disable HTTP cache
@@ -397,6 +420,9 @@ cat << END
                                      for specified CPU, the valid values:
                                      pentium, pentiumpro
 
+  --with-libatomic                   force libatomic_ops library usage
+  --with-libatomic=DIR               set path to libatomic_ops library sources
+
   --with-openssl=DIR                 set path to OpenSSL library sources
   --with-openssl-opt=OPTIONS         set additional options for OpenSSL building
 
@@ -441,6 +467,8 @@ NGX_HTTP_LOG_PATH=${NGX_HTTP_LOG_PATH:-l
 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}
+NGX_HTTP_UWSGI_TEMP_PATH=${NGX_HTTP_UWSGI_TEMP_PATH:-uwsgi_temp}
+NGX_HTTP_SCGI_TEMP_PATH=${NGX_HTTP_SCGI_TEMP_PATH:-scgi_temp}
 
 case ".$NGX_PERL_MODULES" in
     ./*)
--- a/auto/os/features
+++ b/auto/os/features
@@ -172,6 +172,26 @@ if [ $ngx_found = no ]; then
 fi
 
 
+ngx_feature="F_READAHEAD"
+ngx_feature_name="NGX_HAVE_F_READAHEAD"
+ngx_feature_run=no
+ngx_feature_incs="#include <fcntl.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="fcntl(0, F_READAHEAD, 1);"
+. auto/feature
+
+
+ngx_feature="posix_fadvise()"
+ngx_feature_name="NGX_HAVE_POSIX_FADVISE"
+ngx_feature_run=no
+ngx_feature_incs="#include <fcntl.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="posix_fadvise(0, 0, 0, POSIX_FADV_SEQUENTIAL);"
+. auto/feature
+
+
 ngx_feature="O_DIRECT"
 ngx_feature_name="NGX_HAVE_O_DIRECT"
 ngx_feature_run=no
@@ -275,6 +295,24 @@ if [ $ngx_found != yes ]; then
     fi
 fi
 
+ngx_feature="SO_SETFIB"
+ngx_feature_name="NGX_HAVE_SETFIB"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_SETFIB, NULL, 4)"
+. auto/feature
+
+
+ngx_feature="accept4()"
+ngx_feature_name="NGX_HAVE_ACCEPT4"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="accept4(0, NULL, NULL, SOCK_NONBLOCK)"
+. auto/feature
 
 if [ $NGX_FILE_AIO = YES ]; then
 
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -35,6 +35,12 @@ then
 fi
 
 
+# posix_fadvise64() had been implemented in 2.5.60
+
+if [ $version -lt 132412 ]; then
+    have=NGX_HAVE_POSIX_FADVISE . auto/nohave
+fi
+
 # epoll, EPOLLET version
 
 ngx_feature="epoll"
--- a/auto/sources
+++ b/auto/sources
@@ -387,6 +387,10 @@ HTTP_MAP_MODULE=ngx_http_map_module
 HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c
 
 
+HTTP_SPLIT_CLIENTS_MODULE=ngx_http_split_clients_module
+HTTP_SPLIT_CLIENTS_SRCS=src/http/modules/ngx_http_split_clients_module.c
+
+
 HTTP_REFERER_MODULE=ngx_http_referer_module
 HTTP_REFERER_SRCS=src/http/modules/ngx_http_referer_module.c
 
@@ -408,6 +412,14 @@ HTTP_FASTCGI_MODULE=ngx_http_fastcgi_mod
 HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_module.c
 
 
+HTTP_UWSGI_MODULE=ngx_http_uwsgi_module
+HTTP_UWSGI_SRCS=src/http/modules/ngx_http_uwsgi_module.c
+
+
+HTTP_SCGI_MODULE=ngx_http_scgi_module
+HTTP_SCGI_SRCS=src/http/modules/ngx_http_scgi_module.c
+
+
 HTTP_PERL_MODULE=ngx_http_perl_module
 HTTP_PERL_INCS=src/http/modules/perl
 HTTP_PERL_DEPS=src/http/modules/perl/ngx_http_perl_module.h
@@ -438,6 +450,10 @@ HTTP_SECURE_LINK_MODULE=ngx_http_secure_
 HTTP_SECURE_LINK_SRCS=src/http/modules/ngx_http_secure_link_module.c
 
 
+HTTP_DEGRADATION_MODULE=ngx_http_degradation_module
+HTTP_DEGRADATION_SRCS=src/http/modules/ngx_http_degradation_module.c
+
+
 HTTP_FLV_MODULE=ngx_http_flv_module
 HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c
 
--- a/auto/summary
+++ b/auto/summary
@@ -38,7 +38,6 @@ else
     case $PCRE in
         YES)   echo "  + using system PCRE library" ;;
         NONE)  echo "  + PCRE library is not used" ;;
-        NO)    echo "  + PCRE library is not found" ;;
         *)     echo "  + using PCRE library: $PCRE" ;;
     esac
 fi
@@ -46,14 +45,12 @@ fi
 case $OPENSSL in
     YES)   echo "  + using system OpenSSL library" ;;
     NONE)  echo "  + OpenSSL library is not used" ;;
-    NO)    echo "  + OpenSSL library is not found" ;;
     *)     echo "  + using OpenSSL library: $OPENSSL" ;;
 esac
 
 case $MD5 in
     YES)   echo "  + md5: using $MD5_LIB library" ;;
     NONE)  echo "  + md5 library is not used" ;;
-    NO)    echo "  + md5 library is not found" ;;
     *)     echo "  + using md5 library: $MD5" ;;
 esac
 
@@ -67,10 +64,15 @@ esac
 case $ZLIB in
     YES)   echo "  + using system zlib library" ;;
     NONE)  echo "  + zlib library is not used" ;;
-    NO)    echo "  + zlib library is not found" ;;
     *)     echo "  + using zlib library: $ZLIB" ;;
 esac
 
+case $NGX_LIBATOMIC in
+    YES)   echo "  + using system libatomic_ops library" ;;
+    NO)    ;; # not used
+    *)     echo "  + using libatomic_ops library: $NGX_LIBATOMIC" ;;
+esac
+
 echo
 
 
@@ -91,7 +93,20 @@ fi
 cat << END
   nginx http access log file: "$NGX_HTTP_LOG_PATH"
   nginx http client request body temporary files: "$NGX_HTTP_CLIENT_TEMP_PATH"
-  nginx http proxy temporary files: "$NGX_HTTP_PROXY_TEMP_PATH"
-  nginx http fastcgi temporary files: "$NGX_HTTP_FASTCGI_TEMP_PATH"
+END
+
+if [ $HTTP_PROXY = YES ]; then
+    echo "  nginx http proxy temporary files: \"$NGX_HTTP_PROXY_TEMP_PATH\""
+fi
 
-END
+if [ $HTTP_FASTCGI = YES ]; then
+    echo "  nginx http fastcgi temporary files: \"$NGX_HTTP_FASTCGI_TEMP_PATH\""
+fi
+
+if [ $HTTP_UWSGI = YES ]; then
+    echo "  nginx http uwsgi temporary files: \"$NGX_HTTP_UWSGI_TEMP_PATH\""
+fi
+
+if [ $HTTP_SCGI = YES ]; then
+    echo "  nginx http scgi temporary files: \"$NGX_HTTP_SCGI_TEMP_PATH\""
+fi
--- a/auto/unix
+++ b/auto/unix
@@ -109,28 +109,52 @@ ngx_feature_test="char buf[1]; ssize_t n
 . auto/feature
 
 
-ngx_feature="strerror_r()"
-ngx_feature_name="NGX_HAVE_STRERROR_R"
-ngx_feature_run=yes
-ngx_feature_incs="#include <string.h>"
+ngx_feature="sys_nerr"
+ngx_feature_name="NGX_SYS_NERR"
+ngx_feature_run=value
+ngx_feature_incs='#include <stdio.h>'
 ngx_feature_path=
 ngx_feature_libs=
-ngx_feature_test="char buf[1024]; long n; n = strerror_r(1, buf, 1024);
-                  if (n < 0 || n > 1024) return 1;"
+ngx_feature_test='printf("%d", sys_nerr);'
 . auto/feature
 
 
-# GNU style strerror_r() returns not length, but pointer
+if [ $ngx_found = no ]; then
+
+    # Cygiwn defines _sys_nerr
+    ngx_feature="_sys_nerr"
+    ngx_feature_name="NGX_SYS_NERR"
+    ngx_feature_run=value
+    ngx_feature_incs='#include <errno.h>
+                      #include <stdio.h>'
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test='printf("%d", _sys_nerr);'
+    . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
 
-ngx_feature="gnu style strerror_r()"
-ngx_feature_name="NGX_HAVE_GNU_STRERROR_R"
-ngx_feature_run=yes
-ngx_feature_incs="#include <string.h>"
-ngx_feature_path=
-ngx_feature_libs=
-ngx_feature_test="char buf[1024]; long n; n = strerror_r(1, buf, 1024);
-                  if (n >= 0 && n < 1024) return 1;"
-. auto/feature
+    # Solaris has no sys_nerr
+    ngx_feature='maximum errno'
+    ngx_feature_name=NGX_SYS_NERR
+    ngx_feature_run=value
+    ngx_feature_incs='#include <errno.h>
+                      #include <stdio.h>'
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test='int  n;
+                      for (n = 1; n < 1000; n++) {
+                          errno = 0;
+                          strerror(n);
+                          if (errno == EINVAL) {
+                              printf("%d", n);
+                              return 0;
+                          }
+                     }'
+    . auto/feature
+fi
 
 
 ngx_feature="localtime_r()"
new file mode 100644
--- /dev/null
+++ b/conf/fastcgi.conf
@@ -0,0 +1,24 @@
+
+fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
+fastcgi_param  QUERY_STRING       $query_string;
+fastcgi_param  REQUEST_METHOD     $request_method;
+fastcgi_param  CONTENT_TYPE       $content_type;
+fastcgi_param  CONTENT_LENGTH     $content_length;
+
+fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
+fastcgi_param  REQUEST_URI        $request_uri;
+fastcgi_param  DOCUMENT_URI       $document_uri;
+fastcgi_param  DOCUMENT_ROOT      $document_root;
+fastcgi_param  SERVER_PROTOCOL    $server_protocol;
+
+fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
+fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
+
+fastcgi_param  REMOTE_ADDR        $remote_addr;
+fastcgi_param  REMOTE_PORT        $remote_port;
+fastcgi_param  SERVER_ADDR        $server_addr;
+fastcgi_param  SERVER_PORT        $server_port;
+fastcgi_param  SERVER_NAME        $server_name;
+
+# PHP only, required if PHP was built with --enable-force-cgi-redirect
+fastcgi_param  REDIRECT_STATUS    200;
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -32,9 +32,9 @@ types {
     application/vnd.ms-excel              xls;
     application/vnd.ms-powerpoint         ppt;
     application/vnd.wap.wmlc              wmlc;
-    application/vnd.wap.xhtml+xml         xhtml;
     application/vnd.google-earth.kml+xml  kml;
     application/vnd.google-earth.kmz      kmz;
+    application/x-7z-compressed           7z;
     application/x-cocoa                   cco;
     application/x-java-archive-diff       jardiff;
     application/x-java-jnlp-file          jnlp;
@@ -49,6 +49,7 @@ types {
     application/x-tcl                     tcl tk;
     application/x-x509-ca-cert            der pem crt;
     application/x-xpinstall               xpi;
+    application/xhtml+xml                 xhtml;
     application/zip                       zip;
 
     application/octet-stream              bin exe dll;
@@ -60,6 +61,7 @@ types {
 
     audio/midi                            mid midi kar;
     audio/mpeg                            mp3;
+    audio/ogg                             ogg;
     audio/x-realaudio                     ra;
 
     video/3gpp                            3gpp 3gp;
new file mode 100644
--- /dev/null
+++ b/conf/scgi_params
@@ -0,0 +1,15 @@
+
+scgi_param  REQUEST_METHOD     $request_method;
+scgi_param  REQUEST_URI        $request_uri;
+scgi_param  QUERY_STRING       $query_string;
+scgi_param  CONTENT_TYPE       $content_type;
+
+scgi_param  DOCUMENT_URI       $document_uri;
+scgi_param  DOCUMENT_ROOT      $document_root;
+scgi_param  SCGI               1;
+scgi_param  SERVER_PROTOCOL    $server_protocol;
+
+scgi_param  REMOTE_ADDR        $remote_addr;
+scgi_param  REMOTE_PORT        $remote_port;
+scgi_param  SERVER_PORT        $server_port;
+scgi_param  SERVER_NAME        $server_name;
new file mode 100644
--- /dev/null
+++ b/conf/uwsgi_params
@@ -0,0 +1,15 @@
+
+uwsgi_param  QUERY_STRING       $query_string;
+uwsgi_param  REQUEST_METHOD     $request_method;
+uwsgi_param  CONTENT_TYPE       $content_type;
+uwsgi_param  CONTENT_LENGTH     $content_length;
+
+uwsgi_param  REQUEST_URI        $request_uri;
+uwsgi_param  PATH_INFO          $document_uri;
+uwsgi_param  DOCUMENT_ROOT      $document_root;
+uwsgi_param  SERVER_PROTOCOL    $server_protocol;
+
+uwsgi_param  REMOTE_ADDR        $remote_addr;
+uwsgi_param  REMOTE_PORT        $remote_port;
+uwsgi_param  SERVER_PORT        $server_port;
+uwsgi_param  SERVER_NAME        $server_name;
--- a/configure
+++ b/configure
@@ -90,6 +90,10 @@ have=NGX_HTTP_PROXY_TEMP_PATH value="\"$
 . auto/define
 have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\""
 . auto/define
+have=NGX_HTTP_UWSGI_TEMP_PATH value="\"$NGX_HTTP_UWSGI_TEMP_PATH\""
+. auto/define
+have=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\""
+. auto/define
 
 . auto/make
 . auto/lib/make
new file mode 100644
--- /dev/null
+++ b/man/nginx.8
@@ -0,0 +1,201 @@
+.\"
+.\" Copyright (c) 2010 Sergey A. Osokin
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"
+.Dd November 14, 2010
+.Dt NGINX 8
+.Os
+.Sh NAME
+.Nm nginx
+.Nd "HTTP and reverse proxy server, mail proxy server"
+.Sh SYNOPSIS
+.Nm
+.Op Fl hqtvV?
+.Op Fl c Ar file
+.Op Fl g Ar directives
+.Op Fl p Ar prefix
+.Op Fl s Ar signal
+.Sh DESCRIPTION
+The
+.Nm
+(spelled
+.Dq engine x )
+is an HTTP and reverse proxy server, as well as a mail proxy server.
+The
+.Nm
+is known for its high performance, stability, rich feature set, simple
+configuration, and low resource consumption.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl d Ar directives"
+.It Fl ?\& | h
+Print help.
+.It Fl c Ar file
+Use an alternative configuration
+.Ar file .
+.It Fl g Ar directives
+Set global configuration directives.
+See
+.Sx EXAMPLES
+for details.
+.It Fl p Ar prefix
+Set prefix path.
+Default value is
+.Pa %%PREFIX%% .
+.It Fl q
+Suppress non-error messages during configuration testing.
+.It Fl s Ar signal
+Send signal to the master process.
+The argument
+.Ar signal
+can be one of:
+.Cm stop , quit , reopen , reload .
+The following table shows the corresponding system signals.
+.Pp
+.Bl -tag -width ".It Cm reopen" -compact
+.It Cm stop
+.Dv SIGTERM
+.It Cm quit
+.Dv SIGQUIT
+.It Cm reopen
+.Dv SIGUSR1
+.It Cm reload
+.Dv SIGHUP
+.El
+.It Fl t
+Don't run, just test the configuration file.
+The
+.Nm
+checks configuration for correct syntax and then tries to open files
+referred in configuration.
+.It Fl v
+Print
+.Nm
+version.
+.It Fl V
+Print
+.Nm
+version, compiler version and
+.Pa configure
+script parameters.
+.El
+.Sh SIGNALS
+The master process of
+.Nm
+can handle the following signals.
+.Pp
+.Bl -tag -width ".It Dv SIGINT , SIGTERM" -compact
+.It Dv SIGINT , SIGTERM
+Shut down quickly.
+.It Dv SIGHUP
+Reload configuration, start the new worker process with a new
+configuration, gracefully shut down old worker processes.
+.It Dv SIGQUIT
+Shut down gracefully.
+.It Dv SIGUSR1
+Reopen log files.
+.It Dv SIGUSR2
+Upgrade
+.Nm
+executable on the fly.
+.It Dv SIGWINCH
+Shut down gracefully worker processes.
+.El
+.Pp
+While there's no need to explicitly control worker processes normally,
+they support some signals, too:
+.Pp
+.Bl -tag -width ".It Dv SIGINT , SIGTERM" -compact
+.It Dv SIGTERM
+Shut down quickly.
+.It Dv SIGQUIT
+Shut down gracefully.
+.It Dv SIGUSR1
+Reopen log files.
+.El
+.Sh DEBUGGING LOG
+To enable a debugging log, reconfigure
+.Nm
+to build with debugging:
+.Pp
+.Dl "./configure --with-debug ..."
+.Pp
+and then set the
+.Cm debug
+level of the
+.Va error_log :
+.Pp
+.Dl "error_log /path/to/log debug;"
+.Pp
+It is also possible to enable the debugging for some IP address:
+.Bd -literal -offset indent
+events {
+	debug_connection 127.0.0.1;
+}
+.Ed
+.Sh FILES
+.Bl -tag -width indent -compact
+.It Pa %%PID_PATH%%
+Contains the process ID of the
+.Nm
+listening for connections.
+The content of this file is not sensitive; it can be world-readable.
+.It Pa %%CONF_PATH%%
+Main configuration file.
+.It Pa %%ERROR_LOG_PATH%%
+Error log file.
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success, or 1 if the command fails.
+.Sh EXAMPLES
+.Bd -literal
+nginx -t -c ~/mynginx.conf -g "pid /var/run/mynginx.pid; worker_processes 2;"
+.Ed
+Test configuration file
+.Pa ~/mynginx.conf
+with global directives for PID and quantity of worker processes.
+.Sh SEE ALSO
+.Xr nginx.conf 5
+.Sh HISTORY
+Development of
+.Nm
+started in 2002, with the first public release on October 4, 2004.
+.Sh AUTHORS
+.An Igor Sysoev Aq igor@sysoev.ru
+.Pp
+Documentation available on
+.Pa http://nginx.org/
+and
+.Pa http://sysoev.ru/nginx/ .
+.Pp
+This manual page was written by
+.An Sergey A. Osokin Aq osa@FreeBSD.org.ru
+as a result of compilation of many
+.Nm
+documents all over the world.
+.Sh BUGS
+Report to mailing list
+.Aq Li nginx@nginx.org
+if you found one.
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -110,7 +110,7 @@ static ngx_command_t  ngx_core_commands[
 
     { ngx_string("worker_rlimit_core"),
       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
+      ngx_conf_set_off_slot,
       0,
       offsetof(ngx_core_conf_t, rlimit_core),
       NULL },
@@ -203,6 +203,10 @@ main(int argc, char *const *argv)
     ngx_cycle_t      *cycle, init_cycle;
     ngx_core_conf_t  *ccf;
 
+    if (ngx_strerror_init() != NGX_OK) {
+        return 1;
+    }
+
     if (ngx_get_options(argc, argv) != NGX_OK) {
         return 1;
     }
@@ -212,7 +216,7 @@ main(int argc, char *const *argv)
 
         if (ngx_show_help) {
             ngx_log_stderr(0,
-                "Usage: nginx [-?hvVt] [-s signal] [-c filename] "
+                "Usage: nginx [-?hvVtq] [-s signal] [-c filename] "
                              "[-p prefix] [-g directives]" CRLF CRLF
                 "Options:" CRLF
                 "  -?,-h         : this help" CRLF
@@ -220,6 +224,8 @@ main(int argc, char *const *argv)
                 "  -V            : show version and configure options then exit"
                                    CRLF
                 "  -t            : test configuration and exit" CRLF
+                "  -q            : suppress non-error messages "
+                                   "during configuration testing" CRLF
                 "  -s signal     : send signal to a master process: "
                                    "stop, quit, reopen, reload" CRLF
 #ifdef NGX_PREFIX
@@ -239,6 +245,13 @@ main(int argc, char *const *argv)
 #ifdef NGX_COMPILER
             ngx_log_stderr(0, "built by " NGX_COMPILER);
 #endif
+#if (NGX_SSL)
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+            ngx_log_stderr(0, "TLS SNI support enabled");
+#else
+            ngx_log_stderr(0, "TLS SNI support disabled");
+#endif
+#endif
             ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE);
         }
 
@@ -325,8 +338,11 @@ main(int argc, char *const *argv)
     }
 
     if (ngx_test_config) {
-        ngx_log_stderr(0, "configuration file %s test is successful",
-                       cycle->conf_file.data);
+        if (!ngx_quiet_mode) {
+            ngx_log_stderr(0, "configuration file %s test is successful",
+                           cycle->conf_file.data);
+        }
+
         return 0;
     }
 
@@ -373,6 +389,13 @@ main(int argc, char *const *argv)
         }
     }
 
+    if (log->file->fd != ngx_stderr) {
+        if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          ngx_close_file_n " built-in log failed");
+        }
+    }
+
     ngx_use_stderr = 0;
 
     if (ngx_process == NGX_PROCESS_SINGLE) {
@@ -671,6 +694,10 @@ ngx_get_options(int argc, char *const *a
                 ngx_test_config = 1;
                 break;
 
+            case 'q':
+                ngx_quiet_mode = 1;
+                break;
+
             case 'p':
                 if (*p) {
                     ngx_prefix = p;
@@ -845,14 +872,11 @@ ngx_process_options(ngx_cycle_t *cycle)
 #else
 
 #ifdef NGX_CONF_PREFIX
-        cycle->conf_prefix.len = sizeof(NGX_CONF_PREFIX) - 1;
-        cycle->conf_prefix.data = (u_char *) NGX_CONF_PREFIX;
+        ngx_str_set(&cycle->conf_prefix, NGX_CONF_PREFIX);
 #else
-        cycle->conf_prefix.len = sizeof(NGX_PREFIX) - 1;
-        cycle->conf_prefix.data = (u_char *) NGX_PREFIX;
+        ngx_str_set(&cycle->conf_prefix, NGX_PREFIX);
 #endif
-        cycle->prefix.len = sizeof(NGX_PREFIX) - 1;
-        cycle->prefix.data = (u_char *) NGX_PREFIX;
+        ngx_str_set(&cycle->prefix, NGX_PREFIX);
 
 #endif
     }
@@ -862,8 +886,7 @@ ngx_process_options(ngx_cycle_t *cycle)
         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;
+        ngx_str_set(&cycle->conf_file, NGX_CONF_PATH);
     }
 
     if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {
@@ -905,7 +928,7 @@ ngx_core_module_create_conf(ngx_cycle_t 
     }
 
     /*
-     * set by pcalloc()
+     * set by ngx_pcalloc()
      *
      *     ccf->pid = NULL;
      *     ccf->oldpid = NULL;
@@ -922,7 +945,7 @@ ngx_core_module_create_conf(ngx_cycle_t 
     ccf->debug_points = NGX_CONF_UNSET;
 
     ccf->rlimit_nofile = NGX_CONF_UNSET;
-    ccf->rlimit_core = NGX_CONF_UNSET_SIZE;
+    ccf->rlimit_core = NGX_CONF_UNSET;
     ccf->rlimit_sigpending = NGX_CONF_UNSET;
 
     ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT;
@@ -979,8 +1002,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c
 
 
     if (ccf->pid.len == 0) {
-        ccf->pid.len = sizeof(NGX_PID_PATH) - 1;
-        ccf->pid.data = (u_char *) NGX_PID_PATH;
+        ngx_str_set(&ccf->pid, NGX_PID_PATH);
     }
 
     if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) {
@@ -1028,8 +1050,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c
 
 
     if (ccf->lock_file.len == 0) {
-        ccf->lock_file.len = sizeof(NGX_LOCK_PATH) - 1;
-        ccf->lock_file.data = (u_char *) NGX_LOCK_PATH;
+        ngx_str_set(&ccf->lock_file, NGX_LOCK_PATH);
     }
 
     if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) != NGX_OK) {
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8016
-#define NGINX_VERSION      "0.8.16"
+#define nginx_version      1000000
+#define NGINX_VERSION      "1.0.0"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -261,7 +261,7 @@ done:
         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                           ngx_close_file_n " %s failed",
-                          cf->conf_file->file.name.data);
+                          filename->data);
             return NGX_CONF_ERROR;
         }
 
@@ -507,7 +507,7 @@ ngx_conf_read_token(ngx_conf_t *cf)
             }
 
             if (len) {
-                ngx_memcpy(b->start, start, len);
+                ngx_memmove(b->start, start, len);
             }
 
             size = (ssize_t) (file_size - cf->conf_file->file.offset);
@@ -671,7 +671,8 @@ ngx_conf_read_token(ngx_conf_t *cf)
                 }
 
             } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
-                       || ch == ';' || ch == '{') {
+                       || ch == ';' || ch == '{')
+            {
                 last_space = 1;
                 found = 1;
             }
@@ -903,8 +904,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n
     ngx_open_file_t  *file;
 
 #if (NGX_SUPPRESS_WARN)
-    full.len = 0;
-    full.data = NULL;
+    ngx_str_null(&full);
 #endif
 
     if (name->len) {
@@ -1006,7 +1006,7 @@ ngx_conf_flush_files(ngx_cycle_t *cycle)
 
 void ngx_cdecl
 ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
-    char *fmt, ...)
+    const char *fmt, ...)
 {
     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
     va_list  args;
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -322,7 +322,7 @@ ngx_int_t ngx_conf_full_name(ngx_cycle_t
     ngx_uint_t conf_prefix);
 ngx_open_file_t *ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name);
 void ngx_cdecl ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf,
-    ngx_err_t err, char *fmt, ...);
+    ngx_err_t err, const char *fmt, ...);
 
 
 char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -12,9 +12,13 @@
 ngx_os_io_t  ngx_io;
 
 
+static void ngx_drain_connections(void);
+
+
 ngx_listening_t *
 ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
 {
+    size_t            len;
     ngx_listening_t  *ls;
     struct sockaddr  *sa;
     u_char            text[NGX_SOCKADDR_STRLEN];
@@ -36,17 +40,8 @@ ngx_create_listening(ngx_conf_t *cf, voi
     ls->sockaddr = sa;
     ls->socklen = 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;
+    len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
+    ls->addr_text.len = len;
 
     switch (ls->sockaddr->sa_family) {
 #if (NGX_HAVE_INET6)
@@ -54,6 +49,12 @@ ngx_create_listening(ngx_conf_t *cf, voi
          ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
          break;
 #endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+         ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
+         len++;
+         break;
+#endif
     case AF_INET:
          ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
          break;
@@ -62,10 +63,24 @@ ngx_create_listening(ngx_conf_t *cf, voi
          break;
     }
 
+    ls->addr_text.data = ngx_pnalloc(cf->pool, len);
+    if (ls->addr_text.data == NULL) {
+        return NULL;
+    }
+
+    ngx_memcpy(ls->addr_text.data, text, len);
+
+    ls->fd = (ngx_socket_t) -1;
+    ls->type = SOCK_STREAM;
+
     ls->backlog = NGX_LISTEN_BACKLOG;
     ls->rcvbuf = -1;
     ls->sndbuf = -1;
 
+#if (NGX_HAVE_SETFIB)
+    ls->setfib = -1;
+#endif
+
     return ls;
 }
 
@@ -88,14 +103,12 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
 
-        /* AF_INET only */
-
-        ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(struct sockaddr_in));
+        ls[i].sockaddr = ngx_palloc(cycle->pool, NGX_SOCKADDRLEN);
         if (ls[i].sockaddr == NULL) {
             return NGX_ERROR;
         }
 
-        ls[i].socklen = sizeof(struct sockaddr_in);
+        ls[i].socklen = NGX_SOCKADDRLEN;
         if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) {
             ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
                           "getsockname() of the inherited "
@@ -109,11 +122,20 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
 #if (NGX_HAVE_INET6)
         case AF_INET6:
              ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
+             len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1;
+             break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+        case AF_UNIX:
+             ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
+             len = NGX_UNIX_ADDRSTRLEN;
              break;
 #endif
 
         case AF_INET:
              ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
+             len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
              break;
 
         default:
@@ -124,8 +146,6 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
             continue;
         }
 
-        len = ls[i].addr_text_max_len + sizeof(":65535") - 1;
-
         ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len);
         if (ls[i].addr_text.data == NULL) {
             return NGX_ERROR;
@@ -166,6 +186,25 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
             ls[i].sndbuf = -1;
         }
 
+#if 0
+        /* SO_SETFIB is currently a set only option */
+
+#if (NGX_HAVE_SETFIB)
+
+        if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB,
+                       (void *) &ls[i].setfib, &olen)
+            == -1)
+        {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                          "getsockopt(SO_SETFIB) %V failed, ignored",
+                          &ls[i].addr_text);
+
+            ls[i].setfib = -1;
+        }
+
+#endif
+#endif
+
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
 
         ngx_memzero(&af, sizeof(struct accept_filter_arg));
@@ -357,6 +396,29 @@ ngx_open_listening_sockets(ngx_cycle_t *
                 continue;
             }
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+            if (ls[i].sockaddr->sa_family == AF_UNIX) {
+                mode_t   mode;
+                u_char  *name;
+
+                name = ls[i].addr_text.data + sizeof("unix:") - 1;
+                mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+                if (chmod((char *) name, mode) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                                  "chmod() \"%s\" failed", name);
+                }
+
+                if (ngx_test_config) {
+                    if (ngx_delete_file(name) == -1) {
+                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                                      ngx_delete_file_n " %s failed", name);
+                    }
+                }
+            }
+#endif
+
             if (listen(s, ls[i].backlog) == -1) {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                               "listen() to %V, backlog %d failed",
@@ -437,6 +499,19 @@ ngx_configure_listening_sockets(ngx_cycl
             }
         }
 
+#if (NGX_HAVE_SETFIB)
+        if (ls[i].setfib != -1) {
+            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
+                           (const void *) &ls[i].setfib, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "setsockopt(SO_SETFIB, %d) %V failed, ignored",
+                              ls[i].setfib, &ls[i].addr_text);
+            }
+        }
+#endif
+
 #if 0
         if (1) {
             int tcp_nodelay = 1;
@@ -604,6 +679,22 @@ ngx_close_listening_sockets(ngx_cycle_t 
                           ngx_close_socket_n " %V failed", &ls[i].addr_text);
         }
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        if (ls[i].sockaddr->sa_family == AF_UNIX
+            && ngx_process <= NGX_PROCESS_MASTER
+            && ngx_new_binary == 0)
+        {
+            u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
+
+            if (ngx_delete_file(name) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                              ngx_delete_file_n " %s failed", name);
+            }
+        }
+
+#endif
+
         ls[i].fd = (ngx_socket_t) -1;
     }
 }
@@ -631,6 +722,11 @@ ngx_get_connection(ngx_socket_t s, ngx_l
     c = ngx_cycle->free_connections;
 
     if (c == NULL) {
+        ngx_drain_connections();
+        c = ngx_cycle->free_connections;
+    }
+
+    if (c == NULL) {
         ngx_log_error(NGX_LOG_ALERT, log, 0,
                       "%ui worker_connections are not enough",
                       ngx_cycle->connection_n);
@@ -773,6 +869,8 @@ ngx_close_connection(ngx_connection_t *c
 
 #endif
 
+    ngx_reusable_connection(c, 0);
+
     log_error = c->log_error;
 
     ngx_free_connection(c);
@@ -812,6 +910,51 @@ ngx_close_connection(ngx_connection_t *c
 }
 
 
+void
+ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+                   "reusable connection: %ui", reusable);
+
+    if (c->reusable) {
+        ngx_queue_remove(&c->queue);
+    }
+
+    c->reusable = reusable;
+
+    if (reusable) {
+        /* need cast as ngx_cycle is volatile */
+
+        ngx_queue_insert_head(
+            (ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);
+    }
+}
+
+
+static void
+ngx_drain_connections(void)
+{
+    ngx_int_t          i;
+    ngx_queue_t       *q;
+    ngx_connection_t  *c;
+
+    for (i = 0; i < 32; i++) {
+        if (ngx_queue_empty(&ngx_cycle->reusable_connections_queue)) {
+            break;
+        }
+
+        q = ngx_queue_last(&ngx_cycle->reusable_connections_queue);
+        c = ngx_queue_data(q, ngx_connection_t, queue);
+
+        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "reusing connection");
+
+        c->close = 1;
+        c->read->handler(c->read);
+    }
+}
+
+
 ngx_int_t
 ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
     ngx_uint_t port)
@@ -858,7 +1001,6 @@ ngx_connection_local_sockaddr(ngx_connec
             return NGX_ERROR;
         }
 
-        c->local_socklen = len;
         ngx_memcpy(c->local_sockaddr, &sa, len);
     }
 
@@ -917,12 +1059,8 @@ ngx_connection_error(ngx_connection_t *c
             level = NGX_LOG_INFO;
             break;
 
-        case NGX_ERROR_ERR:
+        default:
             level = NGX_LOG_ERR;
-            break;
-
-        default:
-            level = NGX_LOG_ALERT;
         }
 
     } else {
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -69,6 +69,9 @@ struct ngx_listening_s {
     char               *accept_filter;
 #endif
 #endif
+#if (NGX_HAVE_SETFIB)
+    int                 setfib;
+#endif
 
 };
 
@@ -129,10 +132,11 @@ struct ngx_connection_s {
 #endif
 
     struct sockaddr    *local_sockaddr;
-    socklen_t           local_socklen;
 
     ngx_buf_t          *buffer;
 
+    ngx_queue_t         queue;
+
     ngx_atomic_uint_t   number;
 
     ngx_uint_t          requests;
@@ -148,6 +152,7 @@ struct ngx_connection_s {
     unsigned            destroyed:1;
 
     unsigned            idle:1;
+    unsigned            reusable:1;
     unsigned            close:1;
 
     unsigned            sendfile:1;
@@ -184,5 +189,6 @@ ngx_int_t ngx_connection_error(ngx_conne
 ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log);
 void ngx_free_connection(ngx_connection_t *c);
 
+void ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable);
 
 #endif /* _NGX_CONNECTION_H_INCLUDED_ */
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -83,7 +83,9 @@ typedef void (*ngx_connection_handler_pt
 #define CRLF   "\x0d\x0a"
 
 
-#define ngx_abs(value)   (((value) >= 0) ? (value) : - (value))
+#define ngx_abs(value)       (((value) >= 0) ? (value) : - (value))
+#define ngx_max(val1, val2)  ((val1 < val2) ? (val2) : (val1))
+#define ngx_min(val1, val2)  ((val1 > val2) ? (val2) : (val1))
 
 void ngx_cpuinfo(void);
 
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -24,6 +24,7 @@ static ngx_pool_t     *ngx_temp_pool;
 static ngx_event_t     ngx_cleaner_event;
 
 ngx_uint_t             ngx_test_config;
+ngx_uint_t             ngx_quiet_mode;
 
 #if (NGX_THREADS)
 ngx_tls_key_t          ngx_core_tls_key;
@@ -63,7 +64,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     tp = ngx_timeofday();
     tp->sec = 0;
 
-    ngx_time_update(0, 0);
+    ngx_time_update();
 
 
     log = old_cycle->log;
@@ -180,6 +181,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     cycle->listening.pool = pool;
 
 
+    ngx_queue_init(&cycle->reusable_connections_queue);
+
+
     cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
     if (cycle->conf_ctx == NULL) {
         ngx_destroy_pool(pool);
@@ -204,7 +208,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         return NULL;
     }
 
-    ngx_memcpy(cycle->hostname.data, hostname, cycle->hostname.len);
+    ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
 
 
     for (i = 0; ngx_modules[i]; i++) {
@@ -266,7 +270,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         return NULL;
     }
 
-    if (ngx_test_config) {
+    if (ngx_test_config && !ngx_quiet_mode) {
         ngx_log_stderr(0, "the configuration file %s syntax is ok",
                        cycle->conf_file.data);
     }
@@ -666,6 +670,24 @@ old_shm_zone_done:
                           ngx_close_socket_n " listening socket on %V failed",
                           &ls[i].addr_text);
         }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        if (ls[i].sockaddr->sa_family == AF_UNIX) {
+            u_char  *name;
+
+            name = ls[i].addr_text.data + sizeof("unix:") - 1;
+
+            ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
+                          "deleting socket %s", name);
+
+            if (ngx_delete_file(name) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                              ngx_delete_file_n " %s failed", name);
+            }
+        }
+
+#endif
     }
 
 
@@ -835,6 +857,9 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s
 #if (NGX_HAVE_INET6)
     struct sockaddr_in6  *sin61, *sin62;
 #endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+    struct sockaddr_un   *saun1, *saun2;
+#endif
 
     if (sa1->sa_family != sa2->sa_family) {
         return NGX_DECLINED;
@@ -847,7 +872,7 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s
         sin61 = (struct sockaddr_in6 *) sa1;
         sin62 = (struct sockaddr_in6 *) sa2;
 
-        if (sin61->sin6_port != sin61->sin6_port) {
+        if (sin61->sin6_port != sin62->sin6_port) {
             return NGX_DECLINED;
         }
 
@@ -858,6 +883,21 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s
         break;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+       saun1 = (struct sockaddr_un *) sa1;
+       saun2 = (struct sockaddr_un *) sa2;
+
+       if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path,
+                      sizeof(saun1->sun_path))
+           != 0)
+       {
+           return NGX_DECLINED;
+       }
+
+       break;
+#endif
+
     default: /* AF_INET */
 
         sin1 = (struct sockaddr_in *) sa1;
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -44,6 +44,8 @@ struct ngx_cycle_s {
     ngx_connection_t         *free_connections;
     ngx_uint_t                free_connection_n;
 
+    ngx_queue_t               reusable_connections_queue;
+
     ngx_array_t               listening;
     ngx_array_t               pathes;
     ngx_list_t                open_files;
@@ -78,7 +80,7 @@ typedef struct {
 
      ngx_int_t                rlimit_nofile;
      ngx_int_t                rlimit_sigpending;
-     size_t                   rlimit_core;
+     off_t                    rlimit_core;
 
      int                      priority;
 
@@ -130,6 +132,7 @@ extern volatile ngx_cycle_t  *ngx_cycle;
 extern ngx_array_t            ngx_old_cycles;
 extern ngx_module_t           ngx_core_module;
 extern ngx_uint_t             ngx_test_config;
+extern ngx_uint_t             ngx_quiet_mode;
 #if (NGX_THREADS)
 extern ngx_tls_key_t          ngx_core_tls_key;
 #endif
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -183,7 +183,15 @@ ngx_create_full_path(u_char *dir, ngx_ui
     u_char     *p, ch;
     ngx_err_t   err;
 
-    for (p = dir + 1; *p; p++) {
+    err = 0;
+
+#if (NGX_WIN32)
+    p = dir + 3;
+#else
+    p = dir + 1;
+#endif
+
+    for ( /* void */ ; *p; p++) {
         ch = *p;
 
         if (ch != '/') {
@@ -194,7 +202,14 @@ ngx_create_full_path(u_char *dir, ngx_ui
 
         if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
             err = ngx_errno;
-            if (err != NGX_EEXIST) {
+
+            switch (err) {
+            case NGX_EEXIST:
+                err = 0;
+            case NGX_EACCES:
+                break;
+
+            default:
                 return err;
             }
         }
@@ -202,7 +217,7 @@ ngx_create_full_path(u_char *dir, ngx_ui
         *p = '/';
     }
 
-    return 0;
+    return err;
 }
 
 
@@ -576,16 +591,10 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 #if (NGX_WIN32)
 
     if (err == NGX_EEXIST) {
-        if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) {
+        err = ngx_win32_rename_file(src, to, ext->log);
 
-            if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
-                return NGX_OK;
-            }
-
-            err = ngx_errno;
-
-        } else {
-            err = 0;
+        if (err == 0) {
+            return NGX_OK;
         }
     }
 
@@ -753,10 +762,12 @@ ngx_copy_file(u_char *from, u_char *to, 
         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;
+    if (cf->time != -1) {
+        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;
@@ -814,8 +825,7 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_s
     ngx_str_t   file, buf;
     ngx_dir_t   dir;
 
-    buf.len = 0;
-    buf.data = NULL;
+    ngx_str_null(&buf);
 
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
                    "walk tree \"%V\"", tree);
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -245,7 +245,7 @@ ngx_hash_find_combined(ngx_hash_combined
 
 
 #define NGX_HASH_ELT_SIZE(name)                                               \
-    (sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *)))
+    (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
 
 ngx_int_t
 ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
@@ -257,14 +257,6 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
     ngx_hash_elt_t  *elt, **buckets;
 
     for (n = 0; n < nelts; n++) {
-        if (names[n].key.len >= 255) {
-            ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
-                          "the \"%V\" value to hash is to long: %uz bytes, "
-                          "the maximum length can be 255 bytes only",
-                          &names[n].key, names[n].key.len);
-            return NGX_ERROR;
-        }
-
         if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
         {
             ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
@@ -406,7 +398,7 @@ found:
         elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
 
         elt->value = names[n].value;
-        elt->len = (u_char) names[n].key.len;
+        elt->len = (u_short) names[n].key.len;
 
         ngx_strlow(elt->name, names[n].key.data, names[n].key.len);
 
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -14,7 +14,7 @@
 
 typedef struct {
     void             *value;
-    u_char            len;
+    u_short           len;
     u_char            name[1];
 } ngx_hash_elt_t;
 
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -8,9 +8,6 @@
 #include <ngx_core.h>
 
 
-#if (NGX_HAVE_INET6)
-static size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
-#endif
 static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
 static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
 static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u);
@@ -59,6 +56,126 @@ ngx_inet_addr(u_char *text, size_t len)
 }
 
 
+#if (NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
+{
+    u_char      c, *zero, *digit, *s, *d;
+    size_t      len4;
+    ngx_uint_t  n, nibbles, word;
+
+    if (len == 0) {
+        return NGX_ERROR;
+    }
+
+    zero = NULL;
+    digit = NULL;
+    len4 = 0;
+    nibbles = 0;
+    word = 0;
+    n = 8;
+
+    if (p[0] == ':') {
+        p++;
+        len--;
+    }
+
+    for (/* void */; len; len--) {
+        c = *p++;
+
+        if (c == ':') {
+            if (nibbles) {
+                digit = p;
+                len4 = len;
+                *addr++ = (u_char) (word >> 8);
+                *addr++ = (u_char) (word & 0xff);
+
+                if (--n) {
+                    nibbles = 0;
+                    word = 0;
+                    continue;
+                }
+
+            } else {
+                if (zero == NULL) {
+                    digit = p;
+                    len4 = len;
+                    zero = addr;
+                    continue;
+                }
+            }
+
+            return NGX_ERROR;
+        }
+
+        if (c == '.' && nibbles) {
+            if (n < 2) {
+                return NGX_ERROR;
+            }
+
+            word = ngx_inet_addr(digit, len4 - 1);
+            if (word == INADDR_NONE) {
+                return NGX_ERROR;
+            }
+
+            word = ntohl(word);
+            *addr++ = (u_char) ((word >> 24) & 0xff);
+            *addr++ = (u_char) ((word >> 16) & 0xff);
+            n--;
+            break;
+        }
+
+        if (++nibbles > 4) {
+            return NGX_ERROR;
+        }
+
+        if (c >= '0' && c <= '9') {
+            word = word * 16 + (c - '0');
+            continue;
+        }
+
+        c |= 0x20;
+
+        if (c >= 'a' && c <= 'f') {
+            word = word * 16 + (c - 'a') + 10;
+            continue;
+        }
+
+        return NGX_ERROR;
+    }
+
+    if (nibbles == 0 && zero == NULL) {
+        return NGX_ERROR;
+    }
+
+    *addr++ = (u_char) (word >> 8);
+    *addr++ = (u_char) (word & 0xff);
+
+    if (--n) {
+        if (zero) {
+            n *= 2;
+            s = addr - 1;
+            d = s + n;
+            while (s >= zero) {
+                *d-- = *s--;
+            }
+            ngx_memzero(zero, n);
+            return NGX_OK;
+        }
+
+    } else {
+        if (zero == NULL) {
+            return NGX_OK;
+        }
+    }
+
+    return NGX_ERROR;
+}
+
+#endif
+
+
 size_t
 ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
 {
@@ -68,6 +185,9 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha
     size_t                n;
     struct sockaddr_in6  *sin6;
 #endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+    struct sockaddr_un   *saun;
+#endif
 
     switch (sa->sa_family) {
 
@@ -98,7 +218,7 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha
             text[n++] = '[';
         }
 
-        n = ngx_inet6_ntop((u_char *) &sin6->sin6_addr, &text[n], len);
+        n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len);
 
         if (port) {
             n = ngx_sprintf(&text[1 + n], "]:%d",
@@ -108,6 +228,17 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha
         return n;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+    case AF_UNIX:
+        saun = (struct sockaddr_un *) sa;
+
+        /* we do not include trailing zero in address length */
+
+        return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1;
+
+#endif
+
     default:
         return 0;
     }
@@ -144,7 +275,7 @@ ngx_inet_ntop(int family, void *addr, u_
 
 #if (NGX_HAVE_INET6)
 
-static size_t
+size_t
 ngx_inet6_ntop(u_char *p, u_char *text, size_t len)
 {
     u_char      *dst;
@@ -223,31 +354,47 @@ ngx_inet6_ntop(u_char *p, u_char *text, 
 #endif
 
 
-/* AF_INET only */
-
 ngx_int_t
 ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
 {
-    u_char     *addr, *mask, *last;
-    ngx_int_t   shift;
+    u_char      *addr, *mask, *last;
+    size_t       len;
+    ngx_int_t    shift;
+#if (NGX_HAVE_INET6)
+    ngx_int_t    rc;
+    ngx_uint_t   s, i;
+#endif
 
     addr = text->data;
     last = addr + text->len;
 
     mask = ngx_strlchr(addr, last, '/');
+    len = (mask ? mask : last) - addr;
 
-    cidr->u.in.addr = ngx_inet_addr(addr, (mask ? mask : last) - addr);
+    cidr->u.in.addr = ngx_inet_addr(addr, len);
+
+    if (cidr->u.in.addr != INADDR_NONE) {
+        cidr->family = AF_INET;
+
+        if (mask == NULL) {
+            cidr->u.in.mask = 0xffffffff;
+            return NGX_OK;
+        }
 
-    if (cidr->u.in.addr == INADDR_NONE) {
+#if (NGX_HAVE_INET6)
+    } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) {
+        cidr->family = AF_INET6;
+
+        if (mask == NULL) {
+            ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16);
+            return NGX_OK;
+        }
+
+#endif
+    } else {
         return NGX_ERROR;
     }
 
-    if (mask == NULL) {
-        cidr->family = AF_INET;
-        cidr->u.in.mask = 0xffffffff;
-        return NGX_OK;
-    }
-
     mask++;
 
     shift = ngx_atoi(mask, last - mask);
@@ -255,30 +402,108 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t 
         return NGX_ERROR;
     }
 
-    cidr->family = AF_INET;
+    switch (cidr->family) {
 
-    if (shift == 0) {
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        addr = cidr->u.in6.addr.s6_addr;
+        mask = cidr->u.in6.mask.s6_addr;
+        rc = NGX_OK;
+
+        for (i = 0; i < 16; i++) {
+
+            s = (shift > 8) ? 8 : shift;
+            shift -= s;
+
+            mask[i] = (u_char) (0 - (1 << (8 - s)));
 
-        /* the x86 compilers use the shl instruction that shifts by modulo 32 */
+            if (addr[i] != (addr[i] & mask[i])) {
+                rc = NGX_DONE;
+                addr[i] &= mask[i];
+            }
+        }
+
+        return rc;
+#endif
 
-        cidr->u.in.mask = 0;
+    default: /* AF_INET */
+
+        if (shift) {
+            cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
 
-        if (cidr->u.in.addr == 0) {
+        } else {
+            /* x86 compilers use a shl instruction that shifts by modulo 32 */
+            cidr->u.in.mask = 0;
+        }
+
+        if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
             return NGX_OK;
         }
 
+        cidr->u.in.addr &= cidr->u.in.mask;
+
         return NGX_DONE;
     }
+}
+
+
+ngx_int_t
+ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len)
+{
+    in_addr_t             inaddr;
+    ngx_uint_t            family;
+    struct sockaddr_in   *sin;
+#if (NGX_HAVE_INET6)
+    struct in6_addr       inaddr6;
+    struct sockaddr_in6  *sin6;
+
+    /*
+     * prevent MSVC8 waring:
+     *    potentially uninitialized local variable 'inaddr6' used
+     */
+    ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr));
+#endif
+
+    inaddr = ngx_inet_addr(text, len);
+
+    if (inaddr != INADDR_NONE) {
+        family = AF_INET;
+        len = sizeof(struct sockaddr_in);
+
+#if (NGX_HAVE_INET6)
+    } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) {
+        family = AF_INET6;
+        len = sizeof(struct sockaddr_in6);
+
+#endif
+    } else {
+        return NGX_DECLINED;
+    }
 
-    cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
-
-    if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
-        return NGX_OK;
+    addr->sockaddr = ngx_pcalloc(pool, len);
+    if (addr->sockaddr == NULL) {
+        return NGX_ERROR;
     }
 
-    cidr->u.in.addr &= cidr->u.in.mask;
+    addr->sockaddr->sa_family = (u_char) family;
+    addr->socklen = len;
+
+    switch (family) {
 
-    return NGX_DONE;
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *) addr->sockaddr;
+        ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
+        break;
+#endif
+
+    default: /* AF_INET */
+        sin = (struct sockaddr_in *) addr->sockaddr;
+        sin->sin_addr.s_addr = inaddr;
+        break;
+    }
+
+    return NGX_OK;
 }
 
 
@@ -351,7 +576,7 @@ ngx_parse_unix_domain_url(ngx_pool_t *po
     saun->sun_family = AF_UNIX;
     (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
 
-    u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
+    u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
     if (u->addrs == NULL) {
         return NGX_ERROR;
     }
@@ -509,22 +734,22 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
         return NGX_OK;
     }
 
-    if (len++) {
-
-        p = ngx_alloc(len, pool->log);
-        if (p == NULL) {
-            return NGX_ERROR;
-        }
-
-        (void) ngx_cpystrn(p, host, len);
-
-        sin->sin_addr.s_addr = inet_addr((const char *) p);
+    if (len) {
+        sin->sin_addr.s_addr = ngx_inet_addr(host, len);
 
         if (sin->sin_addr.s_addr == INADDR_NONE) {
+            p = ngx_alloc(++len, pool->log);
+            if (p == NULL) {
+                return NGX_ERROR;
+            }
+
+            (void) ngx_cpystrn(p, host, len);
+
             h = gethostbyname((const char *) p);
 
+            ngx_free(p);
+
             if (h == NULL || h->h_addr_list[0] == NULL) {
-                ngx_free(p);
                 u->err = "host not found";
                 return NGX_ERROR;
             }
@@ -536,8 +761,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
             u->wildcard = 1;
         }
 
-        ngx_free(p);
-
     } else {
         sin->sin_addr.s_addr = INADDR_ANY;
         u->wildcard = 1;
@@ -564,7 +787,6 @@ static ngx_int_t
 ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
 {
 #if (NGX_HAVE_INET6)
-    int                   rc;
     u_char               *p, *host, *port, *last, *uri;
     size_t                len;
     ngx_int_t             n;
@@ -636,35 +858,10 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng
         return NGX_ERROR;
     }
 
-    u->host.len = len++;
+    u->host.len = len;
     u->host.data = host;
 
-    p = ngx_alloc(len, pool->log);
-    if (p == NULL) {
-        return NGX_ERROR;
-    }
-
-    (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) {
+    if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
         u->err = "invalid IPv6 address";
         return NGX_ERROR;
     }
@@ -707,20 +904,20 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
     struct hostent      *h;
     struct sockaddr_in  *sin;
 
-    host = ngx_alloc(u->host.len + 1, pool->log);
-    if (host == NULL) {
-        return NGX_ERROR;
-    }
-
-    (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
-
     /* AF_INET only */
 
     port = htons(u->port);
 
-    in_addr = inet_addr((char *) host);
+    in_addr = ngx_inet_addr(u->host.data, u->host.len);
 
     if (in_addr == INADDR_NONE) {
+        host = ngx_alloc(u->host.len + 1, pool->log);
+        if (host == NULL) {
+            return NGX_ERROR;
+        }
+
+        (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
         h = gethostbyname((char *) host);
 
         ngx_free(host);
@@ -739,14 +936,14 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
 
         /* MP: ngx_shared_palloc() */
 
-        u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_peer_addr_t));
+        u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
         if (u->addrs == NULL) {
             return NGX_ERROR;
         }
 
         u->naddrs = i;
 
-        for (i = 0; h->h_addr_list[i] != NULL; i++) {
+        for (i = 0; i < u->naddrs; i++) {
 
             sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
             if (sin == NULL) {
@@ -775,11 +972,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
 
     } else {
 
-        ngx_free(host);
-
         /* MP: ngx_shared_palloc() */
 
-        u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
+        u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
         if (u->addrs == NULL) {
             return NGX_ERROR;
         }
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -12,21 +12,26 @@
 #include <ngx_core.h>
 
 
-#define NGX_INET_ADDRSTRLEN   (sizeof("255.255.255.255") - 1)
-#define NGX_INET6_ADDRSTRLEN                                                 \
-    (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
-
-#define NGX_SOCKADDR_STRLEN   (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1)
-
-
 /*
- * TODO: autoconfigure NGX_SOCKADDRLEN as
+ * TODO: autoconfigure NGX_SOCKADDRLEN and NGX_SOCKADDR_STRLEN as
  *       sizeof(struct sockaddr_storage)
  *       sizeof(struct sockaddr_un)
  *       sizeof(struct sockaddr_in6)
  *       sizeof(struct sockaddr_in)
  */
 
+#define NGX_INET_ADDRSTRLEN   (sizeof("255.255.255.255") - 1)
+#define NGX_INET6_ADDRSTRLEN                                                 \
+    (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
+#define NGX_UNIX_ADDRSTRLEN                                                  \
+    (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+#define NGX_SOCKADDR_STRLEN   (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN)
+#else
+#define NGX_SOCKADDR_STRLEN   (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1)
+#endif
+
 #if (NGX_HAVE_UNIX_DOMAIN)
 #define NGX_SOCKADDRLEN       sizeof(struct sockaddr_un)
 #else
@@ -65,7 +70,7 @@ typedef struct {
     struct sockaddr          *sockaddr;
     socklen_t                 socklen;
     ngx_str_t                 name;
-} ngx_peer_addr_t;
+} ngx_addr_t;
 
 
 typedef struct {
@@ -89,7 +94,7 @@ typedef struct {
     socklen_t                 socklen;
     u_char                    sockaddr[NGX_SOCKADDRLEN];
 
-    ngx_peer_addr_t          *addrs;
+    ngx_addr_t               *addrs;
     ngx_uint_t                naddrs;
 
     char                     *err;
@@ -97,13 +102,18 @@ typedef struct {
 
 
 in_addr_t ngx_inet_addr(u_char *text, size_t len);
+#if (NGX_HAVE_INET6)
+ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr);
+size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
+#endif
 size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len,
     ngx_uint_t port);
 size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
 ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr);
+ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
+    size_t len);
 ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u);
 ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u);
 
 
-
 #endif /* _NGX_INET_H_INCLUDED_ */
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -148,9 +148,9 @@ ngx_log_error_core(ngx_uint_t level, ngx
         return;
     }
 
-    msg -= (err_levels[level].len + 4);
+    msg -= (7 + err_levels[level].len + 3);
 
-    (void) ngx_sprintf(msg, "[%V]: ", &err_levels[level]);
+    (void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);
 
     (void) ngx_write_console(ngx_stderr, msg, p - msg);
 }
@@ -209,9 +209,12 @@ ngx_log_stderr(ngx_err_t err, const char
     u_char    errstr[NGX_MAX_ERROR_STR];
 
     last = errstr + NGX_MAX_ERROR_STR;
+    p = errstr + 7;
+
+    ngx_memcpy(errstr, "nginx: ", 7);
 
     va_start(args, fmt);
-    p = ngx_vslprintf(errstr, last, fmt, args);
+    p = ngx_vslprintf(p, last, fmt, args);
     va_end(args);
 
     if (err) {
@@ -248,7 +251,7 @@ ngx_log_errno(u_char *buf, u_char *last,
     buf = ngx_slprintf(buf, last, " (%d: ", err);
 #endif
 
-    buf = ngx_strerror_r(err, buf, last - buf);
+    buf = ngx_strerror(err, buf, last - buf);
 
     if (buf < last) {
         *buf++ = ')';
@@ -325,7 +328,7 @@ ngx_log_init(u_char *prefix)
 
     if (ngx_log_file.fd == NGX_INVALID_FILE) {
         ngx_log_stderr(ngx_errno,
-                       "[alert]: could not open error log file: "
+                       "[alert] could not open error log file: "
                        ngx_open_file_n " \"%s\" failed", name);
 #if (NGX_WIN32)
         ngx_event_log(ngx_errno,
@@ -429,8 +432,7 @@ ngx_error_log(ngx_conf_t *cf, ngx_comman
     value = cf->args->elts;
 
     if (ngx_strcmp(value[1].data, "stderr") == 0) {
-        name.len = 0;
-        name.data = NULL;
+        ngx_str_null(&name);
 
     } else {
         name = value[1];
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -68,7 +68,23 @@ struct ngx_log_s {
 
 /*********************************/
 
-#if (NGX_HAVE_GCC_VARIADIC_MACROS)
+#if (NGX_HAVE_C99_VARIADIC_MACROS)
+
+#define NGX_HAVE_VARIADIC_MACROS  1
+
+#define ngx_log_error(level, log, ...)                                        \
+    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
+
+void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+    const char *fmt, ...);
+
+#define ngx_log_debug(level, log, ...)                                        \
+    if ((log)->log_level & level)                                             \
+        ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__)
+
+/*********************************/
+
+#elif (NGX_HAVE_GCC_VARIADIC_MACROS)
 
 #define NGX_HAVE_VARIADIC_MACROS  1
 
@@ -84,22 +100,6 @@ void ngx_log_error_core(ngx_uint_t level
 
 /*********************************/
 
-#elif (NGX_HAVE_C99_VARIADIC_MACROS)
-
-#define NGX_HAVE_VARIADIC_MACROS  1
-
-#define ngx_log_error(level, log, ...)                                        \
-    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
-
-void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
-    const char *fmt, ...);
-
-#define ngx_log_debug(level, log, ...)                                        \
-    if ((log)->log_level & level)                                             \
-        ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__)
-
-/*********************************/
-
 #else /* NO VARIADIC MACROS */
 
 #define NGX_HAVE_VARIADIC_MACROS  0
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -17,6 +17,9 @@
  */
 
 
+#define NGX_MIN_READ_AHEAD  (128 * 1024)
+
+
 static void ngx_open_file_cache_cleanup(void *data);
 static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
     ngx_log_t *log);
@@ -487,7 +490,14 @@ ngx_open_and_stat_file(u_char *name, ngx
     }
 
     if (!of->log) {
-        fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+
+        /*
+         * Use non-blocking open() not to hang on FIFO files, etc.
+         * This flag has no effect on a regular files.
+         */
+
+        fd = ngx_open_file(name, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
+                           NGX_FILE_OPEN, 0);
 
     } else {
         fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
@@ -524,8 +534,15 @@ ngx_open_and_stat_file(u_char *name, ngx
     } else {
         of->fd = fd;
 
+        if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) {
+            if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) {
+                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                              ngx_read_ahead_n " \"%s\" failed", name);
+            }
+        }
+
         if (of->directio <= ngx_file_size(&fi)) {
-            if (ngx_directio_on(fd) == -1) {
+            if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                               ngx_directio_on_n " \"%s\" failed", name);
 
--- a/src/core/ngx_open_file_cache.h
+++ b/src/core/ngx_open_file_cache.h
@@ -21,6 +21,7 @@ typedef struct {
     time_t                   mtime;
     off_t                    size;
     off_t                    directio;
+    size_t                   read_ahead;
 
     ngx_err_t                err;
     char                    *failed;
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -74,18 +74,18 @@ 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;
 
     for ( ;; ) {
 
+#if (NGX_HAVE_FILE_AIO)
+        if (ctx->aio) {
+            return NGX_AGAIN;
+        }
+#endif
+
         while (ctx->in) {
 
             /*
@@ -465,10 +465,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
     dst = ctx->buf;
 
     size = ngx_buf_size(src);
-
-    if (size > dst->end - dst->pos) {
-        size = dst->end - dst->pos;
-    }
+    size = ngx_min(size, dst->end - dst->pos);
 
     sendfile = ctx->sendfile & !ctx->directio;
 
@@ -514,7 +511,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
 #if (NGX_HAVE_ALIGNED_DIRECTIO)
 
         if (ctx->unaligned) {
-            if (ngx_directio_off(src->file->fd) == -1) {
+            if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
                               ngx_directio_off_n " \"%s\" failed",
                               src->file->name.data);
@@ -550,7 +547,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
 
             err = ngx_errno;
 
-            if (ngx_directio_on(src->file->fd) == -1) {
+            if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
                               ngx_directio_on_n " \"%s\" failed",
                               src->file->name.data);
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -17,7 +17,7 @@ ngx_create_pool(size_t size, ngx_log_t *
 {
     ngx_pool_t  *p;
 
-    p = ngx_alloc(size, log);
+    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
     if (p == NULL) {
         return NULL;
     }
@@ -181,7 +181,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_
 
     psize = (size_t) (pool->d.end - (u_char *) pool);
 
-    m = ngx_alloc(psize, pool->log);
+    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
     if (m == NULL) {
         return NULL;
     }
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -19,8 +19,11 @@
 #define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)
 
 #define NGX_DEFAULT_POOL_SIZE    (16 * 1024)
+
+#define NGX_POOL_ALIGNMENT       16
 #define NGX_MIN_POOL_SIZE                                                     \
-    (sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t))
+    ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \
+              NGX_POOL_ALIGNMENT)
 
 
 typedef void (*ngx_pool_cleanup_pt)(void *data);
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -23,61 +23,116 @@ ngx_regex_init(void)
 }
 
 
-ngx_regex_t *
-ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, ngx_pool_t *pool,
-    ngx_str_t *err)
+static ngx_inline void
+ngx_regex_malloc_init(ngx_pool_t *pool)
 {
-    int              erroff;
-    const char      *errstr;
-    ngx_regex_t     *re;
 #if (NGX_THREADS)
     ngx_core_tls_t  *tls;
 
-#if (NGX_SUPPRESS_WARN)
-    tls = NULL;
-#endif
-
     if (ngx_threaded) {
         tls = ngx_thread_get_tls(ngx_core_tls_key);
         tls->pool = pool;
-    } else {
-        ngx_pcre_pool = pool;
+        return;
     }
 
-#else
+#endif
 
     ngx_pcre_pool = pool;
+}
+
+
+static ngx_inline void
+ngx_regex_malloc_done(void)
+{
+#if (NGX_THREADS)
+    ngx_core_tls_t  *tls;
+
+    if (ngx_threaded) {
+        tls = ngx_thread_get_tls(ngx_core_tls_key);
+        tls->pool = NULL;
+        return;
+    }
 
 #endif
 
-    re = pcre_compile((const char *) pattern->data, (int) options,
+    ngx_pcre_pool = NULL;
+}
+
+
+ngx_int_t
+ngx_regex_compile(ngx_regex_compile_t *rc)
+{
+    int           n, erroff;
+    char         *p;
+    const char   *errstr;
+    ngx_regex_t  *re;
+
+    ngx_regex_malloc_init(rc->pool);
+
+    re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
                       &errstr, &erroff, NULL);
 
+    /* ensure that there is no current pool */
+    ngx_regex_malloc_done();
+
     if (re == NULL) {
-       if ((size_t) erroff == pattern->len) {
-           ngx_snprintf(err->data, err->len - 1,
-                        "pcre_compile() failed: %s in \"%s\"%Z",
-                        errstr, pattern->data);
+        if ((size_t) erroff == rc->pattern.len) {
+           rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                              "pcre_compile() failed: %s in \"%V\"",
+                               errstr, &rc->pattern)
+                      - rc->err.data;
+
         } else {
-           ngx_snprintf(err->data, err->len - 1,
-                        "pcre_compile() failed: %s in \"%s\" at \"%s\"%Z",
-                        errstr, pattern->data, pattern->data + erroff);
+           rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                              "pcre_compile() failed: %s in \"%V\" at \"%s\"",
+                               errstr, &rc->pattern, rc->pattern.data + erroff)
+                      - rc->err.data;
         }
+
+        return NGX_ERROR;
+    }
+
+    rc->regex = re;
+
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
+        goto failed;
+    }
+
+    if (rc->captures == 0) {
+        return NGX_OK;
     }
 
-    /* ensure that there is no current pool */
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d";
+        goto failed;
+    }
+
+    if (rc->named_captures == 0) {
+        return NGX_OK;
+    }
 
-#if (NGX_THREADS)
-    if (ngx_threaded) {
-        tls->pool = NULL;
-    } else {
-        ngx_pcre_pool = NULL;
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d";
+        goto failed;
     }
-#else
-    ngx_pcre_pool = NULL;
-#endif
+
+    n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names);
+    if (n < 0) {
+        p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d";
+        goto failed;
+    }
 
-    return re;
+    return NGX_OK;
+
+failed:
+
+    rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
+                  - rc->err.data;
+    return NGX_OK;
 }
 
 
@@ -99,22 +154,6 @@ ngx_regex_capture_count(ngx_regex_t *re)
 
 
 ngx_int_t
-ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_int_t size)
-{
-    int  rc;
-
-    rc = pcre_exec(re, NULL, (const char *) s->data, s->len, 0, 0,
-                   captures, size);
-
-    if (rc == -1) {
-        return NGX_REGEX_NO_MATCHED;
-    }
-
-    return rc;
-}
-
-
-ngx_int_t
 ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
 {
     ngx_int_t         n;
@@ -133,7 +172,7 @@ ngx_regex_exec_array(ngx_array_t *a, ngx
 
         if (n < 0) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
-                          ngx_regex_exec_n " failed: %d on \"%V\" using \"%s\"",
+                          ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"",
                           n, s, re[i].name);
             return NGX_ERROR;
         }
@@ -157,11 +196,15 @@ ngx_regex_malloc(size_t size)
     if (ngx_threaded) {
         tls = ngx_thread_get_tls(ngx_core_tls_key);
         pool = tls->pool;
+
     } else {
         pool = ngx_pcre_pool;
     }
+
 #else
+
     pool = ngx_pcre_pool;
+
 #endif
 
     if (pool) {
--- a/src/core/ngx_regex.h
+++ b/src/core/ngx_regex.h
@@ -14,29 +14,42 @@
 #include <pcre.h>
 
 
-#define NGX_REGEX_NO_MATCHED  -1000
+#define NGX_REGEX_NO_MATCHED  PCRE_ERROR_NOMATCH   /* -1 */
 
 #define NGX_REGEX_CASELESS    PCRE_CASELESS
 
 typedef pcre  ngx_regex_t;
 
+
 typedef struct {
-    ngx_regex_t   *regex;
-    u_char        *name;
+    ngx_str_t     pattern;
+    ngx_pool_t   *pool;
+    ngx_int_t     options;
+
+    ngx_regex_t  *regex;
+    int           captures;
+    int           named_captures;
+    int           name_size;
+    u_char       *names;
+    ngx_str_t     err;
+} ngx_regex_compile_t;
+
+
+typedef struct {
+    ngx_regex_t  *regex;
+    u_char       *name;
 } ngx_regex_elt_t;
 
 
 void ngx_regex_init(void);
-ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options,
-    ngx_pool_t *pool, ngx_str_t *err);
-ngx_int_t ngx_regex_capture_count(ngx_regex_t *re);
-ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures,
-    ngx_int_t size);
+ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc);
+
+#define ngx_regex_exec(re, s, captures, size)                                \
+    pcre_exec(re, NULL, (const char *) (s)->data, (s)->len, 0, 0,            \
+              captures, size)
+#define ngx_regex_exec_n      "pcre_exec()"
+
 ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
 
 
-#define ngx_regex_exec_n           "pcre_exec()"
-#define ngx_regex_capture_count_n  "pcre_fullinfo()"
-
-
 #endif /* _NGX_REGEX_H_INCLUDED_ */
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -87,12 +87,11 @@ static void *ngx_resolver_calloc(ngx_res
 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
-
-
-/* STUB: ngx_peer_addr_t * */
+static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
+
 
 ngx_resolver_t *
-ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr)
+ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr)
 {
     ngx_resolver_t        *r;
     ngx_pool_cleanup_t    *cln;
@@ -139,7 +138,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_
     r->valid = 300;
 
     r->log = &cf->cycle->new_log;
-    r->log_level = NGX_LOG_ALERT;
+    r->log_level = NGX_LOG_ERR;
 
     if (addr) {
         uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log);
@@ -152,7 +151,11 @@ 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;
+        uc->log.handler = ngx_resolver_log_error;
+        uc->log.data = uc;
+        uc->log.action = "resolving";
     }
 
     return r;
@@ -464,6 +467,7 @@ ngx_resolve_name_locked(ngx_resolver_t *
 
             ctx->next = rn->waiting;
             rn->waiting = ctx;
+            ctx->state = NGX_AGAIN;
 
             return NGX_AGAIN;
         }
@@ -625,6 +629,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx
 
             ctx->next = rn->waiting;
             rn->waiting = ctx;
+            ctx->state = NGX_AGAIN;
 
             /* unlock addr mutex */
 
@@ -840,7 +845,7 @@ ngx_resolver_send_query(ngx_resolver_t *
     }
 
     if ((size_t) n != (size_t) rn->qlen) {
-        ngx_log_error(NGX_LOG_CRIT, uc->log, 0, "send() incomplete");
+        ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
         return NGX_ERROR;
     }
 
@@ -1717,15 +1722,16 @@ static ngx_int_t
 ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
 {
     u_char                *p, *s;
-    size_t                 len;
+    size_t                 len, nlen;
     ngx_uint_t             ident;
     ngx_resolver_qs_t     *qs;
     ngx_resolver_query_t  *query;
 
-    len = sizeof(ngx_resolver_query_t)
-          + 1 + ctx->name.len + 1 + sizeof(ngx_resolver_qs_t);
-
-    p = ngx_resolver_calloc(ctx->resolver, len);
+    nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
+
+    len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t);
+
+    p = ngx_resolver_alloc(ctx->resolver, len);
     if (p == NULL) {
         return NGX_ERROR;
     }
@@ -1752,7 +1758,7 @@ ngx_resolver_create_name_query(ngx_resol
     query->nns_hi = 0; query->nns_lo = 0;
     query->nar_hi = 0; query->nar_lo = 0;
 
-    p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1;
+    p += sizeof(ngx_resolver_query_t) + nlen;
 
     qs = (ngx_resolver_qs_t *) p;
 
@@ -1806,7 +1812,7 @@ ngx_resolver_create_addr_query(ngx_resol
           + sizeof(".255.255.255.255.in-addr.arpa.") - 1
           + sizeof(ngx_resolver_qs_t);
 
-    p = ngx_resolver_calloc(ctx->resolver, len);
+    p = ngx_resolver_alloc(ctx->resolver, len);
     if (p == NULL) {
         return NGX_ERROR;
     }
@@ -1830,7 +1836,7 @@ ngx_resolver_create_addr_query(ngx_resol
 
     p += sizeof(ngx_resolver_query_t);
 
-    for (n = 0; n < 32; n += 8){
+    for (n = 0; n < 32; n += 8) {
         d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
         *p = (u_char) (d - &p[1]);
         p = d;
@@ -1900,6 +1906,12 @@ done:
         return NGX_OK;
     }
 
+    if (len == -1) {
+        name->len = 0;
+        name->data = NULL;
+        return NGX_OK;
+    }
+
     dst = ngx_resolver_alloc(r, len);
     if (dst == NULL) {
         return NGX_ERROR;
@@ -2064,6 +2076,29 @@ ngx_resolver_strerror(ngx_int_t err)
 }
 
 
+static u_char *
+ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
+{
+    u_char                *p;
+    ngx_udp_connection_t  *uc;
+
+    p = buf;
+
+    if (log->action) {
+        p = ngx_snprintf(buf, len, " while %s", log->action);
+        len -= p - buf;
+    }
+
+    uc = log->data;
+
+    if (uc) {
+        p = ngx_snprintf(p, len, ", resolver: %V", &uc->server);
+    }
+
+    return p;
+}
+
+
 ngx_int_t
 ngx_udp_connect(ngx_udp_connection_t *uc)
 {
@@ -2075,19 +2110,19 @@ ngx_udp_connect(ngx_udp_connection_t *uc
 
     s = ngx_socket(AF_INET, SOCK_DGRAM, 0);
 
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, uc->log, 0, "UDP socket %d", s);
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s);
 
     if (s == -1) {
-        ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
                       ngx_socket_n " failed");
         return NGX_ERROR;
     }
 
-    c = ngx_get_connection(s, uc->log);
+    c = ngx_get_connection(s, &uc->log);
 
     if (c == NULL) {
         if (ngx_close_socket(s) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
+            ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
                           ngx_close_socket_n "failed");
         }
 
@@ -2095,13 +2130,13 @@ ngx_udp_connect(ngx_udp_connection_t *uc
     }
 
     if (ngx_nonblocking(s) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
                       ngx_nonblocking_n " failed");
 
         ngx_free_connection(c);
 
         if (ngx_close_socket(s) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
+            ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
                           ngx_close_socket_n " failed");
         }
 
@@ -2111,8 +2146,8 @@ ngx_udp_connect(ngx_udp_connection_t *uc
     rev = c->read;
     wev = c->write;
 
-    rev->log = uc->log;
-    wev->log = uc->log;
+    rev->log = &uc->log;
+    wev->log = &uc->log;
 
     uc->connection = c;
 
@@ -2129,7 +2164,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc
 
 #endif
 
-    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, uc->log, 0,
+    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0,
                    "connect to %V, fd:%d #%d", &uc->server, s, c->number);
 
     rc = connect(s, uc->sockaddr, uc->socklen);
@@ -2137,8 +2172,8 @@ ngx_udp_connect(ngx_udp_connection_t *uc
     /* TODO: aio, iocp */
 
     if (rc == -1) {
-        ngx_log_error(NGX_LOG_CRIT, uc->log, ngx_socket_errno,
-                      "connect() to %V failed", &uc->server);
+        ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
+                      "connect() failed");
 
         return NGX_ERROR;
     }
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -37,7 +37,7 @@ typedef struct {
     struct sockaddr          *sockaddr;
     socklen_t                 socklen;
     ngx_str_t                 server;
-    ngx_log_t                *log;
+    ngx_log_t                 log;
 } ngx_udp_connection_t;
 
 
@@ -135,7 +135,7 @@ struct ngx_resolver_ctx_s {
 };
 
 
-ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr);
+ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr);
 ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
     ngx_resolver_ctx_t *temp);
 ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -10,15 +10,18 @@
 
 static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
     u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
+static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
+    const u_char *basis);
 
 
 void
 ngx_strlow(u_char *dst, u_char *src, size_t n)
 {
-    while (n--) {
+    while (n) {
         *dst = ngx_tolower(*src);
         dst++;
         src++;
+        n--;
     }
 }
 
@@ -74,7 +77,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t 
  *    %[0][width][u][x|X]D      int32_t/uint32_t
  *    %[0][width][u][x|X]L      int64_t/uint64_t
  *    %[0][width|m][u][x|X]A    ngx_atomic_int_t/ngx_atomic_uint_t
- *    %[0][width][.width]f      float
+ *    %[0][width][.width]f      double, max valid number fits to %18.15f
  *    %P                        ngx_pid_t
  *    %M                        ngx_msec_t
  *    %r                        rlim_t
@@ -142,12 +145,12 @@ ngx_vslprintf(u_char *buf, u_char *last,
 {
     u_char                *p, zero;
     int                    d;
-    float                  f, scale;
+    double                 f, scale;
     size_t                 len, slen;
     int64_t                i64;
     uint64_t               ui64;
     ngx_msec_t             ms;
-    ngx_uint_t             width, sign, hex, max_width, frac_width, i;
+    ngx_uint_t             width, sign, hex, max_width, frac_width, n;
     ngx_str_t             *v;
     ngx_variable_value_t  *vv;
 
@@ -228,9 +231,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
             case 'V':
                 v = va_arg(args, ngx_str_t *);
 
-                len = v->len;
-                len = (buf + len < last) ? len : (size_t) (last - buf);
-
+                len = ngx_min(((size_t) (last - buf)), v->len);
                 buf = ngx_cpymem(buf, v->data, len);
                 fmt++;
 
@@ -239,9 +240,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
             case 'v':
                 vv = va_arg(args, ngx_variable_value_t *);
 
-                len = vv->len;
-                len = (buf + len < last) ? len : (size_t) (last - buf);
-
+                len = ngx_min(((size_t) (last - buf)), vv->len);
                 buf = ngx_cpymem(buf, vv->data, len);
                 fmt++;
 
@@ -256,8 +255,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
                     }
 
                 } else {
-                    len = (buf + slen < last) ? slen : (size_t) (last - buf);
-
+                    len = ngx_min(((size_t) (last - buf)), slen);
                     buf = ngx_cpymem(buf, p, len);
                 }
 
@@ -358,7 +356,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
                 break;
 
             case 'f':
-                f = (float) va_arg(args, double);
+                f = va_arg(args, double);
 
                 if (f < 0) {
                     *buf++ = '-';
@@ -377,7 +375,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
 
                     scale = 1.0;
 
-                    for (i = 0; i < frac_width; i++) {
+                    for (n = frac_width; n; n--) {
                         scale *= 10.0;
                     }
 
@@ -385,7 +383,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
                      * (int64_t) cast is required for msvc6:
                      * it can not convert uint64_t to double
                      */
-                    ui64 = (uint64_t) ((f - (int64_t) ui64) * scale);
+                    ui64 = (uint64_t) ((f - (int64_t) ui64) * scale + 0.5);
 
                     buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
                 }
@@ -876,6 +874,56 @@ ngx_atoi(u_char *line, size_t n)
 }
 
 
+/* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
+
+ngx_int_t
+ngx_atofp(u_char *line, size_t n, size_t point)
+{
+    ngx_int_t   value;
+    ngx_uint_t  dot;
+
+    if (n == 0) {
+        return NGX_ERROR;
+    }
+
+    dot = 0;
+
+    for (value = 0; n--; line++) {
+
+        if (point == 0) {
+            return NGX_ERROR;
+        }
+
+        if (*line == '.') {
+            if (dot) {
+                return NGX_ERROR;
+            }
+
+            dot = 1;
+            continue;
+        }
+
+        if (*line < '0' || *line > '9') {
+            return NGX_ERROR;
+        }
+
+        value = value * 10 + (*line - '0');
+        point -= dot;
+    }
+
+    while (point--) {
+        value = value * 10;
+    }
+
+    if (value < 0) {
+        return NGX_ERROR;
+
+    } else {
+        return value;
+    }
+}
+
+
 ssize_t
 ngx_atosz(u_char *line, size_t n)
 {
@@ -1049,8 +1097,6 @@ ngx_encode_base64(ngx_str_t *dst, ngx_st
 ngx_int_t
 ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
 {
-    size_t          len;
-    u_char         *d, *s;
     static u_char   basis64[] = {
         77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
         77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
@@ -1071,12 +1117,49 @@ ngx_decode_base64(ngx_str_t *dst, ngx_st
         77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
     };
 
+    return ngx_decode_base64_internal(dst, src, basis64);
+}
+
+
+ngx_int_t
+ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
+{
+    static u_char   basis64[] = {
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
+        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
+        77,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
+        77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
+
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
+    };
+
+    return ngx_decode_base64_internal(dst, src, basis64);
+}
+
+
+static ngx_int_t
+ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
+{
+    size_t          len;
+    u_char         *d, *s;
+
     for (len = 0; len < src->len; len++) {
         if (src->data[len] == '=') {
             break;
         }
 
-        if (basis64[src->data[len]] == 77) {
+        if (basis[src->data[len]] == 77) {
             return NGX_ERROR;
         }
     }
@@ -1089,20 +1172,20 @@ ngx_decode_base64(ngx_str_t *dst, ngx_st
     d = dst->data;
 
     while (len > 3) {
-        *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
-        *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
-        *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
+        *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
+        *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
+        *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
 
         s += 4;
         len -= 4;
     }
 
     if (len > 1) {
-        *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
+        *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
     }
 
     if (len > 2) {
-        *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
+        *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
     }
 
     dst->len = d - dst->data;
@@ -1238,10 +1321,8 @@ ngx_utf8_cpystrn(u_char *dst, u_char *sr
             break;
         }
 
-        len--;
-
         while (src < next) {
-            *++dst = *++src;
+            *dst++ = *src++;
             len--;
         }
     }
@@ -1255,7 +1336,7 @@ ngx_utf8_cpystrn(u_char *dst, u_char *sr
 uintptr_t
 ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
 {
-    ngx_uint_t      i, n;
+    ngx_uint_t      n;
     uint32_t       *escape;
     static u_char   hex[] = "0123456789abcdef";
 
@@ -1279,13 +1360,13 @@ ngx_escape_uri(u_char *dst, u_char *src,
         0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
     };
 
-                    /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */
+                    /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
 
     static uint32_t   args[] = {
         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 
                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
-        0x80000829, /* 1000 0000 0000 0000  0000 1000 0010 1001 */
+        0x88000869, /* 1000 1000 0000 0000  0000 1000 0110 1001 */
 
                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
         0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
@@ -1373,17 +1454,18 @@ ngx_escape_uri(u_char *dst, u_char *src,
 
         n = 0;
 
-        for (i = 0; i < size; i++) {
+        while (size) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                 n++;
             }
             src++;
+            size--;
         }
 
         return (uintptr_t) n;
     }
 
-    for (i = 0; i < size; i++) {
+    while (size) {
         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
             *dst++ = '%';
             *dst++ = hex[*src >> 4];
@@ -1393,6 +1475,7 @@ ngx_escape_uri(u_char *dst, u_char *src,
         } else {
             *dst++ = *src++;
         }
+        size--;
     }
 
     return (uintptr_t) dst;
@@ -1533,13 +1616,13 @@ uintptr_t
 ngx_escape_html(u_char *dst, u_char *src, size_t size)
 {
     u_char      ch;
-    ngx_uint_t  i, len;
+    ngx_uint_t  len;
 
     if (dst == NULL) {
 
         len = 0;
 
-        for (i = 0; i < size; i++) {
+        while (size) {
             switch (*src++) {
 
             case '<':
@@ -1557,12 +1640,13 @@ ngx_escape_html(u_char *dst, u_char *src
             default:
                 break;
             }
+            size--;
         }
 
         return (uintptr_t) len;
     }
 
-    for (i = 0; i < size; i++) {
+    while (size) {
         ch = *src++;
 
         switch (ch) {
@@ -1584,12 +1668,96 @@ ngx_escape_html(u_char *dst, u_char *src
             *dst++ = ch;
             break;
         }
+        size--;
     }
 
     return (uintptr_t) dst;
 }
 
 
+void
+ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_str_node_t      *n, *t;
+    ngx_rbtree_node_t  **p;
+
+    for ( ;; ) {
+
+        n = (ngx_str_node_t *) node;
+        t = (ngx_str_node_t *) temp;
+
+        if (node->key != temp->key) {
+
+            p = (node->key < temp->key) ? &temp->left : &temp->right;
+
+        } else if (n->str.len != t->str.len) {
+
+            p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
+
+        } else {
+            p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
+                 ? &temp->left : &temp->right;
+        }
+
+        if (*p == sentinel) {
+            break;
+        }
+
+        temp = *p;
+    }
+
+    *p = node;
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}
+
+
+ngx_str_node_t *
+ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash)
+{
+    ngx_int_t           rc;
+    ngx_str_node_t     *n;
+    ngx_rbtree_node_t  *node, *sentinel;
+
+    node = rbtree->root;
+    sentinel = rbtree->sentinel;
+
+    while (node != sentinel) {
+
+        n = (ngx_str_node_t *) node;
+
+        if (hash != node->key) {
+            node = (hash < node->key) ? node->left : node->right;
+            continue;
+        }
+
+        if (val->len != n->str.len) {
+            node = (val->len < n->str.len) ? node->left : node->right;
+            continue;
+        }
+
+        rc = ngx_memcmp(val->data, n->str.data, val->len);
+
+        if (rc < 0) {
+            node = node->left;
+            continue;
+        }
+
+        if (rc > 0) {
+            node = node->right;
+            continue;
+        }
+
+        return n;
+    }
+
+    return NULL;
+}
+
+
 /* ngx_sort() is implemented as insertion sort because we need stable sort */
 
 void
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -38,6 +38,9 @@ typedef struct {
 
 #define ngx_string(str)     { sizeof(str) - 1, (u_char *) str }
 #define ngx_null_string     { 0, NULL }
+#define ngx_str_set(str, text)                                               \
+    (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
+#define ngx_str_null(str)   (str)->len = 0; (str)->data = NULL
 
 
 #define ngx_tolower(c)      (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
@@ -86,7 +89,7 @@ ngx_strlchr(u_char *p, u_char *last, u_c
 #if (NGX_MEMCPY_LIMIT)
 
 void *ngx_memcpy(void *dst, void *src, size_t n);
-#define ngx_cpymem(dst, src, n)   ((u_char *) ngx_memcpy(dst, src, n)) + (n)
+#define ngx_cpymem(dst, src, n)   (((u_char *) ngx_memcpy(dst, src, n)) + (n))
 
 #else
 
@@ -96,7 +99,7 @@ void *ngx_memcpy(void *dst, void *src, s
  * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves.
  */
 #define ngx_memcpy(dst, src, n)   (void) memcpy(dst, src, n)
-#define ngx_cpymem(dst, src, n)   ((u_char *) memcpy(dst, src, n)) + (n)
+#define ngx_cpymem(dst, src, n)   (((u_char *) memcpy(dst, src, n)) + (n))
 
 #endif
 
@@ -132,6 +135,10 @@ ngx_copy(u_char *dst, u_char *src, size_
 #endif
 
 
+#define ngx_memmove(dst, src, n)   (void) memmove(dst, src, n)
+#define ngx_movemem(dst, src, n)   (((u_char *) memmove(dst, src, n)) + (n))
+
+
 /* msvc and icc7 compile memcmp() to the inline loop */
 #define ngx_memcmp(s1, s2, n)  memcmp((const char *) s1, (const char *) s2, n)
 
@@ -161,6 +168,7 @@ ngx_int_t ngx_memn2cmp(u_char *s1, u_cha
 ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2);
 
 ngx_int_t ngx_atoi(u_char *line, size_t n);
+ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point);
 ssize_t ngx_atosz(u_char *line, size_t n);
 off_t ngx_atoof(u_char *line, size_t n);
 time_t ngx_atotm(u_char *line, size_t n);
@@ -174,6 +182,7 @@ u_char *ngx_hex_dump(u_char *dst, u_char
 
 void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
 ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
+ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src);
 
 uint32_t ngx_utf8_decode(u_char **p, size_t n);
 size_t ngx_utf8_length(u_char *p, size_t n);
@@ -196,6 +205,17 @@ void ngx_unescape_uri(u_char **dst, u_ch
 uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size);
 
 
+typedef struct {
+    ngx_rbtree_node_t         node;
+    ngx_str_t                 str;
+} ngx_str_node_t;
+
+
+void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+ngx_str_node_t *ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *name,
+    uint32_t hash);
+
 
 void ngx_sort(void *base, size_t n, size_t size,
     ngx_int_t (*cmp)(const void *, const void *));
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -27,6 +27,18 @@ volatile ngx_time_t     *ngx_cached_time
 volatile ngx_str_t       ngx_cached_err_log_time;
 volatile ngx_str_t       ngx_cached_http_time;
 volatile ngx_str_t       ngx_cached_http_log_time;
+volatile ngx_str_t       ngx_cached_http_log_iso8601;
+
+#if !(NGX_WIN32)
+
+/*
+ * locatime() and localtime_r() are not Async-Signal-Safe functions, therefore,
+ * they must not be called by a signal handler, so we use the cached
+ * GMT offset value. Fortunately the value is changed only two times a year.
+ */
+
+static ngx_int_t         cached_gmtoff;
+#endif
 
 static ngx_time_t        cached_time[NGX_TIME_SLOTS];
 static u_char            cached_err_log_time[NGX_TIME_SLOTS]
@@ -35,6 +47,8 @@ static u_char            cached_http_tim
                                     [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
 static u_char            cached_http_log_time[NGX_TIME_SLOTS]
                                     [sizeof("28/Sep/1970:12:00:00 +0600")];
+static u_char            cached_http_log_iso8601[NGX_TIME_SLOTS]
+                                    [sizeof("1970-09-28T12:00:00+06:00")];
 
 
 static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -47,18 +61,21 @@ ngx_time_init(void)
     ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
     ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
     ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
+    ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
 
     ngx_cached_time = &cached_time[0];
 
-    ngx_time_update(0, 0);
+    ngx_time_update();
 }
 
 
 void
-ngx_time_update(time_t sec, ngx_uint_t msec)
+ngx_time_update(void)
 {
-    u_char          *p0, *p1, *p2;
+    u_char          *p0, *p1, *p2, *p3;
     ngx_tm_t         tm, gmt;
+    time_t           sec;
+    ngx_uint_t       msec;
     ngx_time_t      *tp;
     struct timeval   tv;
 
@@ -66,12 +83,10 @@ ngx_time_update(time_t sec, ngx_uint_t m
         return;
     }
 
-    if (sec == 0) {
-        ngx_gettimeofday(&tv);
+    ngx_gettimeofday(&tv);
 
-        sec = tv.tv_sec;
-        msec = tv.tv_usec / 1000;
-    }
+    sec = tv.tv_sec;
+    msec = tv.tv_usec / 1000;
 
     ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;
 
@@ -112,12 +127,14 @@ ngx_time_update(time_t sec, ngx_uint_t m
 #elif (NGX_HAVE_GMTOFF)
 
     ngx_localtime(sec, &tm);
-    tp->gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
+    cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
+    tp->gmtoff = cached_gmtoff;
 
 #else
 
     ngx_localtime(sec, &tm);
-    tp->gmtoff = ngx_timezone(tm.ngx_tm_isdst);
+    cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
+    tp->gmtoff = cached_gmtoff;
 
 #endif
 
@@ -139,6 +156,15 @@ ngx_time_update(time_t sec, ngx_uint_t m
                        tp->gmtoff < 0 ? '-' : '+',
                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
 
+    p3 = &cached_http_log_iso8601[slot][0];
+
+    (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+                       tm.ngx_tm_year, tm.ngx_tm_mon,
+                       tm.ngx_tm_mday, tm.ngx_tm_hour,
+                       tm.ngx_tm_min, tm.ngx_tm_sec,
+                       tp->gmtoff < 0 ? '-' : '+',
+                       ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
+
 
     ngx_memory_barrier();
 
@@ -146,11 +172,63 @@ ngx_time_update(time_t sec, ngx_uint_t m
     ngx_cached_http_time.data = p0;
     ngx_cached_err_log_time.data = p1;
     ngx_cached_http_log_time.data = p2;
+    ngx_cached_http_log_iso8601.data = p3;
 
     ngx_unlock(&ngx_time_lock);
 }
 
 
+#if !(NGX_WIN32)
+
+void
+ngx_time_sigsafe_update(void)
+{
+    u_char          *p;
+    ngx_tm_t         tm;
+    time_t           sec;
+    ngx_time_t      *tp;
+    struct timeval   tv;
+
+    if (!ngx_trylock(&ngx_time_lock)) {
+        return;
+    }
+
+    ngx_gettimeofday(&tv);
+
+    sec = tv.tv_sec;
+
+    tp = &cached_time[slot];
+
+    if (tp->sec == sec) {
+        ngx_unlock(&ngx_time_lock);
+        return;
+    }
+
+    if (slot == NGX_TIME_SLOTS - 1) {
+        slot = 0;
+    } else {
+        slot++;
+    }
+
+    ngx_gmtime(sec + cached_gmtoff * 60, &tm);
+
+    p = &cached_err_log_time[slot][0];
+
+    (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
+                       tm.ngx_tm_year, tm.ngx_tm_mon,
+                       tm.ngx_tm_mday, tm.ngx_tm_hour,
+                       tm.ngx_tm_min, tm.ngx_tm_sec);
+
+    ngx_memory_barrier();
+
+    ngx_cached_err_log_time.data = p;
+
+    ngx_unlock(&ngx_time_lock);
+}
+
+#endif
+
+
 u_char *
 ngx_http_time(u_char *buf, time_t t)
 {
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -20,7 +20,8 @@ typedef struct {
 
 
 void ngx_time_init(void);
-void ngx_time_update(time_t sec, ngx_uint_t msec);
+void ngx_time_update(void);
+void ngx_time_sigsafe_update(void);
 u_char *ngx_http_time(u_char *buf, time_t t);
 u_char *ngx_http_cookie_time(u_char *buf, time_t t);
 void ngx_gmtime(time_t t, ngx_tm_t *tp);
@@ -37,6 +38,7 @@ extern volatile ngx_time_t  *ngx_cached_
 extern volatile ngx_str_t    ngx_cached_err_log_time;
 extern volatile ngx_str_t    ngx_cached_http_time;
 extern volatile ngx_str_t    ngx_cached_http_log_time;
+extern volatile ngx_str_t    ngx_cached_http_log_iso8601;
 
 /*
  * milliseconds elapsed since epoch and truncated to ngx_msec_t,
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -371,8 +371,8 @@ ngx_devpoll_process_events(ngx_cycle_t *
 
     err = (events == -1) ? ngx_errno : 0;
 
-    if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+        ngx_time_update();
     }
 
     if (err) {
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -531,8 +531,8 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 
     err = (events == -1) ? ngx_errno : 0;
 
-    if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+        ngx_time_update();
     }
 
     if (err) {
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -405,7 +405,7 @@ ngx_eventport_process_events(ngx_cycle_t
     err = ngx_errno;
 
     if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+        ngx_time_update();
     }
 
     if (n == -1) {
@@ -439,7 +439,7 @@ ngx_eventport_process_events(ngx_cycle_t
     for (i = 0; i < events; i++) {
 
         if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
-            ngx_time_update(0, 0);
+            ngx_time_update();
             continue;
         }
 
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -537,8 +537,8 @@ ngx_kqueue_process_events(ngx_cycle_t *c
 
     err = (events == -1) ? ngx_errno : 0;
 
-    if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+        ngx_time_update();
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
@@ -589,7 +589,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c
 #if (NGX_HAVE_TIMER_EVENT)
 
         if (event_list[i].filter == EVFILT_TIMER) {
-            ngx_time_update(0, 0);
+            ngx_time_update();
             continue;
         }
 
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -72,7 +72,7 @@ ngx_poll_init(ngx_cycle_t *cycle, ngx_ms
         nevents = 0;
     }
 
-    if (ngx_process == NGX_PROCESS_WORKER
+    if (ngx_process >= NGX_PROCESS_WORKER
         || cycle->old_cycle == NULL
         || cycle->old_cycle->connection_n < cycle->connection_n)
     {
@@ -262,8 +262,8 @@ ngx_poll_process_events(ngx_cycle_t *cyc
 
     err = (ready == -1) ? ngx_errno : 0;
 
-    if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+        ngx_time_update();
     }
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -323,7 +323,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy
                        "rtsig signo:%d", signo);
 
         if (flags & NGX_UPDATE_TIME) {
-            ngx_time_update(0, 0);
+            ngx_time_update();
         }
 
         if (err == NGX_EAGAIN) {
@@ -349,7 +349,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy
                    signo, si.si_fd, si.si_band);
 
     if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+        ngx_time_update();
     }
 
     rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
@@ -419,7 +419,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy
 
     } else if (signo == SIGALRM) {
 
-        ngx_time_update(0, 0);
+        ngx_time_update();
 
         return NGX_OK;
 
@@ -671,7 +671,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
     }
 
     if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+        ngx_time_update();
     }
 
     ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -81,7 +81,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_
         nevents = 0;
     }
 
-    if (ngx_process == NGX_PROCESS_WORKER
+    if (ngx_process >= NGX_PROCESS_WORKER
         || cycle->old_cycle == NULL
         || cycle->old_cycle->connection_n < cycle->connection_n)
     {
@@ -262,8 +262,8 @@ ngx_select_process_events(ngx_cycle_t *c
 
     err = (ready == -1) ? ngx_errno : 0;
 
-    if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+        ngx_time_update();
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
--- a/src/event/modules/ngx_win32_select_module.c
+++ b/src/event/modules/ngx_win32_select_module.c
@@ -82,7 +82,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_
         nevents = 0;
     }
 
-    if (ngx_process == NGX_PROCESS_WORKER
+    if (ngx_process >= NGX_PROCESS_WORKER
         || cycle->old_cycle == NULL
         || cycle->old_cycle->connection_n < cycle->connection_n)
     {
@@ -269,7 +269,7 @@ ngx_select_process_events(ngx_cycle_t *c
     err = (ready == -1) ? ngx_socket_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
-        ngx_time_update(0, 0);
+        ngx_time_update();
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -562,8 +562,6 @@ ngx_timer_signal_handler(int signo)
 {
     ngx_event_timer_alarm = 1;
 
-    ngx_time_update(0, 0);
-
 #if 1
     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer signal");
 #endif
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -26,6 +26,9 @@ ngx_event_accept(ngx_event_t *ev)
     ngx_connection_t  *c, *lc;
     ngx_event_conf_t  *ecf;
     u_char             sa[NGX_SOCKADDRLEN];
+#if (NGX_HAVE_ACCEPT4)
+    static ngx_uint_t  use_accept4 = 1;
+#endif
 
     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
 
@@ -46,7 +49,16 @@ ngx_event_accept(ngx_event_t *ev)
     do {
         socklen = NGX_SOCKADDRLEN;
 
+#if (NGX_HAVE_ACCEPT4)
+        if (use_accept4) {
+            s = accept4(lc->fd, (struct sockaddr *) sa, &socklen,
+                        SOCK_NONBLOCK);
+        } else {
+            s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
+        }
+#else
         s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
+#endif
 
         if (s == -1) {
             err = ngx_socket_errno;
@@ -57,9 +69,22 @@ ngx_event_accept(ngx_event_t *ev)
                 return;
             }
 
+#if (NGX_HAVE_ACCEPT4)
+            ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ?
+                                             NGX_LOG_ERR : NGX_LOG_ALERT),
+                          ev->log, err,
+                          use_accept4 ? "accept4() failed" : "accept() failed");
+
+            if (use_accept4 && err == NGX_ENOSYS) {
+                use_accept4 = 0;
+                ngx_inherited_nonblocking = 0;
+                continue;
+            }
+#else
             ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ?
                                              NGX_LOG_ERR : NGX_LOG_ALERT),
                           ev->log, err, "accept() failed");
+#endif
 
             if (err == NGX_ECONNABORTED) {
                 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
@@ -152,10 +177,20 @@ ngx_event_accept(ngx_event_t *ev)
         c->socklen = socklen;
         c->listening = ls;
         c->local_sockaddr = ls->sockaddr;
-        c->local_socklen = ls->socklen;
 
         c->unexpected_eof = 1;
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+        if (c->sockaddr->sa_family == AF_UNIX) {
+            c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
+            c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
+#if (NGX_SOLARIS)
+            /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
+            c->sendfile = 0;
+#endif
+        }
+#endif
+
         rev = c->read;
         wev = c->write;
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -54,15 +54,7 @@ ngx_event_connect_peer(ngx_peer_connecti
         {
             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                           "setsockopt(SO_RCVBUF) failed");
-
-            ngx_free_connection(c);
-
-            if (ngx_close_socket(s) == -1) {
-                ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
-                              ngx_close_socket_n " failed");
-            }
-
-            return NGX_ERROR;
+            goto failed;
         }
     }
 
@@ -70,14 +62,16 @@ ngx_event_connect_peer(ngx_peer_connecti
         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                       ngx_nonblocking_n " failed");
 
-        ngx_free_connection(c);
+        goto failed;
+    }
 
-        if (ngx_close_socket(s) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
-                          ngx_close_socket_n " failed");
+    if (pc->local) {
+        if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
+            ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
+                          "bind(%V) failed", &pc->local->name);
+
+            goto failed;
         }
-
-        return NGX_ERROR;
     }
 
     c->recv = ngx_recv;
@@ -107,27 +101,22 @@ ngx_event_connect_peer(ngx_peer_connecti
 
     pc->connection = c;
 
-    /*
-     * TODO: MT: - ngx_atomic_fetch_add()
-     *             or protection by critical section or mutex
-     *
-     * TODO: MP: - allocated in a shared memory
-     *           - ngx_atomic_fetch_add()
-     *             or protection by critical section or mutex
-     */
-
     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
 
 #if (NGX_THREADS)
+
+    /* TODO: lock event when call completion handler */
+
     rev->lock = pc->lock;
     wev->lock = pc->lock;
     rev->own_lock = &c->lock;
     wev->own_lock = &c->lock;
+
 #endif
 
     if (ngx_add_conn) {
         if (ngx_add_conn(c) == NGX_ERROR) {
-            return NGX_ERROR;
+            goto failed;
         }
     }
 
@@ -199,7 +188,7 @@ ngx_event_connect_peer(ngx_peer_connecti
         if (ngx_blocking(s) == -1) {
             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                           ngx_blocking_n " failed");
-            return NGX_ERROR;
+            goto failed;
         }
 
         /*
@@ -229,7 +218,7 @@ ngx_event_connect_peer(ngx_peer_connecti
     }
 
     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
-        return NGX_ERROR;
+        goto failed;
     }
 
     if (rc == -1) {
@@ -237,7 +226,7 @@ ngx_event_connect_peer(ngx_peer_connecti
         /* NGX_EINPROGRESS */
 
         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
-            return NGX_ERROR;
+            goto failed;
         }
 
         return NGX_AGAIN;
@@ -248,6 +237,17 @@ ngx_event_connect_peer(ngx_peer_connecti
     wev->ready = 1;
 
     return NGX_OK;
+
+failed:
+
+    ngx_free_connection(c);
+
+    if (ngx_close_socket(s) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+                      ngx_close_socket_n " failed");
+    }
+
+    return NGX_ERROR;
 }
 
 
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -55,6 +55,8 @@ struct ngx_peer_connection_s {
     ngx_atomic_t                    *lock;
 #endif
 
+    ngx_addr_t                      *local;
+
     int                              rcvbuf;
 
     ngx_log_t                       *log;
@@ -70,5 +72,4 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
 ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data);
 
 
-
 #endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -15,6 +15,8 @@ typedef struct {
 
 
 static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
+static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
+    int ret);
 static void ngx_ssl_handshake_handler(ngx_event_t *ev);
 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
 static void ngx_ssl_write_handler(ngx_event_t *wev);
@@ -104,6 +106,8 @@ ngx_ssl_init(ngx_log_t *log)
 
     ENGINE_load_builtin_engines();
 
+    OpenSSL_add_all_algorithms();
+
     ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
 
     if (ngx_ssl_connection_index == -1) {
@@ -151,7 +155,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
-    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
 
     /* server side options */
 
@@ -175,6 +178,8 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
 
     SSL_CTX_set_read_ahead(ssl->ctx, 1);
 
+    SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
+
     return NGX_OK;
 }
 
@@ -350,6 +355,22 @@ ngx_http_ssl_verify_callback(int ok, X50
 }
 
 
+static void
+ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
+{
+    ngx_connection_t  *c;
+
+    if (where & SSL_CB_HANDSHAKE_START) {
+        c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
+
+        if (c->ssl->handshaked) {
+            c->ssl->renegotiation = 1;
+            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation");
+        }
+    }
+}
+
+
 ngx_int_t
 ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl)
 {
@@ -539,6 +560,9 @@ ngx_ssl_handshake(ngx_connection_t *c)
 #if (NGX_DEBUG)
         {
         char         buf[129], *s, *d;
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+        const
+#endif
         SSL_CIPHER  *cipher;
 
         cipher = SSL_get_current_cipher(c->ssl->connection);
@@ -587,6 +611,11 @@ ngx_ssl_handshake(ngx_connection_t *c)
         c->recv_chain = ngx_ssl_recv_chain;
         c->send_chain = ngx_ssl_send_chain;
 
+        /* initial handshake done, disable renegotiation (CVE-2009-3555) */
+        if (c->ssl->connection->s3) {
+            c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
+        }
+
         return NGX_OK;
     }
 
@@ -789,6 +818,21 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
     int        sslerr;
     ngx_err_t  err;
 
+    if (c->ssl->renegotiation) {
+        /*
+         * disable renegotiation (CVE-2009-3555):
+         * OpenSSL (at least up to 0.9.8l) does not handle disabled
+         * renegotiation gracefully, so drop connection here
+         */
+
+        ngx_log_error(NGX_LOG_NOTICE, c->log, 0, "SSL renegotiation disabled");
+
+        c->ssl->no_wait_shutdown = 1;
+        c->ssl->no_send_shutdown = 1;
+
+        return NGX_ERROR;
+    }
+
     if (n > 0) {
 
         if (c->ssl->saved_write_handler) {
@@ -946,7 +990,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
 
     for ( ;; ) {
 
-        while (in && buf->last < buf->end) {
+        while (in && buf->last < buf->end && send < limit) {
             if (in->buf->last_buf || in->buf->flush) {
                 flush = 1;
             }
@@ -973,8 +1017,8 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
             ngx_memcpy(buf->last, in->buf->pos, size);
 
             buf->last += size;
-
             in->buf->pos += size;
+            send += size;
 
             if (in->buf->pos == in->buf->last) {
                 in = in->next;
@@ -999,7 +1043,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
         }
 
         buf->pos += n;
-        send += n;
         c->sent += n;
 
         if (n < size) {
@@ -1268,11 +1311,17 @@ ngx_ssl_connection_error(ngx_connection_
         n = ERR_GET_REASON(ERR_peek_error());
 
             /* handshake failures */
-        if (n == SSL_R_DIGEST_CHECK_FAILED                           /*  149 */
+        if (n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG                     /*  129 */
+            || n == SSL_R_DIGEST_CHECK_FAILED                        /*  149 */
+            || n == SSL_R_LENGTH_MISMATCH                            /*  159 */
             || n == SSL_R_NO_CIPHERS_PASSED                          /*  182 */
+            || n == SSL_R_NO_CIPHERS_SPECIFIED                       /*  183 */
             || n == SSL_R_NO_SHARED_CIPHER                           /*  193 */
+            || n == SSL_R_RECORD_LENGTH_MISMATCH                     /*  213 */
             || n == SSL_R_UNEXPECTED_MESSAGE                         /*  244 */
             || n == SSL_R_UNEXPECTED_RECORD                          /*  245 */
+            || n == SSL_R_UNKNOWN_ALERT_TYPE                         /*  246 */
+            || n == SSL_R_UNKNOWN_PROTOCOL                           /*  252 */
             || n == SSL_R_WRONG_VERSION_NUMBER                       /*  267 */
             || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC        /*  281 */
             || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
@@ -1384,6 +1433,8 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
         return NGX_OK;
     }
 
+    SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
+
     if (builtin_session_cache == NGX_SSL_NONE_SCACHE) {
 
         /*
@@ -1415,8 +1466,6 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
 
     SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);
 
-    SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
-
     if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {
 
         if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
@@ -1588,7 +1637,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     hash = ngx_crc32_short(sess->session_id, sess->session_id_length);
 
     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                   "http ssl new session: %08XD:%d:%d",
+                   "ssl new session: %08XD:%d:%d",
                    hash, sess->session_id_length, len);
 
     sess_id->node.key = hash;
@@ -1651,7 +1700,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
     *copy = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                   "http ssl get session: %08XD:%d", hash, len);
+                   "ssl get session: %08XD:%d", hash, len);
 
     shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
                                    ngx_ssl_session_cache_index);
@@ -1765,7 +1814,7 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
     hash = ngx_crc32_short(id, len);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
-                   "http ssl remove session: %08XD:%uz", hash, len);
+                   "ssl remove session: %08XD:%uz", hash, len);
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
@@ -1929,6 +1978,40 @@ ngx_ssl_get_cipher_name(ngx_connection_t
 
 
 ngx_int_t
+ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    int           len;
+    u_char       *p, *buf;
+    SSL_SESSION  *sess;
+
+    sess = SSL_get0_session(c->ssl->connection);
+
+    len = i2d_SSL_SESSION(sess, NULL);
+
+    buf = ngx_alloc(len, c->log);
+    if (buf == NULL) {
+        return NGX_ERROR;
+    }
+
+    s->len = 2 * len;
+    s->data = ngx_pnalloc(pool, 2 * len);
+    if (s->data == NULL) {
+        ngx_free(buf);
+        return NGX_ERROR;
+    }
+
+    p = buf;
+    i2d_SSL_SESSION(sess, &p);
+
+    ngx_hex_dump(s->data, buf, len);
+
+    ngx_free(buf);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 {
     size_t   len;
@@ -2151,21 +2234,17 @@ ngx_ssl_get_client_verify(ngx_connection
     X509  *cert;
 
     if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
-        s->len = sizeof("FAILED") - 1;
-        s->data = (u_char *) "FAILED";
-
+        ngx_str_set(s, "FAILED");
         return NGX_OK;
     }
 
     cert = SSL_get_peer_certificate(c->ssl->connection);
 
     if (cert) {
-        s->len = sizeof("SUCCESS") - 1;
-        s->data = (u_char *) "SUCCESS";
+        ngx_str_set(s, "SUCCESS");
 
     } else {
-        s->len = sizeof("NONE") - 1;
-        s->data = (u_char *) "NONE";
+        ngx_str_set(s, "NONE");
     }
 
     X509_free(cert);
@@ -2237,5 +2316,6 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c
 static void
 ngx_openssl_exit(ngx_cycle_t *cycle)
 {
+    EVP_cleanup();
     ENGINE_cleanup();
 }
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -15,6 +15,7 @@
 #include <openssl/err.h>
 #include <openssl/conf.h>
 #include <openssl/engine.h>
+#include <openssl/evp.h>
 
 #define NGX_SSL_NAME     "OpenSSL"
 
@@ -41,6 +42,7 @@ typedef struct {
     ngx_event_handler_pt        saved_write_handler;
 
     unsigned                    handshaked:1;
+    unsigned                    renegotiation:1;
     unsigned                    buffer:1;
     unsigned                    no_wait_shutdown:1;
     unsigned                    no_send_shutdown:1;
@@ -118,6 +120,8 @@ ngx_int_t ngx_ssl_get_protocol(ngx_conne
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool,
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -10,18 +10,37 @@
 
 
 typedef struct {
-    in_addr_t     mask;
-    in_addr_t     addr;
-    ngx_uint_t    deny;      /* unsigned  deny:1; */
+    in_addr_t         mask;
+    in_addr_t         addr;
+    ngx_uint_t        deny;      /* unsigned  deny:1; */
 } ngx_http_access_rule_t;
 
+#if (NGX_HAVE_INET6)
 
 typedef struct {
-    ngx_array_t  *rules;     /* array of ngx_http_access_rule_t */
+    struct in6_addr   addr;
+    struct in6_addr   mask;
+    ngx_uint_t        deny;      /* unsigned  deny:1; */
+} ngx_http_access_rule6_t;
+
+#endif
+
+typedef struct {
+    ngx_array_t      *rules;     /* array of ngx_http_access_rule_t */
+#if (NGX_HAVE_INET6)
+    ngx_array_t      *rules6;    /* array of ngx_http_access_rule6_t */
+#endif
 } ngx_http_access_loc_conf_t;
 
 
 static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r,
+    ngx_http_access_loc_conf_t *alcf, in_addr_t addr);
+#if (NGX_HAVE_INET6)
+static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r,
+    ngx_http_access_loc_conf_t *alcf, u_char *p);
+#endif
+static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny);
 static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
@@ -87,46 +106,59 @@ ngx_module_t  ngx_http_access_module = {
 static ngx_int_t
 ngx_http_access_handler(ngx_http_request_t *r)
 {
-    ngx_uint_t                   i;
     struct sockaddr_in          *sin;
-    ngx_http_access_rule_t      *rule;
-    ngx_http_core_loc_conf_t    *clcf;
     ngx_http_access_loc_conf_t  *alcf;
 
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
 
-    if (alcf->rules == NULL) {
-        return NGX_DECLINED;
+#if (NGX_HAVE_INET6)
+
+    if (alcf->rules6 && r->connection->sockaddr->sa_family == AF_INET6) {
+        u_char               *p;
+        in_addr_t             addr;
+        struct sockaddr_in6  *sin6;
+
+        sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
+        p = sin6->sin6_addr.s6_addr;
+
+        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+            addr = p[12] << 24;
+            addr += p[13] << 16;
+            addr += p[14] << 8;
+            addr += p[15];
+            return ngx_http_access_inet(r, alcf, htonl(addr));
+        }
+
+        return ngx_http_access_inet6(r, alcf, p);
     }
 
-    /* AF_INET only */
+#endif
 
-    if (r->connection->sockaddr->sa_family != AF_INET) {
-        return NGX_DECLINED;
+    if (alcf->rules && r->connection->sockaddr->sa_family == AF_INET) {
+        sin = (struct sockaddr_in *) r->connection->sockaddr;
+        return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr);
     }
 
-    sin = (struct sockaddr_in *) r->connection->sockaddr;
+    return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
+    in_addr_t addr)
+{
+    ngx_uint_t               i;
+    ngx_http_access_rule_t  *rule;
 
     rule = alcf->rules->elts;
     for (i = 0; i < alcf->rules->nelts; i++) {
 
         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "access: %08XD %08XD %08XD",
-                       sin->sin_addr.s_addr, rule[i].mask, rule[i].addr);
-
-        if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
-            if (rule[i].deny) {
-                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+                       addr, rule[i].mask, rule[i].addr);
 
-                if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
-                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                                  "access forbidden by rule");
-                }
-
-                return NGX_HTTP_FORBIDDEN;
-            }
-
-            return NGX_OK;
+        if ((addr & rule[i].mask) == rule[i].addr) {
+            return ngx_http_access_found(r, rule[i].deny);
         }
     }
 
@@ -134,62 +166,159 @@ ngx_http_access_handler(ngx_http_request
 }
 
 
+#if (NGX_HAVE_INET6)
+
+static ngx_int_t
+ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
+    u_char *p)
+{
+    ngx_uint_t                n;
+    ngx_uint_t                i;
+    ngx_http_access_rule6_t  *rule6;
+
+    rule6 = alcf->rules6->elts;
+    for (i = 0; i < alcf->rules6->nelts; i++) {
+
+#if (NGX_DEBUG)
+        {
+        size_t  cl, ml, al;
+        u_char  ct[NGX_INET6_ADDRSTRLEN];
+        u_char  mt[NGX_INET6_ADDRSTRLEN];
+        u_char  at[NGX_INET6_ADDRSTRLEN];
+
+        cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN);
+        ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN);
+        al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN);
+
+        ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "access: %*s %*s %*s", cl, ct, ml, mt, al, at);
+        }
+#endif
+
+        for (n = 0; n < 16; n++) {
+            if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) {
+                goto next;
+            }
+        }
+
+        return ngx_http_access_found(r, rule6[i].deny);
+
+    next:
+        continue;
+    }
+
+    return NGX_DECLINED;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny)
+{
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (deny) {
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+        if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "access forbidden by rule");
+        }
+
+        return NGX_HTTP_FORBIDDEN;
+    }
+
+    return NGX_OK;
+}
+
+
 static char *
 ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_access_loc_conf_t *alcf = conf;
 
-    ngx_int_t                rc;
-    ngx_str_t               *value;
-    ngx_cidr_t               cidr;
-    ngx_http_access_rule_t  *rule;
+    ngx_int_t                 rc;
+    ngx_uint_t                all;
+    ngx_str_t                *value;
+    ngx_cidr_t                cidr;
+    ngx_http_access_rule_t   *rule;
+#if (NGX_HAVE_INET6)
+    ngx_http_access_rule6_t  *rule6;
+#endif
 
-    if (alcf->rules == NULL) {
-        alcf->rules = ngx_array_create(cf->pool, 4,
-                                       sizeof(ngx_http_access_rule_t));
-        if (alcf->rules == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    rule = ngx_array_push(alcf->rules);
-    if (rule == NULL) {
-        return NGX_CONF_ERROR;
-    }
+    ngx_memzero(&cidr, sizeof(ngx_cidr_t));
 
     value = cf->args->elts;
 
-    rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
+    all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0);
+
+    if (!all) {
+
+        rc = ngx_ptocidr(&value[1], &cidr);
 
-    if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {
-        rule->mask = 0;
-        rule->addr = 0;
+        if (rc == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                         "invalid parameter \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
 
-        return NGX_CONF_OK;
+        if (rc == NGX_DONE) {
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                         "low address bits of %V are meaningless", &value[1]);
+        }
     }
 
-    rc = ngx_ptocidr(&value[1], &cidr);
+    switch (cidr.family) {
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+    case 0: /* all */
 
-    if (rc == NGX_ERROR) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
-                           &value[1]);
-        return NGX_CONF_ERROR;
-    }
+        if (alcf->rules6 == NULL) {
+            alcf->rules6 = ngx_array_create(cf->pool, 4,
+                                            sizeof(ngx_http_access_rule6_t));
+            if (alcf->rules6 == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        rule6 = ngx_array_push(alcf->rules6);
+        if (rule6 == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        rule6->mask = cidr.u.in6.mask;
+        rule6->addr = cidr.u.in6.addr;
+        rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
 
-    if (cidr.family != AF_INET) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "\"allow\" supports IPv4 only");
-        return NGX_CONF_ERROR;
-    }
+        if (!all) {
+            break;
+        }
+
+        /* "all" passes through */
+#endif
+
+    default: /* AF_INET */
 
-    if (rc == NGX_DONE) {
-        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                           "low address bits of %V are meaningless", &value[1]);
+        if (alcf->rules == NULL) {
+            alcf->rules = ngx_array_create(cf->pool, 4,
+                                           sizeof(ngx_http_access_rule_t));
+            if (alcf->rules == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        rule = ngx_array_push(alcf->rules);
+        if (rule == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        rule->mask = cidr.u.in.mask;
+        rule->addr = cidr.u.in.addr;
+        rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
     }
 
-    rule->mask = cidr.u.in.mask;
-    rule->addr = cidr.u.in.addr;
-
     return NGX_CONF_OK;
 }
 
@@ -218,6 +347,12 @@ ngx_http_access_merge_loc_conf(ngx_conf_
         conf->rules = prev->rules;
     }
 
+#if (NGX_HAVE_INET6)
+    if (conf->rules6 == NULL) {
+        conf->rules6 = prev->rules6;
+    }
+#endif
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -237,8 +237,8 @@ ngx_http_addition_merge_conf(ngx_conf_t 
     ngx_conf_merge_str_value(conf->before_body, prev->before_body, "");
     ngx_conf_merge_str_value(conf->after_body, prev->after_body, "");
 
-    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
-                             prev->types_keys, &prev->types,
+    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
+                             &prev->types_keys, &prev->types,
                              ngx_http_html_default_types)
         != NGX_OK)
     {
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -248,7 +248,7 @@ ngx_http_auth_basic_handler(ngx_http_req
 
         if (state == sw_passwd) {
             left = left + n - passwd;
-            ngx_memcpy(buf, &buf[passwd], left);
+            ngx_memmove(buf, &buf[passwd], left);
             passwd = 0;
 
         } else {
@@ -348,8 +348,7 @@ ngx_http_auth_basic_set_realm(ngx_http_r
     }
 
     r->headers_out.www_authenticate->hash = 1;
-    r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1;
-    r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate";
+    ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
     r->headers_out.www_authenticate->value = *realm;
 
     return NGX_HTTP_UNAUTHORIZED;
@@ -425,9 +424,7 @@ ngx_http_auth_basic(ngx_conf_t *cf, void
     u_char  *basic, *p;
 
     if (ngx_strcmp(realm->data, "off") == 0) {
-        realm->len = 0;
-        realm->data = (u_char *) "";
-
+        ngx_str_set(realm, "");
         return NGX_CONF_OK;
     }
 
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -160,10 +160,6 @@ ngx_http_autoindex_handler(ngx_http_requ
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_DECLINED;
     }
@@ -235,8 +231,7 @@ ngx_http_autoindex_handler(ngx_http_requ
 
     r->headers_out.status = NGX_HTTP_OK;
     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";
+    ngx_str_set(&r->headers_out.content_type, "text/html");
 
     rc = ngx_http_send_header(r);
 
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -1550,8 +1550,8 @@ ngx_http_charset_merge_loc_conf(ngx_conf
     ngx_http_charset_recode_t     *recode;
     ngx_http_charset_main_conf_t  *mcf;
 
-    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
-                             prev->types_keys, &prev->types,
+    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
+                             &prev->types_keys, &prev->types,
                              ngx_http_charset_default_types)
         != NGX_OK)
     {
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -50,9 +50,10 @@ static ngx_http_output_body_filter_pt   
 static ngx_int_t
 ngx_http_chunked_header_filter(ngx_http_request_t *r)
 {
+    ngx_http_core_loc_conf_t  *clcf;
+
     if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
         || r->headers_out.status == NGX_HTTP_NO_CONTENT
-        || r->headers_out.status == NGX_HTTP_CREATED
         || r != r->main
         || (r->method & NGX_HTTP_HEAD))
     {
@@ -64,7 +65,14 @@ ngx_http_chunked_header_filter(ngx_http_
             r->keepalive = 0;
 
         } else {
-            r->chunked = 1;
+            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+            if (clcf->chunked_transfer_encoding) {
+                r->chunked = 1;
+
+            } else {
+                r->keepalive = 0;
+            }
         }
     }
 
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -146,10 +146,6 @@ ngx_http_dav_handler(ngx_http_request_t 
     ngx_int_t                 rc;
     ngx_http_dav_loc_conf_t  *dlcf;
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
 
     if (!(r->method & dlcf->methods)) {
@@ -325,13 +321,13 @@ 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) == NGX_FILE_ERROR) {
+    if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) {
         err = ngx_errno;
 
         rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND;
 
         return ngx_http_dav_error(r->connection->log, err,
-                                  rc, ngx_file_info_n, path.data);
+                                  rc, ngx_link_info_n, path.data);
     }
 
     if (ngx_is_dir(&fi)) {
@@ -358,7 +354,7 @@ ok:
 
         /*
          * we do not need to test (r->uri.data[r->uri.len - 1] == '/')
-         * because ngx_file_info("/file/") returned NGX_ENOTDIR above
+         * because ngx_link_info("/file/") returned NGX_ENOTDIR above
          */
 
         depth = ngx_http_dav_depth(r, 0);
@@ -490,6 +486,7 @@ ngx_http_dav_mkcol_handler(ngx_http_requ
     p = ngx_http_map_uri_to_path(r, &path, &root, 0);
 
     *(p - 1) = '\0';
+    r->uri.len--;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http mkcol path: \"%s\"", path.data);
@@ -516,8 +513,8 @@ ngx_http_dav_copy_move_handler(ngx_http_
     size_t                    len, root;
     ngx_err_t                 err;
     ngx_int_t                 rc, depth;
-    ngx_uint_t                overwrite, slash, dir;
-    ngx_str_t                 path, uri;
+    ngx_uint_t                overwrite, slash, dir, flags;
+    ngx_str_t                 path, uri, duri, args;
     ngx_tree_ctx_t            tree;
     ngx_copy_file_t           cf;
     ngx_file_info_t           fi;
@@ -538,6 +535,13 @@ ngx_http_dav_copy_move_handler(ngx_http_
         return NGX_HTTP_BAD_REQUEST;
     }
 
+    p = dest->value.data;
+    /* there is always '\0' even after empty header value */
+    if (p[0] == '/') {
+        last = p + dest->value.len;
+        goto destination_done;
+    }
+
     len = r->headers_in.server.len;
 
     if (len == 0) {
@@ -594,6 +598,14 @@ invalid_destination:
 
 destination_done:
 
+    duri.len = last - p;
+    duri.data = p;
+    flags = 0;
+
+    if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
+        goto invalid_destination;
+    }
+
     if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
         || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
     {
@@ -656,9 +668,7 @@ overwrite_done:
                    "http copy from: \"%s\"", path.data);
 
     uri = r->uri;
-
-    r->uri.len = last - p;
-    r->uri.data = p;
+    r->uri = duri;
 
     ngx_http_map_uri_to_path(r, &copy.path, &root, 0);
 
@@ -678,12 +688,12 @@ 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) == NGX_FILE_ERROR) {
+    if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) {
         err = ngx_errno;
 
         if (err != NGX_ENOENT) {
             return ngx_http_dav_error(r->connection->log, err,
-                                      NGX_HTTP_NOT_FOUND, ngx_file_info_n,
+                                      NGX_HTTP_NOT_FOUND, ngx_link_info_n,
                                       copy.path.data);
         }
 
@@ -712,9 +722,9 @@ overwrite_done:
         dir = ngx_is_dir(&fi);
     }
 
-    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
+    if (ngx_link_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,
+                                  NGX_HTTP_NOT_FOUND, ngx_link_info_n,
                                   path.data);
     }
 
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_degradation_module.c
@@ -0,0 +1,242 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    size_t      sbrk_size;
+} ngx_http_degradation_main_conf_t;
+
+
+typedef struct {
+    ngx_uint_t  degrade;
+} ngx_http_degradation_loc_conf_t;
+
+
+static ngx_conf_enum_t  ngx_http_degrade[] = {
+    { ngx_string("204"), 204 },
+    { ngx_string("444"), 444 },
+    { ngx_null_string, 0 }
+};
+
+
+static void *ngx_http_degradation_create_main_conf(ngx_conf_t *cf);
+static void *ngx_http_degradation_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_degradation_merge_loc_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+static char *ngx_http_degradation(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static ngx_int_t ngx_http_degradation_init(ngx_conf_t *cf);
+
+
+static ngx_command_t  ngx_http_degradation_commands[] = {
+
+    { ngx_string("degradation"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_http_degradation,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("degrade"),
+      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_degradation_loc_conf_t, degrade),
+      &ngx_http_degrade },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_degradation_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_degradation_init,             /* postconfiguration */
+
+    ngx_http_degradation_create_main_conf, /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_degradation_create_loc_conf,  /* create location configuration */
+    ngx_http_degradation_merge_loc_conf    /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_degradation_module = {
+    NGX_MODULE_V1,
+    &ngx_http_degradation_module_ctx,      /* module context */
+    ngx_http_degradation_commands,         /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_degradation_handler(ngx_http_request_t *r)
+{
+    ngx_http_degradation_loc_conf_t  *dlcf;
+
+    dlcf = ngx_http_get_module_loc_conf(r, ngx_http_degradation_module);
+
+    if (dlcf->degrade && ngx_http_degraded(r)) {
+        return dlcf->degrade;
+    }
+
+    return NGX_DECLINED;
+}
+
+
+ngx_uint_t
+ngx_http_degraded(ngx_http_request_t *r)
+{
+    time_t                             now;
+    ngx_uint_t                         log;
+    static size_t                      sbrk_size;
+    static time_t                      sbrk_time;
+    ngx_http_degradation_main_conf_t  *dmcf;
+
+    dmcf = ngx_http_get_module_main_conf(r, ngx_http_degradation_module);
+
+    if (dmcf->sbrk_size) {
+
+        log = 0;
+        now = ngx_time();
+
+        /* lock mutex */
+
+        if (now != sbrk_time) {
+
+            /*
+             * ELF/i386 is loaded at 0x08000000, 128M
+             * ELF/amd64 is loaded at 0x00400000, 4M
+             *
+             * use a function address to substract the loading address
+             */
+
+            sbrk_size = (size_t) sbrk(0) - ((uintptr_t) ngx_palloc & ~0x3FFFFF);
+            sbrk_time = now;
+            log = 1;
+        }
+
+        /* unlock mutex */
+
+        if (sbrk_size >= dmcf->sbrk_size) {
+            if (log) {
+                ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                              "degradation sbrk:%uzM",
+                              sbrk_size / (1024 * 1024));
+            }
+
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
+static void *
+ngx_http_degradation_create_main_conf(ngx_conf_t *cf)
+{
+    ngx_http_degradation_main_conf_t  *dmcf;
+
+    dmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_degradation_main_conf_t));
+    if (dmcf == NULL) {
+        return NULL;
+    }
+
+    return dmcf;
+}
+
+
+static void *
+ngx_http_degradation_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_degradation_loc_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_degradation_loc_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    conf->degrade = NGX_CONF_UNSET_UINT;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_degradation_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_degradation_loc_conf_t  *prev = parent;
+    ngx_http_degradation_loc_conf_t  *conf = child;
+
+    ngx_conf_merge_uint_value(conf->degrade, prev->degrade, 0);
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_degradation(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_degradation_main_conf_t  *dmcf = conf;
+
+    ngx_str_t  *value, s;
+
+    value = cf->args->elts;
+
+    if (ngx_strncmp(value[1].data, "sbrk=", 5) == 0) {
+
+        s.len = value[1].len - 5;
+        s.data = value[1].data + 5;
+
+        dmcf->sbrk_size = ngx_parse_size(&s);
+        if (dmcf->sbrk_size == (size_t) NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid sbrk size \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        return NGX_CONF_OK;
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "invalid parameter \"%V\"", &value[1]);
+
+    return NGX_CONF_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_degradation_init(ngx_conf_t *cf)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_degradation_handler;
+
+    return NGX_OK;
+}
--- a/src/http/modules/ngx_http_empty_gif_module.c
+++ b/src/http/modules/ngx_http_empty_gif_module.c
@@ -105,12 +105,14 @@ ngx_module_t  ngx_http_empty_gif_module 
 };
 
 
+static ngx_str_t  ngx_http_gif_type = ngx_string("image/gif");
+
+
 static ngx_int_t
 ngx_http_empty_gif_handler(ngx_http_request_t *r)
 {
-    ngx_int_t     rc;
-    ngx_buf_t    *b;
-    ngx_chain_t   out;
+    ngx_int_t                 rc;
+    ngx_http_complex_value_t  cv;
 
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_HTTP_NOT_ALLOWED;
@@ -122,42 +124,13 @@ ngx_http_empty_gif_handler(ngx_http_requ
         return rc;
     }
 
-    r->headers_out.content_type_len = sizeof("image/gif") - 1;
-    r->headers_out.content_type.len = sizeof("image/gif") - 1;
-    r->headers_out.content_type.data = (u_char *) "image/gif";
-
-    if (r->method == NGX_HTTP_HEAD) {
-        r->headers_out.status = NGX_HTTP_OK;
-        r->headers_out.content_length_n = sizeof(ngx_empty_gif);
-        r->headers_out.last_modified_time = 23349600;
-
-        return ngx_http_send_header(r);
-    }
+    ngx_memzero(&cv, sizeof(ngx_http_complex_value_t));
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
-    if (b == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    out.buf = b;
-    out.next = NULL;
-
-    b->pos = ngx_empty_gif;
-    b->last = ngx_empty_gif + sizeof(ngx_empty_gif);
-    b->memory = 1;
-    b->last_buf = 1;
-
-    r->headers_out.status = NGX_HTTP_OK;
-    r->headers_out.content_length_n = sizeof(ngx_empty_gif);
+    cv.value.len = sizeof(ngx_empty_gif);
+    cv.value.data = ngx_empty_gif;
     r->headers_out.last_modified_time = 23349600;
 
-    rc = ngx_http_send_header(r);
-
-    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
-        return rc;
-    }
-
-    return ngx_http_output_filter(r, &out);
+    return ngx_http_send_response(r, NGX_HTTP_OK, &ngx_http_gif_type, &cv);
 }
 
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -23,6 +23,9 @@ typedef struct {
     ngx_array_t                   *fastcgi_lengths;
     ngx_array_t                   *fastcgi_values;
 
+    ngx_hash_t                     headers_hash;
+    ngx_uint_t                     header_params;
+
 #if (NGX_HTTP_CACHE)
     ngx_http_complex_value_t       cache_key;
 #endif
@@ -62,7 +65,8 @@ typedef struct {
     size_t                         length;
     size_t                         padding;
 
-    ngx_uint_t                     fastcgi_stdout; /* unsigned :1 */
+    unsigned                       fastcgi_stdout:1;
+    unsigned                       large_stderr:1;
 
     ngx_array_t                   *split_parts;
 
@@ -161,11 +165,6 @@ static char *ngx_http_fastcgi_cache_key(
 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
     void *data);
 
-static char *ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-static char *ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-
 
 static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
     { ngx_http_fastcgi_lowat_check };
@@ -184,15 +183,6 @@ static ngx_conf_bitmask_t  ngx_http_fast
 };
 
 
-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;
 
 
@@ -240,6 +230,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
       NULL },
 
+    { ngx_string("fastcgi_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upstream_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
+      NULL },
+
     { ngx_string("fastcgi_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -313,14 +310,14 @@ static ngx_command_t  ngx_http_fastcgi_c
 #if (NGX_HTTP_CACHE)
 
     { ngx_string("fastcgi_cache"),
-      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_http_fastcgi_cache,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("fastcgi_cache_key"),
-      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_http_fastcgi_cache_key,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -333,6 +330,20 @@ static ngx_command_t  ngx_http_fastcgi_c
       0,
       &ngx_http_fastcgi_module },
 
+    { ngx_string("fastcgi_cache_bypass"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass),
+      NULL },
+
+    { ngx_string("fastcgi_no_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
+      NULL },
+
     { ngx_string("fastcgi_cache_valid"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_file_cache_valid_set_slot,
@@ -391,20 +402,6 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
       &ngx_http_fastcgi_next_upstream_masks },
 
-    { ngx_string("fastcgi_upstream_max_fails"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_fastcgi_upstream_max_fails_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("fastcgi_upstream_fail_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_fastcgi_upstream_fail_timeout_unsupported,
-      0,
-      0,
-      NULL },
-
     { ngx_string("fastcgi_param"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
       ngx_conf_set_keyval_slot,
@@ -413,14 +410,14 @@ static ngx_command_t  ngx_http_fastcgi_c
       NULL },
 
     { ngx_string("fastcgi_pass_header"),
-      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_str_array_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_headers),
       NULL },
 
     { ngx_string("fastcgi_hide_header"),
-      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_str_array_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
@@ -431,7 +428,7 @@ static ngx_command_t  ngx_http_fastcgi_c
       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_http_upstream_ignore_headers_masks },
 
     { ngx_string("fastcgi_catch_stderr"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
@@ -523,6 +520,21 @@ static ngx_str_t  ngx_http_fastcgi_hide_
 };
 
 
+#if (NGX_HTTP_CACHE)
+
+static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
+    { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_RANGE"), ngx_string("") },
+    { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
+    { ngx_null_string, ngx_null_string }
+};
+
+#endif
+
+
 static ngx_path_init_t  ngx_http_fastcgi_temp_path = {
     ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
 };
@@ -564,9 +576,7 @@ ngx_http_fastcgi_handler(ngx_http_reques
 
     u = r->upstream;
 
-    u->schema.len = sizeof("fastcgi://") - 1;
-    u->schema.data = (u_char *) "fastcgi://";
-
+    ngx_str_set(&u->schema, "fastcgi://");
     u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
 
     u->conf = &flcf->upstream;
@@ -603,49 +613,46 @@ ngx_http_fastcgi_handler(ngx_http_reques
 static ngx_int_t
 ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
 {
-    ngx_url_t  u;
-
-    ngx_memzero(&u, sizeof(ngx_url_t));
-
-    if (ngx_http_script_run(r, &u.url, flcf->fastcgi_lengths->elts, 0,
+    ngx_url_t             url;
+    ngx_http_upstream_t  *u;
+
+    ngx_memzero(&url, sizeof(ngx_url_t));
+
+    if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
                             flcf->fastcgi_values->elts)
         == NULL)
     {
         return NGX_ERROR;
     }
 
-    u.no_resolve = 1;
-
-    if (ngx_parse_url(r->pool, &u) != NGX_OK) {
-         if (u.err) {
+    url.no_resolve = 1;
+
+    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+         if (url.err) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "%s in upstream \"%V\"", u.err, &u.url);
+                          "%s in upstream \"%V\"", url.err, &url.url);
         }
 
         return NGX_ERROR;
     }
 
-    if (u.no_port) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no port in upstream \"%V\"", &u.url);
-        return NGX_ERROR;
-    }
-
-    r->upstream->resolved = ngx_pcalloc(r->pool,
-                                        sizeof(ngx_http_upstream_resolved_t));
-    if (r->upstream->resolved == NULL) {
+    u = r->upstream;
+
+    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+    if (u->resolved == NULL) {
         return NGX_ERROR;
     }
 
-    if (u.addrs && u.addrs[0].sockaddr) {
-        r->upstream->resolved->sockaddr = u.addrs[0].sockaddr;
-        r->upstream->resolved->socklen = u.addrs[0].socklen;
-        r->upstream->resolved->naddrs = 1;
-        r->upstream->resolved->host = u.addrs[0].name;
+    if (url.addrs && url.addrs[0].sockaddr) {
+        u->resolved->sockaddr = url.addrs[0].sockaddr;
+        u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->naddrs = 1;
+        u->resolved->host = url.addrs[0].name;
 
     } else {
-        r->upstream->resolved->host = u.host;
-        r->upstream->resolved->port = u.port;
+        u->resolved->host = url.host;
+        u->resolved->port = url.port;
+        u->resolved->no_port = url.no_port;
     }
 
     return NGX_OK;
@@ -681,13 +688,14 @@ static ngx_int_t
 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
 {
     off_t                         file_pos;
-    u_char                        ch, *pos;
-    size_t                        size, len, key_len, val_len, padding;
-    ngx_uint_t                    i, n, next;
+    u_char                        ch, *pos, *lowcase_key;
+    size_t                        size, len, key_len, val_len, padding,
+                                  allocated;
+    ngx_uint_t                    i, n, next, hash, header_params;
     ngx_buf_t                    *b;
     ngx_chain_t                  *cl, *body;
     ngx_list_part_t              *part;
-    ngx_table_elt_t              *header;
+    ngx_table_elt_t              *header, **ignored;
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t      e, le;
     ngx_http_fastcgi_header_t    *h;
@@ -695,6 +703,8 @@ ngx_http_fastcgi_create_request(ngx_http
     ngx_http_script_len_code_pt   lcode;
 
     len = 0;
+    header_params = 0;
+    ignored = NULL;
 
     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
@@ -723,6 +733,16 @@ ngx_http_fastcgi_create_request(ngx_http
 
     if (flcf->upstream.pass_request_headers) {
 
+        allocated = 0;
+        lowcase_key = NULL;
+
+        if (flcf->header_params) {
+            ignored = ngx_palloc(r->pool, flcf->header_params * sizeof(void *));
+            if (ignored == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
         part = &r->headers_in.headers.part;
         header = part->elts;
 
@@ -738,9 +758,44 @@ ngx_http_fastcgi_create_request(ngx_http
                 i = 0;
             }
 
-            len += ((sizeof("HTTP_") - 1 + header[i].key.len > 127) ? 4 : 1)
-                + ((header[i].value.len > 127) ? 4 : 1)
-                + sizeof("HTTP_") - 1 + header[i].key.len + header[i].value.len;
+            if (flcf->header_params) {
+                if (allocated < header[i].key.len) {
+                    allocated = header[i].key.len + 16;
+                    lowcase_key = ngx_pnalloc(r->pool, allocated);
+                    if (lowcase_key == NULL) {
+                        return NGX_ERROR;
+                    }
+                }
+
+                hash = 0;
+
+                for (n = 0; n < header[i].key.len; n++) {
+                    ch = header[i].key.data[n];
+
+                    if (ch >= 'A' && ch <= 'Z') {
+                        ch |= 0x20;
+
+                    } else if (ch == '-') {
+                        ch = '_';
+                    }
+
+                    hash = ngx_hash(hash, ch);
+                    lowcase_key[n] = ch;
+                }
+
+                if (ngx_hash_find(&flcf->headers_hash, hash, lowcase_key, n)) {
+                    ignored[header_params++] = &header[i];
+                    continue;
+                }
+
+                n += sizeof("HTTP_") - 1;
+
+            } else {
+                n = sizeof("HTTP_") - 1 + header[i].key.len;
+            }
+
+            len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
+                + n + header[i].value.len;
         }
     }
 
@@ -860,26 +915,32 @@ ngx_http_fastcgi_create_request(ngx_http
                 i = 0;
             }
 
-            len = sizeof("HTTP_") - 1 + header[i].key.len;
-            if (len > 127) {
-                *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-                *b->last++ = (u_char) ((len >> 16) & 0xff);
-                *b->last++ = (u_char) ((len >> 8) & 0xff);
-                *b->last++ = (u_char) (len & 0xff);
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next;
+                }
+            }
+
+            key_len = sizeof("HTTP_") - 1 + header[i].key.len;
+            if (key_len > 127) {
+                *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
+                *b->last++ = (u_char) ((key_len >> 16) & 0xff);
+                *b->last++ = (u_char) ((key_len >> 8) & 0xff);
+                *b->last++ = (u_char) (key_len & 0xff);
 
             } else {
-                *b->last++ = (u_char) len;
+                *b->last++ = (u_char) key_len;
             }
 
-            len = header[i].value.len;
-            if (len > 127) {
-                *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-                *b->last++ = (u_char) ((len >> 16) & 0xff);
-                *b->last++ = (u_char) ((len >> 8) & 0xff);
-                *b->last++ = (u_char) (len & 0xff);
+            val_len = header[i].value.len;
+            if (val_len > 127) {
+                *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
+                *b->last++ = (u_char) ((val_len >> 16) & 0xff);
+                *b->last++ = (u_char) ((val_len >> 8) & 0xff);
+                *b->last++ = (u_char) (val_len & 0xff);
 
             } else {
-                *b->last++ = (u_char) len;
+                *b->last++ = (u_char) val_len;
             }
 
             b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
@@ -897,8 +958,15 @@ ngx_http_fastcgi_create_request(ngx_http
                 *b->last++ = ch;
             }
 
-            b->last = ngx_copy(b->last, header[i].value.data,
-                               header[i].value.len);
+            b->last = ngx_copy(b->last, header[i].value.data, val_len);
+
+            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "fastcgi param: \"%*s: %*s\"",
+                           key_len, b->last - (key_len + val_len),
+                           val_len, b->last - val_len);
+        next:
+
+            continue;
         }
     }
 
@@ -1057,6 +1125,7 @@ ngx_http_fastcgi_reinit_request(ngx_http
 
     f->state = ngx_http_fastcgi_st_version;
     f->fastcgi_stdout = 0;
+    f->large_stderr = 0;
 
     return NGX_OK;
 }
@@ -1199,8 +1268,18 @@ ngx_http_fastcgi_process_header(ngx_http
                          * of the PHP warnings to not allocate memory
                          */
 
+#if (NGX_HTTP_CACHE)
+                        if (r->cache) {
+                            u->buffer.pos = u->buffer.start
+                                                     + r->cache->header_start;
+                        } else {
+                            u->buffer.pos = u->buffer.start;
+                        }
+#else
                         u->buffer.pos = u->buffer.start;
-                        u->buffer.last = u->buffer.start;
+#endif
+                        u->buffer.last = u->buffer.pos;
+                        f->large_stderr = 1;
                     }
 
                     return NGX_AGAIN;
@@ -1216,6 +1295,46 @@ ngx_http_fastcgi_process_header(ngx_http
 
         /* f->type == NGX_HTTP_FASTCGI_STDOUT */
 
+#if (NGX_HTTP_CACHE)
+
+        if (f->large_stderr && r->cache) {
+            u_char                     *start;
+            ssize_t                     len;
+            ngx_http_fastcgi_header_t  *fh;
+
+            start = u->buffer.start + r->cache->header_start;
+
+            len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);
+
+            /*
+             * A tail of large stderr output before HTTP header is placed
+             * in a cache file without a FastCGI record header.
+             * To workaround it we put a dummy FastCGI record header at the
+             * start of the stderr output or update r->cache_header_start,
+             * if there is no enough place for the record header.
+             */
+
+            if (len >= 0) {
+                fh = (ngx_http_fastcgi_header_t *) start;
+                fh->version = 1;
+                fh->type = NGX_HTTP_FASTCGI_STDERR;
+                fh->request_id_hi = 0;
+                fh->request_id_lo = 1;
+                fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
+                fh->content_length_lo = (u_char) (len & 0xff);
+                fh->padding_length = 0;
+                fh->reserved = 0;
+
+            } else {
+                r->cache->header_start += u->buffer.pos - start
+                                           - sizeof(ngx_http_fastcgi_header_t);
+            }
+
+            f->large_stderr = 0;
+        }
+
+#endif
+
         f->fastcgi_stdout = 1;
 
         start = u->buffer.pos;
@@ -1374,15 +1493,12 @@ ngx_http_fastcgi_process_header(ngx_http
 
                 } else if (u->headers_in.location) {
                     u->headers_in.status_n = 302;
-                    u->headers_in.status_line.len =
-                                           sizeof("302 Moved Temporarily") - 1;
-                    u->headers_in.status_line.data =
-                                           (u_char *) "302 Moved Temporarily";
+                    ngx_str_set(&u->headers_in.status_line,
+                                "302 Moved Temporarily");
 
                 } else {
                     u->headers_in.status_n = 200;
-                    u->headers_in.status_line.len = sizeof("200 OK") - 1;
-                    u->headers_in.status_line.data = (u_char *) "200 OK";
+                    ngx_str_set(&u->headers_in.status_line, "200 OK");
                 }
 
                 if (u->state) {
@@ -1847,8 +1963,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
      *     conf->upstream.store_lengths = NULL;
      *     conf->upstream.store_values = NULL;
      *
-     *     conf->index.len = 0;
-     *     conf->index.data = NULL;
+     *     conf->index.len = { 0, NULL };
      */
 
     conf->upstream.store = NGX_CONF_UNSET;
@@ -1873,6 +1988,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
+    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
 #endif
 
@@ -1900,8 +2017,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     size_t                        size;
     uintptr_t                    *code;
     ngx_uint_t                    i;
+    ngx_array_t                   headers_names;
     ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
+    ngx_http_core_loc_conf_t     *clcf;
     ngx_http_script_compile_t     sc;
     ngx_http_script_copy_code_t  *copy;
 
@@ -2093,6 +2213,18 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
 
+    ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
+                             prev->upstream.cache_bypass, NULL);
+
+    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+                             prev->upstream.no_cache, NULL);
+
+    if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
+        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+             "\"fastcgi_no_cache\" functionality has been changed in 0.8.46, "
+             "now it should be used together with \"fastcgi_cache_bypass\"");
+    }
+
     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                              prev->upstream.cache_valid, NULL);
 
@@ -2120,9 +2252,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     hash.name = "fastcgi_hide_headers_hash";
 
     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
-                                            &prev->upstream,
-                                            ngx_http_fastcgi_hide_headers,
-                                            &hash)
+             &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -2137,6 +2267,13 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         conf->fastcgi_values = prev->fastcgi_values;
     }
 
+    if (conf->upstream.upstream || conf->fastcgi_lengths) {
+        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+        if (clcf->handler == NULL && clcf->lmt_excpt) {
+            clcf->handler = ngx_http_fastcgi_handler;
+        }
+    }
+
 #if (NGX_PCRE)
     if (conf->split_regex == NULL) {
         conf->split_regex = prev->split_regex;
@@ -2149,10 +2286,32 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         conf->params_len = prev->params_len;
         conf->params = prev->params;
         conf->params_source = prev->params_source;
+        conf->headers_hash = prev->headers_hash;
+
+#if (NGX_HTTP_CACHE)
+
+        if (conf->params_source == NULL) {
+
+            if ((conf->upstream.cache == NULL)
+                == (prev->upstream.cache == NULL))
+            {
+                return NGX_CONF_OK;
+            }
+
+            /* 6 is a number of ngx_http_fastcgi_cache_headers entries */
+            conf->params_source = ngx_array_create(cf->pool, 6,
+                                                   sizeof(ngx_keyval_t));
+            if (conf->params_source == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+#else
 
         if (conf->params_source == NULL) {
             return NGX_CONF_OK;
         }
+
+#endif
     }
 
     conf->params_len = ngx_array_create(cf->pool, 64, 1);
@@ -2165,89 +2324,100 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         return NGX_CONF_ERROR;
     }
 
+    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     src = conf->params_source->elts;
-    for (i = 0; i < conf->params_source->nelts; i++) {
-
-        if (ngx_http_script_variables_count(&src[i].value) == 0) {
-            copy = ngx_array_push_n(conf->params_len,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
+
+#if (NGX_HTTP_CACHE)
+
+    if (conf->upstream.cache) {
+        ngx_keyval_t  *h, *s;
+
+        for (h = ngx_http_fastcgi_cache_headers; h->key.len; h++) {
+
+            for (i = 0; i < conf->params_source->nelts; i++) {
+                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+                    goto next;
+                }
+            }
+
+            s = ngx_array_push(conf->params_source);
+            if (s == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            copy->code = (ngx_http_script_code_pt)
-                                                  ngx_http_script_copy_len_code;
-            copy->len = src[i].key.len;
-
-
-            copy = ngx_array_push_n(conf->params_len,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            copy->code = (ngx_http_script_code_pt)
-                                                 ngx_http_script_copy_len_code;
-            copy->len = src[i].value.len;
-
-
-            size = (sizeof(ngx_http_script_copy_code_t)
-                       + src[i].key.len + src[i].value.len
-                       + sizeof(uintptr_t) - 1)
-                    & ~(sizeof(uintptr_t) - 1);
-
-            copy = ngx_array_push_n(conf->params, size);
-            if (copy == NULL) {
+            *s = *h;
+
+            src = conf->params_source->elts;
+
+        next:
+
+            h++;
+        }
+    }
+
+#endif
+
+    for (i = 0; i < conf->params_source->nelts; i++) {
+
+        if (src[i].key.len > sizeof("HTTP_") - 1
+            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
+        {
+            hk = ngx_array_push(&headers_names);
+            if (hk == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            copy->code = ngx_http_script_copy_code;
-            copy->len = src[i].key.len + src[i].value.len;
-
-            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-
-            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
-            ngx_memcpy(p, src[i].value.data, src[i].value.len);
-
-        } else {
-            copy = ngx_array_push_n(conf->params_len,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
-                return NGX_CONF_ERROR;
+            hk->key.len = src[i].key.len - 5;
+            hk->key.data = src[i].key.data + 5;
+            hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
+            hk->value = (void *) 1;
+
+            if (src[i].value.len == 0) {
+                continue;
             }
-
-            copy->code = (ngx_http_script_code_pt)
-                                                 ngx_http_script_copy_len_code;
-            copy->len = src[i].key.len;
-
-
-            size = (sizeof(ngx_http_script_copy_code_t)
-                    + src[i].key.len + sizeof(uintptr_t) - 1)
-                    & ~(sizeof(uintptr_t) - 1);
-
-            copy = ngx_array_push_n(conf->params, size);
-            if (copy == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            copy->code = ngx_http_script_copy_code;
-            copy->len = src[i].key.len;
-
-            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-            ngx_memcpy(p, src[i].key.data, src[i].key.len);
-
-
-            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
-
-            sc.cf = cf;
-            sc.source = &src[i].value;
-            sc.flushes = &conf->flushes;
-            sc.lengths = &conf->params_len;
-            sc.values = &conf->params;
-
-            if (ngx_http_script_compile(&sc) != NGX_OK) {
-                return NGX_CONF_ERROR;
-            }
+        }
+
+        copy = ngx_array_push_n(conf->params_len,
+                                sizeof(ngx_http_script_copy_code_t));
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+        copy->len = src[i].key.len;
+
+
+        size = (sizeof(ngx_http_script_copy_code_t)
+                + src[i].key.len + sizeof(uintptr_t) - 1)
+                & ~(sizeof(uintptr_t) - 1);
+
+        copy = ngx_array_push_n(conf->params, size);
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = ngx_http_script_copy_code;
+        copy->len = src[i].key.len;
+
+        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+        ngx_memcpy(p, src[i].key.data, src[i].key.len);
+
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &src[i].value;
+        sc.flushes = &conf->flushes;
+        sc.lengths = &conf->params_len;
+        sc.values = &conf->params;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
         }
 
         code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
@@ -2273,6 +2443,22 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     *code = (uintptr_t) NULL;
 
+
+    conf->header_params = headers_names.nelts;
+
+    hash.hash = &conf->headers_hash;
+    hash.key = ngx_hash_key_lc;
+    hash.max_size = 512;
+    hash.bucket_size = 64;
+    hash.name = "fastcgi_params_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
+
+    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     return NGX_CONF_OK;
 }
 
@@ -2374,27 +2560,25 @@ ngx_http_fastcgi_split(ngx_http_request_
 
     n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
 
+    if (n >= 0) { /* match */
+        f->script_name.len = captures[3] - captures[2];
+        f->script_name.data = r->uri.data + captures[2];
+
+        f->path_info.len = captures[5] - captures[4];
+        f->path_info.data = r->uri.data + captures[4];
+
+        return f;
+    }
+
     if (n == NGX_REGEX_NO_MATCHED) {
         f->script_name = r->uri;
         return f;
     }
 
-    if (n < 0) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
-                      n, &r->uri, &flcf->split_name);
-        return NULL;
-    }
-
-    /* match */
-
-    f->script_name.len = captures[3] - captures[2];
-    f->script_name.data = r->uri.data;
-
-    f->path_info.len = captures[5] - captures[4];
-    f->path_info.data = r->uri.data + f->script_name.len;
-
-    return f;
+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                  ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
+                  n, &r->uri, &flcf->split_name);
+    return NULL;
 
 #else
 
@@ -2485,39 +2669,34 @@ ngx_http_fastcgi_split_path_info(ngx_con
 #if (NGX_PCRE)
     ngx_http_fastcgi_loc_conf_t *flcf = conf;
 
-    ngx_int_t   n;
-    ngx_str_t  *value, err;
-    u_char      errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t            *value;
+    ngx_regex_compile_t   rc;
+    u_char                errstr[NGX_MAX_CONF_ERRSTR];
 
     value = cf->args->elts;
 
     flcf->split_name = value[1];
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
-
-    flcf->split_regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
-
-    if (flcf->split_regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pattern = value[1];
+    rc.pool = cf->pool;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
+
+    if (ngx_regex_compile(&rc) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
         return NGX_CONF_ERROR;
     }
 
-    n = ngx_regex_capture_count(flcf->split_regex);
-
-    if (n < 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           ngx_regex_capture_count_n " failed for "
-                           "pattern \"%V\"", &value[1]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (n != 2) {
+    if (rc.captures != 2) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "pattern \"%V\" must have 2 captures", &value[1]);
         return NGX_CONF_ERROR;
     }
 
+    flcf->split_regex = rc.regex;
+
     return NGX_CONF_OK;
 
 #else
@@ -2678,29 +2857,3 @@ ngx_http_fastcgi_lowat_check(ngx_conf_t 
 
     return NGX_CONF_OK;
 }
-
-
-static char *
-ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"fastcgi_upstream_max_fails\" is not supported, "
-         "use the \"max_fails\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"fastcgi_upstream_fail_timeout\" is not supported, "
-         "use the \"fail_timeout\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -80,10 +80,6 @@ ngx_http_flv_handler(ngx_http_request_t 
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     rc = ngx_http_discard_request_body(r);
 
     if (rc != NGX_OK) {
@@ -106,6 +102,7 @@ ngx_http_flv_handler(ngx_http_request_t 
 
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
+    of.read_ahead = clcf->read_ahead;
     of.directio = clcf->directio;
     of.valid = clcf->open_file_cache_valid;
     of.min_uses = clcf->open_file_cache_min_uses;
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -10,41 +10,53 @@
 
 
 typedef struct {
+    ngx_http_variable_value_t       *value;
     u_short                          start;
     u_short                          end;
-    ngx_http_variable_value_t       *value;
 } ngx_http_geo_range_t;
 
 
 typedef struct {
-    ngx_http_geo_range_t            *ranges;
-    ngx_uint_t                       n;
-} ngx_http_geo_low_ranges_t;
-
-
-typedef struct {
-    ngx_http_geo_low_ranges_t        low[0x10000];
+    ngx_http_geo_range_t           **low;
     ngx_http_variable_value_t       *default_value;
 } ngx_http_geo_high_ranges_t;
 
 
 typedef struct {
+    ngx_str_node_t                   sn;
+    ngx_http_variable_value_t       *value;
+    size_t                           offset;
+} ngx_http_geo_variable_value_node_t;
+
+
+typedef struct {
     ngx_http_variable_value_t       *value;
     ngx_str_t                       *net;
-    ngx_http_geo_high_ranges_t      *high;
+    ngx_http_geo_high_ranges_t       high;
     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;
+
+    size_t                           data_size;
+
+    ngx_str_t                        include_name;
+    ngx_uint_t                       includes;
+    ngx_uint_t                       entries;
+
+    unsigned                         ranges:1;
+    unsigned                         outside_entries:1;
+    unsigned                         allow_binary_include:1;
+    unsigned                         binary_include:1;
 } ngx_http_geo_conf_ctx_t;
 
 
 typedef struct {
     union {
         ngx_radix_tree_t            *tree;
-        ngx_http_geo_high_ranges_t  *high;
+        ngx_http_geo_high_ranges_t   high;
     } u;
 
     ngx_array_t                     *proxies;
@@ -73,6 +85,13 @@ static char *ngx_http_geo_add_proxy(ngx_
     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 char *ngx_http_geo_include(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
+    ngx_str_t *name);
+static ngx_int_t ngx_http_geo_include_binary_base(ngx_conf_t *cf,
+    ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *name);
+static void ngx_http_geo_create_binary_base(ngx_http_geo_conf_ctx_t *ctx);
+static u_char *ngx_http_geo_copy_values(u_char *base, u_char *p,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 
 
 static ngx_command_t  ngx_http_geo_commands[] = {
@@ -119,6 +138,20 @@ ngx_module_t  ngx_http_geo_module = {
 };
 
 
+typedef struct {
+    u_char    GEORNG[6];
+    u_char    version;
+    u_char    ptr_size;
+    uint32_t  endianess;
+    uint32_t  crc32;
+} ngx_http_geo_header_t;
+
+
+static ngx_http_geo_header_t  ngx_http_geo_header = {
+    { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0
+};
+
+
 /* AF_INET only */
 
 static ngx_int_t
@@ -148,23 +181,24 @@ ngx_http_geo_range_variable(ngx_http_req
     ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
 
     in_addr_t              addr;
-    ngx_uint_t             i, n;
+    ngx_uint_t             n;
     ngx_http_geo_range_t  *range;
 
-    *v = *ctx->u.high->default_value;
+    *v = *ctx->u.high.default_value;
 
     addr = ngx_http_geo_addr(r, ctx);
 
-    range = ctx->u.high->low[addr >> 16].ranges;
-
-    n = addr & 0xffff;
+    range = ctx->u.high.low[addr >> 16];
 
-    for (i = 0; i < ctx->u.high->low[addr >> 16].n; i++) {
-        if (n >= (ngx_uint_t) range[i].start
-            && n <= (ngx_uint_t) range[i].end)
-        {
-            *v = *range[i].value;
-        }
+    if (range) {
+        n = addr & 0xffff;
+        do {
+            if (n >= (ngx_uint_t) range->start && n <= (ngx_uint_t) range->end)
+            {
+                *v = *range->value;
+                break;
+            }
+        } while ((++range)->value);
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -256,6 +290,7 @@ static char *
 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char                     *rv;
+    void                    **p;
     size_t                    len;
     ngx_str_t                *value, name;
     ngx_uint_t                i;
@@ -302,18 +337,20 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
+    ngx_memzero(&ctx, sizeof(ngx_http_geo_conf_ctx_t));
+
     ctx.temp_pool = ngx_create_pool(16384, cf->log);
     if (ctx.temp_pool == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel,
-                    ngx_http_variable_value_rbtree_insert);
+    ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, ngx_str_rbtree_insert_value);
 
-    ctx.high = NULL;
-    ctx.tree = NULL;
-    ctx.proxies = NULL;
     ctx.pool = cf->pool;
+    ctx.data_size = sizeof(ngx_http_geo_header_t)
+                  + sizeof(ngx_http_variable_value_t)
+                  + 0x10000 * sizeof(ngx_http_geo_range_t *);
+    ctx.allow_binary_include = 1;
 
     save = *cf;
     cf->pool = pool;
@@ -327,25 +364,35 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
 
     geo->proxies = ctx.proxies;
 
-    if (ctx.high) {
+    if (ctx.high.low) {
+
+        if (!ctx.binary_include) {
+            for (i = 0; i < 0x10000; i++) {
+                a = (ngx_array_t *) ctx.high.low[i];
+
+                if (a == NULL || a->nelts == 0) {
+                    continue;
+                }
 
-        for (i = 0; i < 0x10000; i++) {
-            a = (ngx_array_t *) ctx.high->low[i].ranges;
+                len = a->nelts * sizeof(ngx_http_geo_range_t);
 
-            if (a == NULL || a->nelts == 0) {
-                continue;
+                ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *));
+                if (ctx.high.low[i] == NULL) {
+                    return NGX_CONF_ERROR;
+                }
+
+                p = (void **) ngx_cpymem(ctx.high.low[i], a->elts, len);
+                *p = NULL;
+                ctx.data_size += len + sizeof(void *);
             }
 
-            ctx.high->low[i].n = a->nelts;
-
-            len = a->nelts * sizeof(ngx_http_geo_range_t);
-
-            ctx.high->low[i].ranges = ngx_palloc(cf->pool, len);
-            if (ctx.high->low[i].ranges == NULL ){
-                return NGX_CONF_ERROR;
+            if (ctx.allow_binary_include
+                && !ctx.outside_entries
+                && ctx.entries > 100000
+                && ctx.includes == 1)
+            {
+                ngx_http_geo_create_binary_base(&ctx);
             }
-
-            ngx_memcpy(ctx.high->low[i].ranges, a->elts, len);
         }
 
         geo->u.high = ctx.high;
@@ -353,13 +400,13 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
         var->get_handler = ngx_http_geo_range_variable;
         var->data = (uintptr_t) geo;
 
+        if (ctx.high.default_value == NULL) {
+            ctx.high.default_value = &ngx_http_variable_null_value;
+        }
+
         ngx_destroy_pool(ctx.temp_pool);
         ngx_destroy_pool(pool);
 
-        if (ctx.high->default_value == NULL) {
-            ctx.high->default_value = &ngx_http_variable_null_value;
-        }
-
     } else {
         if (ctx.tree == NULL) {
             ctx.tree = ngx_radix_tree_create(cf->pool, -1);
@@ -396,7 +443,7 @@ static char *
 ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
 {
     char                     *rv;
-    ngx_str_t                *value, file;
+    ngx_str_t                *value;
     ngx_cidr_t                cidr;
     ngx_http_geo_conf_ctx_t  *ctx;
 
@@ -415,11 +462,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
                 goto failed;
             }
 
-            ctx->high = ngx_pcalloc(ctx->pool,
-                                    sizeof(ngx_http_geo_high_ranges_t));
-            if (ctx->high == NULL) {
-                goto failed;
-            }
+            ctx->ranges = 1;
 
             rv = NGX_CONF_OK;
 
@@ -435,20 +478,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
 
     if (ngx_strcmp(value[0].data, "include") == 0) {
 
-        file.len = value[1].len++;
-
-        file.data = ngx_pstrdup(ctx->temp_pool, &value[1]);
-        if (file.data == NULL) {
-            goto failed;
-        }
-
-        if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){
-            goto failed;
-        }
-
-        ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
-
-        rv = ngx_conf_parse(cf, &file);
+        rv = ngx_http_geo_include(cf, ctx, &value[1]);
 
         goto done;
 
@@ -463,7 +493,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command
         goto done;
     }
 
-    if (ctx->high) {
+    if (ctx->ranges) {
         rv = ngx_http_geo_range(cf, ctx, value);
 
     } else {
@@ -488,30 +518,45 @@ static char *
 ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
     ngx_str_t *value)
 {
-    u_char                     *p, *last;
-    in_addr_t                   start, end;
-    ngx_str_t                  *net;
-    ngx_uint_t                  del;
-    ngx_http_variable_value_t  *old;
+    u_char      *p, *last;
+    in_addr_t    start, end;
+    ngx_str_t   *net;
+    ngx_uint_t   del;
 
     if (ngx_strcmp(value[0].data, "default") == 0) {
 
-        old = ctx->high->default_value;
-
-        ctx->high->default_value = ngx_http_geo_value(cf, ctx, &value[1]);
-        if (ctx->high->default_value == NULL) {
-            return NGX_CONF_ERROR;
+        if (ctx->high.default_value) {
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                "duplicate default geo range value: \"%V\", old value: \"%v\"",
+                &value[1], ctx->high.default_value);
         }
 
-        if (old) {
-            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                    "duplicate range \"%V\", value: \"%v\", old value: \"%v\"",
-                    &value[0], ctx->high->default_value, old);
+        ctx->high.default_value = ngx_http_geo_value(cf, ctx, &value[1]);
+        if (ctx->high.default_value == NULL) {
+            return NGX_CONF_ERROR;
         }
 
         return NGX_CONF_OK;
     }
 
+    if (ctx->binary_include) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "binary geo range base \"%s\" may not be mixed with usual entries",
+            ctx->include_name.data);
+        return NGX_CONF_ERROR;
+    }
+
+    if (ctx->high.low == NULL) {
+        ctx->high.low = ngx_pcalloc(ctx->pool,
+                                    0x10000 * sizeof(ngx_http_geo_range_t *));
+        if (ctx->high.low == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    ctx->entries++;
+    ctx->outside_entries = 1;
+
     if (ngx_strcmp(value[0].data, "delete") == 0) {
         net = &value[1];
         del = 1;
@@ -589,7 +634,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
     ngx_array_t           *a;
     ngx_http_geo_range_t  *range;
 
-    for (n = start; n <= end; n += 0x10000) {
+    for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) {
 
         h = n >> 16;
 
@@ -606,7 +651,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
             e = 0xffff;
         }
 
-        a = (ngx_array_t *) ctx->high->low[h].ranges;
+        a = (ngx_array_t *) ctx->high.low[h];
 
         if (a == NULL) {
             a = ngx_array_create(ctx->temp_pool, 64,
@@ -615,7 +660,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
                 return NGX_CONF_ERROR;
             }
 
-            ctx->high->low[h].ranges = (ngx_http_geo_range_t *) a;
+            ctx->high.low[h] = (ngx_http_geo_range_t *) a;
         }
 
         i = a->nelts;
@@ -640,7 +685,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
 
                 range = a->elts;
 
-                ngx_memcpy(&range[i + 2], &range[i + 1],
+                ngx_memmove(&range[i + 2], &range[i + 1],
                            (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t));
 
                 range[i + 1].start = (u_short) s;
@@ -679,7 +724,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
 
                 range = a->elts;
 
-                ngx_memcpy(&range[i + 3], &range[i + 1],
+                ngx_memmove(&range[i + 3], &range[i + 1],
                            (a->nelts - 3 - i) * sizeof(ngx_http_geo_range_t));
 
                 range[i + 2].start = (u_short) (e + 1);
@@ -707,7 +752,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
 
                 range = a->elts;
 
-                ngx_memcpy(&range[i + 1], &range[i],
+                ngx_memmove(&range[i + 1], &range[i],
                            (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t));
 
                 range[i + 1].start = (u_short) (e + 1);
@@ -731,7 +776,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n
 
                 range = a->elts;
 
-                ngx_memcpy(&range[i + 2], &range[i + 1],
+                ngx_memmove(&range[i + 2], &range[i + 1],
                            (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t));
 
                 range[i + 1].start = (u_short) s;
@@ -803,7 +848,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf
             e = 0xffff;
         }
 
-        a = (ngx_array_t *) ctx->high->low[h].ranges;
+        a = (ngx_array_t *) ctx->high.low[h];
 
         if (a == NULL) {
             warn = 1;
@@ -816,7 +861,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf
             if (s == (ngx_uint_t) range[i].start
                 && e == (ngx_uint_t) range[i].end)
             {
-                ngx_memcpy(&range[i], &range[i + 1],
+                ngx_memmove(&range[i], &range[i + 1],
                            (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t));
 
                 a->nelts--;
@@ -929,16 +974,17 @@ 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)
 {
-    uint32_t                         hash;
-    ngx_http_variable_value_t       *val;
-    ngx_http_variable_value_node_t  *vvn;
+    uint32_t                             hash;
+    ngx_http_variable_value_t           *val;
+    ngx_http_geo_variable_value_node_t  *gvvn;
 
     hash = ngx_crc32_long(value->data, value->len);
 
-    val = ngx_http_variable_value_lookup(&ctx->rbtree, value, hash);
+    gvvn = (ngx_http_geo_variable_value_node_t *)
+               ngx_str_rbtree_lookup(&ctx->rbtree, value, hash);
 
-    if (val) {
-        return val;
+    if (gvvn) {
+        return gvvn->value;
     }
 
     val = ngx_palloc(ctx->pool, sizeof(ngx_http_variable_value_t));
@@ -956,16 +1002,22 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_h
     val->no_cacheable = 0;
     val->not_found = 0;
 
-    vvn = ngx_palloc(ctx->temp_pool, sizeof(ngx_http_variable_value_node_t));
-    if (vvn == NULL) {
+    gvvn = ngx_palloc(ctx->temp_pool,
+                      sizeof(ngx_http_geo_variable_value_node_t));
+    if (gvvn == NULL) {
         return NULL;
     }
 
-    vvn->node.key = hash;
-    vvn->len = val->len;
-    vvn->value = val;
+    gvvn->sn.node.key = hash;
+    gvvn->sn.str.len = val->len;
+    gvvn->sn.str.data = val->data;
+    gvvn->value = val;
+    gvvn->offset = 0;
 
-    ngx_rbtree_insert(&ctx->rbtree, &vvn->node);
+    ngx_rbtree_insert(&ctx->rbtree, &gvvn->sn.node);
+
+    ctx->data_size += ngx_align(sizeof(ngx_http_variable_value_t) + value->len,
+                                sizeof(void *));
 
     return val;
 }
@@ -1030,3 +1082,335 @@ ngx_http_geo_cidr_value(ngx_conf_t *cf, 
 
     return NGX_OK;
 }
+
+
+static char *
+ngx_http_geo_include(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
+    ngx_str_t *name)
+{
+    char       *rv;
+    ngx_str_t   file;
+
+    file.len = name->len + 4;
+    file.data = ngx_pnalloc(ctx->temp_pool, name->len + 5);
+    if (file.data == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_sprintf(file.data, "%V.bin%Z", name);
+
+    if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (ctx->ranges) {
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
+
+        switch (ngx_http_geo_include_binary_base(cf, ctx, &file)) {
+        case NGX_OK:
+            return NGX_CONF_OK;
+        case NGX_ERROR:
+            return NGX_CONF_ERROR;
+        default:
+            break;
+        }
+    }
+
+    file.len -= 4;
+    file.data[file.len] = '\0';
+
+    ctx->include_name = file;
+
+    if (ctx->outside_entries) {
+        ctx->allow_binary_include = 0;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
+
+    rv = ngx_conf_parse(cf, &file);
+
+    ctx->includes++;
+    ctx->outside_entries = 0;
+
+    return rv;
+}
+
+
+static ngx_int_t
+ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
+    ngx_str_t *name)
+{
+    u_char                     *base, ch;
+    time_t                      mtime;
+    size_t                      size, len;
+    ssize_t                     n;
+    uint32_t                    crc32;
+    ngx_err_t                   err;
+    ngx_int_t                   rc;
+    ngx_uint_t                  i;
+    ngx_file_t                  file;
+    ngx_file_info_t             fi;
+    ngx_http_geo_range_t       *range, **ranges;
+    ngx_http_geo_header_t      *header;
+    ngx_http_variable_value_t  *vv;
+
+    ngx_memzero(&file, sizeof(ngx_file_t));
+    file.name = *name;
+    file.log = cf->log;
+
+    file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0);
+    if (file.fd == NGX_INVALID_FILE) {
+        err = ngx_errno;
+        if (err != NGX_ENOENT) {
+            ngx_conf_log_error(NGX_LOG_CRIT, cf, err,
+                               ngx_open_file_n " \"%s\" failed", name->data);
+        }
+        return NGX_DECLINED;
+    }
+
+    if (ctx->outside_entries) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "binary geo range base \"%s\" may not be mixed with usual entries",
+            name->data);
+        rc = NGX_ERROR;
+        goto done;
+    }
+
+    if (ctx->binary_include) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "second binary geo range base \"%s\" may not be mixed with \"%s\"",
+            name->data, ctx->include_name.data);
+        rc = NGX_ERROR;
+        goto done;
+    }
+
+    if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
+        ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+                           ngx_fd_info_n " \"%s\" failed", name->data);
+        goto failed;
+    }
+
+    size = (size_t) ngx_file_size(&fi);
+    mtime = ngx_file_mtime(&fi);
+
+    ch = name->data[name->len - 4];
+    name->data[name->len - 4] = '\0';
+
+    if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
+        ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+                           ngx_file_info_n " \"%s\" failed", name->data);
+        goto failed;
+    }
+
+    name->data[name->len - 4] = ch;
+
+    if (mtime < ngx_file_mtime(&fi)) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "stale binary geo range base \"%s\"", name->data);
+        goto failed;
+    }
+
+    base = ngx_palloc(ctx->pool, size);
+    if (base == NULL) {
+        goto failed;
+    }
+
+    n = ngx_read_file(&file, base, size, 0);
+
+    if (n == NGX_ERROR) {
+        ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+                           ngx_read_file_n " \"%s\" failed", name->data);
+        goto failed;
+    }
+
+    if ((size_t) n != size) {
+        ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
+            ngx_read_file_n " \"%s\" returned only %z bytes instead of %z",
+            name->data, n, size);
+        goto failed;
+    }
+
+    header = (ngx_http_geo_header_t *) base;
+
+    if (size < 16 || ngx_memcmp(&ngx_http_geo_header, header, 12) != 0) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+             "incompatible binary geo range base \"%s\"", name->data);
+        goto failed;
+    }
+
+    ngx_crc32_init(crc32);
+
+    vv = (ngx_http_variable_value_t *) (base + sizeof(ngx_http_geo_header_t));
+
+    while(vv->data) {
+        len = ngx_align(sizeof(ngx_http_variable_value_t) + vv->len,
+                        sizeof(void *));
+        ngx_crc32_update(&crc32, (u_char *) vv, len);
+        vv->data += (size_t) base;
+        vv = (ngx_http_variable_value_t *) ((u_char *) vv + len);
+    }
+    ngx_crc32_update(&crc32, (u_char *) vv, sizeof(ngx_http_variable_value_t));
+    vv++;
+
+    ranges = (ngx_http_geo_range_t **) vv;
+
+    for (i = 0; i < 0x10000; i++) {
+        ngx_crc32_update(&crc32, (u_char *) &ranges[i], sizeof(void *));
+        if (ranges[i]) {
+            ranges[i] = (ngx_http_geo_range_t *)
+                            ((u_char *) ranges[i] + (size_t) base);
+        }
+    }
+
+    range = (ngx_http_geo_range_t *) &ranges[0x10000];
+
+    while ((u_char *) range < base + size) {
+        while (range->value) {
+            ngx_crc32_update(&crc32, (u_char *) range,
+                             sizeof(ngx_http_geo_range_t));
+            range->value = (ngx_http_variable_value_t *)
+                               ((u_char *) range->value + (size_t) base);
+            range++;
+        }
+        ngx_crc32_update(&crc32, (u_char *) range, sizeof(void *));
+        range = (ngx_http_geo_range_t *) ((u_char *) range + sizeof(void *));
+    }
+
+    ngx_crc32_final(crc32);
+
+    if (crc32 != header->crc32) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                  "CRC32 mismatch in binary geo range base \"%s\"", name->data);
+        goto failed;
+    }
+
+    ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
+                       "using binary geo range base \"%s\"", name->data);
+
+    ctx->include_name = *name;
+    ctx->binary_include = 1;
+    ctx->high.low = ranges;
+    rc = NGX_OK;
+
+    goto done;
+
+failed:
+
+    rc = NGX_DECLINED;
+
+done:
+
+    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", name->data);
+    }
+
+    return rc;
+}
+
+
+static void
+ngx_http_geo_create_binary_base(ngx_http_geo_conf_ctx_t *ctx)
+{
+    u_char                              *p;
+    uint32_t                             hash;
+    ngx_str_t                            s;
+    ngx_uint_t                           i;
+    ngx_file_mapping_t                   fm;
+    ngx_http_geo_range_t                *r, *range, **ranges;
+    ngx_http_geo_header_t               *header;
+    ngx_http_geo_variable_value_node_t  *gvvn;
+
+    fm.name = ngx_pnalloc(ctx->temp_pool, ctx->include_name.len + 5);
+    if (fm.name == NULL) {
+        return;
+    }
+
+    ngx_sprintf(fm.name, "%V.bin%Z", &ctx->include_name);
+
+    fm.size = ctx->data_size;
+    fm.log = ctx->pool->log;
+
+    ngx_log_error(NGX_LOG_NOTICE, fm.log, 0,
+                  "creating binary geo range base \"%s\"", fm.name);
+
+    if (ngx_create_file_mapping(&fm) != NGX_OK) {
+        return;
+    }
+
+    p = ngx_cpymem(fm.addr, &ngx_http_geo_header,
+                   sizeof(ngx_http_geo_header_t));
+
+    p = ngx_http_geo_copy_values(fm.addr, p, ctx->rbtree.root,
+                                 ctx->rbtree.sentinel);
+
+    p += sizeof(ngx_http_variable_value_t);
+
+    ranges = (ngx_http_geo_range_t **) p;
+
+    p += 0x10000 * sizeof(ngx_http_geo_range_t *);
+
+    for (i = 0; i < 0x10000; i++) {
+        r = ctx->high.low[i];
+        if (r == NULL) {
+            continue;
+        }
+
+        range = (ngx_http_geo_range_t *) p;
+        ranges[i] = (ngx_http_geo_range_t *) (p - (u_char *) fm.addr);
+
+        do {
+            s.len = r->value->len;
+            s.data = r->value->data;
+            hash = ngx_crc32_long(s.data, s.len);
+            gvvn = (ngx_http_geo_variable_value_node_t *)
+                        ngx_str_rbtree_lookup(&ctx->rbtree, &s, hash);
+
+            range->value = (ngx_http_variable_value_t *) gvvn->offset;
+            range->start = r->start;
+            range->end = r->end;
+            range++;
+
+        } while ((++r)->value);
+
+        range->value = NULL;
+
+        p = (u_char *) range + sizeof(void *);
+    }
+
+    header = fm.addr;
+    header->crc32 = ngx_crc32_long((u_char *) fm.addr
+                                       + sizeof(ngx_http_geo_header_t),
+                                   fm.size - sizeof(ngx_http_geo_header_t));
+
+    ngx_close_file_mapping(&fm);
+}
+
+
+static u_char *
+ngx_http_geo_copy_values(u_char *base, u_char *p, ngx_rbtree_node_t *node,
+    ngx_rbtree_node_t *sentinel)
+{
+    ngx_http_variable_value_t           *vv;
+    ngx_http_geo_variable_value_node_t  *gvvn;
+
+    if (node == sentinel) {
+        return p;
+    }
+
+    gvvn = (ngx_http_geo_variable_value_node_t *) node;
+    gvvn->offset = p - base;
+
+    vv = (ngx_http_variable_value_t *) p;
+    *vv = *gvvn->value;
+    p += sizeof(ngx_http_variable_value_t);
+    vv->data = (u_char *) (p - base);
+
+    p = ngx_cpymem(p, gvvn->sn.str.data, gvvn->sn.str.len);
+
+    p = ngx_align_ptr(p, sizeof(void *));
+
+    p = ngx_http_geo_copy_values(base, p, node->left, sentinel);
+
+    return ngx_http_geo_copy_values(base, p, node->right, sentinel);
+}
--- a/src/http/modules/ngx_http_geoip_module.c
+++ b/src/http/modules/ngx_http_geoip_module.c
@@ -30,6 +30,13 @@ static ngx_int_t ngx_http_geoip_country_
     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_region_name_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r);
 
 static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
 static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
@@ -43,14 +50,14 @@ static void ngx_http_geoip_cleanup(void 
 static ngx_command_t  ngx_http_geoip_commands[] = {
 
     { ngx_string("geoip_country"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
       ngx_http_geoip_country,
       NGX_HTTP_MAIN_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("geoip_city"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
       ngx_http_geoip_city,
       NGX_HTTP_MAIN_CONF_OFFSET,
       0,
@@ -93,29 +100,42 @@ ngx_module_t  ngx_http_geoip_module = {
 
 static ngx_http_variable_t  ngx_http_geoip_vars[] = {
 
-    { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable,
+    { 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,
+    { 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,
+    { 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,
+    { ngx_string("geoip_city_continent_code"), NULL,
+      ngx_http_geoip_city_variable,
+      offsetof(GeoIPRecord, continent_code), 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,
+    { 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_region_name"), NULL,
+      ngx_http_geoip_region_name_variable,
+      0, 0, 0 },
+
     { ngx_string("geoip_city"), NULL,
       ngx_http_geoip_city_variable,
       offsetof(GeoIPRecord, city), 0, 0 },
@@ -124,6 +144,22 @@ static ngx_http_variable_t  ngx_http_geo
       ngx_http_geoip_city_variable,
       offsetof(GeoIPRecord, postal_code), 0, 0 },
 
+    { ngx_string("geoip_latitude"), NULL,
+      ngx_http_geoip_city_float_variable,
+      offsetof(GeoIPRecord, latitude), 0, 0 },
+
+    { ngx_string("geoip_longitude"), NULL,
+      ngx_http_geoip_city_float_variable,
+      offsetof(GeoIPRecord, longitude), 0, 0 },
+
+    { ngx_string("geoip_dma_code"), NULL,
+      ngx_http_geoip_city_int_variable,
+      offsetof(GeoIPRecord, dma_code), 0, 0 },
+
+    { ngx_string("geoip_area_code"), NULL,
+      ngx_http_geoip_city_int_variable,
+      offsetof(GeoIPRecord, area_code), 0, 0 },
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
@@ -179,41 +215,22 @@ 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);
+    char         *val;
+    size_t        len;
+    GeoIPRecord  *gr;
 
-    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);
-
+    gr = ngx_http_geoip_get_city_record(r);
     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;
@@ -243,6 +260,129 @@ not_found:
 
 
 static ngx_int_t
+ngx_http_geoip_region_name_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    size_t        len;
+    const char   *val;
+    GeoIPRecord  *gr;
+
+    gr = ngx_http_geoip_get_city_record(r);
+    if (gr == NULL) {
+        goto not_found;
+    }
+
+    val = GeoIP_region_name_by_code(gr->country_code, gr->region);
+
+    GeoIPRecord_delete(gr);
+
+    if (val == NULL) {
+        goto not_found;
+    }
+
+    len = ngx_strlen(val);
+    v->data = ngx_pnalloc(r->pool, len);
+    if (v->data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(v->data, val, len);
+
+    v->len = len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    return NGX_OK;
+
+not_found:
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    float         val;
+    GeoIPRecord  *gr;
+
+    gr = ngx_http_geoip_get_city_record(r);
+    if (gr == NULL) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN + 5);
+    if (v->data == NULL) {
+        GeoIPRecord_delete(gr);
+        return NGX_ERROR;
+    }
+
+    val = *(float *) ((char *) gr + data);
+
+    v->len = ngx_sprintf(v->data, "%.4f", val) - v->data;
+
+    GeoIPRecord_delete(gr);
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    int           val;
+    GeoIPRecord  *gr;
+
+    gr = ngx_http_geoip_get_city_record(r);
+    if (gr == NULL) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN);
+    if (v->data == NULL) {
+        GeoIPRecord_delete(gr);
+        return NGX_ERROR;
+    }
+
+    val = *(int *) ((char *) gr + data);
+
+    v->len = ngx_sprintf(v->data, "%d", val) - v->data;
+
+    GeoIPRecord_delete(gr);
+
+    return NGX_OK;
+}
+
+
+static GeoIPRecord *
+ngx_http_geoip_get_city_record(ngx_http_request_t *r)
+{
+    u_long                  addr;
+    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 && r->connection->sockaddr->sa_family == AF_INET) {
+
+        sin = (struct sockaddr_in *) r->connection->sockaddr;
+        addr = ntohl(sin->sin_addr.s_addr);
+
+        return GeoIP_record_by_ipnum(gcf->city, addr);
+    }
+
+    return NULL;
+}
+
+
+static ngx_int_t
 ngx_http_geoip_add_variables(ngx_conf_t *cf)
 {
     ngx_http_variable_t  *var, *v;
@@ -306,6 +446,17 @@ ngx_http_geoip_country(ngx_conf_t *cf, n
         return NGX_CONF_ERROR;
     }
 
+    if (cf->args->nelts == 3) {
+        if (ngx_strcmp(value[2].data, "utf8") == 0) {
+            GeoIP_set_charset (gcf->country, GEOIP_CHARSET_UTF8);
+
+        } else {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[2]);
+            return NGX_CONF_ERROR;
+        }
+    }
+
     switch (gcf->country->databaseType) {
 
     case GEOIP_COUNTRY_EDITION:
@@ -345,6 +496,17 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_
         return NGX_CONF_ERROR;
     }
 
+    if (cf->args->nelts == 3) {
+        if (ngx_strcmp(value[2].data, "utf8") == 0) {
+            GeoIP_set_charset (gcf->city, GEOIP_CHARSET_UTF8);
+
+        } else {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[2]);
+            return NGX_CONF_ERROR;
+        }
+    }
+
     switch (gcf->city->databaseType) {
 
     case GEOIP_CITY_EDITION_REV0:
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -246,14 +246,36 @@ ngx_http_gzip_header_filter(ngx_http_req
         || (r->headers_out.status != NGX_HTTP_OK
             && r->headers_out.status != NGX_HTTP_FORBIDDEN
             && r->headers_out.status != NGX_HTTP_NOT_FOUND)
-        || r->header_only
         || (r->headers_out.content_encoding
             && r->headers_out.content_encoding->value.len)
         || (r->headers_out.content_length_n != -1
             && r->headers_out.content_length_n < conf->min_length)
         || ngx_http_test_content_type(r, &conf->types) == NULL
-        || ngx_http_gzip_ok(r) != NGX_OK)
+        || r->header_only)
+    {
+        return ngx_http_next_header_filter(r);
+    }
+
+    r->gzip_vary = 1;
+
+#if (NGX_HTTP_DEGRADATION)
     {
+    ngx_http_core_loc_conf_t  *clcf;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->gzip_disable_degradation && ngx_http_degraded(r)) {
+        return ngx_http_next_header_filter(r);
+    }
+    }
+#endif
+
+    if (!r->gzip_tested) {
+        if (ngx_http_gzip_ok(r) != NGX_OK) {
+            return ngx_http_next_header_filter(r);
+        }
+
+    } else if (!r->gzip_ok) {
         return ngx_http_next_header_filter(r);
     }
 
@@ -275,11 +297,8 @@ ngx_http_gzip_header_filter(ngx_http_req
     }
 
     h->hash = 1;
-    h->key.len = sizeof("Content-Encoding") - 1;
-    h->key.data = (u_char *) "Content-Encoding";
-    h->value.len = sizeof("gzip") - 1;
-    h->value.data = (u_char *) "gzip";
-
+    ngx_str_set(&h->key, "Content-Encoding");
+    ngx_str_set(&h->value, "gzip");
     r->headers_out.content_encoding = h;
 
     r->main_filter_need_in_memory = 1;
@@ -1113,8 +1132,8 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf,
                               MAX_MEM_LEVEL - 1);
     ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
 
-    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
-                             prev->types_keys, &prev->types,
+    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
+                             &prev->types_keys, &prev->types,
                              ngx_http_html_default_types)
         != NGX_OK)
     {
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -89,19 +89,17 @@ ngx_http_gzip_static_handler(ngx_http_re
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
 
     if (!gzcf->enable) {
         return NGX_DECLINED;
     }
 
+    rc = ngx_http_gzip_ok(r);
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) {
+    if (!clcf->gzip_vary && rc != NGX_OK) {
         return NGX_DECLINED;
     }
 
@@ -124,6 +122,7 @@ ngx_http_gzip_static_handler(ngx_http_re
 
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
+    of.read_ahead = clcf->read_ahead;
     of.directio = clcf->directio;
     of.valid = clcf->open_file_cache_valid;
     of.min_uses = clcf->open_file_cache_min_uses;
@@ -142,7 +141,6 @@ ngx_http_gzip_static_handler(ngx_http_re
         case NGX_ENOTDIR:
         case NGX_ENAMETOOLONG:
 
-            r->gzip = 0;
             return NGX_DECLINED;
 
         case NGX_EACCES:
@@ -162,6 +160,12 @@ ngx_http_gzip_static_handler(ngx_http_re
         return NGX_DECLINED;
     }
 
+    r->gzip_vary = 1;
+
+    if (rc != NGX_OK) {
+        return NGX_DECLINED;
+    }
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
 
     if (of.is_dir) {
@@ -172,7 +176,7 @@ ngx_http_gzip_static_handler(ngx_http_re
 #if !(NGX_WIN32) /* the not regular files are probably Unix specific */
 
     if (!of.is_file) {
-        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+        ngx_log_error(NGX_LOG_CRIT, log, 0,
                       "\"%s\" is not a regular file", path.data);
 
         return NGX_HTTP_NOT_FOUND;
@@ -204,12 +208,10 @@ ngx_http_gzip_static_handler(ngx_http_re
     }
 
     h->hash = 1;
-    h->key.len = sizeof("Content-Encoding") - 1;
-    h->key.data = (u_char *) "Content-Encoding";
-    h->value.len = sizeof("gzip") - 1;
-    h->value.data = (u_char *) "gzip";
+    ngx_str_set(&h->key, "Content-Encoding");
+    ngx_str_set(&h->value, "gzip");
+    r->headers_out.content_encoding = h;
 
-    r->headers_out.content_encoding = h;
     r->ignore_content_encoding = 1;
 
     /* we need to allocate all before the header would be sent */
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -196,8 +196,7 @@ ngx_http_set_expires(ngx_http_request_t 
         r->headers_out.expires = expires;
 
         expires->hash = 1;
-        expires->key.len = sizeof("Expires") - 1;
-        expires->key.data = (u_char *) "Expires";
+        ngx_str_set(&expires->key, "Expires");
     }
 
     len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
@@ -225,9 +224,7 @@ ngx_http_set_expires(ngx_http_request_t 
         }
 
         cc->hash = 1;
-        cc->key.len = sizeof("Cache-Control") - 1;
-        cc->key.data = (u_char *) "Cache-Control";
-
+        ngx_str_set(&cc->key, "Cache-Control");
         *ccp = cc;
 
     } else {
@@ -240,20 +237,14 @@ ngx_http_set_expires(ngx_http_request_t 
 
     if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
         expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
-
-        cc->value.len = sizeof("no-cache") - 1;
-        cc->value.data = (u_char *) "no-cache";
-
+        ngx_str_set(&cc->value, "no-cache");
         return NGX_OK;
     }
 
     if (conf->expires == NGX_HTTP_EXPIRES_MAX) {
         expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT";
-
         /* 10 years */
-        cc->value.len = sizeof("max-age=315360000") - 1;
-        cc->value.data = (u_char *) "max-age=315360000";
-
+        ngx_str_set(&cc->value, "max-age=315360000");
         return NGX_OK;
     }
 
@@ -265,10 +256,7 @@ ngx_http_set_expires(ngx_http_request_t 
     if (conf->expires_time == 0) {
         ngx_memcpy(expires->value.data, ngx_cached_http_time.data,
                    ngx_cached_http_time.len + 1);
-
-        cc->value.len = sizeof("max-age=0") - 1;
-        cc->value.data = (u_char *) "max-age=0";
-
+        ngx_str_set(&cc->value, "max-age=0");
         return NGX_OK;
     }
 
@@ -291,10 +279,8 @@ ngx_http_set_expires(ngx_http_request_t 
 
     ngx_http_time(expires->value.data, expires_time);
 
-    if (conf->expires_time < 0) {
-        cc->value.len = sizeof("no-cache") - 1;
-        cc->value.data = (u_char *) "no-cache";
-
+    if (conf->expires_time < 0 || max_age < 0) {
+        ngx_str_set(&cc->value, "no-cache");
         return NGX_OK;
     }
 
@@ -361,8 +347,7 @@ ngx_http_add_cache_control(ngx_http_requ
     }
 
     cc->hash = 1;
-    cc->key.len = sizeof("Cache-Control") - 1;
-    cc->key.data = (u_char *) "Cache-Control";
+    ngx_str_set(&cc->key, "Cache-Control");
     cc->value = *value;
 
     *ccp = cc;
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -16,6 +16,7 @@
 #define NGX_HTTP_IMAGE_SIZE      2
 #define NGX_HTTP_IMAGE_RESIZE    3
 #define NGX_HTTP_IMAGE_CROP      4
+#define NGX_HTTP_IMAGE_ROTATE    5
 
 
 #define NGX_HTTP_IMAGE_START     0
@@ -38,12 +39,15 @@ typedef struct {
     ngx_uint_t                   filter;
     ngx_uint_t                   width;
     ngx_uint_t                   height;
-    ngx_int_t                    jpeg_quality;
+    ngx_uint_t                   angle;
+    ngx_uint_t                   jpeg_quality;
 
     ngx_flag_t                   transparency;
 
     ngx_http_complex_value_t    *wcv;
     ngx_http_complex_value_t    *hcv;
+    ngx_http_complex_value_t    *acv;
+    ngx_http_complex_value_t    *jqcv;
 
     size_t                       buffer_size;
 } ngx_http_image_filter_conf_t;
@@ -57,12 +61,13 @@ typedef struct {
 
     ngx_uint_t                   width;
     ngx_uint_t                   height;
-
     ngx_uint_t                   max_width;
     ngx_uint_t                   max_height;
+    ngx_uint_t                   angle;
 
     ngx_uint_t                   phase;
     ngx_uint_t                   type;
+    ngx_uint_t                   force;
 } ngx_http_image_filter_ctx_t;
 
 
@@ -98,13 +103,15 @@ static char *ngx_http_image_filter_merge
     void *child);
 static char *ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_image_filter_jpeg_quality(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_LOC_CONF|NGX_CONF_TAKE13|NGX_CONF_TAKE2,
       ngx_http_image_filter,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -112,9 +119,9 @@ static ngx_command_t  ngx_http_image_fil
 
     { 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_image_filter_jpeg_quality,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_image_filter_conf_t, jpeg_quality),
+      0,
       NULL },
 
     { ngx_string("image_filter_transparency"),
@@ -227,7 +234,7 @@ ngx_http_image_header_filter(ngx_http_re
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "image filter: too big response: %O", len);
 
-        return NGX_ERROR;
+        return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
     }
 
     if (len == -1) {
@@ -488,6 +495,17 @@ ngx_http_image_process(ngx_http_request_
         return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
     }
 
+    ctx->angle = ngx_http_image_filter_get_value(r, conf->acv, conf->angle);
+
+    if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
+
+        if (ctx->angle != 90 && ctx->angle != 180 && ctx->angle != 270) {
+            return NULL;
+        }
+
+        return ngx_http_image_resize(r, ctx);
+    }
+
     ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
     if (ctx->max_width == 0) {
         return NULL;
@@ -501,7 +519,9 @@ ngx_http_image_process(ngx_http_request_
 
     if (rc == NGX_OK
         && ctx->width <= ctx->max_width
-        && ctx->height <= ctx->max_height)
+        && ctx->height <= ctx->max_height
+        && ctx->angle == 0
+        && !ctx->force)
     {
         return ngx_http_image_asis(r, ctx);
     }
@@ -527,8 +547,7 @@ ngx_http_image_json(ngx_http_request_t *
     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";
+    ngx_str_set(&r->headers_out.content_type, "text/plain");
     r->headers_out.content_type_lowcase = NULL;
 
     if (ctx == NULL) {
@@ -601,6 +620,7 @@ static ngx_int_t
 ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
 {
     u_char      *p, *last;
+    size_t       len, app;
     ngx_uint_t   width, height;
 
     p = ctx->image;
@@ -611,26 +631,38 @@ ngx_http_image_size(ngx_http_request_t *
 
         p += 2;
         last = ctx->image + ctx->length - 10;
+        width = 0;
+        height = 0;
+        app = 0;
 
         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));
+                               "JPEG: %02xd %02xd", p[0], p[1]);
 
                 p++;
 
-                if (*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3
-                    || *p == 0xc9 || *p == 0xca || *p == 0xcb)
+                if ((*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3
+                     || *p == 0xc9 || *p == 0xca || *p == 0xcb)
+                    && (width == 0 || height == 0))
                 {
-                    goto found;
+                    width = p[6] * 256 + p[7];
+                    height = p[4] * 256 + p[5];
                 }
 
                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                                "JPEG: %02xd %02xd", p[1], p[2]);
 
-                p += p[1] * 256 + p[2];
+                len = p[1] * 256 + p[2];
+
+                if (*p >= 0xe1 && *p <= 0xef) {
+                    /* application data, e.g., EXIF, Adobe XMP, etc. */
+                    app += len;
+                }
+
+                p += len;
 
                 continue;
             }
@@ -638,12 +670,16 @@ ngx_http_image_size(ngx_http_request_t *
             p++;
         }
 
-        return NGX_DECLINED;
+        if (width == 0 || height == 0) {
+            return NGX_DECLINED;
+        }
 
-    found:
-
-        width = p[6] * 256 + p[7];
-        height = p[4] * 256 + p[5];
+        if (ctx->length / 20 < app) {
+            /* force conversion if application data consume more than 5% */
+            ctx->force = 1;
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "app data size: %uz", app);
+        }
 
         break;
 
@@ -689,7 +725,7 @@ ngx_http_image_resize(ngx_http_request_t
 {
     int                            sx, sy, dx, dy, ox, oy, size,
                                    colors, palette, transparent,
-                                   red, green, blue;
+                                   red, green, blue, t;
     u_char                        *out;
     ngx_buf_t                     *b;
     ngx_uint_t                     resize;
@@ -708,7 +744,9 @@ ngx_http_image_resize(ngx_http_request_t
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
 
-    if ((ngx_uint_t) sx <= ctx->max_width
+    if (!ctx->force
+        && ctx->angle == 0
+        && (ngx_uint_t) sx <= ctx->max_width
         && (ngx_uint_t) sy <= ctx->max_height)
     {
         gdImageDestroy(src);
@@ -759,6 +797,10 @@ transparent:
 
         resize = 1;
 
+    } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
+
+        resize = 0;
+
     } else { /* NGX_HTTP_IMAGE_CROP */
 
         resize = 0;
@@ -807,6 +849,38 @@ transparent:
         dst = src;
     }
 
+    if (ctx->angle) {
+        src = dst;
+
+        switch (ctx->angle) {
+
+        case 90:
+        case 270:
+            dst = ngx_http_image_new(r, dy, dx, palette);
+            if (dst == NULL) {
+                gdImageDestroy(src);
+                return NULL;
+            }
+            gdImageCopyRotated(dst, src, dy/2, dx/2, 0, 0, dx, dy, ctx->angle);
+            gdImageDestroy(src);
+
+            t = dx;
+            dx = dy;
+            dy = t;
+            break;
+
+        case 180:
+            dst = ngx_http_image_new(r, dx, dy, palette);
+            if (dst == NULL) {
+                gdImageDestroy(src);
+                return NULL;
+            }
+            gdImageCopyRotated(dst, src, dx/2, dy/2, 0, 0, dx, dy, ctx->angle);
+            gdImageDestroy(src);
+            break;
+        }
+    }
+
     if (conf->filter == NGX_HTTP_IMAGE_CROP) {
 
         src = dst;
@@ -970,6 +1044,7 @@ ngx_http_image_out(ngx_http_request_t *r
 {
     char                          *failed;
     u_char                        *out;
+    ngx_int_t                      jq;
     ngx_http_image_filter_conf_t  *conf;
 
     out = NULL;
@@ -978,7 +1053,13 @@ ngx_http_image_out(ngx_http_request_t *r
 
     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);
+
+        jq = ngx_http_image_filter_get_value(r, conf->jqcv, conf->jpeg_quality);
+        if (jq <= 0) {
+            return NULL;
+        }
+
+        out = gdImageJpegPtr(img, size, jq);
         failed = "gdImageJpegPtr() failed";
         break;
 
@@ -1060,7 +1141,8 @@ ngx_http_image_filter_create_conf(ngx_co
     }
 
     conf->filter = NGX_CONF_UNSET_UINT;
-    conf->jpeg_quality = NGX_CONF_UNSET;
+    conf->jpeg_quality = NGX_CONF_UNSET_UINT;
+    conf->angle = NGX_CONF_UNSET_UINT;
     conf->transparency = NGX_CONF_UNSET;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
 
@@ -1089,7 +1171,16 @@ ngx_http_image_filter_merge_conf(ngx_con
     }
 
     /* 75 is libjpeg default quality */
-    ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75);
+    ngx_conf_merge_uint_value(conf->jpeg_quality, prev->jpeg_quality, 75);
+
+    if (conf->jqcv == NULL) {
+        conf->jqcv = prev->jqcv;
+    }
+
+    ngx_conf_merge_uint_value(conf->angle, prev->angle, 0);
+    if (conf->acv == NULL) {
+        conf->acv = prev->acv;
+    }
 
     ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
 
@@ -1130,6 +1221,46 @@ ngx_http_image_filter(ngx_conf_t *cf, ng
         }
 
         return NGX_CONF_OK;
+
+    } else if (cf->args->nelts == 3) {
+
+        if (ngx_strcmp(value[i].data, "rotate") == 0) {
+            imcf->filter = NGX_HTTP_IMAGE_ROTATE;
+
+            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 != 90 && n != 180 && n != 270) {
+                    goto failed;
+                }
+
+                imcf->angle = (ngx_uint_t) n;
+
+            } else {
+                imcf->acv = ngx_palloc(cf->pool,
+                                       sizeof(ngx_http_complex_value_t));
+                if (imcf->acv == NULL) {
+                    return NGX_CONF_ERROR;
+                }
+
+                *imcf->acv = cv;
+            }
+
+            return NGX_CONF_OK;
+
+        } else {
+            goto failed;
+        }
     }
 
     if (ngx_strcmp(value[i].data, "resize") == 0) {
@@ -1209,6 +1340,53 @@ failed:
 }
 
 
+static char *
+ngx_http_image_filter_jpeg_quality(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_http_complex_value_t           cv;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    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[1]);
+
+        if (n <= 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        imcf->jpeg_quality = (ngx_uint_t) n;
+
+    } else {
+        imcf->jqcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->jqcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->jqcv = cv;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
 static ngx_int_t
 ngx_http_image_filter_init(ngx_conf_t *cf)
 {
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -116,10 +116,6 @@ ngx_http_index_handler(ngx_http_request_
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
@@ -205,6 +201,7 @@ ngx_http_index_handler(ngx_http_request_
 
         ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
+        of.read_ahead = clcf->read_ahead;
         of.directio = clcf->directio;
         of.valid = clcf->open_file_cache_valid;
         of.min_uses = clcf->open_file_cache_min_uses;
@@ -222,7 +219,10 @@ ngx_http_index_handler(ngx_http_request_
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
-            if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) {
+            if (of.err == NGX_ENOTDIR
+                || of.err == NGX_ENAMETOOLONG
+                || of.err == NGX_EACCES)
+            {
                 return ngx_http_index_error(r, clcf, path.data, of.err);
             }
 
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -42,13 +42,16 @@ typedef struct {
     ngx_shm_zone_t              *shm_zone;
     /* integer value, 1 corresponds to 0.001 r/s */
     ngx_uint_t                   burst;
-    ngx_uint_t                   nodelay;/* unsigned  nodelay:1 */
+    ngx_uint_t                   limit_log_level;
+    ngx_uint_t                   delay_log_level;
+
+    ngx_uint_t                   nodelay; /* unsigned  nodelay:1 */
 } ngx_http_limit_req_conf_t;
 
 
 static void ngx_http_limit_req_delay(ngx_http_request_t *r);
 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf,
-    ngx_uint_t hash, u_char *data, size_t len, ngx_http_limit_req_node_t **lrp);
+    ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep);
 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
     ngx_uint_t n);
 
@@ -62,6 +65,15 @@ static char *ngx_http_limit_req(ngx_conf
 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf);
 
 
+static ngx_conf_enum_t  ngx_http_limit_req_log_levels[] = {
+    { ngx_string("info"), NGX_LOG_INFO },
+    { ngx_string("notice"), NGX_LOG_NOTICE },
+    { ngx_string("warn"), NGX_LOG_WARN },
+    { ngx_string("error"), NGX_LOG_ERR },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_limit_req_commands[] = {
 
     { ngx_string("limit_req_zone"),
@@ -78,6 +90,13 @@ static ngx_command_t  ngx_http_limit_req
       0,
       NULL },
 
+    { ngx_string("limit_req_log_level"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_limit_req_conf_t, limit_log_level),
+      &ngx_http_limit_req_log_levels },
+
       ngx_null_command
 };
 
@@ -167,96 +186,83 @@ ngx_http_limit_req_handler(ngx_http_requ
 
     ngx_http_limit_req_expire(ctx, 1);
 
-    rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr);
-
-    if (lr) {
-        ngx_queue_remove(&lr->queue);
-
-        ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
-
-        excess = lr->excess;
-
-    } else {
-        excess = 0;
-    }
+    rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess);
 
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
 
-    if (rc == NGX_BUSY) {
+    if (rc == NGX_DECLINED) {
+
+        n = offsetof(ngx_rbtree_node_t, color)
+            + offsetof(ngx_http_limit_req_node_t, data)
+            + len;
+
+        node = ngx_slab_alloc_locked(ctx->shpool, n);
+        if (node == NULL) {
+
+            ngx_http_limit_req_expire(ctx, 0);
+
+            node = ngx_slab_alloc_locked(ctx->shpool, n);
+            if (node == NULL) {
+                ngx_shmtx_unlock(&ctx->shpool->mutex);
+                return NGX_HTTP_SERVICE_UNAVAILABLE;
+            }
+        }
+
+        lr = (ngx_http_limit_req_node_t *) &node->color;
+
+        node->key = hash;
+        lr->len = (u_char) len;
+
+        tp = ngx_timeofday();
+        lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
+
+        lr->excess = 0;
+        ngx_memcpy(lr->data, vv->data, len);
+
+        ngx_rbtree_insert(&ctx->sh->rbtree, node);
+
+        ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
+
         ngx_shmtx_unlock(&ctx->shpool->mutex);
 
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+        return NGX_DECLINED;
+    }
+
+    ngx_shmtx_unlock(&ctx->shpool->mutex);
+
+    if (rc == NGX_OK) {
+        return NGX_DECLINED;
+    }
+
+    if (rc == NGX_BUSY) {
+        ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                       "limiting requests, excess: %ui.%03ui by zone \"%V\"",
                       excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
 
         return NGX_HTTP_SERVICE_UNAVAILABLE;
     }
 
-    if (rc == NGX_AGAIN) {
-        ngx_shmtx_unlock(&ctx->shpool->mutex);
-
-        if (lrcf->nodelay) {
-            return NGX_DECLINED;
-        }
-
-        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->shm.name);
+    /* rc == NGX_AGAIN */
 
-        if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        r->read_event_handler = ngx_http_test_reading;
-        r->write_event_handler = ngx_http_limit_req_delay;
-        ngx_add_timer(r->connection->write, (ngx_msec_t) excess);
-
-        return NGX_AGAIN;
-    }
-
-    if (rc == NGX_OK) {
-        goto done;
+    if (lrcf->nodelay) {
+        return NGX_DECLINED;
     }
 
-    /* rc == NGX_DECLINED */
-
-    n = offsetof(ngx_rbtree_node_t, color)
-        + offsetof(ngx_http_limit_req_node_t, data)
-        + len;
+    ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
+                  "delaying request, excess: %ui.%03ui, by zone \"%V\"",
+                  excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
 
-    node = ngx_slab_alloc_locked(ctx->shpool, n);
-    if (node == NULL) {
-
-        ngx_http_limit_req_expire(ctx, 0);
-
-        node = ngx_slab_alloc_locked(ctx->shpool, n);
-        if (node == NULL) {
-            ngx_shmtx_unlock(&ctx->shpool->mutex);
-            return NGX_HTTP_SERVICE_UNAVAILABLE;
-        }
+    if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    lr = (ngx_http_limit_req_node_t *) &node->color;
-
-    node->key = hash;
-    lr->len = (u_char) len;
-
-    tp = ngx_timeofday();
-    lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
+    r->read_event_handler = ngx_http_test_reading;
+    r->write_event_handler = ngx_http_limit_req_delay;
+    ngx_add_timer(r->connection->write,
+                  (ngx_msec_t) excess * 1000 / ctx->rate);
 
-    lr->excess = 0;
-    ngx_memcpy(lr->data, vv->data, len);
-
-    ngx_rbtree_insert(&ctx->sh->rbtree, node);
-
-    ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
-
-done:
-
-    ngx_shmtx_unlock(&ctx->shpool->mutex);
-
-    return NGX_DECLINED;
+    return NGX_AGAIN;
 }
 
 
@@ -336,7 +342,7 @@ ngx_http_limit_req_rbtree_insert_value(n
 
 static ngx_int_t
 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
-    u_char *data, size_t len, ngx_http_limit_req_node_t **lrp)
+    u_char *data, size_t len, ngx_uint_t *ep)
 {
     ngx_int_t                   rc, excess;
     ngx_time_t                 *tp;
@@ -371,6 +377,8 @@ ngx_http_limit_req_lookup(ngx_http_limit
             rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len);
 
             if (rc == 0) {
+                ngx_queue_remove(&lr->queue);
+                ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
 
                 tp = ngx_timeofday();
 
@@ -383,15 +391,15 @@ ngx_http_limit_req_lookup(ngx_http_limit
                     excess = 0;
                 }
 
-                lr->excess = excess;
-                lr->last = now;
-
-                *lrp = lr;
+                *ep = excess;
 
                 if ((ngx_uint_t) excess > lrcf->burst) {
                     return NGX_BUSY;
                 }
 
+                lr->excess = excess;
+                lr->last = now;
+
                 if (excess) {
                     return NGX_AGAIN;
                 }
@@ -406,7 +414,7 @@ ngx_http_limit_req_lookup(ngx_http_limit
         break;
     }
 
-    *lrp = NULL;
+    *ep = 0;
 
     return NGX_DECLINED;
 }
@@ -548,6 +556,8 @@ ngx_http_limit_req_create_conf(ngx_conf_
      *     conf->nodelay = 0;
      */
 
+    conf->limit_log_level = NGX_CONF_UNSET_UINT;
+
     return conf;
 }
 
@@ -562,6 +572,12 @@ ngx_http_limit_req_merge_conf(ngx_conf_t
         *conf = *prev;
     }
 
+    ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level,
+                              NGX_LOG_ERR);
+
+    conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ?
+                                NGX_LOG_INFO : conf->limit_log_level + 1;
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -33,6 +33,7 @@ typedef struct {
 typedef struct {
     ngx_shm_zone_t     *shm_zone;
     ngx_uint_t          conn;
+    ngx_uint_t          log_level;
 } ngx_http_limit_zone_conf_t;
 
 
@@ -48,6 +49,15 @@ static char *ngx_http_limit_conn(ngx_con
 static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf);
 
 
+static ngx_conf_enum_t  ngx_http_limit_conn_log_levels[] = {
+    { ngx_string("info"), NGX_LOG_INFO },
+    { ngx_string("notice"), NGX_LOG_NOTICE },
+    { ngx_string("warn"), NGX_LOG_WARN },
+    { ngx_string("error"), NGX_LOG_ERR },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_limit_zone_commands[] = {
 
     { ngx_string("limit_zone"),
@@ -64,6 +74,13 @@ static ngx_command_t  ngx_http_limit_zon
       0,
       NULL },
 
+    { ngx_string("limit_conn_log_level"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_limit_zone_conf_t, log_level),
+      &ngx_http_limit_conn_log_levels },
+
       ngx_null_command
 };
 
@@ -189,7 +206,7 @@ ngx_http_limit_zone_handler(ngx_http_req
 
                 ngx_shmtx_unlock(&shpool->mutex);
 
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                ngx_log_error(lzcf->log_level, r->connection->log, 0,
                               "limiting connections by zone \"%V\"",
                               &lzcf->shm_zone->shm.name);
 
@@ -391,6 +408,8 @@ ngx_http_limit_zone_create_conf(ngx_conf
      *     conf->conn = 0;
      */
 
+    conf->log_level = NGX_CONF_UNSET_UINT;
+
     return conf;
 }
 
@@ -405,6 +424,8 @@ ngx_http_limit_zone_merge_conf(ngx_conf_
         *conf = *prev;
     }
 
+    ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -83,6 +83,8 @@ static u_char *ngx_http_log_pipe(ngx_htt
     ngx_http_log_op_t *op);
 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
+static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
+    ngx_http_log_op_t *op);
 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
@@ -193,6 +195,8 @@ static ngx_http_log_var_t  ngx_http_log_
     { ngx_string("pipe"), 1, ngx_http_log_pipe },
     { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
                           ngx_http_log_time },
+    { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
+                          ngx_http_log_iso8601 },
     { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
     { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
                           ngx_http_log_request_time },
@@ -510,6 +514,12 @@ ngx_http_log_time(ngx_http_request_t *r,
                       ngx_cached_http_log_time.len);
 }
 
+static u_char *
+ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
+{
+    return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
+                      ngx_cached_http_log_iso8601.len);
+}
 
 static u_char *
 ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
@@ -533,7 +543,7 @@ ngx_http_log_request_time(ngx_http_reque
 
     ms = (ngx_msec_int_t)
              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
-    ms = (ms >= 0) ? ms : 0;
+    ms = ngx_max(ms, 0);
 
     return ngx_sprintf(buf, "%T.%03M", ms / 1000, ms % 1000);
 }
@@ -542,8 +552,25 @@ ngx_http_log_request_time(ngx_http_reque
 static u_char *
 ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
 {
-    return ngx_sprintf(buf, "%ui",
-                       r->err_status ? r->err_status : r->headers_out.status);
+    ngx_uint_t  status;
+
+    if (r->err_status) {
+        status = r->err_status;
+
+    } else if (r->headers_out.status) {
+        status = r->headers_out.status;
+
+    } else if (r->http_version == NGX_HTTP_VERSION_9) {
+        *buf++ = '0';
+        *buf++ = '0';
+        *buf++ = '9';
+        return buf;
+
+    } else {
+        status = 0;
+    }
+
+    return ngx_sprintf(buf, "%ui", status);
 }
 
 
@@ -650,7 +677,7 @@ ngx_http_log_variable(ngx_http_request_t
 static uintptr_t
 ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
 {
-    ngx_uint_t      i, n;
+    ngx_uint_t      n;
     static u_char   hex[] = "0123456789ABCDEF";
 
     static uint32_t   escape[] = {
@@ -678,17 +705,18 @@ ngx_http_log_escape(u_char *dst, u_char 
 
         n = 0;
 
-        for (i = 0; i < size; i++) {
+        while (size) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                 n++;
             }
             src++;
+            size--;
         }
 
         return (uintptr_t) n;
     }
 
-    for (i = 0; i < size; i++) {
+    while (size) {
         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
             *dst++ = '\\';
             *dst++ = 'x';
@@ -699,6 +727,7 @@ ngx_http_log_escape(u_char *dst, u_char 
         } else {
             *dst++ = *src++;
         }
+        size--;
     }
 
     return (uintptr_t) dst;
@@ -728,8 +757,7 @@ ngx_http_log_create_main_conf(ngx_conf_t
         return NULL;
     }
 
-    fmt->name.len = sizeof("combined") - 1;
-    fmt->name.data = (u_char *) "combined";
+    ngx_str_set(&fmt->name, "combined");
 
     fmt->flushes = NULL;
 
@@ -903,8 +931,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
         }
 
     } else {
-        name.len = sizeof("combined") - 1;
-        name.data = (u_char *) "combined";
+        ngx_str_set(&name, "combined");
         lmcf->combined_used = 1;
     }
 
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -19,15 +19,20 @@ typedef struct {
     ngx_hash_keys_arrays_t      keys;
 
     ngx_array_t                *values_hash;
+    ngx_array_t                 var_values;
+#if (NGX_PCRE)
+    ngx_array_t                 regexes;
+#endif
 
     ngx_http_variable_value_t  *default_value;
+    ngx_conf_t                 *cf;
     ngx_uint_t                  hostnames;      /* unsigned  hostnames:1 */
 } ngx_http_map_conf_ctx_t;
 
 
 typedef struct {
-    ngx_hash_combined_t         hash;
-    ngx_int_t                   index;
+    ngx_http_map_t              map;
+    ngx_http_complex_value_t    value;
     ngx_http_variable_value_t  *default_value;
     ngx_uint_t                  hostnames;      /* unsigned  hostnames:1 */
 } ngx_http_map_ctx_t;
@@ -105,49 +110,43 @@ ngx_http_map_variable(ngx_http_request_t
     ngx_http_map_ctx_t  *map = (ngx_http_map_ctx_t *) data;
 
     size_t                      len;
-    u_char                     *name;
+    ngx_str_t                   val;
     ngx_uint_t                  key;
-    ngx_http_variable_value_t  *vv, *value;
+    ngx_http_variable_value_t  *value;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http map started");
 
-    vv = ngx_http_get_flushed_variable(r, map->index);
-
-    if (vv == NULL || vv->not_found) {
-        *v = *map->default_value;
-        return NGX_OK;
+    if (ngx_http_complex_value(r, &map->value, &val) != NGX_OK) {
+        return NGX_ERROR;
     }
 
-    len = vv->len;
+    len = val.len;
 
-    if (len && map->hostnames && vv->data[len - 1] == '.') {
+    if (len && map->hostnames && val.data[len - 1] == '.') {
         len--;
     }
 
-    if (len == 0) {
-        *v = *map->default_value;
-        return NGX_OK;
-    }
+    key = ngx_hash_strlow(val.data, val.data, len);
 
-    name = ngx_pnalloc(r->pool, len);
-    if (name == NULL) {
-        return NGX_ERROR;
+    value = ngx_http_map_find(r, &map->map, key, val.data, len, &val);
+
+    if (value == NULL) {
+        value = map->default_value;
     }
 
-    key = ngx_hash_strlow(name, vv->data, len);
-
-    value = ngx_hash_find_combined(&map->hash, key, name, len);
+    if (!value->valid) {
+        value = ngx_http_get_flushed_variable(r, (ngx_uint_t) value->data);
 
-    if (value) {
-        *v = *value;
-
-    } else {
-        *v = *map->default_value;
+        if (value == NULL || value->not_found) {
+            value = &ngx_http_variable_null_value;
+        }
     }
 
+    *v = *value;
+
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http map: \"%v\" \"%v\"", vv, v);
+                   "http map: \"%v\" \"%v\"", &val, v);
 
     return NGX_OK;
 }
@@ -175,14 +174,15 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
 {
     ngx_http_map_conf_t  *mcf = conf;
 
-    char                      *rv;
-    ngx_str_t                 *value, name;
-    ngx_conf_t                 save;
-    ngx_pool_t                *pool;
-    ngx_hash_init_t            hash;
-    ngx_http_map_ctx_t        *map;
-    ngx_http_variable_t       *var;
-    ngx_http_map_conf_ctx_t    ctx;
+    char                              *rv;
+    ngx_str_t                         *value, name;
+    ngx_conf_t                         save;
+    ngx_pool_t                        *pool;
+    ngx_hash_init_t                    hash;
+    ngx_http_map_ctx_t                *map;
+    ngx_http_variable_t               *var;
+    ngx_http_map_conf_ctx_t            ctx;
+    ngx_http_compile_complex_value_t   ccv;
 
     if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) {
         mcf->hash_max_size = 2048;
@@ -203,13 +203,13 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
 
     value = cf->args->elts;
 
-    name = value[1];
-    name.len--;
-    name.data++;
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
 
-    map->index = ngx_http_get_variable_index(cf, &name);
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = &map->value;
 
-    if (map->index == NGX_ERROR) {
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
@@ -244,7 +244,25 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
+    if (ngx_array_init(&ctx.var_values, cf->pool, 2,
+                       sizeof(ngx_http_variable_value_t))
+        != NGX_OK)
+    {
+        ngx_destroy_pool(pool);
+        return NGX_CONF_ERROR;
+    }
+
+#if (NGX_PCRE)
+    if (ngx_array_init(&ctx.regexes, cf->pool, 2, sizeof(ngx_http_map_regex_t))
+        != NGX_OK)
+    {
+        ngx_destroy_pool(pool);
+        return NGX_CONF_ERROR;
+    }
+#endif
+
     ctx.default_value = NULL;
+    ctx.cf = &save;
     ctx.hostnames = 0;
 
     save = *cf;
@@ -272,7 +290,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
     hash.pool = cf->pool;
 
     if (ctx.keys.keys.nelts) {
-        hash.hash = &map->hash.hash;
+        hash.hash = &map->map.hash.hash;
         hash.temp_pool = NULL;
 
         if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts)
@@ -300,7 +318,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
             return NGX_CONF_ERROR;
         }
 
-        map->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
+        map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
     }
 
     if (ctx.keys.dns_wc_tail.nelts) {
@@ -320,9 +338,18 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
             return NGX_CONF_ERROR;
         }
 
-        map->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
+        map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
     }
 
+#if (NGX_PCRE)
+
+    if (ctx.regexes.nelts) {
+        map->map.regex = ctx.regexes.elts;
+        map->map.nregex = ctx.regexes.nelts;
+    }
+
+#endif
+
     ngx_destroy_pool(pool);
 
     return rv;
@@ -344,8 +371,8 @@ ngx_http_map_cmp_dns_wildcards(const voi
 static char *
 ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
 {
-    ngx_int_t                   rc;
-    ngx_str_t                  *value, file;
+    ngx_int_t                   rc, index;
+    ngx_str_t                  *value, file, name;
     ngx_uint_t                  i, key;
     ngx_http_map_conf_ctx_t    *ctx;
     ngx_http_variable_value_t  *var, **vp;
@@ -364,17 +391,12 @@ ngx_http_map(ngx_conf_t *cf, ngx_command
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "invalid number of the map parameters");
         return NGX_CONF_ERROR;
-
-    } else if (value[0].len == 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "invalid first parameter");
-        return NGX_CONF_ERROR;
     }
 
     if (ngx_strcmp(value[0].data, "include") == 0) {
         file = value[1];
 
-        if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){
+        if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
 
@@ -383,6 +405,45 @@ ngx_http_map(ngx_conf_t *cf, ngx_command
         return ngx_conf_parse(cf, &file);
     }
 
+    if (value[1].data[0] == '$') {
+        name = value[1];
+        name.len--;
+        name.data++;
+
+        index = ngx_http_get_variable_index(ctx->cf, &name);
+        if (index == NGX_ERROR) {
+            return NGX_CONF_ERROR;
+        }
+
+        var = ctx->var_values.elts;
+
+        for (i = 0; i < ctx->var_values.nelts; i++) {
+            if (index == (ngx_int_t) var[i].data) {
+                goto found;
+            }
+        }
+
+        var = ngx_palloc(ctx->keys.pool, sizeof(ngx_http_variable_value_t));
+        if (var == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        var->valid = 0;
+        var->no_cacheable = 0;
+        var->not_found = 0;
+        var->len = 0;
+        var->data = (u_char *) index;
+
+        vp = ngx_array_push(&ctx->var_values);
+        if (vp == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *vp = var;
+
+        goto found;
+    }
+
     key = 0;
 
     for (i = 0; i < value[1].len; i++) {
@@ -451,7 +512,40 @@ found:
         return NGX_CONF_OK;
     }
 
-    if (value[0].len && value[0].data[0] == '!') {
+#if (NGX_PCRE)
+
+    if (value[0].len && value[0].data[0] == '~') {
+        ngx_regex_compile_t    rc;
+        ngx_http_map_regex_t  *regex;
+        u_char                 errstr[NGX_MAX_CONF_ERRSTR];
+
+        regex = ngx_array_push(&ctx->regexes);
+        if (regex == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        value[0].len--;
+        value[0].data++;
+
+        ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+        rc.pattern = value[0];
+        rc.err.len = NGX_MAX_CONF_ERRSTR;
+        rc.err.data = errstr;
+
+        regex->regex = ngx_http_regex_compile(ctx->cf, &rc);
+        if (regex->regex == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        regex->value = var;
+
+        return NGX_CONF_OK;
+    }
+
+#endif
+
+    if (value[0].len && value[0].data[0] == '\\') {
         value[0].len--;
         value[0].data++;
     }
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -38,11 +38,6 @@ static char *ngx_http_memcached_merge_lo
 static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
-static char *ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-static char *ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-
 
 static ngx_conf_bitmask_t  ngx_http_memcached_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -63,6 +58,13 @@ static ngx_command_t  ngx_http_memcached
       0,
       NULL },
 
+    { ngx_string("memcached_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upstream_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
+      NULL },
+
     { ngx_string("memcached_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -98,20 +100,6 @@ static ngx_command_t  ngx_http_memcached
       offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
       &ngx_http_memcached_next_upstream_masks },
 
-    { ngx_string("memcached_upstream_max_fails"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_memcached_upstream_max_fails_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("memcached_upstream_fail_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_memcached_upstream_fail_timeout_unsupported,
-      0,
-      0,
-      NULL },
-
       ngx_null_command
 };
 
@@ -182,9 +170,7 @@ ngx_http_memcached_handler(ngx_http_requ
 
     u = r->upstream;
 
-    u->schema.len = sizeof("memcached://") - 1;
-    u->schema.data = (u_char *) "memcached://";
-
+    ngx_str_set(&u->schema, "memcached://");
     u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
 
     mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
@@ -425,15 +411,20 @@ ngx_http_memcached_filter(void *data, ss
 
         if (ngx_strncmp(b->last,
                    ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
-                   ctx->rest)
+                   bytes)
             != 0)
         {
             ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
                           "memcached sent invalid trailer");
+
+            u->length = 0;
+            ctx->rest = 0;
+
+            return NGX_OK;
         }
 
-        u->length = 0;
-        ctx->rest = 0;
+        u->length -= bytes;
+        ctx->rest -= bytes;
 
         return NGX_OK;
     }
@@ -630,29 +621,3 @@ ngx_http_memcached_pass(ngx_conf_t *cf, 
 
     return NGX_CONF_OK;
 }
-
-
-static char *
-ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"memcached_upstream_max_fails\" is not supported, "
-         "use the \"max_fails\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"memcached_upstream_fail_timeout\" is not supported, "
-         "use the \"fail_timeout\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -9,7 +9,8 @@
 #include <ngx_http.h>
 
 
-
+static ngx_int_t ngx_http_test_precondition(ngx_http_request_t *r);
+static ngx_int_t ngx_http_test_not_modified(ngx_http_request_t *r);
 static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);
 
 
@@ -50,17 +51,51 @@ static ngx_http_output_header_filter_pt 
 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;
-
     if (r->headers_out.status != NGX_HTTP_OK
         || r != r->main
-        || r->headers_in.if_modified_since == NULL
         || r->headers_out.last_modified_time == -1)
     {
         return ngx_http_next_header_filter(r);
     }
 
+    if (r->headers_in.if_unmodified_since) {
+        return ngx_http_test_precondition(r);
+    }
+
+    if (r->headers_in.if_modified_since) {
+        return ngx_http_test_not_modified(r);
+    }
+
+    return ngx_http_next_header_filter(r);
+}
+
+
+static ngx_int_t
+ngx_http_test_precondition(ngx_http_request_t *r)
+{
+    time_t  iums;
+
+    iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data,
+                               r->headers_in.if_unmodified_since->value.len);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                 "http iums:%d lm:%d", iums, r->headers_out.last_modified_time);
+
+    if (iums >= r->headers_out.last_modified_time) {
+        return ngx_http_next_header_filter(r);
+    }
+
+    return ngx_http_filter_finalize_request(r, NULL,
+                                            NGX_HTTP_PRECONDITION_FAILED);
+}
+
+
+static ngx_int_t
+ngx_http_test_not_modified(ngx_http_request_t *r)
+{
+    time_t                     ims;
+    ngx_http_core_loc_conf_t  *clcf;
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
@@ -88,6 +123,11 @@ ngx_http_not_modified_header_filter(ngx_
     ngx_http_clear_content_length(r);
     ngx_http_clear_accept_ranges(r);
 
+    if (r->headers_out.content_encoding) {
+        r->headers_out.content_encoding->hash = 0;
+        r->headers_out.content_encoding = NULL;
+    }
+
     return ngx_http_next_header_filter(r);
 }
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -51,7 +51,6 @@ typedef struct {
     ngx_hash_t                     headers_set_hash;
 
     ngx_array_t                   *headers_source;
-    ngx_array_t                   *headers_names;
 
     ngx_array_t                   *proxy_lengths;
     ngx_array_t                   *proxy_values;
@@ -78,20 +77,12 @@ typedef struct {
 
 
 typedef struct {
-    ngx_uint_t                     status;
-    ngx_uint_t                     status_count;
-    u_char                        *status_start;
-    u_char                        *status_end;
-
+    ngx_http_status_t              status;
     ngx_http_proxy_vars_t          vars;
-
     size_t                         internal_body_length;
 } ngx_http_proxy_ctx_t;
 
 
-#define NGX_HTTP_PROXY_PARSE_NO_HEADER  20
-
-
 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
     ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
 #if (NGX_HTTP_CACHE)
@@ -100,8 +91,6 @@ static ngx_int_t ngx_http_proxy_create_k
 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
-static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r,
-    ngx_http_proxy_ctx_t *ctx);
 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
@@ -142,11 +131,6 @@ static char *ngx_http_proxy_cache_key(ng
 
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
 
-static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-
 #if (NGX_HTTP_SSL)
 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
     ngx_http_proxy_loc_conf_t *plcf);
@@ -173,15 +157,6 @@ static ngx_conf_bitmask_t  ngx_http_prox
 };
 
 
-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;
 
 
@@ -229,6 +204,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
       NULL },
 
+    { ngx_string("proxy_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upstream_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
+      NULL },
+
     { ngx_string("proxy_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -337,14 +319,14 @@ static ngx_command_t  ngx_http_proxy_com
 #if (NGX_HTTP_CACHE)
 
     { ngx_string("proxy_cache"),
-      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_http_proxy_cache,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("proxy_cache_key"),
-      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_http_proxy_cache_key,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -357,6 +339,20 @@ static ngx_command_t  ngx_http_proxy_com
       0,
       &ngx_http_proxy_module },
 
+    { ngx_string("proxy_cache_bypass"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
+      NULL },
+
+    { ngx_string("proxy_no_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
+      NULL },
+
     { ngx_string("proxy_cache_valid"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_file_cache_valid_set_slot,
@@ -415,29 +411,15 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
       &ngx_http_proxy_next_upstream_masks },
 
-    { ngx_string("proxy_upstream_max_fails"),
+    { ngx_string("proxy_pass_header"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_upstream_max_fails_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("proxy_upstream_fail_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_upstream_fail_timeout_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("proxy_pass_header"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_str_array_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
       NULL },
 
     { ngx_string("proxy_hide_header"),
-      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_str_array_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
@@ -448,7 +430,7 @@ static ngx_command_t  ngx_http_proxy_com
       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 },
+      &ngx_http_upstream_ignore_headers_masks },
 
 #if (NGX_HTTP_SSL)
 
@@ -530,28 +512,13 @@ static ngx_keyval_t  ngx_http_proxy_cach
     { 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-None-Match"), 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
 
 
@@ -605,7 +572,7 @@ ngx_http_proxy_handler(ngx_http_request_
 
     u = r->upstream;
 
-    if (plcf->proxy_lengths == 0) {
+    if (plcf->proxy_lengths == NULL) {
         ctx->vars = plcf->vars;
         u->schema = plcf->vars.schema;
 #if (NGX_HTTP_SSL)
@@ -630,6 +597,7 @@ ngx_http_proxy_handler(ngx_http_request_
     u->process_header = ngx_http_proxy_process_status_line;
     u->abort_request = ngx_http_proxy_abort_request;
     u->finalize_request = ngx_http_proxy_finalize_request;
+    r->state = 0;
 
     if (plcf->redirects) {
         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
@@ -717,17 +685,22 @@ ngx_http_proxy_eval(ngx_http_request_t *
         return NGX_ERROR;
     }
 
-    if (url.uri.len && url.uri.data[0] == '?') {
-        p = ngx_pnalloc(r->pool, url.uri.len + 1);
-        if (p == NULL) {
-            return NGX_ERROR;
+    if (url.uri.len) {
+        if (url.uri.data[0] == '?') {
+            p = ngx_pnalloc(r->pool, url.uri.len + 1);
+            if (p == NULL) {
+                return NGX_ERROR;
+            }
+
+            *p++ = '/';
+            ngx_memcpy(p, url.uri.data, url.uri.len);
+
+            url.uri.len++;
+            url.uri.data = p - 1;
         }
 
-        *p++ = '/';
-        ngx_memcpy(p, url.uri.data, url.uri.len);
-
-        url.uri.len++;
-        url.uri.data = p - 1;
+    } else {
+        url.uri = r->unparsed_uri;
     }
 
     ctx->vars.key_start = u->schema;
@@ -911,7 +884,7 @@ ngx_http_proxy_create_request(ngx_http_r
         loc_len = (r->valid_location && ctx->vars.uri.len) ?
                       plcf->location.len : 0;
 
-        if (r->quoted_uri || r->internal) {
+        if (r->quoted_uri || r->space_in_uri || r->internal) {
             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
         }
@@ -1180,12 +1153,13 @@ ngx_http_proxy_reinit_request(ngx_http_r
         return NGX_OK;
     }
 
-    ctx->status = 0;
-    ctx->status_count = 0;
-    ctx->status_start = NULL;
-    ctx->status_end = NULL;
+    ctx->status.code = 0;
+    ctx->status.count = 0;
+    ctx->status.start = NULL;
+    ctx->status.end = NULL;
 
     r->upstream->process_header = ngx_http_proxy_process_status_line;
+    r->state = 0;
 
     return NGX_OK;
 }
@@ -1194,6 +1168,7 @@ ngx_http_proxy_reinit_request(ngx_http_r
 static ngx_int_t
 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
 {
+    size_t                 len;
     ngx_int_t              rc;
     ngx_http_upstream_t   *u;
     ngx_http_proxy_ctx_t  *ctx;
@@ -1204,21 +1179,20 @@ ngx_http_proxy_process_status_line(ngx_h
         return NGX_ERROR;
     }
 
-    rc = ngx_http_proxy_parse_status_line(r, ctx);
+    u = r->upstream;
+
+    rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
 
     if (rc == NGX_AGAIN) {
         return rc;
     }
 
-    u = r->upstream;
-
-    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
+    if (rc == NGX_ERROR) {
 
 #if (NGX_HTTP_CACHE)
 
         if (r->cache) {
             r->http_version = NGX_HTTP_VERSION_9;
-            u->headers_in.status_n = NGX_HTTP_OK;
             return NGX_OK;
         }
 
@@ -1234,27 +1208,26 @@ ngx_http_proxy_process_status_line(ngx_h
 #endif
 
         r->http_version = NGX_HTTP_VERSION_9;
-        u->headers_in.status_n = NGX_HTTP_OK;
         u->state->status = NGX_HTTP_OK;
 
         return NGX_OK;
     }
 
     if (u->state) {
-        u->state->status = ctx->status;
+        u->state->status = ctx->status.code;
     }
 
-    u->headers_in.status_n = ctx->status;
-
-    u->headers_in.status_line.len = ctx->status_end - ctx->status_start;
-    u->headers_in.status_line.data = ngx_pnalloc(r->pool,
-                                                 u->headers_in.status_line.len);
+    u->headers_in.status_n = ctx->status.code;
+
+    len = ctx->status.end - ctx->status.start;
+    u->headers_in.status_line.len = len;
+
+    u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
     if (u->headers_in.status_line.data == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_memcpy(u->headers_in.status_line.data, ctx->status_start,
-               u->headers_in.status_line.len);
+    ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http proxy status %ui \"%V\"",
@@ -1267,214 +1240,6 @@ ngx_http_proxy_process_status_line(ngx_h
 
 
 static ngx_int_t
-ngx_http_proxy_parse_status_line(ngx_http_request_t *r,
-    ngx_http_proxy_ctx_t *ctx)
-{
-    u_char                ch;
-    u_char               *p;
-    ngx_http_upstream_t  *u;
-    enum  {
-        sw_start = 0,
-        sw_H,
-        sw_HT,
-        sw_HTT,
-        sw_HTTP,
-        sw_first_major_digit,
-        sw_major_digit,
-        sw_first_minor_digit,
-        sw_minor_digit,
-        sw_status,
-        sw_space_after_status,
-        sw_status_text,
-        sw_almost_done
-    } state;
-
-    u = r->upstream;
-
-    state = r->state;
-
-    for (p = u->buffer.pos; p < u->buffer.last; p++) {
-        ch = *p;
-
-        switch (state) {
-
-        /* "HTTP/" */
-        case sw_start:
-            switch (ch) {
-            case 'H':
-                state = sw_H;
-                break;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        case sw_H:
-            switch (ch) {
-            case 'T':
-                state = sw_HT;
-                break;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        case sw_HT:
-            switch (ch) {
-            case 'T':
-                state = sw_HTT;
-                break;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        case sw_HTT:
-            switch (ch) {
-            case 'P':
-                state = sw_HTTP;
-                break;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        case sw_HTTP:
-            switch (ch) {
-            case '/':
-                state = sw_first_major_digit;
-                break;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        /* the first digit of major HTTP version */
-        case sw_first_major_digit:
-            if (ch < '1' || ch > '9') {
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-
-            state = sw_major_digit;
-            break;
-
-        /* the major HTTP version or dot */
-        case sw_major_digit:
-            if (ch == '.') {
-                state = sw_first_minor_digit;
-                break;
-            }
-
-            if (ch < '0' || ch > '9') {
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-
-            break;
-
-        /* the first digit of minor HTTP version */
-        case sw_first_minor_digit:
-            if (ch < '0' || ch > '9') {
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-
-            state = sw_minor_digit;
-            break;
-
-        /* the minor HTTP version or the end of the request line */
-        case sw_minor_digit:
-            if (ch == ' ') {
-                state = sw_status;
-                break;
-            }
-
-            if (ch < '0' || ch > '9') {
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-
-            break;
-
-        /* HTTP status code */
-        case sw_status:
-            if (ch == ' ') {
-                break;
-            }
-
-            if (ch < '0' || ch > '9') {
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-
-            ctx->status = ctx->status * 10 + ch - '0';
-
-            if (++ctx->status_count == 3) {
-                state = sw_space_after_status;
-                ctx->status_start = p - 2;
-            }
-
-            break;
-
-         /* space or end of line */
-         case sw_space_after_status:
-            switch (ch) {
-            case ' ':
-                state = sw_status_text;
-                break;
-            case '.':                    /* IIS may send 403.1, 403.2, etc */
-                state = sw_status_text;
-                break;
-            case CR:
-                state = sw_almost_done;
-                break;
-            case LF:
-                goto done;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        /* any text until end of line */
-        case sw_status_text:
-            switch (ch) {
-            case CR:
-                state = sw_almost_done;
-
-                break;
-            case LF:
-                goto done;
-            }
-            break;
-
-        /* end of status line */
-        case sw_almost_done:
-            ctx->status_end = p - 1;
-            switch (ch) {
-            case LF:
-                goto done;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-        }
-    }
-
-    u->buffer.pos = p;
-    r->state = state;
-
-    return NGX_AGAIN;
-
-done:
-
-    u->buffer.pos = p + 1;
-
-    if (ctx->status_end == NULL) {
-        ctx->status_end = p;
-    }
-
-    r->state = sw_start;
-
-    return NGX_OK;
-}
-
-
-static ngx_int_t
 ngx_http_proxy_process_header(ngx_http_request_t *r)
 {
     ngx_int_t                       rc;
@@ -1556,10 +1321,8 @@ ngx_http_proxy_process_header(ngx_http_r
                 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
                                     ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
 
-                h->key.len = sizeof("Server") - 1;
-                h->key.data = (u_char *) "Server";
-                h->value.len = 0;
-                h->value.data = NULL;
+                ngx_str_set(&h->key, "Server");
+                ngx_str_null(&h->value);
                 h->lowcase_key = (u_char *) "server";
             }
 
@@ -1571,10 +1334,8 @@ ngx_http_proxy_process_header(ngx_http_r
 
                 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
 
-                h->key.len = sizeof("Date") - 1;
-                h->key.data = (u_char *) "Date";
-                h->value.len = 0;
-                h->value.data = NULL;
+                ngx_str_set(&h->key, "Date");
+                ngx_str_null(&h->value);
                 h->lowcase_key = (u_char *) "date";
             }
 
@@ -1770,16 +1531,14 @@ ngx_http_proxy_rewrite_redirect_text(ngx
         return NGX_DECLINED;
     }
 
-    len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len;
+    len = pr->replacement.text.len + h->value.len - pr->redirect.len;
 
     data = ngx_pnalloc(r->pool, len);
     if (data == NULL) {
         return NGX_ERROR;
     }
 
-    p = data;
-
-    p = ngx_copy(p, h->value.data, prefix);
+    p = ngx_copy(data, h->value.data, prefix);
 
     if (pr->replacement.text.len) {
         p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len);
@@ -1817,7 +1576,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx
     e.ip = pr->replacement.vars.lengths;
     e.request = r;
 
-    len = prefix + h->value.len - pr->redirect.len;
+    len = h->value.len - pr->redirect.len;
 
     while (*(uintptr_t *) e.ip) {
         lcode = *(ngx_http_script_len_code_pt *) e.ip;
@@ -1829,9 +1588,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx
         return NGX_ERROR;
     }
 
-    p = data;
-
-    p = ngx_copy(p, h->value.data, prefix);
+    p = ngx_copy(data, h->value.data, prefix);
 
     e.ip = pr->replacement.vars.values;
     e.pos = p;
@@ -1903,7 +1660,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
      *     conf->body_set_len = NULL;
      *     conf->body_set = NULL;
      *     conf->body_source = { 0, NULL };
-     *     conf->rewrite_locations = NULL;
+     *     conf->redirects = NULL;
      */
 
     conf->upstream.store = NGX_CONF_UNSET;
@@ -1928,6 +1685,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
+    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
 #endif
 
@@ -1958,10 +1717,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_http_proxy_loc_conf_t *prev = parent;
     ngx_http_proxy_loc_conf_t *conf = child;
 
+    u_char                     *p;
     size_t                      size;
-    ngx_str_t                  *h;
     ngx_keyval_t               *s;
     ngx_hash_init_t             hash;
+    ngx_http_core_loc_conf_t   *clcf;
     ngx_http_proxy_redirect_t  *pr;
     ngx_http_script_compile_t   sc;
 
@@ -2152,6 +1912,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
                                          |NGX_HTTP_UPSTREAM_FT_OFF;
     }
 
+    ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
+                             prev->upstream.cache_bypass, NULL);
+
+    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+                             prev->upstream.no_cache, NULL);
+
+    if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
+        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+             "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
+             "now it should be used together with \"proxy_cache_bypass\"");
+    }
+
     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                              prev->upstream.cache_valid, NULL);
 
@@ -2204,24 +1976,29 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
             }
 
             pr->handler = ngx_http_proxy_rewrite_redirect_text;
-            pr->redirect = conf->url;
 
             if (conf->vars.uri.len) {
+                pr->redirect = conf->url;
                 pr->replacement.text = conf->location;
 
             } else {
-                pr->replacement.text.len = 0;
-                pr->replacement.text.data = NULL;
+                pr->redirect.len = conf->url.len + sizeof("/") - 1;
+
+                p = ngx_pnalloc(cf->pool, pr->redirect.len);
+                if (p == NULL) {
+                    return NGX_CONF_ERROR;
+                }
+
+                pr->redirect.data = p;
+
+                p = ngx_cpymem(p, conf->url.data, conf->url.len);
+                *p = '/';
+
+                ngx_str_set(&pr->replacement.text, "/");
             }
         }
     }
 
-    /* STUB */
-    if (prev->proxy_lengths) {
-        conf->proxy_lengths = prev->proxy_lengths;
-        conf->proxy_values = prev->proxy_values;
-    }
-
 #if (NGX_HTTP_SSL)
     if (conf->upstream.ssl == NULL) {
         conf->upstream.ssl = prev->upstream.ssl;
@@ -2241,18 +2018,8 @@ 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, h, &hash)
+            &prev->upstream, ngx_http_proxy_hide_headers, &hash)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -2263,6 +2030,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
         conf->vars = prev->vars;
     }
 
+    if (conf->proxy_lengths == NULL) {
+        conf->proxy_lengths = prev->proxy_lengths;
+        conf->proxy_values = prev->proxy_values;
+    }
+
+    if (conf->upstream.upstream || conf->proxy_lengths) {
+        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+        if (clcf->handler == NULL && clcf->lmt_excpt) {
+            clcf->handler = ngx_http_proxy_handler;
+            conf->location = prev->location;
+        }
+    }
 
     if (conf->body_source.data == NULL) {
         conf->body_source = prev->body_source;
@@ -2299,10 +2078,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
             return NGX_CONF_ERROR;
         }
 
-        s->key.len = sizeof("Content-Length") - 1;
-        s->key.data = (u_char *) "Content-Length";
-        s->value.len = sizeof("$proxy_internal_body_length") - 1;
-        s->value.data = (u_char *) "$proxy_internal_body_length";
+        ngx_str_set(&s->key, "Content-Length");
+        ngx_str_set(&s->value, "$proxy_internal_body_length");
     }
 
     if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
@@ -2321,6 +2098,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     size_t                        size;
     uintptr_t                    *code;
     ngx_uint_t                    i;
+    ngx_array_t                   headers_names;
     ngx_keyval_t                 *src, *s, *h;
     ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
@@ -2345,8 +2123,9 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     }
 
 
-    conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t));
-    if (conf->headers_names == NULL) {
+    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
         return NGX_ERROR;
     }
 
@@ -2407,7 +2186,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     src = conf->headers_source->elts;
     for (i = 0; i < conf->headers_source->nelts; i++) {
 
-        hk = ngx_array_push(conf->headers_names);
+        hk = ngx_array_push(&headers_names);
         if (hk == NULL) {
             return NGX_ERROR;
         }
@@ -2555,14 +2334,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     hash.pool = cf->pool;
     hash.temp_pool = NULL;
 
-    if (ngx_hash_init(&hash, conf->headers_names->elts,
-                      conf->headers_names->nelts)
-        != NGX_OK)
-    {
-        return NGX_ERROR;
-    }
-
-    return NGX_OK;
+    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
 }
 
 
@@ -2697,6 +2469,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, 
 {
     ngx_http_proxy_loc_conf_t *plcf = conf;
 
+    u_char                     *p;
     ngx_str_t                  *value;
     ngx_array_t                *vars_lengths, *vars_values;
     ngx_http_script_compile_t   sc;
@@ -2744,22 +2517,40 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, 
     }
 
     if (ngx_strcmp(value[1].data, "default") == 0) {
+        if (plcf->proxy_lengths) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "\"proxy_redirect default\" may not be used "
+                               "with \"proxy_pass\" directive with variables");
+            return NGX_CONF_ERROR;
+        }
+
         if (plcf->url.data == NULL) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "\"proxy_rewrite_location default\" must go "
+                               "\"proxy_redirect default\" must go "
                                "after the \"proxy_pass\" directive");
             return NGX_CONF_ERROR;
         }
 
         pr->handler = ngx_http_proxy_rewrite_redirect_text;
-        pr->redirect = plcf->url;
 
         if (plcf->vars.uri.len) {
+            pr->redirect = plcf->url;
             pr->replacement.text = plcf->location;
 
         } else {
-            pr->replacement.text.len = 0;
-            pr->replacement.text.data = NULL;
+            pr->redirect.len = plcf->url.len + sizeof("/") - 1;
+
+            p = ngx_pnalloc(cf->pool, pr->redirect.len);
+            if (p == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            pr->redirect.data = p;
+
+            p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
+            *p = '/';
+
+            ngx_str_set(&pr->replacement.text, "/");
         }
 
         return NGX_CONF_OK;
@@ -2948,32 +2739,6 @@ ngx_http_proxy_lowat_check(ngx_conf_t *c
 }
 
 
-static char *
-ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"proxy_upstream_max_fails\" is not supported, "
-         "use the \"max_fails\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"proxy_upstream_fail_timeout\" is not supported, "
-         "use the \"fail_timeout\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
 #if (NGX_HTTP_SSL)
 
 static ngx_int_t
@@ -3019,12 +2784,10 @@ ngx_http_proxy_set_vars(ngx_url_t *u, ng
             v->host_header = u->host;
 
             if (u->default_port == 80) {
-                v->port.len = sizeof("80") - 1;
-                v->port.data = (u_char *) "80";
+                ngx_str_set(&v->port, "80");
 
             } else {
-                v->port.len = sizeof("443") - 1;
-                v->port.data = (u_char *) "443";
+                ngx_str_set(&v->port, "443");
             }
 
         } else {
@@ -3036,10 +2799,8 @@ ngx_http_proxy_set_vars(ngx_url_t *u, ng
         v->key_start.len += v->host_header.len;
 
     } else {
-        v->host_header.len = sizeof("localhost") - 1;
-        v->host_header.data = (u_char *) "localhost";
-        v->port.len = 0;
-        v->port.data = (u_char *) "";
+        ngx_str_set(&v->host_header, "localhost");
+        ngx_str_null(&v->port);
         v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
     }
 
--- a/src/http/modules/ngx_http_random_index_module.c
+++ b/src/http/modules/ngx_http_random_index_module.c
@@ -86,10 +86,6 @@ ngx_http_random_index_handler(ngx_http_r
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
         return NGX_DECLINED;
     }
@@ -175,7 +171,7 @@ ngx_http_random_index_handler(ngx_http_r
 
         len = ngx_de_namelen(&dir);
 
-        if (!dir.valid_type) {
+        if (dir.type == 0 || ngx_de_is_link(&dir)) {
 
             /* 1 byte for '/' and 1 byte for terminating '\0' */
 
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -224,10 +224,8 @@ next_filter:
     }
 
     r->headers_out.accept_ranges->hash = 1;
-    r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1;
-    r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges";
-    r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1;
-    r->headers_out.accept_ranges->value.data = (u_char *) "bytes";
+    ngx_str_set(&r->headers_out.accept_ranges->key, "Accept-Ranges");
+    ngx_str_set(&r->headers_out.accept_ranges->value, "bytes");
 
     return ngx_http_next_header_filter(r);
 }
@@ -355,8 +353,7 @@ ngx_http_range_singlepart_header(ngx_htt
     r->headers_out.content_range = content_range;
 
     content_range->hash = 1;
-    content_range->key.len = sizeof("Content-Range") - 1;
-    content_range->key.data = (u_char *) "Content-Range";
+    ngx_str_set(&content_range->key, "Content-Range");
 
     content_range->value.data = ngx_pnalloc(r->pool,
                                     sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
@@ -520,8 +517,7 @@ ngx_http_range_not_satisfiable(ngx_http_
     r->headers_out.content_range = content_range;
 
     content_range->hash = 1;
-    content_range->key.len = sizeof("Content-Range") - 1;
-    content_range->key.data = (u_char *) "Content-Range";
+    ngx_str_set(&content_range->key, "Content-Range");
 
     content_range->value.data = ngx_pnalloc(r->pool,
                                        sizeof("bytes */") - 1 + NGX_OFF_T_LEN);
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -25,17 +25,23 @@ typedef struct {
     ngx_uint_t         type;
     ngx_uint_t         hash;
     ngx_str_t          header;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    ngx_uint_t         unixsock; /* unsigned  unixsock:2; */
+#endif
 } ngx_http_realip_loc_conf_t;
 
 
 typedef struct {
     ngx_connection_t  *connection;
-    in_addr_t          addr;
+    struct sockaddr   *sockaddr;
+    socklen_t          socklen;
     ngx_str_t          addr_text;
 } ngx_http_realip_ctx_t;
 
 
 static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip,
+    size_t len);
 static void ngx_http_realip_cleanup(void *data);
 static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -103,13 +109,11 @@ ngx_http_realip_handler(ngx_http_request
 {
     u_char                      *ip, *p;
     size_t                       len;
-    in_addr_t                    addr;
     ngx_uint_t                   i, hash;
     ngx_list_part_t             *part;
     ngx_table_elt_t             *header;
     struct sockaddr_in          *sin;
     ngx_connection_t            *c;
-    ngx_pool_cleanup_t          *cln;
     ngx_http_realip_ctx_t       *ctx;
     ngx_http_realip_from_t      *from;
     ngx_http_realip_loc_conf_t  *rlcf;
@@ -120,14 +124,14 @@ ngx_http_realip_handler(ngx_http_request
         return NGX_DECLINED;
     }
 
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
-    if (cln == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
 
-    if (rlcf->from == NULL) {
+    if (rlcf->from == NULL
+#if (NGX_HAVE_UNIX_DOMAIN)
+        && !rlcf->unixsock
+#endif
+       )
+    {
         return NGX_DECLINED;
     }
 
@@ -207,52 +211,83 @@ found:
 
     /* AF_INET only */
 
-    if (r->connection->sockaddr->sa_family != AF_INET) {
-        return NGX_DECLINED;
+    if (c->sockaddr->sa_family == AF_INET) {
+        sin = (struct sockaddr_in *) c->sockaddr;
+
+        from = rlcf->from->elts;
+        for (i = 0; i < rlcf->from->nelts; i++) {
+
+            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                           "realip: %08XD %08XD %08XD",
+                           sin->sin_addr.s_addr, from[i].mask, from[i].addr);
+
+            if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
+                return ngx_http_realip_set_addr(r, ip, len);
+            }
+        }
+    }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+    if (c->sockaddr->sa_family == AF_UNIX && rlcf->unixsock) {
+        return ngx_http_realip_set_addr(r, ip, len);
     }
 
-    sin = (struct sockaddr_in *) c->sockaddr;
+#endif
 
-    from = rlcf->from->elts;
-    for (i = 0; i < rlcf->from->nelts; i++) {
+    return NGX_DECLINED;
+}
 
-        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                       "realip: %08XD %08XD %08XD",
-                       sin->sin_addr.s_addr, from[i].mask, from[i].addr);
 
-        if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
-
-            ctx = cln->data;
-
-            ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
+static ngx_int_t
+ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip, size_t len)
+{
+    u_char                 *p;
+    ngx_int_t               rc;
+    ngx_addr_t              addr;
+    ngx_connection_t       *c;
+    ngx_pool_cleanup_t     *cln;
+    ngx_http_realip_ctx_t  *ctx;
 
-            addr = inet_addr((char *) ip);
+    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
+    if (cln == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-            if (addr == INADDR_NONE) {
-                return NGX_DECLINED;
-            }
+    ctx = cln->data;
+    ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
+
+    c = r->connection;
+
+    rc = ngx_parse_addr(c->pool, &addr, ip, len);
 
-            p = ngx_pnalloc(c->pool, len);
-            if (p == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
+    switch (rc) {
+    case NGX_DECLINED:
+        return NGX_DECLINED;
+    case NGX_ERROR:
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    default: /* NGX_OK */
+        break;
+    }
 
-            ngx_memcpy(p, ip, len);
-
-            cln->handler = ngx_http_realip_cleanup;
+    p = ngx_pnalloc(c->pool, len);
+    if (p == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-            ctx->connection = c;
-            ctx->addr = sin->sin_addr.s_addr;
-            ctx->addr_text = c->addr_text;
+    ngx_memcpy(p, ip, len);
 
-            sin->sin_addr.s_addr = addr;
+    cln->handler = ngx_http_realip_cleanup;
 
-            c->addr_text.len = len;
-            c->addr_text.data = p;
+    ctx->connection = c;
+    ctx->sockaddr = c->sockaddr;
+    ctx->socklen = c->socklen;
+    ctx->addr_text = c->addr_text;
 
-            return NGX_DECLINED;
-        }
-    }
+    c->sockaddr = addr.sockaddr;
+    c->socklen = addr.socklen;
+    c->addr_text.len = len;
+    c->addr_text.data = p;
 
     return NGX_DECLINED;
 }
@@ -263,14 +298,12 @@ ngx_http_realip_cleanup(void *data)
 {
     ngx_http_realip_ctx_t *ctx = data;
 
-    ngx_connection_t    *c;
-    struct sockaddr_in  *sin;
+    ngx_connection_t  *c;
 
     c = ctx->connection;
 
-    sin = (struct sockaddr_in *) c->sockaddr;
-    sin->sin_addr.s_addr = ctx->addr;
-
+    c->sockaddr = ctx->sockaddr;
+    c->socklen = ctx->socklen;
     c->addr_text = ctx->addr_text;
 }
 
@@ -285,6 +318,17 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
     ngx_cidr_t               cidr;
     ngx_http_realip_from_t  *from;
 
+    value = cf->args->elts;
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+    if (ngx_strcmp(value[1].data, "unix:") == 0) {
+         rlcf->unixsock = 1;
+         return NGX_CONF_OK;
+    }
+
+#endif
+
     if (rlcf->from == NULL) {
         rlcf->from = ngx_array_create(cf->pool, 2,
                                       sizeof(ngx_http_realip_from_t));
@@ -298,8 +342,6 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    value = cf->args->elts;
-
     rc = ngx_ptocidr(&value[1], &cidr);
 
     if (rc == NGX_ERROR) {
@@ -310,7 +352,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
 
     if (cidr.family != AF_INET) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "\"realip_from\" supports IPv4 only");
+                           "\"set_real_ip_from\" supports IPv4 only");
         return NGX_CONF_ERROR;
     }
 
@@ -372,6 +414,9 @@ ngx_http_realip_create_loc_conf(ngx_conf
      */
 
     conf->type = NGX_CONF_UNSET_UINT;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    conf->unixsock = 2;
+#endif
 
     return conf;
 }
@@ -387,6 +432,12 @@ ngx_http_realip_merge_loc_conf(ngx_conf_
         conf->from = prev->from;
     }
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+    if (conf->unixsock == 2) {
+        conf->unixsock = (prev->unixsock == 2) ? 0 : prev->unixsock;
+    }
+#endif
+
     ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
 
     if (conf->header.len == 0) {
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -124,18 +124,27 @@ ngx_http_referer_variable(ngx_http_reque
     len = r->headers_in.referer->value.len;
     ref = r->headers_in.referer->value.data;
 
-    if (len < sizeof("http://i.ru") - 1
-        || (ngx_strncasecmp(ref, (u_char *) "http://", 7) != 0))
-    {
-        if (rlcf->blocked_referer) {
-            goto valid;
+    if (len >= sizeof("http://i.ru") - 1) {
+        last = ref + len;
+
+        if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) {
+            ref += 7;
+            goto valid_scheme;
+
+        } else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) {
+            ref += 8;
+            goto valid_scheme;
         }
-
-        goto invalid;
     }
 
-    last = ref + len;
-    ref += 7;
+    if (rlcf->blocked_referer) {
+        goto valid;
+    }
+
+    goto invalid;
+
+valid_scheme:
+
     i = 0;
     key = 0;
 
@@ -354,8 +363,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
     ngx_http_server_name_t    *sn;
     ngx_http_core_srv_conf_t  *cscf;
 
-    name.len = sizeof("invalid_referer") - 1;
-    name.data = (u_char *) "invalid_referer";
+    ngx_str_set(&name, "invalid_referer");
 
     var = ngx_http_add_variable(cf, &name,
                                 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH);
@@ -398,8 +406,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
             continue;
         }
 
-        uri.len = 0;
-        uri.data = NULL;
+        ngx_str_null(&uri);
 
         if (ngx_strcmp(value[i].data, "server_names") == 0) {
 
@@ -412,7 +419,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
                 if (sn[n].regex) {
 
                     if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name,
-                                                   sn[n].regex)
+                                                   sn[n].regex->regex)
                         != NGX_OK)
                     {
                         return NGX_CONF_ERROR;
@@ -502,9 +509,9 @@ ngx_http_add_regex_referer(ngx_conf_t *c
     ngx_str_t *name, ngx_regex_t *regex)
 {
 #if (NGX_PCRE)
-    ngx_str_t         err;
-    ngx_regex_elt_t  *re;
-    u_char            errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_regex_elt_t      *re;
+    ngx_regex_compile_t   rc;
+    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);
@@ -530,19 +537,23 @@ ngx_http_add_regex_referer(ngx_conf_t *c
         return NGX_CONF_OK;
     }
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
-
     name->len--;
     name->data++;
 
-    re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err);
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
 
-    if (re->regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+    rc.pattern = *name;
+    rc.pool = cf->pool;
+    rc.options = NGX_REGEX_CASELESS;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
+
+    if (ngx_regex_compile(&rc) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
         return NGX_CONF_ERROR;
     }
 
+    re->regex = rc.regex;
     re->name = name->data;
 
     return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -52,7 +52,7 @@ static ngx_command_t  ngx_http_rewrite_c
 
     { ngx_string("return"),
       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
-                       |NGX_CONF_TAKE1,
+                       |NGX_CONF_TAKE12,
       ngx_http_rewrite_return,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -294,9 +294,9 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 {
     ngx_http_rewrite_loc_conf_t  *lcf = conf;
 
-    ngx_str_t                         *value, err;
-    ngx_int_t                          n;
+    ngx_str_t                         *value;
     ngx_uint_t                         last;
+    ngx_regex_compile_t                rc;
     ngx_http_script_code_pt           *code;
     ngx_http_script_compile_t          sc;
     ngx_http_script_regex_code_t      *regex;
@@ -313,15 +313,16 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 
     value = cf->args->elts;
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pattern = value[1];
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
 
     /* TODO: NGX_REGEX_CASELESS */
 
-    regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
-
+    regex->regex = ngx_http_regex_compile(cf, &rc);
     if (regex->regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
         return NGX_CONF_ERROR;
     }
 
@@ -340,13 +341,10 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 
     last = 0;
 
-    if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) {
-        regex->status = NGX_HTTP_MOVED_TEMPORARILY;
-        regex->redirect = 1;
-        last = 1;
-    }
-
-    if (ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0) {
+    if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
+        || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
+        || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
+    {
         regex->status = NGX_HTTP_MOVED_TEMPORARILY;
         regex->redirect = 1;
         last = 1;
@@ -394,7 +392,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 
     regex = sc.main;
 
-    regex->ncaptures = sc.ncaptures;
     regex->size = sc.size;
     regex->args = sc.args;
 
@@ -402,31 +399,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
         regex->lengths = NULL;
     }
 
-    n = ngx_regex_capture_count(regex->regex);
-
-    if (n < 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           ngx_regex_capture_count_n " failed for "
-                           "pattern \"%V\"", &value[1]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (regex->ncaptures > (ngx_uint_t) n) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "pattern \"%V\" has less captures "
-                           "than referrenced in substitution \"%V\"",
-                           &value[1], &value[2]);
-        return NGX_CONF_ERROR;
-    }
-
-    if (regex->ncaptures < (ngx_uint_t) n) {
-        regex->ncaptures = (ngx_uint_t) n;
-    }
-
-    if (regex->ncaptures) {
-        regex->ncaptures = (regex->ncaptures + 1) * 3;
-    }
-
     regex_end = ngx_http_script_add_code(lcf->codes,
                                       sizeof(ngx_http_script_regex_end_code_t),
                                       &regex);
@@ -446,7 +418,7 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
             return NGX_CONF_ERROR;
         }
 
-        *code = (uintptr_t) NULL;
+        *code = NULL;
     }
 
     regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
@@ -461,8 +433,10 @@ ngx_http_rewrite_return(ngx_conf_t *cf, 
 {
     ngx_http_rewrite_loc_conf_t  *lcf = conf;
 
-    ngx_str_t                      *value;
-    ngx_http_script_return_code_t  *ret;
+    u_char                            *p;
+    ngx_str_t                         *value, *v;
+    ngx_http_script_return_code_t     *ret;
+    ngx_http_compile_complex_value_t   ccv;
 
     ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
                                      sizeof(ngx_http_script_return_code_t));
@@ -472,12 +446,46 @@ ngx_http_rewrite_return(ngx_conf_t *cf, 
 
     value = cf->args->elts;
 
+    ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));
+
     ret->code = ngx_http_script_return_code;
-    ret->null = (uintptr_t) NULL;
 
-    ret->status = ngx_atoi(value[1].data, value[1].len);
+    p = value[1].data;
+
+    ret->status = ngx_atoi(p, value[1].len);
 
     if (ret->status == (uintptr_t) NGX_ERROR) {
+
+        if (cf->args->nelts == 2
+            && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
+                || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
+                || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
+        {
+            ret->status = NGX_HTTP_MOVED_TEMPORARILY;
+            v = &value[1];
+
+        } else {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid return code \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+    } else {
+
+        if (cf->args->nelts == 2) {
+            return NGX_CONF_OK;
+        }
+
+        v = &value[2];
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = v;
+    ccv.complex_value = &ret->text;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
@@ -624,8 +632,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t
 {
     u_char                        *p;
     size_t                         len;
-    ngx_str_t                     *value, err;
-    ngx_uint_t                     cur, last, n;
+    ngx_str_t                     *value;
+    ngx_uint_t                     cur, last;
+    ngx_regex_compile_t            rc;
     ngx_http_script_code_pt       *code;
     ngx_http_script_file_code_t   *fop;
     ngx_http_script_regex_code_t  *regex;
@@ -733,15 +742,15 @@ ngx_http_rewrite_if_condition(ngx_conf_t
 
             ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
 
-            err.len = NGX_MAX_CONF_ERRSTR;
-            err.data = errstr;
+            ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
 
-            regex->regex = ngx_regex_compile(&value[last],
-                                  (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0,
-                                   cf->pool, &err);
+            rc.pattern = value[last];
+            rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
+            rc.err.len = NGX_MAX_CONF_ERRSTR;
+            rc.err.data = errstr;
 
+            regex->regex = ngx_http_regex_compile(cf, &rc);
             if (regex->regex == NULL) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
                 return NGX_CONF_ERROR;
             }
 
@@ -753,12 +762,6 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             }
             regex->name = value[last];
 
-            n = ngx_regex_capture_count(regex->regex);
-
-            if (n) {
-                regex->ncaptures = (n + 1) * 3;
-            }
-
             return NGX_CONF_OK;
         }
 
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -0,0 +1,1656 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Manlio Perillo (manlio.perillo@gmail.com)
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    ngx_http_upstream_conf_t   upstream;
+
+    ngx_array_t               *flushes;
+    ngx_array_t               *params_len;
+    ngx_array_t               *params;
+    ngx_array_t               *params_source;
+
+    ngx_hash_t                 headers_hash;
+    ngx_uint_t                 header_params;
+
+    ngx_array_t               *scgi_lengths;
+    ngx_array_t               *scgi_values;
+
+#if (NGX_HTTP_CACHE)
+    ngx_http_complex_value_t   cache_key;
+#endif
+} ngx_http_scgi_loc_conf_t;
+
+
+static ngx_int_t ngx_http_scgi_eval(ngx_http_request_t *r,
+    ngx_http_scgi_loc_conf_t *scf);
+static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
+static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
+static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
+static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
+
+static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+
+#if (NGX_HTTP_CACHE)
+static ngx_int_t ngx_http_scgi_create_key(ngx_http_request_t *r);
+static char *ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+#endif
+
+
+static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = {
+    { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
+    { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
+    { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
+    { 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 }
+};
+
+
+ngx_module_t  ngx_http_scgi_module;
+
+
+static ngx_command_t ngx_http_scgi_commands[] = {
+
+    { ngx_string("scgi_pass"),
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
+      ngx_http_scgi_pass,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("scgi_store"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_scgi_store,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("scgi_store_access"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+      ngx_conf_set_access_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.store_access),
+      NULL },
+
+    { ngx_string("scgi_ignore_client_abort"),
+      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_scgi_loc_conf_t, upstream.ignore_client_abort),
+      NULL },
+
+    { ngx_string("scgi_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upstream_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.local),
+      NULL },
+
+    { ngx_string("scgi_connect_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.connect_timeout),
+      NULL },
+
+    { ngx_string("scgi_send_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.send_timeout),
+      NULL },
+
+    { ngx_string("scgi_buffer_size"),
+      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_scgi_loc_conf_t, upstream.buffer_size),
+      NULL },
+
+    { ngx_string("scgi_pass_request_headers"),
+      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_scgi_loc_conf_t, upstream.pass_request_headers),
+      NULL },
+
+    { ngx_string("scgi_pass_request_body"),
+      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_scgi_loc_conf_t, upstream.pass_request_body),
+      NULL },
+
+    { ngx_string("scgi_intercept_errors"),
+      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_scgi_loc_conf_t, upstream.intercept_errors),
+      NULL },
+
+    { ngx_string("scgi_read_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.read_timeout),
+      NULL },
+
+    { ngx_string("scgi_buffers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_bufs_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.bufs),
+      NULL },
+
+    { ngx_string("scgi_busy_buffers_size"),
+      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_scgi_loc_conf_t, upstream.busy_buffers_size_conf),
+      NULL },
+
+#if (NGX_HTTP_CACHE)
+
+    { ngx_string("scgi_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_scgi_cache,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("scgi_cache_key"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_scgi_cache_key,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("scgi_cache_path"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
+      ngx_http_file_cache_set_slot,
+      0,
+      0,
+      &ngx_http_scgi_module },
+
+    { ngx_string("scgi_cache_bypass"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_bypass),
+      NULL },
+
+    { ngx_string("scgi_no_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.no_cache),
+      NULL },
+
+    { ngx_string("scgi_cache_valid"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_file_cache_valid_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_valid),
+      NULL },
+
+    { ngx_string("scgi_cache_min_uses"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses),
+      NULL },
+
+    { ngx_string("scgi_cache_use_stale"),
+      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_scgi_loc_conf_t, upstream.cache_use_stale),
+      &ngx_http_scgi_next_upstream_masks },
+
+    { ngx_string("scgi_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_scgi_loc_conf_t, upstream.cache_methods),
+      &ngx_http_upstream_cache_method_mask },
+
+#endif
+
+    { ngx_string("scgi_temp_path"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+      ngx_conf_set_path_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_path),
+      NULL },
+
+    { ngx_string("scgi_max_temp_file_size"),
+      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_scgi_loc_conf_t, upstream.max_temp_file_size_conf),
+      NULL },
+
+    { ngx_string("scgi_temp_file_write_size"),
+      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_scgi_loc_conf_t, upstream.temp_file_write_size_conf),
+      NULL },
+
+    { ngx_string("scgi_next_upstream"),
+      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_scgi_loc_conf_t, upstream.next_upstream),
+      &ngx_http_scgi_next_upstream_masks },
+
+    { ngx_string("scgi_param"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_keyval_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, params_source),
+      NULL },
+
+    { ngx_string("scgi_pass_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_array_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_headers),
+      NULL },
+
+    { ngx_string("scgi_hide_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_array_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.hide_headers),
+      NULL },
+
+    { ngx_string("scgi_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_scgi_loc_conf_t, upstream.ignore_headers),
+      &ngx_http_upstream_ignore_headers_masks },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_scgi_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_scgi_create_loc_conf,         /* create location configuration */
+    ngx_http_scgi_merge_loc_conf           /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_scgi_module = {
+    NGX_MODULE_V1,
+    &ngx_http_scgi_module_ctx,             /* module context */
+    ngx_http_scgi_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_str_t ngx_http_scgi_hide_headers[] = {
+    ngx_string("Status"),
+    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_null_string
+};
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_keyval_t  ngx_http_scgi_cache_headers[] = {
+    { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_RANGE"), ngx_string("") },
+    { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
+    { ngx_null_string, ngx_null_string }
+};
+
+#endif
+
+
+static ngx_path_init_t ngx_http_scgi_temp_path = {
+    ngx_string(NGX_HTTP_SCGI_TEMP_PATH), { 1, 2, 0 }
+};
+
+
+static ngx_int_t
+ngx_http_scgi_handler(ngx_http_request_t *r)
+{
+    ngx_int_t                  rc;
+    ngx_http_status_t         *status;
+    ngx_http_upstream_t       *u;
+    ngx_http_scgi_loc_conf_t  *scf;
+
+    if (r->subrequest_in_memory) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "ngx_http_scgi_module does not support "
+                      "subrequests in memory");
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (ngx_http_upstream_create(r) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
+    if (status == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ngx_http_set_ctx(r, status, ngx_http_scgi_module);
+
+    scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
+
+    if (scf->scgi_lengths) {
+        if (ngx_http_scgi_eval(r, scf) != NGX_OK) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    u = r->upstream;
+
+    ngx_str_set(&u->schema, "scgi://");
+    u->output.tag = (ngx_buf_tag_t) &ngx_http_scgi_module;
+
+    u->conf = &scf->upstream;
+
+#if (NGX_HTTP_CACHE)
+    u->create_key = ngx_http_scgi_create_key;
+#endif
+    u->create_request = ngx_http_scgi_create_request;
+    u->reinit_request = ngx_http_scgi_reinit_request;
+    u->process_header = ngx_http_scgi_process_status_line;
+    u->abort_request = ngx_http_scgi_abort_request;
+    u->finalize_request = ngx_http_scgi_finalize_request;
+
+    u->buffering = 1;
+
+    u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
+    if (u->pipe == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
+    u->pipe->input_ctx = r;
+
+    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        return rc;
+    }
+
+    return NGX_DONE;
+}
+
+
+static ngx_int_t
+ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf)
+{
+    ngx_url_t             url;
+    ngx_http_upstream_t  *u;
+
+    ngx_memzero(&url, sizeof(ngx_url_t));
+
+    if (ngx_http_script_run(r, &url.url, scf->scgi_lengths->elts, 0,
+                            scf->scgi_values->elts)
+        == NULL)
+    {
+        return NGX_ERROR;
+    }
+
+    url.no_resolve = 1;
+
+    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+        if (url.err) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "%s in upstream \"%V\"", url.err, &url.url);
+        }
+
+        return NGX_ERROR;
+    }
+
+    u = r->upstream;
+
+    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+    if (u->resolved == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (url.addrs && url.addrs[0].sockaddr) {
+        u->resolved->sockaddr = url.addrs[0].sockaddr;
+        u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->naddrs = 1;
+        u->resolved->host = url.addrs[0].name;
+
+    } else {
+        u->resolved->host = url.host;
+        u->resolved->port = url.port;
+        u->resolved->no_port = url.no_port;
+    }
+
+    return NGX_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_int_t
+ngx_http_scgi_create_key(ngx_http_request_t *r)
+{
+    ngx_str_t                 *key;
+    ngx_http_scgi_loc_conf_t  *scf;
+
+    key = ngx_array_push(&r->cache->keys);
+    if (key == NULL) {
+        return NGX_ERROR;
+    }
+
+    scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
+
+    if (ngx_http_complex_value(r, &scf->cache_key, key) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_http_scgi_create_request(ngx_http_request_t *r)
+{
+    u_char                        ch, *key, *val, *lowcase_key;
+    size_t                        len, allocated;
+    ngx_buf_t                    *b;
+    ngx_str_t                    *content_length;
+    ngx_uint_t                    i, n, hash, header_params;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header, **ignored;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_scgi_loc_conf_t     *scf;
+    ngx_http_script_len_code_pt   lcode;
+    static ngx_str_t              zero = ngx_string("0");
+
+    content_length = r->headers_in.content_length ?
+                         &r->headers_in.content_length->value : &zero;
+
+    len = sizeof("CONTENT_LENGTH") + content_length->len + 1;
+
+    header_params = 0;
+    ignored = NULL;
+
+    scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
+
+    if (scf->params_len) {
+        ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
+
+        ngx_http_script_flush_no_cacheable_variables(r, scf->flushes);
+        le.flushed = 1;
+
+        le.ip = scf->params_len->elts;
+        le.request = r;
+
+        while (*(uintptr_t *) le.ip) {
+
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            len += lcode(&le);
+
+            while (*(uintptr_t *) le.ip) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+                len += lcode(&le) + 1;
+            }
+            le.ip += sizeof(uintptr_t);
+        }
+    }
+
+    if (scf->upstream.pass_request_headers) {
+
+        allocated = 0;
+        lowcase_key = NULL;
+
+        if (scf->header_params) {
+            ignored = ngx_palloc(r->pool, scf->header_params * sizeof(void *));
+            if (ignored == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
+
+            if (scf->header_params) {
+                if (allocated < header[i].key.len) {
+                    allocated = header[i].key.len + 16;
+                    lowcase_key = ngx_pnalloc(r->pool, allocated);
+                    if (lowcase_key == NULL) {
+                        return NGX_ERROR;
+                    }
+                }
+
+                hash = 0;
+
+                for (n = 0; n < header[i].key.len; n++) {
+                    ch = header[i].key.data[n];
+
+                    if (ch >= 'A' && ch <= 'Z') {
+                        ch |= 0x20;
+
+                    } else if (ch == '-') {
+                        ch = '_';
+                    }
+
+                    hash = ngx_hash(hash, ch);
+                    lowcase_key[n] = ch;
+                }
+
+                if (ngx_hash_find(&scf->headers_hash, hash, lowcase_key, n)) {
+                    ignored[header_params++] = &header[i];
+                    continue;
+                }
+            }
+
+            len += sizeof("HTTP_") - 1 + header[i].key.len + 1
+                + header[i].value.len + 1;
+        }
+    }
+
+    /* netstring: "length:" + packet + "," */
+
+    b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1);
+    if (b == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl = ngx_alloc_chain_link(r->pool);
+    if (cl == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl->buf = b;
+
+    b->last = ngx_snprintf(b->last,
+                           NGX_SIZE_T_LEN + 1 + sizeof("CONTENT_LENGTH")
+                           + NGX_OFF_T_LEN + 1,
+                           "%ui:CONTENT_LENGTH%Z%V%Z",
+                           len, content_length);
+
+    if (scf->params_len) {
+        ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+        e.ip = scf->params->elts;
+        e.pos = b->last;
+        e.request = r;
+        e.flushed = 1;
+
+        while (*(uintptr_t *) e.ip) {
+
+#if (NGX_DEBUG)
+            key = e.pos;
+#endif
+            code = *(ngx_http_script_code_pt *) e.ip;
+            code((ngx_http_script_engine_t *) & e);
+
+#if (NGX_DEBUG)
+            val = e.pos;
+#endif
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
+            }
+            *e.pos++ = '\0';
+            e.ip += sizeof(uintptr_t);
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "scgi param: \"%s: %s\"", key, val);
+        }
+
+        b->last = e.pos;
+    }
+
+    if (scf->upstream.pass_request_headers) {
+
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
+
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next;
+                }
+            }
+
+            key = b->last;
+            b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1);
+
+            for (n = 0; n < header[i].key.len; n++) {
+                ch = header[i].key.data[n];
+
+                if (ch >= 'a' && ch <= 'z') {
+                    ch &= ~0x20;
+
+                } else if (ch == '-') {
+                    ch = '_';
+                }
+
+                *b->last++ = ch;
+            }
+
+            *b->last++ = (u_char) 0;
+
+            val = b->last;
+            b->last = ngx_copy(val, header[i].value.data, header[i].value.len);
+            *b->last++ = (u_char) 0;
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "scgi param: \"%s: %s\"", key, val);
+
+        next:
+
+            continue;
+         }
+    }
+
+    *b->last++ = (u_char) ',';
+
+    if (scf->upstream.pass_request_body) {
+        body = r->upstream->request_bufs;
+        r->upstream->request_bufs = cl;
+
+        while (body) {
+            b = ngx_alloc_buf(r->pool);
+            if (b == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+            cl->next = ngx_alloc_chain_link(r->pool);
+            if (cl->next == NULL) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+            body = body->next;
+        }
+
+    } else {
+        r->upstream->request_bufs = cl;
+    }
+
+    cl->next = NULL;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_scgi_reinit_request(ngx_http_request_t *r)
+{
+    ngx_http_status_t  *status;
+
+    status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
+
+    if (status == NULL) {
+        return NGX_OK;
+    }
+
+    status->code = 0;
+    status->count = 0;
+    status->start = NULL;
+    status->end = NULL;
+
+    r->upstream->process_header = ngx_http_scgi_process_status_line;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_scgi_process_status_line(ngx_http_request_t *r)
+{
+    size_t                len;
+    ngx_int_t             rc;
+    ngx_http_status_t    *status;
+    ngx_http_upstream_t  *u;
+
+    status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
+
+    if (status == NULL) {
+        return NGX_ERROR;
+    }
+
+    u = r->upstream;
+
+    rc = ngx_http_parse_status_line(r, &u->buffer, status);
+
+    if (rc == NGX_AGAIN) {
+        return rc;
+    }
+
+    if (rc == NGX_ERROR) {
+
+        r->http_version = NGX_HTTP_VERSION_9;
+
+        u->process_header = ngx_http_scgi_process_header;
+
+        return ngx_http_scgi_process_header(r);
+    }
+
+    if (u->state) {
+        u->state->status = status->code;
+    }
+
+    u->headers_in.status_n = status->code;
+
+    len = status->end - status->start;
+    u->headers_in.status_line.len = len;
+
+    u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
+    if (u->headers_in.status_line.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(u->headers_in.status_line.data, status->start, len);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http scgi status %ui \"%V\"",
+                   u->headers_in.status_n, &u->headers_in.status_line);
+
+    u->process_header = ngx_http_scgi_process_header;
+
+    return ngx_http_scgi_process_header(r);
+}
+
+
+static ngx_int_t
+ngx_http_scgi_process_header(ngx_http_request_t *r)
+{
+    ngx_str_t                      *status_line;
+    ngx_int_t                       rc, status;
+    ngx_table_elt_t                *h;
+    ngx_http_upstream_t            *u;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+
+    for ( ;; ) {
+
+        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
+
+        if (rc == NGX_OK) {
+
+            /* a header line has been parsed successfully */
+
+            h = ngx_list_push(&r->upstream->headers_in.headers);
+            if (h == NULL) {
+                return NGX_ERROR;
+            }
+
+            h->hash = r->header_hash;
+
+            h->key.len = r->header_name_end - r->header_name_start;
+            h->value.len = r->header_end - r->header_start;
+
+            h->key.data = ngx_pnalloc(r->pool,
+                                      h->key.len + 1 + h->value.len + 1
+                                      + h->key.len);
+            if (h->key.data == NULL) {
+                return NGX_ERROR;
+            }
+
+            h->value.data = h->key.data + h->key.len + 1;
+            h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
+
+            ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
+            ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
+
+            if (h->key.len == r->lowcase_index) {
+                ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
+
+            } else {
+                ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
+            }
+
+            hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
+                               h->lowcase_key, h->key.len);
+
+            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
+                return NGX_ERROR;
+            }
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http scgi header: \"%V: %V\"", &h->key, &h->value);
+
+            continue;
+        }
+
+        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+
+            /* a whole header has been parsed successfully */
+
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http scgi header done");
+
+            if (r->http_version > NGX_HTTP_VERSION_9) {
+                return NGX_OK;
+            }
+
+            u = r->upstream;
+
+            if (u->headers_in.status) {
+                status_line = &u->headers_in.status->value;
+
+                status = ngx_atoi(status_line->data, 3);
+                if (status == NGX_ERROR) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "upstream sent invalid status \"%V\"",
+                                  status_line);
+                    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+                }
+
+                r->http_version = NGX_HTTP_VERSION_10;
+                u->headers_in.status_n = status;
+                u->headers_in.status_line = *status_line;
+
+            } else if (u->headers_in.location) {
+                r->http_version = NGX_HTTP_VERSION_10;
+                u->headers_in.status_n = 302;
+                ngx_str_set(&u->headers_in.status_line,
+                            "302 Moved Temporarily");
+
+            } else {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent neither valid HTTP/1.0 header "
+                              "nor \"Status\" header line");
+                u->headers_in.status_n = 200;
+                ngx_str_set(&u->headers_in.status_line, "200 OK");
+            }
+
+            if (u->state) {
+                u->state->status = u->headers_in.status_n;
+            }
+
+            return NGX_OK;
+        }
+
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        /* there was error while a header line parsing */
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent invalid header");
+
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+}
+
+
+static void
+ngx_http_scgi_abort_request(ngx_http_request_t *r)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "abort http scgi request");
+
+    return;
+}
+
+
+static void
+ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "finalize http scgi request");
+
+    return;
+}
+
+
+static void *
+ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_scgi_loc_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_loc_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    conf->upstream.store = NGX_CONF_UNSET;
+    conf->upstream.store_access = NGX_CONF_UNSET_UINT;
+    conf->upstream.buffering = NGX_CONF_UNSET;
+    conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+
+    conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
+
+    conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
+    conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
+    conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
+    conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+    conf->upstream.pass_request_body = NGX_CONF_UNSET;
+
+#if (NGX_HTTP_CACHE)
+    conf->upstream.cache = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
+    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+#endif
+
+    conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
+    conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
+
+    conf->upstream.intercept_errors = NGX_CONF_UNSET;
+
+    /* "scgi_cyclic_temp_file" is disabled */
+    conf->upstream.cyclic_temp_file = 0;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_scgi_loc_conf_t *prev = parent;
+    ngx_http_scgi_loc_conf_t *conf = child;
+
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i;
+    ngx_array_t                   headers_names;
+    ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
+    ngx_hash_init_t               hash;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
+
+    if (conf->upstream.store != 0) {
+        ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
+
+        if (conf->upstream.store_lengths == NULL) {
+            conf->upstream.store_lengths = prev->upstream.store_lengths;
+            conf->upstream.store_values = prev->upstream.store_values;
+        }
+    }
+
+    ngx_conf_merge_uint_value(conf->upstream.store_access,
+                              prev->upstream.store_access, 0600);
+
+    ngx_conf_merge_value(conf->upstream.buffering,
+                              prev->upstream.buffering, 1);
+
+    ngx_conf_merge_value(conf->upstream.ignore_client_abort,
+                              prev->upstream.ignore_client_abort, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
+                              prev->upstream.connect_timeout, 60000);
+
+    ngx_conf_merge_msec_value(conf->upstream.send_timeout,
+                              prev->upstream.send_timeout, 60000);
+
+    ngx_conf_merge_msec_value(conf->upstream.read_timeout,
+                              prev->upstream.read_timeout, 60000);
+
+    ngx_conf_merge_size_value(conf->upstream.send_lowat,
+                              prev->upstream.send_lowat, 0);
+
+    ngx_conf_merge_size_value(conf->upstream.buffer_size,
+                              prev->upstream.buffer_size,
+                              (size_t) ngx_pagesize);
+
+
+    ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
+                              8, ngx_pagesize);
+
+    if (conf->upstream.bufs.num < 2) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "there must be at least 2 \"scgi_buffers\"");
+        return NGX_CONF_ERROR;
+    }
+
+
+    size = conf->upstream.buffer_size;
+    if (size < conf->upstream.bufs.size) {
+        size = conf->upstream.bufs.size;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
+                              prev->upstream.busy_buffers_size_conf,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.busy_buffers_size = 2 * size;
+    } else {
+        conf->upstream.busy_buffers_size =
+            conf->upstream.busy_buffers_size_conf;
+    }
+
+    if (conf->upstream.busy_buffers_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"scgi_busy_buffers_size\" must be equal or bigger "
+            "than maximum of the value of \"scgi_buffer_size\" and "
+            "one of the \"scgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->upstream.busy_buffers_size
+        > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"scgi_busy_buffers_size\" must be less than "
+            "the size of all \"scgi_buffers\" minus one buffer");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
+                              prev->upstream.temp_file_write_size_conf,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.temp_file_write_size = 2 * size;
+    } else {
+        conf->upstream.temp_file_write_size =
+            conf->upstream.temp_file_write_size_conf;
+    }
+
+    if (conf->upstream.temp_file_write_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"scgi_temp_file_write_size\" must be equal or bigger than "
+            "maximum of the value of \"scgi_buffer_size\" and "
+            "one of the \"scgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
+                              prev->upstream.max_temp_file_size_conf,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
+    } else {
+        conf->upstream.max_temp_file_size =
+            conf->upstream.max_temp_file_size_conf;
+    }
+
+    if (conf->upstream.max_temp_file_size != 0
+        && conf->upstream.max_temp_file_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"scgi_max_temp_file_size\" must be equal to zero to disable "
+            "the temporary files usage or must be equal or bigger than "
+            "maximum of the value of \"scgi_buffer_size\" and "
+            "one of the \"scgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    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
+                                  |NGX_HTTP_UPSTREAM_FT_ERROR
+                                  |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
+
+    if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
+        conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
+                                       |NGX_HTTP_UPSTREAM_FT_OFF;
+    }
+
+    if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
+                                  prev->upstream.temp_path,
+                                  &ngx_http_scgi_temp_path)
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+#if (NGX_HTTP_CACHE)
+
+    ngx_conf_merge_ptr_value(conf->upstream.cache,
+                              prev->upstream.cache, NULL);
+
+    if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+        ngx_shm_zone_t  *shm_zone;
+
+        shm_zone = conf->upstream.cache;
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "\"scgi_cache\" zone \"%V\" is unknown",
+                           &shm_zone->shm.name);
+
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
+                              prev->upstream.cache_min_uses, 1);
+
+    ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
+                              prev->upstream.cache_use_stale,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_HTTP_UPSTREAM_FT_OFF));
+
+    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;
+    }
+
+    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_bypass,
+                             prev->upstream.cache_bypass, NULL);
+
+    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+                             prev->upstream.no_cache, NULL);
+
+    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,
+                         prev->upstream.pass_request_headers, 1);
+    ngx_conf_merge_value(conf->upstream.pass_request_body,
+                         prev->upstream.pass_request_body, 1);
+
+    ngx_conf_merge_value(conf->upstream.intercept_errors,
+                         prev->upstream.intercept_errors, 0);
+
+    hash.max_size = 512;
+    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
+    hash.name = "scgi_hide_headers_hash";
+
+    if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
+            &prev->upstream, ngx_http_scgi_hide_headers, &hash)
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->upstream.upstream == NULL) {
+        conf->upstream.upstream = prev->upstream.upstream;
+    }
+
+    if (conf->scgi_lengths == NULL) {
+        conf->scgi_lengths = prev->scgi_lengths;
+        conf->scgi_values = prev->scgi_values;
+    }
+
+    if (conf->upstream.upstream || conf->scgi_lengths) {
+        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+        if (clcf->handler == NULL && clcf->lmt_excpt) {
+            clcf->handler = ngx_http_scgi_handler;
+        }
+    }
+
+    if (conf->params_source == NULL) {
+        conf->flushes = prev->flushes;
+        conf->params_len = prev->params_len;
+        conf->params = prev->params;
+        conf->params_source = prev->params_source;
+        conf->headers_hash = prev->headers_hash;
+
+#if (NGX_HTTP_CACHE)
+
+        if (conf->params_source == NULL) {
+
+            if ((conf->upstream.cache == NULL)
+                == (prev->upstream.cache == NULL))
+            {
+                return NGX_CONF_OK;
+            }
+
+            /* 6 is a number of ngx_http_scgi_cache_headers entries */
+            conf->params_source = ngx_array_create(cf->pool, 6,
+                                                   sizeof(ngx_keyval_t));
+            if (conf->params_source == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+#else
+
+        if (conf->params_source == NULL) {
+            return NGX_CONF_OK;
+        }
+
+#endif
+    }
+
+    conf->params_len = ngx_array_create(cf->pool, 64, 1);
+    if (conf->params_len == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->params = ngx_array_create(cf->pool, 512, 1);
+    if (conf->params == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    src = conf->params_source->elts;
+
+#if (NGX_HTTP_CACHE)
+
+    if (conf->upstream.cache) {
+        ngx_keyval_t  *h, *s;
+
+        for (h = ngx_http_scgi_cache_headers; h->key.len; h++) {
+
+            for (i = 0; i < conf->params_source->nelts; i++) {
+                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+                    goto next;
+                }
+            }
+
+            s = ngx_array_push(conf->params_source);
+            if (s == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            *s = *h;
+
+            src = conf->params_source->elts;
+
+        next:
+
+            h++;
+        }
+    }
+
+#endif
+
+    for (i = 0; i < conf->params_source->nelts; i++) {
+
+        if (src[i].key.len > sizeof("HTTP_") - 1
+            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
+        {
+            hk = ngx_array_push(&headers_names);
+            if (hk == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            hk->key.len = src[i].key.len - 5;
+            hk->key.data = src[i].key.data + 5;
+            hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
+            hk->value = (void *) 1;
+
+            if (src[i].value.len == 0) {
+                continue;
+            }
+        }
+
+        copy = ngx_array_push_n(conf->params_len,
+                                sizeof(ngx_http_script_copy_code_t));
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+        copy->len = src[i].key.len + 1;
+
+
+        size = (sizeof(ngx_http_script_copy_code_t)
+                + src[i].key.len + 1 + sizeof(uintptr_t) - 1)
+               & ~(sizeof(uintptr_t) - 1);
+
+        copy = ngx_array_push_n(conf->params, size);
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = ngx_http_script_copy_code;
+        copy->len = src[i].key.len + 1;
+
+        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+        (void) ngx_cpystrn(p, src[i].key.data, src[i].key.len + 1);
+
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &src[i].value;
+        sc.flushes = &conf->flushes;
+        sc.lengths = &conf->params_len;
+        sc.values = &conf->params;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+
+
+        code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
+
+    code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+    code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+    conf->header_params = headers_names.nelts;
+
+    hash.hash = &conf->headers_hash;
+    hash.key = ngx_hash_key_lc;
+    hash.max_size = 512;
+    hash.bucket_size = 64;
+    hash.name = "scgi_params_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
+
+    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_scgi_loc_conf_t *scf = conf;
+
+    ngx_url_t                   u;
+    ngx_str_t                  *value, *url;
+    ngx_uint_t                  n;
+    ngx_http_core_loc_conf_t   *clcf;
+    ngx_http_script_compile_t   sc;
+
+    if (scf->upstream.upstream || scf->scgi_lengths) {
+        return "is duplicate";
+    }
+
+    clcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_core_module);
+    clcf->handler = ngx_http_scgi_handler;
+
+    value = cf->args->elts;
+
+    url = &value[1];
+
+    n = ngx_http_script_variables_count(url);
+
+    if (n) {
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = url;
+        sc.lengths = &scf->scgi_lengths;
+        sc.values = &scf->scgi_values;
+        sc.variables = n;
+        sc.complete_lengths = 1;
+        sc.complete_values = 1;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        return NGX_CONF_OK;
+    }
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.url = value[1];
+    u.no_resolve = 1;
+
+    scf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+    if (scf->upstream.upstream == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_scgi_loc_conf_t *scf = conf;
+
+    ngx_str_t                  *value;
+    ngx_http_script_compile_t   sc;
+
+    if (scf->upstream.store != NGX_CONF_UNSET || scf->upstream.store_lengths) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        scf->upstream.store = 0;
+        return NGX_CONF_OK;
+    }
+
+#if (NGX_HTTP_CACHE)
+
+    if (scf->upstream.cache != NGX_CONF_UNSET_PTR
+        && scf->upstream.cache != NULL)
+    {
+        return "is incompatible with \"scgi_cache\"";
+    }
+
+#endif
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        scf->upstream.store = 1;
+        return NGX_CONF_OK;
+    }
+
+    /* include the terminating '\0' into script */
+    value[1].len++;
+
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+    sc.cf = cf;
+    sc.source = &value[1];
+    sc.lengths = &scf->upstream.store_lengths;
+    sc.values = &scf->upstream.store_values;
+    sc.variables = ngx_http_script_variables_count(&value[1]);;
+    sc.complete_lengths = 1;
+    sc.complete_values = 1;
+
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static char *
+ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_scgi_loc_conf_t *scf = conf;
+
+    ngx_str_t  *value;
+
+    value = cf->args->elts;
+
+    if (scf->upstream.cache != NGX_CONF_UNSET_PTR) {
+        return "is duplicate";
+    }
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        scf->upstream.cache = NULL;
+        return NGX_CONF_OK;
+    }
+
+    if (scf->upstream.store > 0 || scf->upstream.store_lengths) {
+        return "is incompatible with \"scgi_store\"";
+    }
+
+    scf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
+                                                &ngx_http_scgi_module);
+    if (scf->upstream.cache == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_scgi_loc_conf_t *scf = conf;
+
+    ngx_str_t                         *value;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    if (scf->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 = &scf->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_secure_link_module.c
+++ b/src/http/modules/ngx_http_secure_link_module.c
@@ -11,10 +11,22 @@
 
 
 typedef struct {
-    ngx_str_t  secret;
+    ngx_http_complex_value_t  *variable;
+    ngx_http_complex_value_t  *md5;
+    ngx_str_t                  secret;
 } ngx_http_secure_link_conf_t;
 
 
+typedef struct {
+    ngx_str_t                  expires;
+} ngx_http_secure_link_ctx_t;
+
+
+static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r,
+    ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
+    uintptr_t data);
+static ngx_int_t ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static void *ngx_http_secure_link_create_conf(ngx_conf_t *cf);
 static char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent,
     void *child);
@@ -23,6 +35,20 @@ static ngx_int_t ngx_http_secure_link_ad
 
 static ngx_command_t  ngx_http_secure_link_commands[] = {
 
+    { ngx_string("secure_link"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_set_complex_value_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_secure_link_conf_t, variable),
+      NULL },
+
+    { ngx_string("secure_link_md5"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_set_complex_value_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_secure_link_conf_t, md5),
+      NULL },
+
     { ngx_string("secure_link_secret"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -65,27 +91,122 @@ ngx_module_t  ngx_http_secure_link_modul
 };
 
 
-static ngx_str_t  ngx_http_secure_link = ngx_string("secure_link");
+static ngx_str_t  ngx_http_secure_link_name = ngx_string("secure_link");
+static ngx_str_t  ngx_http_secure_link_expires_name =
+    ngx_string("secure_link_expires");
 
 
 static ngx_int_t
 ngx_http_secure_link_variable(ngx_http_request_t *r,
-     ngx_http_variable_value_t *v, uintptr_t data)
+    ngx_http_variable_value_t *v, uintptr_t data)
 {
-    u_char                        *p, *start, *end, *last;
-    size_t                         len;
-    ngx_int_t                      n;
-    ngx_uint_t                     i;
-    ngx_md5_t                      md5;
+    u_char                       *p, *last;
+    ngx_str_t                     val, hash;
+    time_t                        expires;
+    ngx_md5_t                     md5;
+    ngx_http_secure_link_ctx_t   *ctx;
     ngx_http_secure_link_conf_t  *conf;
-    u_char                         hash[16];
+    u_char                        hash_buf[16], md5_buf[16];
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
 
-    if (conf->secret.len == 0) {
+    if (conf->secret.len) {
+        return ngx_http_secure_link_old_variable(r, conf, v, data);
+    }
+
+    if (conf->variable == NULL || conf->md5 == NULL) {
+        goto not_found;
+    }
+
+    if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "secure link: \"%V\"", &val);
+
+    last = val.data + val.len;
+
+    p = ngx_strlchr(val.data, last, ',');
+    expires = 0;
+
+    if (p) {
+        val.len = p++ - val.data;
+
+        expires = ngx_atotm(p, last - p);
+        if (expires <= 0) {
+            goto not_found;
+        }
+
+        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
+        if (ctx == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);
+
+        ctx->expires.len = last - p;
+        ctx->expires.data = p;
+    }
+
+    if (val.len > 24) {
         goto not_found;
     }
 
+    hash.len = 16;
+    hash.data = hash_buf;
+
+    if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
+        goto not_found;
+    }
+
+    if (hash.len != 16) {
+        goto not_found;
+    }
+
+    if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "secure link md5: \"%V\"", &val);
+
+    ngx_md5_init(&md5);
+    ngx_md5_update(&md5, val.data, val.len);
+    ngx_md5_final(md5_buf, &md5);
+
+    if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
+        goto not_found;
+    }
+
+    v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1");
+    v->len = 1;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    return NGX_OK;
+
+not_found:
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_secure_link_old_variable(ngx_http_request_t *r,
+    ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
+    uintptr_t data)
+{
+    u_char      *p, *start, *end, *last;
+    size_t       len;
+    ngx_int_t    n;
+    ngx_uint_t   i;
+    ngx_md5_t    md5;
+    u_char       hash[16];
+
     p = &r->unparsed_uri.data[1];
     last = r->unparsed_uri.data + r->unparsed_uri.len;
 
@@ -145,6 +266,29 @@ not_found:
 }
 
 
+static ngx_int_t
+ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_http_secure_link_ctx_t  *ctx;
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module);
+
+    if (ctx) {
+        v->len = ctx->expires.len;
+        v->valid = 1;
+        v->no_cacheable = 0;
+        v->not_found = 0;
+        v->data = ctx->expires.data;
+
+    } else {
+        v->not_found = 1;
+    }
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_http_secure_link_create_conf(ngx_conf_t *cf)
 {
@@ -158,7 +302,9 @@ ngx_http_secure_link_create_conf(ngx_con
     /*
      * set by ngx_pcalloc():
      *
-     *     conf->secret = { 0, NULL }
+     *     conf->variable = NULL;
+     *     conf->md5 = NULL;
+     *     conf->secret = { 0, NULL };
      */
 
     return conf;
@@ -173,6 +319,14 @@ ngx_http_secure_link_merge_conf(ngx_conf
 
     ngx_conf_merge_str_value(conf->secret, prev->secret, "");
 
+    if (conf->variable == NULL) {
+        conf->variable = prev->variable;
+    }
+
+    if (conf->md5 == NULL) {
+        conf->md5 = prev->md5;
+    }
+
     return NGX_CONF_OK;
 }
 
@@ -182,12 +336,19 @@ ngx_http_secure_link_add_variables(ngx_c
 {
     ngx_http_variable_t  *var;
 
-    var = ngx_http_add_variable(cf, &ngx_http_secure_link, NGX_HTTP_VAR_NOHASH);
+    var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0);
     if (var == NULL) {
         return NGX_ERROR;
     }
 
     var->get_handler = ngx_http_secure_link_variable;
 
+    var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0);
+    if (var == NULL) {
+        return NGX_ERROR;
+    }
+
+    var->get_handler = ngx_http_secure_link_expires_variable;
+
     return NGX_OK;
 }
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_split_clients_module.c
@@ -0,0 +1,241 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    uint32_t                    percent;
+    ngx_http_variable_value_t   value;
+} ngx_http_split_clients_part_t;
+
+
+typedef struct {
+    ngx_http_complex_value_t    value;
+    ngx_array_t                 parts;
+} ngx_http_split_clients_ctx_t;
+
+
+static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_split_clients(ngx_conf_t *cf, ngx_command_t *dummy,
+    void *conf);
+
+static ngx_command_t  ngx_http_split_clients_commands[] = {
+
+    { ngx_string("split_clients"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
+      ngx_conf_split_clients_block,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_split_clients_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    NULL,                                  /* 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_split_clients_module = {
+    NGX_MODULE_V1,
+    &ngx_http_split_clients_module_ctx,    /* module context */
+    ngx_http_split_clients_commands,       /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_split_clients_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_http_split_clients_ctx_t *ctx = (ngx_http_split_clients_ctx_t *) data;
+
+    uint32_t                        hash;
+    ngx_str_t                       val;
+    ngx_uint_t                      i;
+    ngx_http_split_clients_part_t  *part;
+
+    *v = ngx_http_variable_null_value;
+
+    if (ngx_http_complex_value(r, &ctx->value, &val) != NGX_OK) {
+        return NGX_OK;
+    }
+
+    hash = ngx_crc32_short(val.data, val.len);
+
+    part = ctx->parts.elts;
+
+    for (i = 0; i < ctx->parts.nelts; i++) {
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "%D %D", hash, part[i].percent);
+
+        if (hash < part[i].percent) {
+            *v = part[i].value;
+            return NGX_OK;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+static char *
+ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char                                *rv;
+    ngx_str_t                           *value, name;
+    ngx_uint_t                           i, sum, last;
+    ngx_conf_t                           save;
+    ngx_http_variable_t                 *var;
+    ngx_http_split_clients_ctx_t        *ctx;
+    ngx_http_split_clients_part_t       *part;
+    ngx_http_compile_complex_value_t     ccv;
+
+    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_split_clients_ctx_t));
+    if (ctx == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = &ctx->value;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    name = value[2];
+    name.len--;
+    name.data++;
+
+    var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
+    if (var == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    var->get_handler = ngx_http_split_clients_variable;
+    var->data = (uintptr_t) ctx;
+
+    if (ngx_array_init(&ctx->parts, cf->pool, 2,
+                       sizeof(ngx_http_split_clients_part_t))
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    save = *cf;
+    cf->ctx = ctx;
+    cf->handler = ngx_http_split_clients;
+    cf->handler_conf = conf;
+
+    rv = ngx_conf_parse(cf, NULL);
+
+    *cf = save;
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    sum = 0;
+    last = 0;
+    part = ctx->parts.elts;
+
+    for (i = 0; i < ctx->parts.nelts; i++) {
+        sum = part[i].percent ? sum + part[i].percent : 10000;
+        if (sum > 10000) {
+           ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                              "percent sum is more than 100%%");
+           return NGX_CONF_ERROR;
+        }
+
+        if (part[i].percent) {
+            part[i].percent = (uint32_t)
+                                 (last + 0xffffffff / 10000 * part[i].percent);
+        } else {
+            part[i].percent = 0xffffffff;
+        }
+
+        last = part[i].percent;
+    }
+
+    return rv;
+}
+
+
+static char *
+ngx_http_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
+{
+    ngx_int_t                       n;
+    ngx_str_t                      *value;
+    ngx_http_split_clients_ctx_t   *ctx;
+    ngx_http_split_clients_part_t  *part;
+
+    ctx = cf->ctx;
+    value = cf->args->elts;
+
+    part = ngx_array_push(&ctx->parts);
+    if (part == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (value[0].len == 1 && value[0].data[0] == '*') {
+        part->percent = 0;
+
+    } else {
+        if (value[0].data[value[0].len - 1] != '%') {
+            goto invalid;
+        }
+
+        n = ngx_atofp(value[0].data, value[0].len - 1, 2);
+        if (n == NGX_ERROR || n == 0) {
+            goto invalid;
+        }
+
+        part->percent = (uint32_t) n;
+    }
+
+    part->value.len = value[1].len;
+    part->value.valid = 1;
+    part->value.no_cacheable = 0;
+    part->value.not_found = 0;
+    part->value.data = value[1].data;
+
+    return NGX_CONF_OK;
+
+invalid:
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "invalid percent value \"%V\"", &value[0]);
+    return NGX_CONF_ERROR;
+}
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -14,7 +14,6 @@
 
 #define NGX_HTTP_SSI_ADD_PREFIX     1
 #define NGX_HTTP_SSI_ADD_ZERO       2
-#define NGX_HTTP_SSI_EXPR_TEST      4
 
 
 typedef struct {
@@ -71,6 +70,8 @@ typedef enum {
 
 static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx);
+static void ngx_http_ssi_buffered(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx);
 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx);
 static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r,
@@ -347,13 +348,9 @@ ngx_http_ssi_header_filter(ngx_http_requ
     ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N;
     ctx->params.pool = r->pool;
 
-    ctx->timefmt.len = sizeof("%A, %d-%b-%Y %H:%M:%S %Z") - 1;
-    ctx->timefmt.data = (u_char *) "%A, %d-%b-%Y %H:%M:%S %Z";
-
-    ctx->errmsg.len =
-              sizeof("[an error occurred while processing the directive]") - 1;
-    ctx->errmsg.data = (u_char *)
-                     "[an error occurred while processing the directive]";
+    ngx_str_set(&ctx->timefmt, "%A, %d-%b-%Y %H:%M:%S %Z");
+    ngx_str_set(&ctx->errmsg,
+                "[an error occurred while processing the directive]");
 
     r->filter_need_in_memory = 1;
 
@@ -436,7 +433,7 @@ ngx_http_ssi_body_filter(ngx_http_reques
 
     while (ctx->in || ctx->buf) {
 
-        if (ctx->buf == NULL ){
+        if (ctx->buf == NULL) {
             ctx->buf = ctx->in->buf;
             ctx->in = ctx->in->next;
             ctx->pos = ctx->buf->pos;
@@ -798,6 +795,7 @@ ngx_http_ssi_body_filter(ngx_http_reques
                 }
 
                 if (rc == NGX_DONE || rc == NGX_AGAIN || rc == NGX_ERROR) {
+                    ngx_http_ssi_buffered(r, ctx);
                     return rc;
                 }
             }
@@ -950,14 +948,21 @@ ngx_http_ssi_output(ngx_http_request_t *
         }
     }
 
+    ngx_http_ssi_buffered(r, ctx);
+
+    return rc;
+}
+
+
+static void
+ngx_http_ssi_buffered(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
+{
     if (ctx->in || ctx->buf) {
         r->buffered |= NGX_HTTP_SSI_BUFFERED;
 
     } else {
         r->buffered &= ~NGX_HTTP_SSI_BUFFERED;
     }
-
-    return rc;
 }
 
 
@@ -1701,8 +1706,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re
             val = ngx_http_ssi_get_variable(r, &var, key);
 
             if (val == NULL) {
-                vv = ngx_http_get_variable(r, &var, key,
-                                           flags & NGX_HTTP_SSI_EXPR_TEST);
+                vv = ngx_http_get_variable(r, &var, key);
                 if (vv == NULL) {
                     return NGX_ERROR;
                 }
@@ -1898,7 +1902,7 @@ ngx_http_ssi_include(ngx_http_request_t 
 
     len = (uri->data + uri->len) - src;
     if (len) {
-        dst = ngx_copy(dst, src, len);
+        dst = ngx_movemem(dst, src, len);
     }
 
     uri->len = dst - uri->data;
@@ -1906,9 +1910,8 @@ ngx_http_ssi_include(ngx_http_request_t 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "ssi include: \"%V\"", uri);
 
-    args.len = 0;
-    args.data = NULL;
-    flags = 0;
+    ngx_str_null(&args);
+    flags = NGX_HTTP_LOG_UNSAFE;
 
     if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
         return NGX_HTTP_SSI_ERROR;
@@ -2061,9 +2064,9 @@ ngx_http_ssi_stub_output(ngx_http_reques
     out = data;
 
     if (!r->header_sent) {
-        if (ngx_http_set_content_type(r) != NGX_OK) {
-            return NGX_ERROR;
-        }
+        r->headers_out.content_type_len =
+                                      r->parent->headers_out.content_type_len;
+        r->headers_out.content_type = r->parent->headers_out.content_type;
 
         if (ngx_http_send_header(r) == NGX_ERROR) {
             return NGX_ERROR;
@@ -2110,7 +2113,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
     value = ngx_http_ssi_get_variable(r, var, key);
 
     if (value == NULL) {
-        vv = ngx_http_get_variable(r, var, key, 1);
+        vv = ngx_http_get_variable(r, var, key);
 
         if (vv == NULL) {
             return NGX_HTTP_SSI_ERROR;
@@ -2161,11 +2164,10 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
         }
     }
 
+    p = value->data;
+
     switch (ctx->encoding) {
 
-    case NGX_HTTP_SSI_NO_ENCODING:
-        break;
-
     case NGX_HTTP_SSI_URL_ENCODING:
         len = 2 * ngx_escape_uri(NULL, value->data, value->len,
                                  NGX_ESCAPE_HTML);
@@ -2177,11 +2179,9 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
             }
 
             (void) ngx_escape_uri(p, value->data, value->len, NGX_ESCAPE_HTML);
-
-            value->len += len;
-            value->data = p;
         }
 
+        len += value->len;
         break;
 
     case NGX_HTTP_SSI_ENTITY_ENCODING:
@@ -2194,11 +2194,13 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
             }
 
             (void) ngx_escape_html(p, value->data, value->len);
-
-            value->len += len;
-            value->data = p;
         }
 
+        len += value->len;
+        break;
+
+    default: /* NGX_HTTP_SSI_NO_ENCODING */
+        len = value->len;
         break;
     }
 
@@ -2213,8 +2215,8 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
     }
 
     b->memory = 1;
-    b->pos = value->data;
-    b->last = value->data + value->len;
+    b->pos = p;
+    b->last = p + len;
 
     cl->buf = b;
     cl->next = NULL;
@@ -2362,7 +2364,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
         p++;
     }
 
-    flags = (p == last) ? NGX_HTTP_SSI_EXPR_TEST : 0;
+    flags = 0;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "left: \"%V\"", &left);
@@ -2450,27 +2452,28 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
 
     } else {
 #if (NGX_PCRE)
-        ngx_str_t     err;
-        ngx_regex_t  *regex;
-        u_char        errstr[NGX_MAX_CONF_ERRSTR];
-
-        err.len = NGX_MAX_CONF_ERRSTR;
-        err.data = errstr;
+        ngx_regex_compile_t  rgc;
+        u_char               errstr[NGX_MAX_CONF_ERRSTR];
 
         right.data[right.len] = '\0';
 
-        regex = ngx_regex_compile(&right, 0, r->pool, &err);
-
-        if (regex == NULL) {
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", err.data);
+        ngx_memzero(&rgc, sizeof(ngx_regex_compile_t));
+
+        rgc.pattern = right;
+        rgc.pool = r->pool;
+        rgc.err.len = NGX_MAX_CONF_ERRSTR;
+        rgc.err.data = errstr;
+
+        if (ngx_regex_compile(&rgc) != NGX_OK) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err);
             return NGX_HTTP_SSI_ERROR;
         }
 
-        rc = ngx_regex_exec(regex, &left, NULL, 0);
-
-        if (rc != NGX_REGEX_NO_MATCHED && rc < 0) {
+        rc = ngx_regex_exec(rgc.regex, &left, NULL, 0);
+
+        if (rc < NGX_REGEX_NO_MATCHED) {
             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                          ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
+                          ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
                           rc, &left, &right);
             return NGX_HTTP_SSI_ERROR;
         }
@@ -2614,8 +2617,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx
             return NGX_ERROR;
         }
 
-        v->len = ngx_sprintf(v->data, "%T", tp->sec + (gmt ? 0 : tp->gmtoff))
-                 - v->data;
+        v->len = ngx_sprintf(v->data, "%T", tp->sec) - v->data;
 
         return NGX_OK;
     }
@@ -2772,8 +2774,8 @@ ngx_http_ssi_merge_loc_conf(ngx_conf_t *
     ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024);
     ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256);
 
-    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
-                             prev->types_keys, &prev->types,
+    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
+                             &prev->types_keys, &prev->types,
                              ngx_http_html_default_types)
         != NGX_OK)
     {
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -13,7 +13,7 @@ typedef ngx_int_t (*ngx_ssl_variable_han
     ngx_pool_t *pool, ngx_str_t *s);
 
 
-#define NGX_DEFAULT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
+#define NGX_DEFAULT_CIPHERS  "HIGH:!ADH:!MD5"
 
 
 static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r,
@@ -184,6 +184,9 @@ static ngx_http_variable_t  ngx_http_ssl
     { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable,
       (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
@@ -311,8 +314,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
      *     sscf->dhparam = { 0, NULL };
      *     sscf->client_certificate = { 0, NULL };
      *     sscf->crl = { 0, NULL };
-     *     sscf->ciphers.len = 0;
-     *     sscf->ciphers.data = NULL;
+     *     sscf->ciphers = { 0, NULL };
      *     sscf->shm_zone = NULL;
      */
 
@@ -344,8 +346,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
                          prev->prefer_server_ciphers, 0);
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
-                         (NGX_CONF_BITMASK_SET
-                          |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
+                         (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
 
     ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
     ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
@@ -407,7 +408,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         == 0)
     {
         ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-            "nginx was build with SNI support, however, now it is linked "
+            "nginx was built with SNI support, however, now it is linked "
             "dynamically to an OpenSSL library which has no tlsext support, "
             "therefore SNI is not available");
     }
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -66,10 +66,6 @@ ngx_http_static_handler(ngx_http_request
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     log = r->connection->log;
 
     /*
@@ -91,6 +87,7 @@ ngx_http_static_handler(ngx_http_request
 
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
+    of.read_ahead = clcf->read_ahead;
     of.directio = clcf->directio;
     of.valid = clcf->open_file_cache_valid;
     of.min_uses = clcf->open_file_cache_min_uses;
@@ -188,7 +185,7 @@ ngx_http_static_handler(ngx_http_request
 #if !(NGX_WIN32) /* the not regular files are probably Unix specific */
 
     if (!of.is_file) {
-        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+        ngx_log_error(NGX_LOG_CRIT, log, 0,
                       "\"%s\" is not a regular file", path.data);
 
         return NGX_HTTP_NOT_FOUND;
--- a/src/http/modules/ngx_http_stub_status_module.c
+++ b/src/http/modules/ngx_http_stub_status_module.c
@@ -75,8 +75,7 @@ static ngx_int_t ngx_http_status_handler
         return rc;
     }
 
-    r->headers_out.content_type.len = sizeof("text/plain") - 1;
-    r->headers_out.content_type.data = (u_char *) "text/plain";
+    ngx_str_set(&r->headers_out.content_type, "text/plain");
 
     if (r->method == NGX_HTTP_HEAD) {
         r->headers_out.status = NGX_HTTP_OK;
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -29,6 +29,8 @@ typedef enum {
 
 typedef struct {
     ngx_str_t                  match;
+    ngx_str_t                  saved;
+    ngx_str_t                  looked;
 
     ngx_uint_t                 once;   /* unsigned  once:1 */
 
@@ -47,8 +49,6 @@ typedef struct {
     ngx_str_t                  sub;
 
     ngx_uint_t                 state;
-    size_t                     saved;
-    size_t                     looked;
 } ngx_http_sub_ctx_t;
 
 
@@ -147,6 +147,16 @@ ngx_http_sub_header_filter(ngx_http_requ
         return NGX_ERROR;
     }
 
+    ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len);
+    if (ctx->saved.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len);
+    if (ctx->looked.data == NULL) {
+        return NGX_ERROR;
+    }
+
     ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
 
     ctx->match = slcf->match;
@@ -210,7 +220,7 @@ ngx_http_sub_body_filter(ngx_http_reques
 
     while (ctx->in || ctx->buf) {
 
-        if (ctx->buf == NULL ){
+        if (ctx->buf == NULL) {
             ctx->buf = ctx->in->buf;
             ctx->in = ctx->in->next;
             ctx->pos = ctx->buf->pos;
@@ -226,13 +236,13 @@ ngx_http_sub_body_filter(ngx_http_reques
         while (ctx->pos < ctx->buf->last) {
 
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "saved: %d state: %d", ctx->saved, ctx->state);
+                           "saved: \"%V\" state: %d", &ctx->saved, ctx->state);
 
             rc = ngx_http_sub_parse(r, ctx);
 
             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "parse: %d, looked: %d %p-%p",
-                           rc, ctx->looked, ctx->copy_start, ctx->copy_end);
+                           "parse: %d, looked: \"%V\" %p-%p",
+                           rc, &ctx->looked, ctx->copy_start, ctx->copy_end);
 
             if (rc == NGX_ERROR) {
                 return rc;
@@ -241,9 +251,9 @@ ngx_http_sub_body_filter(ngx_http_reques
             if (ctx->copy_start != ctx->copy_end) {
 
                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                               "saved: %d", ctx->saved);
+                               "saved: \"%V\"", &ctx->saved);
 
-                if (ctx->saved) {
+                if (ctx->saved.len) {
 
                     if (ctx->free) {
                         cl = ctx->free;
@@ -265,14 +275,19 @@ ngx_http_sub_body_filter(ngx_http_reques
                         cl->buf = b;
                     }
 
+                    b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
+                    if (b->pos == NULL) {
+                        return NGX_ERROR;
+                    }
+
+                    ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
+                    b->last = b->pos + ctx->saved.len;
                     b->memory = 1;
-                    b->pos = ctx->match.data;
-                    b->last = ctx->match.data + ctx->saved;
 
                     *ctx->last_out = cl;
                     ctx->last_out = &cl->next;
 
-                    ctx->saved = 0;
+                    ctx->saved.len = 0;
                 }
 
                 if (ctx->free) {
@@ -405,7 +420,8 @@ ngx_http_sub_body_filter(ngx_http_reques
 
         ctx->buf = NULL;
 
-        ctx->saved = ctx->looked;
+        ctx->saved.len = ctx->looked.len;
+        ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len);
     }
 
     if (ctx->out == NULL && ctx->busy == NULL) {
@@ -496,7 +512,7 @@ ngx_http_sub_parse(ngx_http_request_t *r
         ctx->copy_start = ctx->pos;
         ctx->copy_end = ctx->buf->last;
         ctx->pos = ctx->buf->last;
-        ctx->looked = 0;
+        ctx->looked.len = 0;
 
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once");
 
@@ -504,7 +520,7 @@ ngx_http_sub_parse(ngx_http_request_t *r
     }
 
     state = ctx->state;
-    looked = ctx->looked;
+    looked = ctx->looked.len;
     last = ctx->buf->last;
     copy_end = ctx->copy_end;
 
@@ -522,6 +538,7 @@ ngx_http_sub_parse(ngx_http_request_t *r
             for ( ;; ) {
                 if (ch == match) {
                     copy_end = p;
+                    ctx->looked.data[0] = *p;
                     looked = 1;
                     state = sub_match_state;
 
@@ -538,7 +555,7 @@ ngx_http_sub_parse(ngx_http_request_t *r
 
             ctx->state = state;
             ctx->pos = p;
-            ctx->looked = looked;
+            ctx->looked.len = looked;
             ctx->copy_end = p;
 
             if (ctx->copy_start == NULL) {
@@ -555,16 +572,17 @@ ngx_http_sub_parse(ngx_http_request_t *r
         /* state == sub_match_state */
 
         if (ch == ctx->match.data[looked]) {
+            ctx->looked.data[looked] = *p;
             looked++;
 
             if (looked == ctx->match.len) {
                 if ((size_t) (p - ctx->pos) < looked) {
-                    ctx->saved = 0;
+                    ctx->saved.len = 0;
                 }
 
                 ctx->state = sub_start_state;
                 ctx->pos = p + 1;
-                ctx->looked = 0;
+                ctx->looked.len = 0;
                 ctx->copy_end = copy_end;
 
                 if (ctx->copy_start == NULL && copy_end) {
@@ -576,6 +594,7 @@ ngx_http_sub_parse(ngx_http_request_t *r
 
         } else if (ch == ctx->match.data[0]) {
             copy_end = p;
+            ctx->looked.data[0] = *p;
             looked = 1;
 
         } else {
@@ -587,7 +606,7 @@ ngx_http_sub_parse(ngx_http_request_t *r
 
     ctx->state = state;
     ctx->pos = p;
-    ctx->looked = looked;
+    ctx->looked.len = looked;
 
     ctx->copy_end = (state == sub_start_state) ? p : copy_end;
 
@@ -671,8 +690,8 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, 
         conf->value = prev->value;
     }
 
-    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
-                             prev->types_keys, &prev->types,
+    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
+                             &prev->types_keys, &prev->types,
                              ngx_http_html_default_types)
         != NGX_OK)
     {
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -47,6 +47,8 @@ static ngx_int_t ngx_http_userid_variabl
     ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid);
 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,
     ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
+static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r,
+    ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
 
 static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf);
 static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf);
@@ -199,7 +201,7 @@ ngx_http_userid_filter(ngx_http_request_
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
 
-    if (conf->enable <= NGX_HTTP_USERID_LOG) {
+    if (conf->enable < NGX_HTTP_USERID_V1) {
         return ngx_http_next_header_filter(r);
     }
 
@@ -209,23 +211,6 @@ ngx_http_userid_filter(ngx_http_request_
         return NGX_ERROR;
     }
 
-    if (ctx->uid_got[3] != 0) {
-
-        if (conf->mark == '\0') {
-            return ngx_http_next_header_filter(r);
-
-        } else {
-            if (ctx->cookie.len > 23
-                && ctx->cookie.data[22] == conf->mark
-                && ctx->cookie.data[23] == '=')
-            {
-                return ngx_http_next_header_filter(r);
-            }
-        }
-    }
-
-    /* ctx->status == NGX_DECLINED */
-
     if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) {
         return ngx_http_next_header_filter(r);
     }
@@ -248,18 +233,16 @@ ngx_http_userid_got_variable(ngx_http_re
         return NGX_OK;
     }
 
-    ctx = ngx_http_userid_get_uid(r, conf);
+    ctx = ngx_http_userid_get_uid(r->main, conf);
 
     if (ctx == NULL) {
         return NGX_ERROR;
     }
 
     if (ctx->uid_got[3] != 0) {
-        return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_got);
+        return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_got);
     }
 
-    /* ctx->status == NGX_DECLINED */
-
     v->not_found = 1;
 
     return NGX_OK;
@@ -273,16 +256,29 @@ ngx_http_userid_set_variable(ngx_http_re
     ngx_http_userid_ctx_t   *ctx;
     ngx_http_userid_conf_t  *conf;
 
-    ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
+    conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
 
-    if (ctx == NULL || ctx->uid_set[3] == 0) {
+    if (conf->enable < NGX_HTTP_USERID_V1) {
         v->not_found = 1;
         return NGX_OK;
     }
 
-    conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
+    ctx = ngx_http_userid_get_uid(r->main, conf);
+
+    if (ctx == NULL) {
+        return NGX_ERROR;
+    }
 
-    return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_set);
+    if (ngx_http_userid_create_uid(r->main, ctx, conf) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    if (ctx->uid_set[3] == 0) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_set);
 }
 
 
@@ -360,82 +356,17 @@ static ngx_int_t
 ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
     ngx_http_userid_conf_t *conf)
 {
-    u_char               *cookie, *p;
-    size_t                len;
-    ngx_str_t             src, dst;
-    ngx_table_elt_t      *set_cookie, *p3p;
-    ngx_connection_t     *c;
-    struct sockaddr_in   *sin;
-#if (NGX_HAVE_INET6)
-    struct sockaddr_in6  *sin6;
-#endif
-
-    /*
-     * TODO: in the threaded mode the sequencers should be in TLS and their
-     * ranges should be divided between threads
-     */
-
-    if (ctx->uid_got[3] == 0) {
-
-        if (conf->enable == NGX_HTTP_USERID_V1) {
-            if (conf->service == NGX_CONF_UNSET) {
-                ctx->uid_set[0] = 0;
-            } else {
-                ctx->uid_set[0] = conf->service;
-            }
-            ctx->uid_set[1] = (uint32_t) ngx_time();
-            ctx->uid_set[2] = start_value;
-            ctx->uid_set[3] = sequencer_v1;
-            sequencer_v1 += 0x100;
-
-        } else {
-            if (conf->service == NGX_CONF_UNSET) {
-
-                c = r->connection;
-
-                if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
-                    return NGX_ERROR;
-                }
+    u_char           *cookie, *p;
+    size_t            len;
+    ngx_str_t         src, dst;
+    ngx_table_elt_t  *set_cookie, *p3p;
 
-                switch (c->local_sockaddr->sa_family) {
-
-#if (NGX_HAVE_INET6)
-                case AF_INET6:
-                    sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
-
-                    p = (u_char *) &ctx->uid_set[0];
-
-                    *p++ = sin6->sin6_addr.s6_addr[12];
-                    *p++ = sin6->sin6_addr.s6_addr[13];
-                    *p++ = sin6->sin6_addr.s6_addr[14];
-                    *p = sin6->sin6_addr.s6_addr[15];
+    if (ngx_http_userid_create_uid(r, ctx, conf) != NGX_OK) {
+        return NGX_ERROR;
+    }
 
-                    break;
-#endif
-                default: /* AF_INET */
-                    sin = (struct sockaddr_in *) c->local_sockaddr;
-                    ctx->uid_set[0] = sin->sin_addr.s_addr;
-                    break;
-                }
-
-            } else {
-                ctx->uid_set[0] = htonl(conf->service);
-            }
-
-            ctx->uid_set[1] = htonl((uint32_t) ngx_time());
-            ctx->uid_set[2] = htonl(start_value);
-            ctx->uid_set[3] = htonl(sequencer_v2);
-            sequencer_v2 += 0x100;
-            if (sequencer_v2 < 0x03030302) {
-                sequencer_v2 = 0x03030302;
-            }
-        }
-
-    } else {
-        ctx->uid_set[0] = ctx->uid_got[0];
-        ctx->uid_set[1] = ctx->uid_got[1];
-        ctx->uid_set[2] = ctx->uid_got[2];
-        ctx->uid_set[3] = ctx->uid_got[3];
+    if (ctx->uid_set[3] == 0) {
+        return NGX_OK;
     }
 
     len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
@@ -493,8 +424,7 @@ ngx_http_userid_set_uid(ngx_http_request
     }
 
     set_cookie->hash = 1;
-    set_cookie->key.len = sizeof("Set-Cookie") - 1;
-    set_cookie->key.data = (u_char *) "Set-Cookie";
+    ngx_str_set(&set_cookie->key, "Set-Cookie");
     set_cookie->value.len = p - cookie;
     set_cookie->value.data = cookie;
 
@@ -511,8 +441,7 @@ ngx_http_userid_set_uid(ngx_http_request
     }
 
     p3p->hash = 1;
-    p3p->key.len = sizeof("P3P") - 1;
-    p3p->key.data = (u_char *) "P3P";
+    ngx_str_set(&p3p->key, "P3P");
     p3p->value = conf->p3p;
 
     return NGX_OK;
@@ -520,6 +449,102 @@ ngx_http_userid_set_uid(ngx_http_request
 
 
 static ngx_int_t
+ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
+    ngx_http_userid_conf_t *conf)
+{
+    ngx_connection_t     *c;
+    struct sockaddr_in   *sin;
+#if (NGX_HAVE_INET6)
+    u_char               *p;
+    struct sockaddr_in6  *sin6;
+#endif
+
+    if (ctx->uid_set[3] != 0) {
+        return NGX_OK;
+    }
+
+    if (ctx->uid_got[3] != 0) {
+
+        if (conf->mark == '\0'
+            || (ctx->cookie.len > 23
+                && ctx->cookie.data[22] == conf->mark
+                && ctx->cookie.data[23] == '='))
+        {
+            return NGX_OK;
+        }
+
+        ctx->uid_set[0] = ctx->uid_got[0];
+        ctx->uid_set[1] = ctx->uid_got[1];
+        ctx->uid_set[2] = ctx->uid_got[2];
+        ctx->uid_set[3] = ctx->uid_got[3];
+
+        return NGX_OK;
+    }
+
+    /*
+     * TODO: in the threaded mode the sequencers should be in TLS and their
+     * ranges should be divided between threads
+     */
+
+    if (conf->enable == NGX_HTTP_USERID_V1) {
+        if (conf->service == NGX_CONF_UNSET) {
+            ctx->uid_set[0] = 0;
+        } else {
+            ctx->uid_set[0] = conf->service;
+        }
+        ctx->uid_set[1] = (uint32_t) ngx_time();
+        ctx->uid_set[2] = start_value;
+        ctx->uid_set[3] = sequencer_v1;
+        sequencer_v1 += 0x100;
+
+    } else {
+        if (conf->service == NGX_CONF_UNSET) {
+
+            c = r->connection;
+
+            if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
+                return NGX_ERROR;
+            }
+
+            switch (c->local_sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+            case AF_INET6:
+                sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
+
+                p = (u_char *) &ctx->uid_set[0];
+
+                *p++ = sin6->sin6_addr.s6_addr[12];
+                *p++ = sin6->sin6_addr.s6_addr[13];
+                *p++ = sin6->sin6_addr.s6_addr[14];
+                *p = sin6->sin6_addr.s6_addr[15];
+
+                break;
+#endif
+            default: /* AF_INET */
+                sin = (struct sockaddr_in *) c->local_sockaddr;
+                ctx->uid_set[0] = sin->sin_addr.s_addr;
+                break;
+            }
+
+        } else {
+            ctx->uid_set[0] = htonl(conf->service);
+        }
+
+        ctx->uid_set[1] = htonl((uint32_t) ngx_time());
+        ctx->uid_set[2] = htonl(start_value);
+        ctx->uid_set[3] = htonl(sequencer_v2);
+        sequencer_v2 += 0x100;
+        if (sequencer_v2 < 0x03030302) {
+            sequencer_v2 = 0x03030302;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     ngx_str_t *name, uint32_t *uid)
 {
@@ -545,14 +570,14 @@ ngx_http_userid_add_variables(ngx_conf_t
 {
     ngx_http_variable_t  *var;
 
-    var = ngx_http_add_variable(cf, &ngx_http_userid_got, NGX_HTTP_VAR_NOHASH);
+    var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
     if (var == NULL) {
         return NGX_ERROR;
     }
 
     var->get_handler = ngx_http_userid_got_variable;
 
-    var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH);
+    var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
     if (var == NULL) {
         return NGX_ERROR;
     }
@@ -576,14 +601,10 @@ ngx_http_userid_create_conf(ngx_conf_t *
     /*
      * set by ngx_pcalloc():
      *
-     *     conf->name.len = 0;
-     *     conf->name.date = NULL;
-     *     conf->domain.len = 0;
-     *     conf->domain.date = NULL;
-     *     conf->path.len = 0;
-     *     conf->path.date = NULL;
-     *     conf->p3p.len = 0;
-     *     conf->p3p.date = NULL;
+     *     conf->name = { 0, NULL };
+     *     conf->domain = { 0, NULL };
+     *     conf->path = { 0, NULL };
+     *     conf->p3p = { 0, NULL };
      */
 
     conf->enable = NGX_CONF_UNSET_UINT;
@@ -642,9 +663,7 @@ ngx_http_userid_domain(ngx_conf_t *cf, v
     u_char  *p, *new;
 
     if (ngx_strcmp(domain->data, "none") == 0) {
-        domain->len = 0;
-        domain->data = (u_char *) "";
-
+        ngx_str_set(domain, "");
         return NGX_CONF_OK;
     }
 
@@ -727,8 +746,7 @@ ngx_http_userid_p3p(ngx_conf_t *cf, void
     ngx_str_t  *p3p = data;
 
     if (ngx_strcmp(p3p->data, "none") == 0) {
-        p3p->len = 0;
-        p3p->data = (u_char *) "";
+        ngx_str_set(p3p, "");
     }
 
     return NGX_CONF_OK;
@@ -780,4 +798,3 @@ ngx_http_userid_init_worker(ngx_cycle_t 
 
     return NGX_OK;
 }
-
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -0,0 +1,1708 @@
+
+/*
+ * Copyright (C) Unbit S.a.s. 2009-2010
+ * Copyright (C) 2008 Manlio Perillo (manlio.perillo@gmail.com)
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    ngx_http_upstream_conf_t   upstream;
+
+    ngx_array_t               *flushes;
+    ngx_array_t               *params_len;
+    ngx_array_t               *params;
+    ngx_array_t               *params_source;
+
+    ngx_hash_t                 headers_hash;
+    ngx_uint_t                 header_params;
+
+    ngx_array_t               *uwsgi_lengths;
+    ngx_array_t               *uwsgi_values;
+
+#if (NGX_HTTP_CACHE)
+    ngx_http_complex_value_t   cache_key;
+#endif
+
+    ngx_str_t                  uwsgi_string;
+
+    ngx_uint_t                 modifier1;
+    ngx_uint_t                 modifier2;
+} ngx_http_uwsgi_loc_conf_t;
+
+
+static ngx_int_t ngx_http_uwsgi_eval(ngx_http_request_t *r,
+    ngx_http_uwsgi_loc_conf_t *uwcf);
+static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r);
+static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
+static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
+static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
+    ngx_int_t rc);
+
+static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+static char *ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+
+#if (NGX_HTTP_CACHE)
+static ngx_int_t ngx_http_uwsgi_create_key(ngx_http_request_t *r);
+static char *ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+#endif
+
+
+static ngx_conf_num_bounds_t  ngx_http_uwsgi_modifier_bounds = {
+    ngx_conf_check_num_bounds, 0, 255
+};
+
+
+static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = {
+    { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
+    { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
+    { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
+    { 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 }
+};
+
+
+ngx_module_t  ngx_http_uwsgi_module;
+
+
+static ngx_command_t ngx_http_uwsgi_commands[] = {
+
+    { ngx_string("uwsgi_pass"),
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
+      ngx_http_uwsgi_pass,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("uwsgi_modifier1"),
+      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_uwsgi_loc_conf_t, modifier1),
+      &ngx_http_uwsgi_modifier_bounds },
+
+    { ngx_string("uwsgi_modifier2"),
+      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_uwsgi_loc_conf_t, modifier2),
+      &ngx_http_uwsgi_modifier_bounds },
+
+    { ngx_string("uwsgi_store"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_uwsgi_store,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("uwsgi_store_access"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+      ngx_conf_set_access_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.store_access),
+      NULL },
+
+    { ngx_string("uwsgi_ignore_client_abort"),
+      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_uwsgi_loc_conf_t, upstream.ignore_client_abort),
+      NULL },
+
+    { ngx_string("uwsgi_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upstream_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.local),
+      NULL },
+
+    { ngx_string("uwsgi_connect_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.connect_timeout),
+      NULL },
+
+    { ngx_string("uwsgi_send_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.send_timeout),
+      NULL },
+
+    { ngx_string("uwsgi_buffer_size"),
+      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_uwsgi_loc_conf_t, upstream.buffer_size),
+      NULL },
+
+    { ngx_string("uwsgi_pass_request_headers"),
+      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_uwsgi_loc_conf_t, upstream.pass_request_headers),
+      NULL },
+
+    { ngx_string("uwsgi_pass_request_body"),
+      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_uwsgi_loc_conf_t, upstream.pass_request_body),
+      NULL },
+
+    { ngx_string("uwsgi_intercept_errors"),
+      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_uwsgi_loc_conf_t, upstream.intercept_errors),
+      NULL },
+
+    { ngx_string("uwsgi_read_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.read_timeout),
+      NULL },
+
+    { ngx_string("uwsgi_buffers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_bufs_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.bufs),
+      NULL },
+
+    { ngx_string("uwsgi_busy_buffers_size"),
+      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_uwsgi_loc_conf_t, upstream.busy_buffers_size_conf),
+      NULL },
+
+#if (NGX_HTTP_CACHE)
+
+    { ngx_string("uwsgi_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_uwsgi_cache,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("uwsgi_cache_key"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_uwsgi_cache_key,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("uwsgi_cache_path"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
+      ngx_http_file_cache_set_slot,
+      0,
+      0,
+      &ngx_http_uwsgi_module },
+
+    { ngx_string("uwsgi_cache_bypass"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_bypass),
+      NULL },
+
+    { ngx_string("uwsgi_no_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_set_predicate_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.no_cache),
+      NULL },
+
+    { ngx_string("uwsgi_cache_valid"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_file_cache_valid_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_valid),
+      NULL },
+
+    { ngx_string("uwsgi_cache_min_uses"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_min_uses),
+      NULL },
+
+    { ngx_string("uwsgi_cache_use_stale"),
+      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_uwsgi_loc_conf_t, upstream.cache_use_stale),
+      &ngx_http_uwsgi_next_upstream_masks },
+
+    { ngx_string("uwsgi_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_uwsgi_loc_conf_t, upstream.cache_methods),
+      &ngx_http_upstream_cache_method_mask },
+
+#endif
+
+    { ngx_string("uwsgi_temp_path"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+      ngx_conf_set_path_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.temp_path),
+      NULL },
+
+    { ngx_string("uwsgi_max_temp_file_size"),
+      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_uwsgi_loc_conf_t, upstream.max_temp_file_size_conf),
+      NULL },
+
+    { ngx_string("uwsgi_temp_file_write_size"),
+      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_uwsgi_loc_conf_t, upstream.temp_file_write_size_conf),
+      NULL },
+
+    { ngx_string("uwsgi_next_upstream"),
+      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_uwsgi_loc_conf_t, upstream.next_upstream),
+      &ngx_http_uwsgi_next_upstream_masks },
+
+    { ngx_string("uwsgi_param"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_keyval_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, params_source),
+      NULL },
+
+    { ngx_string("uwsgi_string"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, uwsgi_string),
+      NULL },
+
+    { ngx_string("uwsgi_pass_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_array_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_headers),
+      NULL },
+
+    { ngx_string("uwsgi_hide_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_array_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.hide_headers),
+      NULL },
+
+    { ngx_string("uwsgi_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_uwsgi_loc_conf_t, upstream.ignore_headers),
+      &ngx_http_upstream_ignore_headers_masks },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_uwsgi_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_uwsgi_create_loc_conf,        /* create location configuration */
+    ngx_http_uwsgi_merge_loc_conf          /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_uwsgi_module = {
+    NGX_MODULE_V1,
+    &ngx_http_uwsgi_module_ctx,            /* module context */
+    ngx_http_uwsgi_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_str_t ngx_http_uwsgi_hide_headers[] = {
+    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_null_string
+};
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_keyval_t  ngx_http_uwsgi_cache_headers[] = {
+    { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_RANGE"), ngx_string("") },
+    { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
+    { ngx_null_string, ngx_null_string }
+};
+
+#endif
+
+
+static ngx_path_init_t ngx_http_uwsgi_temp_path = {
+    ngx_string(NGX_HTTP_UWSGI_TEMP_PATH), { 1, 2, 0 }
+};
+
+
+static ngx_int_t
+ngx_http_uwsgi_handler(ngx_http_request_t *r)
+{
+    ngx_int_t                   rc;
+    ngx_http_status_t          *status;
+    ngx_http_upstream_t        *u;
+    ngx_http_uwsgi_loc_conf_t  *uwcf;
+
+    if (r->subrequest_in_memory) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "ngx_http_uwsgi_module does not support "
+                      "subrequests in memory");
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (ngx_http_upstream_create(r) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
+    if (status == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ngx_http_set_ctx(r, status, ngx_http_uwsgi_module);
+
+    uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
+
+    if (uwcf->uwsgi_lengths) {
+        if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    u = r->upstream;
+
+    ngx_str_set(&u->schema, "uwsgi://");
+    u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module;
+
+    u->conf = &uwcf->upstream;
+
+#if (NGX_HTTP_CACHE)
+    u->create_key = ngx_http_uwsgi_create_key;
+#endif
+    u->create_request = ngx_http_uwsgi_create_request;
+    u->reinit_request = ngx_http_uwsgi_reinit_request;
+    u->process_header = ngx_http_uwsgi_process_status_line;
+    u->abort_request = ngx_http_uwsgi_abort_request;
+    u->finalize_request = ngx_http_uwsgi_finalize_request;
+
+    u->buffering = 1;
+
+    u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
+    if (u->pipe == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
+    u->pipe->input_ctx = r;
+
+    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        return rc;
+    }
+
+    return NGX_DONE;
+}
+
+
+static ngx_int_t
+ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
+{
+    ngx_url_t             url;
+    ngx_http_upstream_t  *u;
+
+    ngx_memzero(&url, sizeof(ngx_url_t));
+
+    if (ngx_http_script_run(r, &url.url, uwcf->uwsgi_lengths->elts, 0,
+                            uwcf->uwsgi_values->elts)
+        == NULL)
+    {
+        return NGX_ERROR;
+    }
+
+    url.no_resolve = 1;
+
+    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+        if (url.err) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "%s in upstream \"%V\"", url.err, &url.url);
+        }
+
+        return NGX_ERROR;
+    }
+
+    u = r->upstream;
+
+    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+    if (u->resolved == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (url.addrs && url.addrs[0].sockaddr) {
+        u->resolved->sockaddr = url.addrs[0].sockaddr;
+        u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->naddrs = 1;
+        u->resolved->host = url.addrs[0].name;
+
+    } else {
+        u->resolved->host = url.host;
+        u->resolved->port = url.port;
+        u->resolved->no_port = url.no_port;
+    }
+
+    return NGX_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_int_t
+ngx_http_uwsgi_create_key(ngx_http_request_t *r)
+{
+    ngx_str_t                  *key;
+    ngx_http_uwsgi_loc_conf_t  *uwcf;
+
+    key = ngx_array_push(&r->cache->keys);
+    if (key == NULL) {
+        return NGX_ERROR;
+    }
+
+    uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
+
+    if (ngx_http_complex_value(r, &uwcf->cache_key, key) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_http_uwsgi_create_request(ngx_http_request_t *r)
+{
+    u_char                        ch, *lowcase_key;
+    size_t                        key_len, val_len, len, allocated;
+    ngx_uint_t                    i, n, hash, header_params;
+    ngx_buf_t                    *b;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header, **ignored;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_uwsgi_loc_conf_t    *uwcf;
+    ngx_http_script_len_code_pt   lcode;
+
+    len = 0;
+    header_params = 0;
+    ignored = NULL;
+
+    uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
+
+    if (uwcf->params_len) {
+        ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
+
+        ngx_http_script_flush_no_cacheable_variables(r, uwcf->flushes);
+        le.flushed = 1;
+
+        le.ip = uwcf->params_len->elts;
+        le.request = r;
+
+        while (*(uintptr_t *) le.ip) {
+
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            key_len = lcode(&le);
+
+            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode (&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+            le.ip += sizeof(uintptr_t);
+
+            len += 2 + key_len + 2 + val_len;
+        }
+    }
+
+    if (uwcf->upstream.pass_request_headers) {
+
+        allocated = 0;
+        lowcase_key = NULL;
+
+        if (uwcf->header_params) {
+            ignored = ngx_palloc(r->pool, uwcf->header_params * sizeof(void *));
+            if (ignored == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */ ; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
+
+            if (uwcf->header_params) {
+                if (allocated < header[i].key.len) {
+                    allocated = header[i].key.len + 16;
+                    lowcase_key = ngx_pnalloc(r->pool, allocated);
+                    if (lowcase_key == NULL) {
+                        return NGX_ERROR;
+                    }
+                }
+
+                hash = 0;
+
+                for (n = 0; n < header[i].key.len; n++) {
+                    ch = header[i].key.data[n];
+
+                    if (ch >= 'A' && ch <= 'Z') {
+                        ch |= 0x20;
+
+                    } else if (ch == '-') {
+                        ch = '_';
+                    }
+
+                    hash = ngx_hash(hash, ch);
+                    lowcase_key[n] = ch;
+                }
+
+                if (ngx_hash_find(&uwcf->headers_hash, hash, lowcase_key, n)) {
+                    ignored[header_params++] = &header[i];
+                    continue;
+                }
+            }
+
+            len += 2 + sizeof("HTTP_") - 1 + header[i].key.len
+                 + 2 + header[i].value.len;
+        }
+    }
+
+    len += uwcf->uwsgi_string.len;
+
+#if 0
+    /* allow custom uwsgi packet */
+    if (len > 0 && len < 2) {
+        ngx_log_error (NGX_LOG_ALERT, r->connection->log, 0,
+                       "uwsgi request is too little: %uz", len);
+        return NGX_ERROR;
+    }
+#endif
+
+    b = ngx_create_temp_buf(r->pool, len + 4);
+    if (b == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl = ngx_alloc_chain_link(r->pool);
+    if (cl == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl->buf = b;
+
+    *b->last++ = (u_char) uwcf->modifier1;
+    *b->last++ = (u_char) (len & 0xff);
+    *b->last++ = (u_char) ((len >> 8) & 0xff);
+    *b->last++ = (u_char) uwcf->modifier2;
+
+    if (uwcf->params_len) {
+        ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+        e.ip = uwcf->params->elts;
+        e.pos = b->last;
+        e.request = r;
+        e.flushed = 1;
+
+        le.ip = uwcf->params_len->elts;
+
+        while (*(uintptr_t *) le.ip) {
+
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            key_len = (u_char) lcode (&le);
+
+            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+            le.ip += sizeof(uintptr_t);
+
+            *e.pos++ = (u_char) (key_len & 0xff);
+            *e.pos++ = (u_char) ((key_len >> 8) & 0xff);
+
+            code = *(ngx_http_script_code_pt *) e.ip;
+            code((ngx_http_script_engine_t *) & e);
+
+            *e.pos++ = (u_char) (val_len & 0xff);
+            *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
+
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) & e);
+            }
+
+            e.ip += sizeof(uintptr_t);
+
+            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "uwsgi param: \"%*s: %*s\"",
+                           key_len, e.pos - (key_len + 2 + val_len),
+                           val_len, e.pos - val_len);
+        }
+
+        b->last = e.pos;
+    }
+
+    if (uwcf->upstream.pass_request_headers) {
+
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */ ; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
+
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next;
+                }
+            }
+
+            key_len = sizeof("HTTP_") - 1 + header[i].key.len;
+            *b->last++ = (u_char) (key_len & 0xff);
+            *b->last++ = (u_char) ((key_len >> 8) & 0xff);
+
+            b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
+            for (n = 0; n < header[i].key.len; n++) {
+                ch = header[i].key.data[n];
+
+                if (ch >= 'a' && ch <= 'z') {
+                    ch &= ~0x20;
+
+                } else if (ch == '-') {
+                    ch = '_';
+                }
+
+                *b->last++ = ch;
+            }
+
+            val_len = header[i].value.len;
+            *b->last++ = (u_char) (val_len & 0xff);
+            *b->last++ = (u_char) ((val_len >> 8) & 0xff);
+            b->last = ngx_copy(b->last, header[i].value.data, val_len);
+
+            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "uwsgi param: \"%*s: %*s\"",
+                           key_len, b->last - (key_len + 2 + val_len),
+                           val_len, b->last - val_len);
+        next:
+
+            continue;
+        }
+    }
+
+    b->last = ngx_copy(b->last, uwcf->uwsgi_string.data,
+                       uwcf->uwsgi_string.len);
+
+    if (uwcf->upstream.pass_request_body) {
+        body = r->upstream->request_bufs;
+        r->upstream->request_bufs = cl;
+
+        while (body) {
+            b = ngx_alloc_buf(r->pool);
+            if (b == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+            cl->next = ngx_alloc_chain_link(r->pool);
+            if (cl->next == NULL) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+            body = body->next;
+        }
+
+    } else {
+        r->upstream->request_bufs = cl;
+    }
+
+    cl->next = NULL;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_uwsgi_reinit_request(ngx_http_request_t *r)
+{
+    ngx_http_status_t  *status;
+
+    status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
+
+    if (status == NULL) {
+        return NGX_OK;
+    }
+
+    status->code = 0;
+    status->count = 0;
+    status->start = NULL;
+    status->end = NULL;
+
+    r->upstream->process_header = ngx_http_uwsgi_process_status_line;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_uwsgi_process_status_line(ngx_http_request_t *r)
+{
+    size_t                 len;
+    ngx_int_t              rc;
+    ngx_http_status_t     *status;
+    ngx_http_upstream_t   *u;
+
+    status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
+
+    if (status == NULL) {
+        return NGX_ERROR;
+    }
+
+    u = r->upstream;
+
+    rc = ngx_http_parse_status_line(r, &u->buffer, status);
+
+    if (rc == NGX_AGAIN) {
+        return rc;
+    }
+
+    if (rc == NGX_ERROR) {
+        r->http_version = NGX_HTTP_VERSION_9;
+
+        u->process_header = ngx_http_uwsgi_process_header;
+
+        return ngx_http_uwsgi_process_header(r);
+    }
+
+    if (u->state) {
+        u->state->status = status->code;
+    }
+
+    u->headers_in.status_n = status->code;
+
+    len = status->end - status->start;
+    u->headers_in.status_line.len = len;
+
+    u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
+    if (u->headers_in.status_line.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(u->headers_in.status_line.data, status->start, len);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http uwsgi status %ui \"%V\"",
+                   u->headers_in.status_n, &u->headers_in.status_line);
+
+    u->process_header = ngx_http_uwsgi_process_header;
+
+    return ngx_http_uwsgi_process_header(r);
+}
+
+
+static ngx_int_t
+ngx_http_uwsgi_process_header(ngx_http_request_t *r)
+{
+    ngx_str_t                      *status_line;
+    ngx_int_t                       rc, status;
+    ngx_table_elt_t                *h;
+    ngx_http_upstream_t            *u;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+
+    for ( ;; ) {
+
+        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
+
+        if (rc == NGX_OK) {
+
+            /* a header line has been parsed successfully */
+
+            h = ngx_list_push(&r->upstream->headers_in.headers);
+            if (h == NULL) {
+                return NGX_ERROR;
+            }
+
+            h->hash = r->header_hash;
+
+            h->key.len = r->header_name_end - r->header_name_start;
+            h->value.len = r->header_end - r->header_start;
+
+            h->key.data = ngx_pnalloc(r->pool,
+                                      h->key.len + 1 + h->value.len + 1
+                                      + h->key.len);
+            if (h->key.data == NULL) {
+                return NGX_ERROR;
+            }
+
+            h->value.data = h->key.data + h->key.len + 1;
+            h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
+
+            ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
+            ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
+
+            if (h->key.len == r->lowcase_index) {
+                ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
+
+            } else {
+                ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
+            }
+
+            hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
+                               h->lowcase_key, h->key.len);
+
+            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
+                return NGX_ERROR;
+            }
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http uwsgi header: \"%V: %V\"", &h->key, &h->value);
+
+            continue;
+        }
+
+        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+
+            /* a whole header has been parsed successfully */
+
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http uwsgi header done");
+
+            if (r->http_version > NGX_HTTP_VERSION_9) {
+                return NGX_OK;
+            }
+
+            u = r->upstream;
+
+            if (u->headers_in.status) {
+                status_line = &u->headers_in.status->value;
+
+                status = ngx_atoi(status_line->data, 3);
+                if (status == NGX_ERROR) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "upstream sent invalid status \"%V\"",
+                                  status_line);
+                    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+                }
+
+                r->http_version = NGX_HTTP_VERSION_10;
+                u->headers_in.status_n = status;
+                u->headers_in.status_line = *status_line;
+
+            } else if (u->headers_in.location) {
+                r->http_version = NGX_HTTP_VERSION_10;
+                u->headers_in.status_n = 302;
+                ngx_str_set(&u->headers_in.status_line,
+                            "302 Moved Temporarily");
+
+            } else {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent neither valid HTTP/1.0 header "
+                              "nor \"Status\" header line");
+                u->headers_in.status_n = 200;
+                ngx_str_set(&u->headers_in.status_line, "200 OK");
+            }
+
+            if (u->state) {
+                u->state->status = u->headers_in.status_n;
+            }
+
+            return NGX_OK;
+        }
+
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        /* there was error while a header line parsing */
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent invalid header");
+
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+}
+
+
+static void
+ngx_http_uwsgi_abort_request(ngx_http_request_t *r)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "abort http uwsgi request");
+
+    return;
+}
+
+
+static void
+ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "finalize http uwsgi request");
+
+    return;
+}
+
+
+static void *
+ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_uwsgi_loc_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_uwsgi_loc_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    conf->modifier1 = NGX_CONF_UNSET_UINT;
+    conf->modifier2 = NGX_CONF_UNSET_UINT;
+
+    conf->upstream.store = NGX_CONF_UNSET;
+    conf->upstream.store_access = NGX_CONF_UNSET_UINT;
+    conf->upstream.buffering = NGX_CONF_UNSET;
+    conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+
+    conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
+
+    conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
+    conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
+    conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
+    conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+    conf->upstream.pass_request_body = NGX_CONF_UNSET;
+
+#if (NGX_HTTP_CACHE)
+    conf->upstream.cache = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
+    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
+    conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+#endif
+
+    conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
+    conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
+
+    conf->upstream.intercept_errors = NGX_CONF_UNSET;
+
+    /* "uwsgi_cyclic_temp_file" is disabled */
+    conf->upstream.cyclic_temp_file = 0;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_uwsgi_loc_conf_t *prev = parent;
+    ngx_http_uwsgi_loc_conf_t *conf = child;
+
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i;
+    ngx_array_t                   headers_names;
+    ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
+    ngx_hash_init_t               hash;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
+
+    if (conf->upstream.store != 0) {
+        ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
+
+        if (conf->upstream.store_lengths == NULL) {
+            conf->upstream.store_lengths = prev->upstream.store_lengths;
+            conf->upstream.store_values = prev->upstream.store_values;
+        }
+    }
+
+    ngx_conf_merge_uint_value(conf->upstream.store_access,
+                              prev->upstream.store_access, 0600);
+
+    ngx_conf_merge_value(conf->upstream.buffering,
+                              prev->upstream.buffering, 1);
+
+    ngx_conf_merge_value(conf->upstream.ignore_client_abort,
+                              prev->upstream.ignore_client_abort, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
+                              prev->upstream.connect_timeout, 60000);
+
+    ngx_conf_merge_msec_value(conf->upstream.send_timeout,
+                              prev->upstream.send_timeout, 60000);
+
+    ngx_conf_merge_msec_value(conf->upstream.read_timeout,
+                              prev->upstream.read_timeout, 60000);
+
+    ngx_conf_merge_size_value(conf->upstream.send_lowat,
+                              prev->upstream.send_lowat, 0);
+
+    ngx_conf_merge_size_value(conf->upstream.buffer_size,
+                              prev->upstream.buffer_size,
+                              (size_t) ngx_pagesize);
+
+
+    ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
+                              8, ngx_pagesize);
+
+    if (conf->upstream.bufs.num < 2) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "there must be at least 2 \"uwsgi_buffers\"");
+        return NGX_CONF_ERROR;
+    }
+
+
+    size = conf->upstream.buffer_size;
+    if (size < conf->upstream.bufs.size) {
+        size = conf->upstream.bufs.size;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
+                              prev->upstream.busy_buffers_size_conf,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.busy_buffers_size = 2 * size;
+    } else {
+        conf->upstream.busy_buffers_size =
+            conf->upstream.busy_buffers_size_conf;
+    }
+
+    if (conf->upstream.busy_buffers_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"uwsgi_busy_buffers_size\" must be equal or bigger "
+            "than maximum of the value of \"uwsgi_buffer_size\" and "
+            "one of the \"uwsgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->upstream.busy_buffers_size
+        > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"uwsgi_busy_buffers_size\" must be less than "
+            "the size of all \"uwsgi_buffers\" minus one buffer");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
+                              prev->upstream.temp_file_write_size_conf,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.temp_file_write_size = 2 * size;
+    } else {
+        conf->upstream.temp_file_write_size =
+            conf->upstream.temp_file_write_size_conf;
+    }
+
+    if (conf->upstream.temp_file_write_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"uwsgi_temp_file_write_size\" must be equal or bigger than "
+            "maximum of the value of \"uwsgi_buffer_size\" and "
+            "one of the \"uwsgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
+                              prev->upstream.max_temp_file_size_conf,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
+    } else {
+        conf->upstream.max_temp_file_size =
+            conf->upstream.max_temp_file_size_conf;
+    }
+
+    if (conf->upstream.max_temp_file_size != 0
+        && conf->upstream.max_temp_file_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+            "\"uwsgi_max_temp_file_size\" must be equal to zero to disable "
+            "the temporary files usage or must be equal or bigger than "
+            "maximum of the value of \"uwsgi_buffer_size\" and "
+            "one of the \"uwsgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    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
+                                  |NGX_HTTP_UPSTREAM_FT_ERROR
+                                  |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
+
+    if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
+        conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
+                                       |NGX_HTTP_UPSTREAM_FT_OFF;
+    }
+
+    if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
+                                  prev->upstream.temp_path,
+                                  &ngx_http_uwsgi_temp_path)
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+#if (NGX_HTTP_CACHE)
+
+    ngx_conf_merge_ptr_value(conf->upstream.cache,
+                              prev->upstream.cache, NULL);
+
+    if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+        ngx_shm_zone_t  *shm_zone;
+
+        shm_zone = conf->upstream.cache;
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "\"uwsgi_cache\" zone \"%V\" is unknown",
+                           &shm_zone->shm.name);
+
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
+                              prev->upstream.cache_min_uses, 1);
+
+    ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
+                              prev->upstream.cache_use_stale,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_HTTP_UPSTREAM_FT_OFF));
+
+    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;
+    }
+
+    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_bypass,
+                             prev->upstream.cache_bypass, NULL);
+
+    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+                             prev->upstream.no_cache, NULL);
+
+    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,
+                         prev->upstream.pass_request_headers, 1);
+    ngx_conf_merge_value(conf->upstream.pass_request_body,
+                         prev->upstream.pass_request_body, 1);
+
+    ngx_conf_merge_value(conf->upstream.intercept_errors,
+                         prev->upstream.intercept_errors, 0);
+
+    ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, "");
+
+    hash.max_size = 512;
+    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
+    hash.name = "uwsgi_hide_headers_hash";
+
+    if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
+            &prev->upstream, ngx_http_uwsgi_hide_headers, &hash)
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->upstream.upstream == NULL) {
+        conf->upstream.upstream = prev->upstream.upstream;
+    }
+
+    if (conf->uwsgi_lengths == NULL) {
+        conf->uwsgi_lengths = prev->uwsgi_lengths;
+        conf->uwsgi_values = prev->uwsgi_values;
+    }
+
+    if (conf->upstream.upstream || conf->uwsgi_lengths) {
+        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+        if (clcf->handler == NULL && clcf->lmt_excpt) {
+            clcf->handler = ngx_http_uwsgi_handler;
+        }
+    }
+
+    ngx_conf_merge_uint_value(conf->modifier1, prev->modifier1, 0);
+    ngx_conf_merge_uint_value(conf->modifier2, prev->modifier2, 0);
+
+    if (conf->params_source == NULL) {
+        conf->flushes = prev->flushes;
+        conf->params_len = prev->params_len;
+        conf->params = prev->params;
+        conf->params_source = prev->params_source;
+        conf->headers_hash = prev->headers_hash;
+
+#if (NGX_HTTP_CACHE)
+
+        if (conf->params_source == NULL) {
+
+            if ((conf->upstream.cache == NULL)
+                == (prev->upstream.cache == NULL))
+            {
+                return NGX_CONF_OK;
+            }
+
+            /* 6 is a number of ngx_http_uwsgi_cache_headers entries */
+            conf->params_source = ngx_array_create(cf->pool, 6,
+                                                   sizeof(ngx_keyval_t));
+            if (conf->params_source == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+#else
+
+        if (conf->params_source == NULL) {
+            return NGX_CONF_OK;
+        }
+
+#endif
+    }
+
+    conf->params_len = ngx_array_create(cf->pool, 64, 1);
+    if (conf->params_len == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->params = ngx_array_create(cf->pool, 512, 1);
+    if (conf->params == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    src = conf->params_source->elts;
+
+#if (NGX_HTTP_CACHE)
+
+    if (conf->upstream.cache) {
+        ngx_keyval_t  *h, *s;
+
+        for (h = ngx_http_uwsgi_cache_headers; h->key.len; h++) {
+
+            for (i = 0; i < conf->params_source->nelts; i++) {
+                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+                    goto next;
+                }
+            }
+
+            s = ngx_array_push(conf->params_source);
+            if (s == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            *s = *h;
+
+            src = conf->params_source->elts;
+
+        next:
+
+            h++;
+        }
+    }
+
+#endif
+
+    for (i = 0; i < conf->params_source->nelts; i++) {
+
+        if (src[i].key.len > sizeof("HTTP_") - 1
+            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
+        {
+            hk = ngx_array_push(&headers_names);
+            if (hk == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            hk->key.len = src[i].key.len - 5;
+            hk->key.data = src[i].key.data + 5;
+            hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
+            hk->value = (void *) 1;
+
+            if (src[i].value.len == 0) {
+                continue;
+            }
+        }
+
+        copy = ngx_array_push_n(conf->params_len,
+                                sizeof(ngx_http_script_copy_code_t));
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+        copy->len = src[i].key.len;
+
+
+        size = (sizeof(ngx_http_script_copy_code_t)
+                + src[i].key.len + sizeof(uintptr_t) - 1)
+               & ~(sizeof(uintptr_t) - 1);
+
+        copy = ngx_array_push_n(conf->params, size);
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = ngx_http_script_copy_code;
+        copy->len = src[i].key.len;
+
+        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+        ngx_memcpy(p, src[i].key.data, src[i].key.len);
+
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &src[i].value;
+        sc.flushes = &conf->flushes;
+        sc.lengths = &conf->params_len;
+        sc.values = &conf->params;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+
+
+        code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
+
+    code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+    conf->header_params = headers_names.nelts;
+
+    hash.hash = &conf->headers_hash;
+    hash.key = ngx_hash_key_lc;
+    hash.max_size = 512;
+    hash.bucket_size = 64;
+    hash.name = "uwsgi_params_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
+
+    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
+
+    ngx_url_t                   u;
+    ngx_str_t                  *value, *url;
+    ngx_uint_t                  n;
+    ngx_http_core_loc_conf_t   *clcf;
+    ngx_http_script_compile_t   sc;
+
+    if (uwcf->upstream.upstream || uwcf->uwsgi_lengths) {
+        return "is duplicate";
+    }
+
+    clcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_core_module);
+    clcf->handler = ngx_http_uwsgi_handler;
+
+    value = cf->args->elts;
+
+    url = &value[1];
+
+    n = ngx_http_script_variables_count(url);
+
+    if (n) {
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = url;
+        sc.lengths = &uwcf->uwsgi_lengths;
+        sc.values = &uwcf->uwsgi_values;
+        sc.variables = n;
+        sc.complete_lengths = 1;
+        sc.complete_values = 1;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        return NGX_CONF_OK;
+    }
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.url = value[1];
+    u.no_resolve = 1;
+
+    uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+    if (uwcf->upstream.upstream == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
+
+    ngx_str_t                  *value;
+    ngx_http_script_compile_t   sc;
+
+    if (uwcf->upstream.store != NGX_CONF_UNSET || uwcf->upstream.store_lengths)
+    {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        uwcf->upstream.store = 0;
+        return NGX_CONF_OK;
+    }
+
+#if (NGX_HTTP_CACHE)
+
+    if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR
+        && uwcf->upstream.cache != NULL)
+    {
+        return "is incompatible with \"uwsgi_cache\"";
+    }
+
+#endif
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        uwcf->upstream.store = 1;
+        return NGX_CONF_OK;
+    }
+
+    /* include the terminating '\0' into script */
+    value[1].len++;
+
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+    sc.cf = cf;
+    sc.source = &value[1];
+    sc.lengths = &uwcf->upstream.store_lengths;
+    sc.values = &uwcf->upstream.store_values;
+    sc.variables = ngx_http_script_variables_count(&value[1]);;
+    sc.complete_lengths = 1;
+    sc.complete_values = 1;
+
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static char *
+ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
+
+    ngx_str_t  *value;
+
+    value = cf->args->elts;
+
+    if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR) {
+        return "is duplicate";
+    }
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        uwcf->upstream.cache = NULL;
+        return NGX_CONF_OK;
+    }
+
+    if (uwcf->upstream.store > 0 || uwcf->upstream.store_lengths) {
+        return "is incompatible with \"uwsgi_store\"";
+    }
+
+    uwcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
+                                                 &ngx_http_uwsgi_module);
+    if (uwcf->upstream.cache == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
+
+    ngx_str_t                         *value;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    if (uwcf->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 = &uwcf->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_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -54,7 +54,6 @@ typedef struct {
 typedef struct {
     xmlDocPtr            doc;
     xmlParserCtxtPtr     ctxt;
-    xmlSAXHandler       *sax;
     ngx_http_request_t  *request;
     ngx_array_t          params;
 
@@ -68,49 +67,8 @@ static ngx_int_t ngx_http_xslt_add_chunk
     ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
 
 
-static void ngx_http_xslt_sax_start_document(void *data);
-static void ngx_http_xslt_sax_end_document(void *data);
-static void ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
-    const xmlChar *externalId, const xmlChar *systemId);
 static void ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
     const xmlChar *externalId, const xmlChar *systemId);
-static void ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name,
-    int type, const xmlChar *publicId, const xmlChar *systemId,
-    xmlChar *content);
-static void ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
-    const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
-    xmlEnumerationPtr tree);
-static void ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name,
-    int type, xmlElementContentPtr content);
-static void ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
-    const xmlChar *publicId, const xmlChar *systemId);
-static void ngx_http_xslt_sax_unparsed_entity_decl(void *data,
-    const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId,
-    const xmlChar *notationName);
-static void ngx_http_xslt_sax_start_element(void *data,
-    const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
-    int nb_namespaces, const xmlChar **namespaces, int nb_attributes,
-    int nb_defaulted, const xmlChar **attributes);
-static void ngx_http_xslt_sax_end_element(void *data,
-    const xmlChar * localname ATTRIBUTE_UNUSED,
-    const xmlChar * prefix ATTRIBUTE_UNUSED,
-    const xmlChar * URI ATTRIBUTE_UNUSED);
-static void ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len);
-static void ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p,
-    int len);
-static xmlEntityPtr ngx_http_xslt_sax_get_entity(void *data,
-    const xmlChar *name);
-static xmlEntityPtr ngx_http_xslt_sax_get_parameter_entity(void *data,
-    const xmlChar *name);
-static xmlParserInputPtr ngx_http_xslt_sax_resolve_entity(void *data,
-    const xmlChar *publicId, const xmlChar *systemId);
-static void ngx_http_xslt_sax_reference(void *data, const xmlChar *name);
-static void ngx_http_xslt_sax_comment(void *data, const xmlChar *value);
-static void ngx_http_xslt_sax_processing_instruction(void *data,
-    const xmlChar *target, const xmlChar *pidata);
-static int ngx_http_xslt_sax_is_standalone(void *data);
-static int ngx_http_xslt_sax_has_internal_subset(void *data);
-static int ngx_http_xslt_sax_has_external_subset(void *data);
 static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...);
 
 
@@ -268,7 +226,7 @@ ngx_http_xslt_body_filter(ngx_http_reque
 
         if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) {
 
-            if (ctx->ctxt->myDoc){
+            if (ctx->ctxt->myDoc) {
 
 #if (NGX_HTTP_XSLT_REUSE_DTD)
                 ctx->ctxt->myDoc->extSubset = NULL;
@@ -366,9 +324,8 @@ 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)
 {
-    int                err;
-    xmlSAXHandler     *sax;
-    xmlParserCtxtPtr   ctxt;
+    int               err;
+    xmlParserCtxtPtr  ctxt;
 
     if (ctx->ctxt == NULL) {
 
@@ -379,50 +336,12 @@ ngx_http_xslt_add_chunk(ngx_http_request
             return NGX_ERROR;
         }
 
-        ctx->sax = ngx_palloc(r->pool, sizeof(xmlSAXHandler));
-        if (ctx->sax == NULL) {
-            return NGX_ERROR;
-        }
-
-        sax = ctxt->sax;
-
-        ngx_memcpy(ctx->sax, sax, sizeof(xmlSAXHandler));
-
-        sax->startDocument = ngx_http_xslt_sax_start_document;
-        sax->endDocument = ngx_http_xslt_sax_end_document;
-
-        sax->internalSubset = ngx_http_xslt_sax_internal_subset;
-        sax->externalSubset = ngx_http_xslt_sax_external_subset;
-        sax->entityDecl = ngx_http_xslt_sax_entity_decl;
-        sax->attributeDecl = ngx_http_xslt_sax_attribute_decl;
-        sax->elementDecl = ngx_http_xslt_sax_element_decl;
-        sax->notationDecl = ngx_http_xslt_sax_notation_decl;
-        sax->unparsedEntityDecl = ngx_http_xslt_sax_unparsed_entity_decl;
-        sax->setDocumentLocator = NULL;
-
-        sax->startElementNs = ngx_http_xslt_sax_start_element;
-        sax->endElementNs = ngx_http_xslt_sax_end_element;
-
-        sax->characters = 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;
-        sax->getParameterEntity = ngx_http_xslt_sax_get_parameter_entity;
-        sax->reference = ngx_http_xslt_sax_reference;
-        sax->comment = ngx_http_xslt_sax_comment;
-        sax->processingInstruction = ngx_http_xslt_sax_processing_instruction;
-
-        sax->isStandalone = ngx_http_xslt_sax_is_standalone;
-        sax->hasInternalSubset = ngx_http_xslt_sax_has_internal_subset;
-        sax->hasExternalSubset = ngx_http_xslt_sax_has_external_subset;
-
-        sax->warning = NULL;
-        sax->error = ngx_http_xslt_sax_error;
-        sax->fatalError = ngx_http_xslt_sax_error;
-
-        ctxt->userData = ctx;
-
+        ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset;
+        ctxt->sax->setDocumentLocator = NULL;
+        ctxt->sax->warning = NULL;
+        ctxt->sax->error = ngx_http_xslt_sax_error;
+        ctxt->sax->fatalError = ngx_http_xslt_sax_error;
+        ctxt->sax->_private = ctx;
         ctxt->replaceEntities = 1;
         ctxt->loadsubset = 1;
 
@@ -446,44 +365,18 @@ ngx_http_xslt_add_chunk(ngx_http_request
 
 
 static void
-ngx_http_xslt_sax_start_document(void *data)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->startDocument(ctx->ctxt);
-}
-
-
-static void
-ngx_http_xslt_sax_end_document(void *data)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->endDocument(ctx->ctxt);
-}
-
-
-static void
-ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
-    const xmlChar *externalId, const xmlChar *systemId)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->internalSubset(ctx->ctxt, name, externalId, systemId);
-}
-
-
-static void
 ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
     const xmlChar *externalId, const xmlChar *systemId)
 {
-    ngx_http_xslt_filter_ctx_t *ctx = data;
+    xmlParserCtxtPtr ctxt = data;
 
     xmlDocPtr                         doc;
     xmlDtdPtr                         dtd;
     ngx_http_request_t               *r;
+    ngx_http_xslt_filter_ctx_t       *ctx;
     ngx_http_xslt_filter_loc_conf_t  *conf;
 
+    ctx = ctxt->sax->_private;
     r = ctx->request;
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
@@ -494,7 +387,7 @@ ngx_http_xslt_sax_external_subset(void *
                    externalId ? externalId : (xmlChar *) "",
                    systemId ? systemId : (xmlChar *) "");
 
-    doc = ctx->ctxt->myDoc;
+    doc = ctxt->myDoc;
 
 #if (NGX_HTTP_XSLT_REUSE_DTD)
 
@@ -522,194 +415,17 @@ ngx_http_xslt_sax_external_subset(void *
 }
 
 
-static void
-ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name, int type,
-    const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->entityDecl(ctx->ctxt, name, type, publicId, systemId, content);
-}
-
-
-static void
-ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
-    const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
-    xmlEnumerationPtr tree)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->attributeDecl(ctx->ctxt, elem, fullname, type, def, defaultValue,
-                            tree);
-}
-
-
-static void
-ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name, int type,
-    xmlElementContentPtr content)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->elementDecl(ctx->ctxt, name, type, content);
-}
-
-
-static void
-ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
-    const xmlChar *publicId, const xmlChar *systemId)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->notationDecl(ctx->ctxt, name, publicId, systemId);
-}
-
-
-static void
-ngx_http_xslt_sax_unparsed_entity_decl(void *data, const xmlChar *name,
-    const xmlChar *publicId, const xmlChar *systemId,
-    const xmlChar *notationName)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->unparsedEntityDecl(ctx->ctxt, name, publicId, systemId,
-                                 notationName);
-}
-
-
-static void
-ngx_http_xslt_sax_start_element(void *data, const xmlChar *localname,
-    const xmlChar *prefix, const xmlChar *URI, int nb_namespaces,
-    const xmlChar **namespaces, int nb_attributes, int nb_defaulted,
-    const xmlChar **attributes)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->startElementNs(ctx->ctxt, localname, prefix, URI, nb_namespaces,
-        namespaces, nb_attributes, nb_defaulted, attributes);
-}
-
-
-static void
-ngx_http_xslt_sax_end_element(void *data,
-    const xmlChar * localname ATTRIBUTE_UNUSED,
-    const xmlChar * prefix ATTRIBUTE_UNUSED,
-    const xmlChar * URI ATTRIBUTE_UNUSED)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->endElementNs(ctx->ctxt, localname, prefix, URI);
-}
-
-
-static void
-ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->characters(ctx->ctxt, p, len);
-}
-
-
-static void
-ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p, int len)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->cdataBlock(ctx->ctxt, p, len);
-}
-
-
-static xmlEntityPtr
-ngx_http_xslt_sax_get_entity(void *data, const xmlChar *name)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    return ctx->sax->getEntity(ctx->ctxt, name);
-}
-
-
-static xmlEntityPtr
-ngx_http_xslt_sax_get_parameter_entity(void *data, const xmlChar *name)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    return ctx->sax->getParameterEntity(ctx->ctxt, name);
-}
-
-
-static xmlParserInputPtr
-ngx_http_xslt_sax_resolve_entity(void *data, const xmlChar *publicId,
-    const xmlChar *systemId)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    return ctx->sax->resolveEntity(ctx->ctxt, publicId, systemId);
-}
-
-
-static void
-ngx_http_xslt_sax_reference(void *data, const xmlChar *name)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->reference(ctx->ctxt, name);
-}
-
-
-static void
-ngx_http_xslt_sax_comment(void *data, const xmlChar *value)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->comment(ctx->ctxt, value);
-}
-
-
-static void
-ngx_http_xslt_sax_processing_instruction(void *data, const xmlChar *target,
-    const xmlChar *pidata)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    ctx->sax->processingInstruction(ctx->ctxt, target, pidata);
-}
-
-
-static int
-ngx_http_xslt_sax_is_standalone(void *data)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    return ctx->sax->isStandalone(ctx->ctxt);
-}
-
-
-static int
-ngx_http_xslt_sax_has_internal_subset(void *data)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    return ctx->sax->hasInternalSubset(ctx->ctxt);
-}
-
-
-static int
-ngx_http_xslt_sax_has_external_subset(void *data)
-{
-    ngx_http_xslt_filter_ctx_t *ctx = data;
-
-    return ctx->sax->hasExternalSubset(ctx->ctxt);
-}
-
-
 static void ngx_cdecl
 ngx_http_xslt_sax_error(void *data, const char *msg, ...)
 {
-    ngx_http_xslt_filter_ctx_t *ctx = data;
+    xmlParserCtxtPtr ctxt = data;
 
-    size_t    n;
-    va_list   args;
-    u_char    buf[NGX_MAX_ERROR_STR];
+    size_t                       n;
+    va_list                      args;
+    ngx_http_xslt_filter_ctx_t  *ctx;
+    u_char                       buf[NGX_MAX_ERROR_STR];
+
+    ctx = ctxt->sax->_private;
 
     buf[0] = '\0';
 
@@ -837,8 +553,7 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
     } else if (doc_type == XML_HTML_DOCUMENT_NODE) {
 
         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";
+        ngx_str_set(&r->headers_out.content_type, "text/html");
     }
 
     r->headers_out.content_type_lowcase = NULL;
@@ -1144,7 +859,6 @@ found:
         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
-
     }
 
     return NGX_CONF_OK;
@@ -1230,8 +944,8 @@ ngx_http_xslt_filter_merge_conf(ngx_conf
         conf->sheets = prev->sheets;
     }
 
-    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
-                             prev->types_keys, &prev->types,
+    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
+                             &prev->types_keys, &prev->types,
                              ngx_http_xslt_default_types)
         != NGX_OK)
     {
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -14,6 +14,7 @@ our @EXPORT = qw(
 
     HTTP_OK
     HTTP_CREATED
+    HTTP_ACCEPTED
     HTTP_NO_CONTENT
     HTTP_PARTIAL_CONTENT
 
@@ -47,7 +48,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.16';
+our $VERSION = '1.0.0';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
@@ -59,6 +60,7 @@ use constant DECLINED                   
 
 use constant HTTP_OK                        => 200;
 use constant HTTP_CREATED                   => 201;
+use constant HTTP_ACCEPTED                  => 202;
 use constant HTTP_NO_CONTENT                => 204;
 use constant HTTP_PARTIAL_CONTENT           => 206;
 
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -467,7 +467,7 @@ header_out(r, key, value)
     }
 
     if (header->key.len == sizeof("Content-Length") - 1
-        && ngx_strncasecmp(header->key.data, "Content-Length",
+        && ngx_strncasecmp(header->key.data, (u_char *) "Content-Length",
                            sizeof("Content-Length") - 1) == 0)
     {
         r->headers_out.content_length_n = (off_t) SvIV(value);
@@ -642,12 +642,13 @@ sendfile(r, filename, offset = -1, bytes
         XSRETURN_EMPTY;
     }
 
-    (void) ngx_cpystrn(path.data, filename, path.len + 1);
+    (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1);
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
+    of.read_ahead = clcf->read_ahead;
     of.directio = clcf->directio;
     of.valid = clcf->open_file_cache_valid;
     of.min_uses = clcf->open_file_cache_min_uses;
@@ -847,7 +848,7 @@ variable(r, name, value = NULL)
 
     #endif
 
-    vv = ngx_http_get_variable(r, &var, hash, 1);
+    vv = ngx_http_get_variable(r, &var, hash);
     if (vv == NULL) {
         XSRETURN_UNDEF;
     }
@@ -901,9 +902,6 @@ variable(r, name, value = NULL)
             XSRETURN_UNDEF;
         }
 
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "variable \"%V\" not found", &var);
-
         XSRETURN_UNDEF;
     }
 
@@ -946,6 +944,7 @@ sleep(r, sleep, next)
     ngx_add_timer(r->connection->write, sleep);
 
     r->write_event_handler = ngx_http_perl_sleep_handler;
+    r->main->count++;
 
 
 void
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -13,8 +13,8 @@
 typedef struct {
     PerlInterpreter   *perl;
     HV                *nginx;
-    ngx_str_t          modules;
-    ngx_array_t        requires;
+    ngx_array_t       *modules;
+    ngx_array_t       *requires;
 } ngx_http_perl_main_conf_t;
 
 
@@ -30,12 +30,6 @@ typedef struct {
 } ngx_http_perl_variable_t;
 
 
-typedef struct {
-    SV                *sv;
-    PerlInterpreter   *perl;
-} ngx_http_perl_cleanup_t;
-
-
 #if (NGX_HTTP_SSI)
 static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
@@ -57,8 +51,6 @@ static char *ngx_http_perl_init_main_con
 static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent,
     void *child);
-static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
 static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
@@ -74,16 +66,16 @@ static ngx_command_t  ngx_http_perl_comm
 
     { ngx_string("perl_modules"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+      ngx_conf_set_str_array_slot,
       NGX_HTTP_MAIN_CONF_OFFSET,
       offsetof(ngx_http_perl_main_conf_t, modules),
       NULL },
 
     { ngx_string("perl_require"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
-      ngx_http_perl_require,
+      ngx_conf_set_str_array_slot,
       NGX_HTTP_MAIN_CONF_OFFSET,
-      0,
+      offsetof(ngx_http_perl_main_conf_t, requires),
       NULL },
 
     { ngx_string("perl"),
@@ -154,12 +146,13 @@ static ngx_http_ssi_command_t  ngx_http_
 #endif
 
 
-static ngx_str_t    ngx_null_name = ngx_null_string;
-
-static HV          *nginx_stash;
+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;
+static ngx_uint_t        ngx_perl_term;
+#else
+static PerlInterpreter  *perl;
 #endif
 
 
@@ -175,10 +168,6 @@ ngx_http_perl_xs_init(pTHX)
 static ngx_int_t
 ngx_http_perl_handler(ngx_http_request_t *r)
 {
-    if (r->zero_in_uri) {
-        return NGX_HTTP_NOT_FOUND;
-    }
-
     r->main->count++;
 
     ngx_http_perl_handle_request(r);
@@ -463,27 +452,41 @@ ngx_http_perl_ssi(ngx_http_request_t *r,
 static char *
 ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
 {
+    ngx_str_t           *m;
+    ngx_uint_t           i;
 #if (NGX_HAVE_PERL_MULTIPLICITY)
-    ngx_pool_cleanup_t       *cln;
+    ngx_pool_cleanup_t  *cln;
 
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
         return NGX_CONF_ERROR;
     }
 
-#else
-    static PerlInterpreter  *perl;
 #endif
 
 #ifdef NGX_PERL_MODULES
-    if (pmcf->modules.data == NULL) {
-        pmcf->modules.data = NGX_PERL_MODULES;
+    if (pmcf->modules == NGX_CONF_UNSET_PTR) {
+
+        pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
+        if (pmcf->modules == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        m = ngx_array_push(pmcf->modules);
+        if (m == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_str_set(m, NGX_PERL_MODULES);
     }
 #endif
 
-    if (pmcf->modules.data) {
-        if (ngx_conf_full_name(cf->cycle, &pmcf->modules, 0) != NGX_OK) {
-            return NGX_CONF_ERROR;
+    if (pmcf->modules != NGX_CONF_UNSET_PTR) {
+        m = pmcf->modules->elts;
+        for (i = 0; i < pmcf->modules->nelts; i++) {
+            if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
         }
     }
 
@@ -495,7 +498,7 @@ ngx_http_perl_init_interpreter(ngx_conf_
             return NGX_CONF_ERROR;
         }
 
-        if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log)
+        if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log)
             != NGX_OK)
         {
             return NGX_CONF_ERROR;
@@ -543,7 +546,9 @@ ngx_http_perl_create_interpreter(ngx_con
     int                n;
     STRLEN             len;
     SV                *sv;
-    char              *ver, *embedding[6];
+    char              *ver, **embedding;
+    ngx_str_t         *m;
+    ngx_uint_t         i;
     PerlInterpreter   *perl;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
@@ -569,15 +574,21 @@ ngx_http_perl_create_interpreter(ngx_con
     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
 #endif
 
+    n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0;
+
+    embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *));
+    if (embedding == NULL) {
+        goto fail;
+    }
+
     embedding[0] = "";
 
-    if (pmcf->modules.data) {
-        embedding[1] = "-I";
-        embedding[2] = (char *) pmcf->modules.data;
-        n = 3;
-
-    } else {
-        n = 1;
+    if (n++) {
+        m = pmcf->modules->elts;
+        for (i = 0; i < pmcf->modules->nelts; i++) {
+            embedding[2 * i + 1] = "-I";
+            embedding[2 * i + 2] = (char *) m[i].data;
+        }
     }
 
     embedding[n++] = "-Mnginx";
@@ -601,7 +612,7 @@ ngx_http_perl_create_interpreter(ngx_con
         goto fail;
     }
 
-    if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) {
+    if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) {
         goto fail;
     }
 
@@ -622,26 +633,28 @@ fail:
 static ngx_int_t
 ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
 {
-    char       **script;
+    u_char      *err;
     STRLEN       len;
-    ngx_str_t    err;
+    ngx_str_t   *script;
     ngx_uint_t   i;
 
+    if (requires == NGX_CONF_UNSET_PTR) {
+        return NGX_OK;
+    }
+
     script = requires->elts;
     for (i = 0; i < requires->nelts; i++) {
 
-        require_pv(script[i]);
+        require_pv((char *) script[i].data);
 
         if (SvTRUE(ERRSV)) {
 
-            err.data = (u_char *) SvPV(ERRSV, len);
-            for (len--; err.data[len] == LF || err.data[len] == CR; len--) {
-                /* void */
-            }
-            err.len = len + 1;
+            err = (u_char *) SvPV(ERRSV, len);
+            while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }
 
             ngx_log_error(NGX_LOG_EMERG, log, 0,
-                          "require_pv(\"%s\") failed: \"%V\"", script[i], &err);
+                          "require_pv(\"%s\") failed: \"%*s\"",
+                          script[i].data, len + 1, err);
 
             return NGX_ERROR;
         }
@@ -658,8 +671,8 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
     SV                *sv;
     int                n, status;
     char              *line;
+    u_char            *err;
     STRLEN             len, n_a;
-    ngx_str_t          err;
     ngx_uint_t         i;
     ngx_connection_t  *c;
 
@@ -720,14 +733,11 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
 
     if (SvTRUE(ERRSV)) {
 
-        err.data = (u_char *) SvPV(ERRSV, len);
-        for (len--; err.data[len] == LF || err.data[len] == CR; len--) {
-            /* void */
-        }
-        err.len = len + 1;
+        err = (u_char *) SvPV(ERRSV, len);
+        while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }
 
         ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                      "call_sv(\"%V\") failed: \"%V\"", handler, &err);
+                      "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err);
 
         if (rv) {
             return NGX_ERROR;
@@ -786,11 +796,8 @@ ngx_http_perl_create_main_conf(ngx_conf_
         return NULL;
     }
 
-    if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *))
-        != NGX_OK)
-    {
-        return NULL;
-    }
+    pmcf->modules = NGX_CONF_UNSET_PTR;
+    pmcf->requires = NGX_CONF_UNSET_PTR;
 
     return pmcf;
 }
@@ -897,28 +904,6 @@ ngx_http_perl_merge_loc_conf(ngx_conf_t 
 
 
 static char *
-ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_http_perl_main_conf_t *pmcf = conf;
-
-    u_char     **p;
-    ngx_str_t   *value;
-
-    value = cf->args->elts;
-
-    p = ngx_array_push(&pmcf->requires);
-
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    *p = value[1].data;
-
-    return NGX_CONF_OK;
-}
-
-
-static char *
 ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_perl_loc_conf_t *plcf = conf;
@@ -1067,19 +1052,21 @@ ngx_http_perl_exit(ngx_cycle_t *cycle)
 {
 #if (NGX_HAVE_PERL_MULTIPLICITY)
 
+    /*
+     * the master exit hook is run before global pool cleanup,
+     * therefore just set flag here
+     */
+
     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) {
+    if (nginx_stash) {
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term");
 
-        (void) perl_destruct(pmcf->perl);
+        (void) perl_destruct(perl);
 
-        perl_free(pmcf->perl);
+        perl_free(perl);
 
         PERL_SYS_TERM();
     }
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -17,20 +17,18 @@ static ngx_int_t ngx_http_init_headers_i
 static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf,
     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 *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);
 static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
-    ngx_http_listen_t *listen);
+    ngx_http_listen_opt_t *lsopt);
 static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
-    ngx_http_listen_t *listen);
-static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
+    ngx_http_listen_opt_t *lsopt);
+static ngx_int_t ngx_http_add_server(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr);
 
+static char *ngx_http_merge_servers(ngx_conf_t *cf,
+    ngx_http_core_main_conf_t *cmcf, ngx_http_module_t *module,
+    ngx_uint_t ctx_index);
 static char *ngx_http_merge_locations(ngx_conf_t *cf,
     ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module,
     ngx_uint_t ctx_index);
@@ -122,7 +120,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     char                        *rv;
     ngx_uint_t                   mi, m, s;
     ngx_conf_t                   pcf;
-    ngx_array_t                  ports;
     ngx_http_module_t           *module;
     ngx_http_conf_ctx_t         *ctx;
     ngx_http_core_loc_conf_t    *clcf;
@@ -269,39 +266,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
             }
         }
 
-        for (s = 0; s < cmcf->servers.nelts; s++) {
-
-            /* merge the server{}s' srv_conf's */
-
-            if (module->merge_srv_conf) {
-                rv = module->merge_srv_conf(cf, ctx->srv_conf[mi],
-                                            cscfp[s]->ctx->srv_conf[mi]);
-                if (rv != NGX_CONF_OK) {
-                    goto failed;
-                }
-            }
-
-            if (module->merge_loc_conf) {
-
-                /* merge the server{}'s loc_conf */
-
-                rv = module->merge_loc_conf(cf, ctx->loc_conf[mi],
-                                            cscfp[s]->ctx->loc_conf[mi]);
-                if (rv != NGX_CONF_OK) {
-                    goto failed;
-                }
-
-                /* merge the locations{}' loc_conf's */
-
-                clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
-
-                rv = ngx_http_merge_locations(cf, clcf->locations,
-                                              cscfp[s]->ctx->loc_conf,
-                                              module, mi);
-                if (rv != NGX_CONF_OK) {
-                    goto failed;
-                }
-            }
+        rv = ngx_http_merge_servers(cf, cmcf, module, mi);
+        if (rv != NGX_CONF_OK) {
+            goto failed;
         }
     }
 
@@ -362,19 +329,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     }
 
 
-    /*
-     * create the lists of ports, addresses and server names
-     * to find quickly the server core module configuration at run-time
-     */
-
-    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, &ports) != NGX_OK) {
+    if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
@@ -525,7 +482,7 @@ ngx_http_init_phase_handlers(ngx_conf_t 
             if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
                 cmcf->phase_engine.server_rewrite_index = n;
             }
-            checker = ngx_http_core_generic_phase;
+            checker = ngx_http_core_rewrite_phase;
 
             break;
 
@@ -542,7 +499,7 @@ ngx_http_init_phase_handlers(ngx_conf_t 
             if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
                 cmcf->phase_engine.location_rewrite_index = n;
             }
-            checker = ngx_http_core_generic_phase;
+            checker = ngx_http_core_rewrite_phase;
 
             break;
 
@@ -602,11 +559,74 @@ ngx_http_init_phase_handlers(ngx_conf_t 
 
 
 static char *
+ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
+    ngx_http_module_t *module, ngx_uint_t ctx_index)
+{
+    char                        *rv;
+    ngx_uint_t                   s;
+    ngx_http_conf_ctx_t         *ctx, saved;
+    ngx_http_core_loc_conf_t    *clcf;
+    ngx_http_core_srv_conf_t   **cscfp;
+
+    cscfp = cmcf->servers.elts;
+    ctx = (ngx_http_conf_ctx_t *) cf->ctx;
+    saved = *ctx;
+    rv = NGX_CONF_OK;
+
+    for (s = 0; s < cmcf->servers.nelts; s++) {
+
+        /* merge the server{}s' srv_conf's */
+
+        ctx->srv_conf = cscfp[s]->ctx->srv_conf;
+
+        if (module->merge_srv_conf) {
+            rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],
+                                        cscfp[s]->ctx->srv_conf[ctx_index]);
+            if (rv != NGX_CONF_OK) {
+                goto failed;
+            }
+        }
+
+        if (module->merge_loc_conf) {
+
+            /* merge the server{}'s loc_conf */
+
+            ctx->loc_conf = cscfp[s]->ctx->loc_conf;
+
+            rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
+                                        cscfp[s]->ctx->loc_conf[ctx_index]);
+            if (rv != NGX_CONF_OK) {
+                goto failed;
+            }
+
+            /* merge the locations{}' loc_conf's */
+
+            clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
+
+            rv = ngx_http_merge_locations(cf, clcf->locations,
+                                          cscfp[s]->ctx->loc_conf,
+                                          module, ctx_index);
+            if (rv != NGX_CONF_OK) {
+                goto failed;
+            }
+        }
+    }
+
+failed:
+
+    *ctx = saved;
+
+    return rv;
+}
+
+
+static char *
 ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
     void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
 {
     char                       *rv;
     ngx_queue_t                *q;
+    ngx_http_conf_ctx_t        *ctx, saved;
     ngx_http_core_loc_conf_t   *clcf;
     ngx_http_location_queue_t  *lq;
 
@@ -614,6 +634,9 @@ ngx_http_merge_locations(ngx_conf_t *cf,
         return NGX_CONF_OK;
     }
 
+    ctx = (ngx_http_conf_ctx_t *) cf->ctx;
+    saved = *ctx;
+
     for (q = ngx_queue_head(locations);
          q != ngx_queue_sentinel(locations);
          q = ngx_queue_next(q))
@@ -621,6 +644,7 @@ ngx_http_merge_locations(ngx_conf_t *cf,
         lq = (ngx_http_location_queue_t *) q;
 
         clcf = lq->exact ? lq->exact : lq->inclusive;
+        ctx->loc_conf = clcf->loc_conf;
 
         rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
                                     clcf->loc_conf[ctx_index]);
@@ -635,6 +659,8 @@ ngx_http_merge_locations(ngx_conf_t *cf,
         }
     }
 
+    *ctx = saved;
+
     return NGX_CONF_OK;
 }
 
@@ -1109,72 +1135,55 @@ inclusive:
 }
 
 
-static ngx_int_t
-ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers,
-    ngx_array_t *ports)
+ngx_int_t
+ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+    ngx_http_listen_opt_t *lsopt)
 {
-    ngx_uint_t                  s, i;
-    ngx_http_listen_t          *listen;
-    ngx_http_core_srv_conf_t  **cscfp;
-
-    if (ngx_array_init(ports, cf->temp_pool, 2, sizeof(ngx_http_conf_port_t))
-        != NGX_OK)
-    {
-        return NGX_ERROR;
-    }
-
-    /* "server" directives */
-
-    cscfp = servers->elts;
-    for (s = 0; s < servers->nelts; s++) {
-
-        /* "listen" directives */
-
-        listen = cscfp[s]->listen.elts;
-        for (i = 0; i < cscfp[s]->listen.nelts; i++) {
-
-            if (ngx_http_add_ports(cf, cscfp[s], ports, &listen[i]) != NGX_OK) {
-                return NGX_ERROR;
-            }
+    in_port_t                   p;
+    ngx_uint_t                  i;
+    struct sockaddr            *sa;
+    struct sockaddr_in         *sin;
+    ngx_http_conf_port_t       *port;
+    ngx_http_core_main_conf_t  *cmcf;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6        *sin6;
+#endif
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    if (cmcf->ports == NULL) {
+        cmcf->ports = ngx_array_create(cf->temp_pool, 2,
+                                       sizeof(ngx_http_conf_port_t));
+        if (cmcf->ports == NULL) {
+            return NGX_ERROR;
         }
     }
 
-    return NGX_OK;
-}
-
-
-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)
-{
-    in_port_t                 p;
-    ngx_uint_t                i;
-    struct sockaddr          *sa;
-    struct sockaddr_in       *sin;
-    ngx_http_conf_port_t     *port;
-#if (NGX_HAVE_INET6)
-    struct sockaddr_in6      *sin6;
-#endif
-
-    sa = (struct sockaddr *) &listen->sockaddr;
+    sa = &lsopt->u.sockaddr;
 
     switch (sa->sa_family) {
 
 #if (NGX_HAVE_INET6)
     case AF_INET6:
-        sin6 = (struct sockaddr_in6 *) sa;
+        sin6 = &lsopt->u.sockaddr_in6;
         p = sin6->sin6_port;
         break;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+        p = 0;
+        break;
+#endif
+
     default: /* AF_INET */
-        sin = (struct sockaddr_in *) sa;
+        sin = &lsopt->u.sockaddr_in;
         p = sin->sin_port;
         break;
     }
 
-    port = ports->elts;
-    for (i = 0; i < ports->nelts; i++) {
+    port = cmcf->ports->elts;
+    for (i = 0; i < cmcf->ports->nelts; i++) {
 
         if (p != port[i].port || sa->sa_family != port[i].family) {
             continue;
@@ -1182,12 +1191,12 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h
 
         /* a port is already in the port list */
 
-        return ngx_http_add_addresses(cf, cscf, &port[i], listen);
+        return ngx_http_add_addresses(cf, cscf, &port[i], lsopt);
     }
 
     /* add a port to the port list */
 
-    port = ngx_array_push(ports);
+    port = ngx_array_push(cmcf->ports);
     if (port == NULL) {
         return NGX_ERROR;
     }
@@ -1196,26 +1205,32 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h
     port->port = p;
     port->addrs.elts = NULL;
 
-    return ngx_http_add_address(cf, cscf, port, listen);
+    return ngx_http_add_address(cf, cscf, port, lsopt);
 }
 
 
 static ngx_int_t
 ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
-    ngx_http_conf_port_t *port, ngx_http_listen_t *listen)
+    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
 {
     u_char                *p;
     size_t                 len, off;
-    ngx_uint_t             i;
+    ngx_uint_t             i, default_server;
     struct sockaddr       *sa;
     ngx_http_conf_addr_t  *addr;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    struct sockaddr_un    *saun;
+#endif
+#if (NGX_HTTP_SSL)
+    ngx_uint_t             ssl;
+#endif
 
     /*
      * we can not compare whole sockaddr struct's as kernel
      * may fill some fields in inherited sockaddr struct's
      */
 
-    sa = (struct sockaddr *) &listen->sockaddr;
+    sa = &lsopt->u.sockaddr;
 
     switch (sa->sa_family) {
 
@@ -1226,54 +1241,78 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
         break;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+        off = offsetof(struct sockaddr_un, sun_path);
+        len = sizeof(saun->sun_path);
+        break;
+#endif
+
     default: /* AF_INET */
         off = offsetof(struct sockaddr_in, sin_addr);
         len = 4;
         break;
     }
 
-    p = listen->sockaddr + off;
+    p = lsopt->u.sockaddr_data + off;
 
     addr = port->addrs.elts;
 
     for (i = 0; i < port->addrs.nelts; i++) {
 
-        if (ngx_memcmp(p, (u_char *) addr[i].sockaddr + off, len) != 0) {
+        if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) {
             continue;
         }
 
         /* the address is already in the address list */
 
-        if (ngx_http_add_names(cf, cscf, &addr[i]) != NGX_OK) {
+        if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) {
             return NGX_ERROR;
         }
 
+        /* preserve default_server bit during listen options overwriting */
+        default_server = addr[i].opt.default_server;
+
+#if (NGX_HTTP_SSL)
+        ssl = lsopt->ssl || addr[i].opt.ssl;
+#endif
+
+        if (lsopt->set) {
+
+            if (addr[i].opt.set) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                        "a duplicate listen options for %s", addr[i].opt.addr);
+                return NGX_ERROR;
+            }
+
+            addr[i].opt = *lsopt;
+        }
+
         /* check the duplicate "default" server for this address:port */
 
-        if (listen->conf.default_server) {
-
-            if (addr[i].default_server) {
-                ngx_log_error(NGX_LOG_ERR, cf->log, 0,
-                              "the duplicate default server in %s:%ui",
-                               listen->file_name, listen->line);
-
+        if (lsopt->default_server) {
+
+            if (default_server) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                        "a duplicate default server for %s", addr[i].opt.addr);
                 return NGX_ERROR;
             }
 
-            addr[i].core_srv_conf = cscf;
-            addr[i].default_server = 1;
+            default_server = 1;
+            addr[i].default_server = cscf;
+        }
+
+        addr[i].opt.default_server = default_server;
 #if (NGX_HTTP_SSL)
-            addr[i].ssl = listen->conf.ssl;
+        addr[i].opt.ssl = ssl;
 #endif
-            addr[i].listen_conf = &listen->conf;
-        }
 
         return NGX_OK;
     }
 
     /* add the address to the addresses list that bound to this port */
 
-    return ngx_http_add_address(cf, cscf, port, listen);
+    return ngx_http_add_address(cf, cscf, port, lsopt);
 }
 
 
@@ -1284,7 +1323,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 
 static ngx_int_t
 ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
-    ngx_http_conf_port_t *port, ngx_http_listen_t *listen)
+    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
 {
     ngx_http_conf_addr_t  *addr;
 
@@ -1302,69 +1341,57 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
         return NGX_ERROR;
     }
 
-    addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
-    addr->socklen = listen->socklen;
+    addr->opt = *lsopt;
     addr->hash.buckets = NULL;
     addr->hash.size = 0;
     addr->wc_head = NULL;
     addr->wc_tail = NULL;
-    addr->names.elts = NULL;
 #if (NGX_PCRE)
     addr->nregex = 0;
     addr->regex = NULL;
 #endif
-    addr->core_srv_conf = cscf;
-    addr->default_server = listen->conf.default_server;
-    addr->bind = listen->conf.bind;
-    addr->wildcard = listen->conf.wildcard;
-#if (NGX_HTTP_SSL)
-    addr->ssl = listen->conf.ssl;
-#endif
-    addr->listen_conf = &listen->conf;
-
-    return ngx_http_add_names(cf, cscf, addr);
+    addr->default_server = cscf;
+    addr->servers.elts = NULL;
+
+    return ngx_http_add_server(cf, cscf, addr);
 }
 
 
-/*
- * add the server names and the server core module
- * configurations to the address:port
- */
+/* add the server core module configuration to the address:port */
 
 static ngx_int_t
-ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
     ngx_http_conf_addr_t *addr)
 {
-    ngx_uint_t               i;
-    ngx_http_server_name_t  *server_names, *name;
-
-    if (addr->names.elts == NULL) {
-        if (ngx_array_init(&addr->names, cf->temp_pool, 4,
-                           sizeof(ngx_http_server_name_t))
+    ngx_uint_t                  i;
+    ngx_http_core_srv_conf_t  **server;
+
+    if (addr->servers.elts == NULL) {
+        if (ngx_array_init(&addr->servers, cf->temp_pool, 4,
+                           sizeof(ngx_http_core_srv_conf_t *))
             != NGX_OK)
         {
             return NGX_ERROR;
         }
+
+    } else {
+        server = addr->servers.elts;
+        for (i = 0; i < addr->servers.nelts; i++) {
+            if (server[i] == cscf) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "a duplicate listen %s", addr->opt.addr);
+                return NGX_ERROR;
+            }
+        }
     }
 
-    server_names = cscf->server_names.elts;
-
-    for (i = 0; i < cscf->server_names.nelts; i++) {
-
-        ngx_strlow(server_names[i].name.data, server_names[i].name.data,
-                   server_names[i].name.len);
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                       "name: %V", &server_names[i].name);
-
-        name = ngx_array_push(&addr->names);
-        if (name == NULL) {
-            return NGX_ERROR;
-        }
-
-        *name = server_names[i];
+    server = ngx_array_push(&addr->servers);
+    if (server == NULL) {
+        return NGX_ERROR;
     }
 
+    *server = cscf;
+
     return NGX_OK;
 }
 
@@ -1373,10 +1400,13 @@ 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             p, a;
+    ngx_http_conf_port_t  *port;
+    ngx_http_conf_addr_t  *addr;
+
+    if (ports == NULL) {
+        return NGX_OK;
+    }
 
     port = ports->elts;
     for (p = 0; p < ports->nelts; p++) {
@@ -1392,23 +1422,15 @@ ngx_http_optimize_servers(ngx_conf_t *cf
         addr = port[p].addrs.elts;
         for (a = 0; a < port[p].addrs.nelts; a++) {
 
-            name = addr[a].names.elts;
-            for (s = 0; s < addr[a].names.nelts; s++) {
-
-                if (addr[a].core_srv_conf == name[s].core_srv_conf
+            if (addr[a].servers.nelts > 1
 #if (NGX_PCRE)
-                    && name[s].captures == 0
+                || addr[a].default_server->captures
 #endif
-                    )
-                {
-                    continue;
-                }
-
+               )
+            {
                 if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
                     return NGX_ERROR;
                 }
-
-                break;
             }
         }
 
@@ -1425,13 +1447,14 @@ 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_hash_keys_arrays_t   ha;
-    ngx_http_server_name_t  *name;
+    ngx_int_t                   rc;
+    ngx_uint_t                  n, s;
+    ngx_hash_init_t             hash;
+    ngx_hash_keys_arrays_t      ha;
+    ngx_http_server_name_t     *name;
+    ngx_http_core_srv_conf_t  **cscfp;
 #if (NGX_PCRE)
-    ngx_uint_t               regex, i;
+    ngx_uint_t                  regex, i;
 
     regex = 0;
 #endif
@@ -1449,35 +1472,40 @@ ngx_http_server_names(ngx_conf_t *cf, ng
         goto failed;
     }
 
-    name = addr->names.elts;
-
-    for (s = 0; s < addr->names.nelts; s++) {
+    cscfp = addr->servers.elts;
+
+    for (s = 0; s < addr->servers.nelts; s++) {
+
+        name = cscfp[s]->server_names.elts;
+
+        for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
 
 #if (NGX_PCRE)
-        if (name[s].regex) {
-            regex++;
-            continue;
-        }
+            if (name[n].regex) {
+                regex++;
+                continue;
+            }
 #endif
 
-        rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
-                              NGX_HASH_WILDCARD_KEY);
-
-        if (rc == NGX_ERROR) {
-            return NGX_ERROR;
-        }
-
-        if (rc == NGX_DECLINED) {
-            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "invalid server name or wildcard \"%V\" on %s",
-                          &name[s].name, addr->listen_conf->addr);
-            return NGX_ERROR;
-        }
-
-        if (rc == NGX_BUSY) {
-            ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-                          "conflicting server name \"%V\" on %s, ignored",
-                          &name[s].name, addr->listen_conf->addr);
+            rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,
+                                  NGX_HASH_WILDCARD_KEY);
+
+            if (rc == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (rc == NGX_DECLINED) {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                              "invalid server name or wildcard \"%V\" on %s",
+                              &name[n].name, addr->opt.addr);
+                return NGX_ERROR;
+            }
+
+            if (rc == NGX_BUSY) {
+                ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+                              "conflicting server name \"%V\" on %s, ignored",
+                              &name[n].name, addr->opt.addr);
+            }
         }
     }
 
@@ -1546,9 +1574,16 @@ ngx_http_server_names(ngx_conf_t *cf, ng
         return NGX_ERROR;
     }
 
-    for (i = 0, s = 0; s < addr->names.nelts; s++) {
-        if (name[s].regex) {
-            addr->regex[i++] = name[s];
+    i = 0;
+
+    for (s = 0; s < addr->servers.nelts; s++) {
+
+        name = cscfp[s]->server_names.elts;
+
+        for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
+            if (name[n].regex) {
+                addr->regex[i++] = name[n];
+            }
         }
     }
 
@@ -1572,17 +1607,17 @@ ngx_http_cmp_conf_addrs(const void *one,
     first = (ngx_http_conf_addr_t *) one;
     second = (ngx_http_conf_addr_t *) two;
 
-    if (first->wildcard) {
+    if (first->opt.wildcard) {
         /* a wildcard address must be the last resort, shift it to the end */
         return 1;
     }
 
-    if (first->bind && !second->bind) {
+    if (first->opt.bind && !second->opt.bind) {
         /* shift explicit bind()ed addresses to the start */
         return -1;
     }
 
-    if (!first->bind && second->bind) {
+    if (!first->opt.bind && second->opt.bind) {
         /* shift explicit bind()ed addresses to the start */
         return 1;
     }
@@ -1623,8 +1658,8 @@ ngx_http_init_listening(ngx_conf_t *cf, 
      * implicit bindings go, and wildcard binding is in the end.
      */
 
-    if (addr[last - 1].wildcard) {
-        addr[last - 1].bind = 1;
+    if (addr[last - 1].opt.wildcard) {
+        addr[last - 1].opt.bind = 1;
         bind_wildcard = 1;
 
     } else {
@@ -1635,7 +1670,7 @@ ngx_http_init_listening(ngx_conf_t *cf, 
 
     while (i < last) {
 
-        if (bind_wildcard && !addr[i].bind) {
+        if (bind_wildcard && !addr[i].opt.bind) {
             i++;
             continue;
         }
@@ -1691,7 +1726,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
 
-    ls = ngx_create_listening(cf, addr->sockaddr, addr->socklen);
+    ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen);
     if (ls == NULL) {
         return NULL;
     }
@@ -1700,7 +1735,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n
 
     ls->handler = ngx_http_init_connection;
 
-    cscf = addr->core_srv_conf;
+    cscf = addr->default_server;
     ls->pool_size = cscf->connection_pool_size;
     ls->post_accept_timeout = cscf->client_header_timeout;
 
@@ -1721,20 +1756,24 @@ ngx_http_add_listening(ngx_conf_t *cf, n
     }
 #endif
 
-    ls->backlog = addr->listen_conf->backlog;
-    ls->rcvbuf = addr->listen_conf->rcvbuf;
-    ls->sndbuf = addr->listen_conf->sndbuf;
+    ls->backlog = addr->opt.backlog;
+    ls->rcvbuf = addr->opt.rcvbuf;
+    ls->sndbuf = addr->opt.sndbuf;
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-    ls->accept_filter = addr->listen_conf->accept_filter;
+    ls->accept_filter = addr->opt.accept_filter;
 #endif
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-    ls->deferred_accept = addr->listen_conf->deferred_accept;
+    ls->deferred_accept = addr->opt.deferred_accept;
 #endif
 
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
-    ls->ipv6only = addr->listen_conf->ipv6only;
+    ls->ipv6only = addr->opt.ipv6only;
+#endif
+
+#if (NGX_HAVE_SETFIB)
+    ls->setfib = addr->opt.setfib;
 #endif
 
     return ls;
@@ -1760,11 +1799,11 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h
 
     for (i = 0; i < hport->naddrs; i++) {
 
-        sin = (struct sockaddr_in *) addr[i].sockaddr;
+        sin = &addr[i].opt.u.sockaddr_in;
         addrs[i].addr = sin->sin_addr.s_addr;
-        addrs[i].conf.core_srv_conf = addr[i].core_srv_conf;
+        addrs[i].conf.default_server = addr[i].default_server;
 #if (NGX_HTTP_SSL)
-        addrs[i].conf.ssl = addr[i].ssl;
+        addrs[i].conf.ssl = addr[i].opt.ssl;
 #endif
 
         if (addr[i].hash.buckets == NULL
@@ -1821,18 +1860,22 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_
 
     for (i = 0; i < hport->naddrs; i++) {
 
-        sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
+        sin6 = &addr[i].opt.u.sockaddr_in6;
         addrs6[i].addr6 = sin6->sin6_addr;
-        addrs6[i].conf.core_srv_conf = addr[i].core_srv_conf;
+        addrs6[i].conf.default_server = addr[i].default_server;
 #if (NGX_HTTP_SSL)
-        addrs6[i].conf.ssl = addr[i].ssl;
+        addrs6[i].conf.ssl = addr[i].opt.ssl;
 #endif
 
         if (addr[i].hash.buckets == NULL
             && (addr[i].wc_head == NULL
                 || addr[i].wc_head->hash.buckets == NULL)
-            && (addr[i].wc_head == NULL
-                || addr[i].wc_head->hash.buckets == NULL))
+            && (addr[i].wc_tail == NULL
+                || addr[i].wc_tail->hash.buckets == NULL)
+#if (NGX_PCRE)
+            && addr[i].nregex == 0
+#endif
+            )
         {
             continue;
         }
@@ -1871,6 +1914,10 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_
 
     types = (ngx_array_t **) (p + cmd->offset);
 
+    if (*types == (void *) -1) {
+        return NGX_CONF_OK;
+    }
+
     default_type = cmd->post;
 
     if (*types == NULL) {
@@ -1896,6 +1943,11 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_
 
     for (i = 1; i < cf->args->nelts; i++) {
 
+        if (value[i].len == 1 && value[i].data[0] == '*') {
+            *types = (void *) -1;
+            return NGX_CONF_OK;
+        }
+
         hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
         value[i].data[value[i].len] = '\0';
 
@@ -1924,13 +1976,17 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_
 
 
 char *
-ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, ngx_hash_t *types_hash,
-    ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash,
+ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t **keys, ngx_hash_t *types_hash,
+    ngx_array_t **prev_keys, ngx_hash_t *prev_types_hash,
     ngx_str_t *default_types)
 {
     ngx_hash_init_t  hash;
 
-    if (keys) {
+    if (*keys) {
+
+        if (*keys == (void *) -1) {
+            return NGX_CONF_OK;
+        }
 
         hash.hash = types_hash;
         hash.key = NULL;
@@ -1940,7 +1996,7 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx
         hash.pool = cf->pool;
         hash.temp_pool = NULL;
 
-        if (ngx_hash_init(&hash, keys->elts, keys->nelts) != NGX_OK) {
+        if (ngx_hash_init(&hash, (*keys)->elts, (*keys)->nelts) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
 
@@ -1949,13 +2005,17 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx
 
     if (prev_types_hash->buckets == NULL) {
 
-        if (prev_keys == NULL) {
-
-            if (ngx_http_set_default_types(cf, &prev_keys, default_types)
+        if (*prev_keys == NULL) {
+
+            if (ngx_http_set_default_types(cf, prev_keys, default_types)
                 != NGX_OK)
             {
                 return NGX_CONF_ERROR;
             }
+
+        } else if (*prev_keys == (void *) -1) {
+            *keys = *prev_keys;
+            return NGX_CONF_OK;
         }
 
         hash.hash = prev_types_hash;
@@ -1966,7 +2026,9 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx
         hash.pool = cf->pool;
         hash.temp_pool = NULL;
 
-        if (ngx_hash_init(&hash, prev_keys->elts, prev_keys->nelts) != NGX_OK) {
+        if (ngx_hash_init(&hash, (*prev_keys)->elts, (*prev_keys)->nelts)
+            != NGX_OK)
+        {
             return NGX_CONF_ERROR;
         }
     }
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -51,12 +51,22 @@ struct ngx_http_log_ctx_s {
 };
 
 
+typedef struct {
+    ngx_uint_t           code;
+    ngx_uint_t           count;
+    u_char              *start;
+    u_char              *end;
+} ngx_http_status_t;
+
+
 #define ngx_http_get_module_ctx(r, module)  (r)->ctx[module.ctx_index]
 #define ngx_http_set_ctx(r, c, module)      r->ctx[module.ctx_index] = c;
 
 
 ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
     ngx_http_core_loc_conf_t *clcf);
+ngx_int_t ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+    ngx_http_listen_opt_t *lsopt);
 
 
 void ngx_http_init_connection(ngx_connection_t *c);
@@ -68,6 +78,8 @@ int ngx_http_ssl_servername(ngx_ssl_conn
 ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b);
 ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r,
     ngx_uint_t merge_slashes);
+ngx_int_t ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
+    ngx_http_status_t *status);
 ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
     ngx_str_t *args, ngx_uint_t *flags);
 ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
@@ -92,7 +104,7 @@ void ngx_http_empty_handler(ngx_event_t 
 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_ephemeral(r)  (void *) (&r->uri_start)
 
 
 #define NGX_HTTP_LAST   1
@@ -118,17 +130,22 @@ size_t ngx_http_get_time(char *buf, time
 
 
 ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r);
+void ngx_http_discarded_request_body_handler(ngx_http_request_t *r);
 void ngx_http_block_reading(ngx_http_request_t *r);
 void ngx_http_test_reading(ngx_http_request_t *r);
 
 
 char *ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys,
-    ngx_hash_t *types_hash, ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash,
-    ngx_str_t *default_types);
+char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t **keys,
+    ngx_hash_t *types_hash, ngx_array_t **prev_keys,
+    ngx_hash_t *prev_types_hash, ngx_str_t *default_types);
 ngx_int_t ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types,
     ngx_str_t *default_type);
 
+#if (NGX_HTTP_DEGRADATION)
+ngx_uint_t  ngx_http_degraded(ngx_http_request_t *);
+#endif
+
 
 extern ngx_module_t  ngx_http_module;
 
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -14,11 +14,12 @@
 
 
 #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_BYPASS        2
+#define NGX_HTTP_CACHE_EXPIRED       3
+#define NGX_HTTP_CACHE_STALE         4
+#define NGX_HTTP_CACHE_UPDATING      5
+#define NGX_HTTP_CACHE_HIT           6
+#define NGX_HTTP_CACHE_SCARCE        7
 
 #define NGX_HTTP_CACHE_KEY_LEN       16
 
@@ -42,7 +43,8 @@ typedef struct {
     unsigned                         error:10;
     unsigned                         exists:1;
     unsigned                         updating:1;
-                                     /* 12 unused bits */
+    unsigned                         deleting:1;
+                                     /* 11 unused bits */
 
     ngx_file_uniq_t                  uniq;
     time_t                           expire;
@@ -77,6 +79,7 @@ struct ngx_http_cache_s {
     ngx_http_file_cache_node_t      *node;
 
     unsigned                         updated:1;
+    unsigned                         updating:1;
     unsigned                         exists:1;
     unsigned                         temp_file:1;
 };
@@ -121,12 +124,14 @@ struct ngx_http_file_cache_s {
 };
 
 
+ngx_int_t ngx_http_file_cache_new(ngx_http_request_t *r);
+ngx_int_t ngx_http_file_cache_create(ngx_http_request_t *r);
 void ngx_http_file_cache_create_key(ngx_http_request_t *r);
 ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r);
 void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
 void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
 ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
-void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf);
+void ngx_http_file_cache_free(ngx_http_cache_t *c, 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,
@@ -134,6 +139,7 @@ char *ngx_http_file_cache_set_slot(ngx_c
 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[];
 
 
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -56,10 +56,6 @@ typedef struct {
 #define ngx_http_get_module_srv_conf(r, module)  (r)->srv_conf[module.ctx_index]
 #define ngx_http_get_module_loc_conf(r, module)  (r)->loc_conf[module.ctx_index]
 
-/*
- * ngx_http_conf_get_module_srv_conf() and ngx_http_conf_get_module_loc_conf()
- * must not be used at the merge phase because cf->ctx points to http{}'s ctx
- */
 
 #define ngx_http_conf_get_module_main_conf(cf, module)                        \
     ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -118,15 +118,19 @@ ngx_http_copy_filter(ngx_http_request_t 
         ctx->filter_ctx = r;
 
 #if (NGX_HAVE_FILE_AIO)
-        if (clcf->aio) {
-            ctx->aio_handler = ngx_http_copy_aio_handler;
+        if (ngx_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;
+        if (in && in->buf && ngx_buf_size(in->buf)) {
+            r->request_output = 1;
+        }
     }
 
 #if (NGX_HAVE_FILE_AIO)
@@ -209,6 +213,7 @@ ngx_http_copy_aio_handler(ngx_output_cha
 
     r->main->blocked++;
     r->aio = 1;
+    ctx->aio = 1;
 }
 
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -133,6 +133,14 @@ static ngx_conf_enum_t  ngx_http_core_if
 };
 
 
+static ngx_conf_enum_t  ngx_http_core_keepalive_disable[] = {
+    { ngx_string("none"), NGX_HTTP_KEEPALIVE_DISABLE_NONE },
+    { ngx_string("msie6"), NGX_HTTP_KEEPALIVE_DISABLE_MSIE6 },
+    { ngx_string("safari"), NGX_HTTP_KEEPALIVE_DISABLE_SAFARI },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_path_init_t  ngx_http_client_temp_path = {
     ngx_string(NGX_HTTP_CLIENT_TEMP_PATH), { 0, 0, 0 }
 };
@@ -408,6 +416,13 @@ static ngx_command_t  ngx_http_core_comm
 
 #endif
 
+    { ngx_string("read_ahead"),
+      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_core_loc_conf_t, read_ahead),
+      NULL },
+
     { ngx_string("directio"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_http_core_directio,
@@ -487,6 +502,13 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, keepalive_requests),
       NULL },
 
+    { ngx_string("keepalive_disable"),
+      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, keepalive_disable),
+      &ngx_http_core_keepalive_disable },
+
     { ngx_string("satisfy"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_enum_slot,
@@ -592,6 +614,13 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, if_modified_since),
       &ngx_http_core_if_modified_since },
 
+    { ngx_string("chunked_transfer_encoding"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, chunked_transfer_encoding),
+      NULL },
+
     { ngx_string("error_page"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                         |NGX_CONF_2MORE,
@@ -760,11 +789,7 @@ ngx_http_handler(ngx_http_request_t *r)
     if (!r->internal) {
         switch (r->headers_in.connection_type) {
         case 0:
-            if (r->http_version > NGX_HTTP_VERSION_10) {
-                r->keepalive = 1;
-            } else {
-                r->keepalive = 0;
-            }
+            r->keepalive = (r->http_version > NGX_HTTP_VERSION_10);
             break;
 
         case NGX_HTTP_CONNECTION_CLOSE:
@@ -776,23 +801,7 @@ ngx_http_handler(ngx_http_request_t *r)
             break;
         }
 
-        if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) {
-
-            /*
-             * MSIE may wait for some time if an response for
-             * a POST request was sent over a keepalive connection
-             */
-
-            r->keepalive = 0;
-        }
-
-        if (r->headers_in.content_length_n > 0) {
-            r->lingering_close = 1;
-
-        } else {
-            r->lingering_close = 0;
-        }
-
+        r->lingering_close = (r->headers_in.content_length_n > 0);
         r->phase_handler = 0;
 
     } else {
@@ -800,12 +809,12 @@ ngx_http_handler(ngx_http_request_t *r)
         r->phase_handler = cmcf->phase_engine.server_rewrite_index;
     }
 
-    if (r->unparsed_uri.len) {
-        r->valid_unparsed_uri = 1;
-    }
-
     r->valid_location = 1;
-    r->gzip = 0;
+#if (NGX_HTTP_GZIP)
+    r->gzip_tested = 0;
+    r->gzip_ok = 0;
+    r->gzip_vary = 0;
+#endif
 
     r->write_event_handler = ngx_http_core_run_phases;
     ngx_http_core_run_phases(r);
@@ -841,7 +850,7 @@ ngx_http_core_generic_phase(ngx_http_req
 
     /*
      * generic phase checker,
-     * used by the post read, server rewrite, rewrite, and pre-access phases
+     * used by the post read and pre-access phases
      */
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -872,6 +881,33 @@ ngx_http_core_generic_phase(ngx_http_req
 
 
 ngx_int_t
+ngx_http_core_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
+{
+    ngx_int_t  rc;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "rewrite phase: %ui", r->phase_handler);
+
+    rc = ph->handler(r);
+
+    if (rc == NGX_DECLINED) {
+        r->phase_handler++;
+        return NGX_AGAIN;
+    }
+
+    if (rc == NGX_DONE) {
+        return NGX_OK;
+    }
+
+    /* NGX_OK, NGX_AGAIN, NGX_ERROR, NGX_HTTP_...  */
+
+    ngx_http_finalize_request(r, rc);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_http_core_find_config_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph)
 {
@@ -994,7 +1030,6 @@ 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;
     }
@@ -1073,17 +1108,21 @@ ngx_int_t
 ngx_http_core_post_access_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph)
 {
+    ngx_int_t  access_code;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "post access phase: %ui", r->phase_handler);
 
-    if (r->access_code) {
-
-        if (r->access_code == NGX_HTTP_FORBIDDEN) {
+    access_code = r->access_code;
+
+    if (access_code) {
+        if (access_code == NGX_HTTP_FORBIDDEN) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                           "access forbidden by rule");
         }
 
-        ngx_http_finalize_request(r, r->access_code);
+        r->access_code = 0;
+        ngx_http_finalize_request(r, access_code);
         return NGX_OK;
     }
 
@@ -1125,7 +1164,7 @@ ngx_http_core_try_files_phase(ngx_http_r
 
     tf = clcf->try_files;
 
-    alias = clcf->alias ? clcf->name.len : 0;
+    alias = clcf->alias;
 
     for ( ;; ) {
 
@@ -1186,7 +1225,7 @@ ngx_http_core_try_files_phase(ngx_http_r
             *e.pos = '\0';
 
             if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) {
-                ngx_memcpy(name, name + alias, len - alias);
+                ngx_memmove(name, name + alias, len - alias);
                 path.len -= alias;
             }
         }
@@ -1195,8 +1234,9 @@ ngx_http_core_try_files_phase(ngx_http_r
 
         tf++;
 
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "try to use file: \"%s\" \"%s\"", name, path.data);
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "try to use %s: \"%s\" \"%s\"",
+                       test_dir ? "dir" : "file", name, path.data);
 
         if (tf->lengths == NULL && tf->name.len == 0) {
 
@@ -1233,7 +1273,10 @@ ngx_http_core_try_files_phase(ngx_http_r
         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
             != NGX_OK)
         {
-            if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+            if (of.err != NGX_ENOENT
+                && of.err != NGX_ENOTDIR
+                && of.err != NGX_ENAMETOOLONG)
+            {
                 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
                               "%s \"%s\" failed", of.failed, path.data);
             }
@@ -1251,6 +1294,13 @@ ngx_http_core_try_files_phase(ngx_http_r
         if (!alias) {
             r->uri = path;
 
+#if (NGX_PCRE)
+        } else if (clcf->regex) {
+            if (!test_dir) {
+                r->uri = path;
+                r->add_uri_to_alias = 1;
+            }
+#endif
         } else {
             r->uri.len = alias + path.len;
             r->uri.data = ngx_pnalloc(r->pool, r->uri.len);
@@ -1311,7 +1361,7 @@ ngx_http_core_content_phase(ngx_http_req
 
     /* no content handler was found */
 
-    if (r->uri.data[r->uri.len - 1] == '/' && !r->zero_in_uri) {
+    if (r->uri.data[r->uri.len - 1] == '/') {
 
         if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -1375,6 +1425,28 @@ ngx_http_update_location_config(ngx_http
 
         } else if (r->connection->requests >= clcf->keepalive_requests) {
             r->keepalive = 0;
+
+        } else if (r->headers_in.msie6
+                   && r->method == NGX_HTTP_POST
+                   && (clcf->keepalive_disable
+                       & NGX_HTTP_KEEPALIVE_DISABLE_MSIE6))
+        {
+            /*
+             * MSIE may wait for some time if an response for
+             * a POST request was sent over a keepalive connection
+             */
+            r->keepalive = 0;
+
+        } else if (r->headers_in.safari
+                   && (clcf->keepalive_disable
+                       & NGX_HTTP_KEEPALIVE_DISABLE_SAFARI))
+        {
+            /*
+             * Safari may send a POST request to a closed keepalive
+             * connection and may stall for some time, see
+             *     https://bugs.webkit.org/show_bug.cgi?id=5760
+             */
+            r->keepalive = 0;
         }
     }
 
@@ -1407,7 +1479,7 @@ ngx_http_core_find_location(ngx_http_req
     ngx_int_t                  rc;
     ngx_http_core_loc_conf_t  *pclcf;
 #if (NGX_PCRE)
-    ngx_int_t                  n, len;
+    ngx_int_t                  n;
     ngx_uint_t                 noregex;
     ngx_http_core_loc_conf_t  *clcf, **clcfp;
 
@@ -1441,51 +1513,28 @@ ngx_http_core_find_location(ngx_http_req
 
     if (noregex == 0 && pclcf->regex_locations) {
 
-        len = 0;
-
         for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) {
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "test location: ~ \"%V\"", &(*clcfp)->name);
 
-            if ((*clcfp)->captures) {
-
-                len = (NGX_HTTP_MAX_CAPTURES + 1) * 3;
-
-                if (r->captures == NULL) {
-                    r->captures = ngx_palloc(r->pool, len * sizeof(int));
-                    if (r->captures == NULL) {
-                        return NGX_ERROR;
-                    }
-                }
+            n = ngx_http_regex_exec(r, (*clcfp)->regex, &r->uri);
+
+            if (n == NGX_OK) {
+                r->loc_conf = (*clcfp)->loc_conf;
+
+                /* look up nested locations */
+
+                rc = ngx_http_core_find_location(r);
+
+                return (rc == NGX_ERROR) ? rc : NGX_OK;
             }
 
-            n = ngx_regex_exec((*clcfp)->regex, &r->uri, r->captures, len);
-
-            if (n == NGX_REGEX_NO_MATCHED) {
+            if (n == NGX_DECLINED) {
                 continue;
             }
 
-            if (n < 0) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                              ngx_regex_exec_n
-                              " failed: %d on \"%V\" using \"%V\"",
-                              n, &r->uri, &(*clcfp)->name);
-                return NGX_ERROR;
-            }
-
-            /* match */
-
-            r->loc_conf = (*clcfp)->loc_conf;
-
-            r->ncaptures = len;
-            r->captures_data = r->uri.data;
-
-            /* look up nested locations */
-
-            rc = ngx_http_core_find_location(r);
-
-            return (rc == NGX_ERROR) ? rc : NGX_OK;
+            return NGX_ERROR;
         }
     }
 #endif
@@ -1556,9 +1605,14 @@ ngx_http_core_find_static_location(ngx_h
 
         if (len == (size_t) node->len) {
 
-            r->loc_conf = (node->exact) ? node->exact->loc_conf:
-                                          node->inclusive->loc_conf;
-            return NGX_OK;
+            if (node->exact) {
+                r->loc_conf = node->exact->loc_conf;
+                return NGX_OK;
+
+            } else {
+                r->loc_conf = node->inclusive->loc_conf;
+                return NGX_AGAIN;
+            }
         }
 
         /* len < node->len */
@@ -1582,6 +1636,10 @@ ngx_http_test_content_type(ngx_http_requ
     size_t      len;
     ngx_uint_t  i, hash;
 
+    if (types_hash->size == 0) {
+        return (void *) 4;
+    }
+
     if (r->headers_out.content_type.len == 0) {
         return NULL;
     }
@@ -1674,8 +1732,7 @@ ngx_http_set_exten(ngx_http_request_t *r
 {
     ngx_int_t  i;
 
-    r->exten.len = 0;
-    r->exten.data = NULL;
+    ngx_str_null(&r->exten);
 
     for (i = r->uri.len - 1; i > 1; i--) {
         if (r->uri.data[i] == '.' && r->uri.data[i - 1] != '/') {
@@ -1695,6 +1752,80 @@ ngx_http_set_exten(ngx_http_request_t *r
 
 
 ngx_int_t
+ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
+    ngx_str_t *ct, ngx_http_complex_value_t *cv)
+{
+    ngx_int_t     rc;
+    ngx_str_t     val;
+    ngx_buf_t    *b;
+    ngx_chain_t   out;
+
+    r->headers_out.status = status;
+
+    if (status == NGX_HTTP_NO_CONTENT) {
+        r->header_only = 1;
+        return ngx_http_send_header(r);
+    }
+
+    if (ngx_http_complex_value(r, cv, &val) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (status >= NGX_HTTP_MOVED_PERMANENTLY && status <= NGX_HTTP_SEE_OTHER) {
+
+        r->headers_out.location = ngx_list_push(&r->headers_out.headers);
+        if (r->headers_out.location == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        r->headers_out.location->hash = 1;
+        ngx_str_set(&r->headers_out.location->key, "Location");
+        r->headers_out.location->value = val;
+
+        return status;
+    }
+
+    r->headers_out.content_length_n = val.len;
+
+    if (ct) {
+        r->headers_out.content_type_len = ct->len;
+        r->headers_out.content_type = *ct;
+
+    } else {
+        if (ngx_http_set_content_type(r) != NGX_OK) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    if (r->method == NGX_HTTP_HEAD || (r != r->main && val.len == 0)) {
+        return ngx_http_send_header(r);
+    }
+
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    if (b == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    b->pos = val.data;
+    b->last = val.data + val.len;
+    b->memory = val.len ? 1 : 0;
+    b->last_buf = (r == r->main) ? 1 : 0;
+    b->last_in_chain = 1;
+
+    out.buf = b;
+    out.next = NULL;
+
+    rc = ngx_http_send_header(r);
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
+    }
+
+    return ngx_http_output_filter(r, &out);
+}
+
+
+ngx_int_t
 ngx_http_send_header(ngx_http_request_t *r)
 {
     if (r->err_status) {
@@ -1738,7 +1869,7 @@ ngx_http_map_uri_to_path(ngx_http_reques
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    alias = clcf->alias ? clcf->name.len : 0;
+    alias = clcf->alias;
 
     if (alias && !r->valid_location) {
         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
@@ -1765,8 +1896,10 @@ ngx_http_map_uri_to_path(ngx_http_reques
 #if (NGX_PCRE)
         ngx_uint_t  captures;
 
-        captures = alias && clcf->captures;
-        reserved += captures ? 1 : r->uri.len - alias + 1;
+        captures = alias && clcf->regex;
+
+        reserved += captures ? r->add_uri_to_alias ? r->uri.len + 1 : 1
+                             : r->uri.len - alias + 1;
 #else
         reserved += r->uri.len - alias + 1;
 #endif
@@ -1787,8 +1920,12 @@ ngx_http_map_uri_to_path(ngx_http_reques
 
 #if (NGX_PCRE)
         if (captures) {
-            *last = '\0';
-            return last;
+            if (!r->add_uri_to_alias) {
+                *last = '\0';
+                return last;
+            }
+
+            alias = 0;
         }
 #endif
     }
@@ -1882,15 +2019,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
     ngx_table_elt_t           *e, *d;
     ngx_http_core_loc_conf_t  *clcf;
 
-    if (r->gzip == 1) {
-        return NGX_OK;
-    }
-
-    if (r->gzip == 2) {
-        return NGX_DECLINED;
-    }
-
-    r->gzip = 2;
+    r->gzip_tested = 1;
 
     if (r != r->main
         || r->headers_in.accept_encoding == NULL
@@ -2025,7 +2154,7 @@ ok:
 
 #endif
 
-    r->gzip = 1;
+    r->gzip_ok = 1;
 
     return NGX_OK;
 }
@@ -2038,6 +2167,7 @@ ngx_http_subrequest(ngx_http_request_t *
     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
     ngx_http_post_subrequest_t *ps, ngx_uint_t flags)
 {
+    ngx_time_t                    *tp;
     ngx_connection_t              *c;
     ngx_http_request_t            *sr;
     ngx_http_core_srv_conf_t      *cscf;
@@ -2102,7 +2232,6 @@ ngx_http_subrequest(ngx_http_request_t *
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http subrequest \"%V?%V\"", uri, &sr->args);
 
-    sr->zero_in_uri = (flags & NGX_HTTP_ZERO_IN_URI) != 0;
     sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;
     sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;
 
@@ -2151,6 +2280,10 @@ ngx_http_subrequest(ngx_http_request_t *
 
     sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
 
+    tp = ngx_timeofday();
+    r->start_sec = tp->sec;
+    r->start_msec = tp->msec;
+
     r->main->subrequests++;
     r->main->count++;
 
@@ -2184,8 +2317,7 @@ ngx_http_internal_redirect(ngx_http_requ
         r->args = *args;
 
     } else {
-        r->args.len = 0;
-        r->args.data = NULL;
+        ngx_str_null(&r->args);
     }
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -2206,6 +2338,7 @@ ngx_http_internal_redirect(ngx_http_requ
 #endif
 
     r->internal = 1;
+    r->add_uri_to_alias = 0;
     r->main->count++;
 
     ngx_http_handler(r);
@@ -2309,7 +2442,9 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
     ngx_uint_t                   i;
     ngx_conf_t                   pcf;
     ngx_http_module_t           *module;
+    struct sockaddr_in          *sin;
     ngx_http_conf_ctx_t         *ctx, *http_ctx;
+    ngx_http_listen_opt_t        lsopt;
     ngx_http_core_srv_conf_t    *cscf, **cscfp;
     ngx_http_core_main_conf_t   *cmcf;
 
@@ -2388,6 +2523,37 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
 
     *cf = pcf;
 
+    if (rv == NGX_CONF_OK && !cscf->listen) {
+        ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
+
+        sin = &lsopt.u.sockaddr_in;
+
+        sin->sin_family = AF_INET;
+#if (NGX_WIN32)
+        sin->sin_port = htons(80);
+#else
+        sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
+#endif
+        sin->sin_addr.s_addr = INADDR_ANY;
+
+        lsopt.socklen = sizeof(struct sockaddr_in);
+
+        lsopt.backlog = NGX_LISTEN_BACKLOG;
+        lsopt.rcvbuf = -1;
+        lsopt.sndbuf = -1;
+#if (NGX_HAVE_SETFIB)
+        lsopt.setfib = -1;
+#endif
+        lsopt.wildcard = 1;
+
+        (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,
+                             NGX_SOCKADDR_STRLEN, 1);
+
+        if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
     return rv;
 }
 
@@ -2591,26 +2757,27 @@ ngx_http_core_regex_location(ngx_conf_t 
     ngx_str_t *regex, ngx_uint_t caseless)
 {
 #if (NGX_PCRE)
-    ngx_str_t  err;
-    u_char     errstr[NGX_MAX_CONF_ERRSTR];
-
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
+    ngx_regex_compile_t  rc;
+    u_char               errstr[NGX_MAX_CONF_ERRSTR];
+
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pattern = *regex;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
 
 #if (NGX_HAVE_CASELESS_FILESYSTEM)
-    caseless = 1;
+    rc.options = NGX_REGEX_CASELESS;
+#else
+    rc.options = caseless;
 #endif
 
-    clcf->regex = ngx_regex_compile(regex, caseless ? NGX_REGEX_CASELESS: 0,
-                                    cf->pool, &err);
-
+    clcf->regex = ngx_http_regex_compile(cf, &rc);
     if (clcf->regex == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
         return NGX_ERROR;
     }
 
     clcf->name = *regex;
-    clcf->captures = (ngx_regex_capture_count(clcf->regex) > 0);
 
     return NGX_OK;
 
@@ -2628,14 +2795,14 @@ ngx_http_core_regex_location(ngx_conf_t 
 static char *
 ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     char        *rv;
     ngx_conf_t   save;
 
-    if (lcf->types == NULL) {
-        lcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
-        if (lcf->types == NULL) {
+    if (clcf->types == NULL) {
+        clcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
+        if (clcf->types == NULL) {
             return NGX_CONF_ERROR;
         }
     }
@@ -2655,7 +2822,7 @@ ngx_http_core_types(ngx_conf_t *cf, ngx_
 static char *
 ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t       *value, *content_type, *old, file;
     ngx_uint_t       i, n, hash;
@@ -2686,8 +2853,8 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c
 
         hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
 
-        type = lcf->types->elts;
-        for (n = 0; n < lcf->types->nelts; n++) {
+        type = clcf->types->elts;
+        for (n = 0; n < clcf->types->nelts; n++) {
             if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {
                 old = type[n].value;
                 type[n].value = content_type;
@@ -2702,7 +2869,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c
         }
 
 
-        type = ngx_array_push(lcf->types);
+        type = ngx_array_push(clcf->types);
         if (type == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -2778,6 +2945,10 @@ ngx_http_core_init_main_conf(ngx_conf_t 
     cmcf->variables_hash_bucket_size =
                ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
 
+    if (cmcf->ncaptures) {
+        cmcf->ncaptures = (cmcf->ncaptures + 1) * 3;
+    }
+
     return NGX_CONF_OK;
 }
 
@@ -2798,13 +2969,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t
      *     conf->client_large_buffers.num = 0;
      */
 
-    if (ngx_array_init(&cscf->listen, cf->temp_pool, 4,
-                       sizeof(ngx_http_listen_t))
-        != NGX_OK)
-    {
-        return NULL;
-    }
-
     if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
                        sizeof(ngx_http_server_name_t))
         != NGX_OK)
@@ -2830,58 +2994,11 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
     ngx_http_core_srv_conf_t *prev = parent;
     ngx_http_core_srv_conf_t *conf = child;
 
-    ngx_http_listen_t       *ls;
-    struct sockaddr_in      *sin;
+    ngx_str_t                name;
     ngx_http_server_name_t  *sn;
 
     /* TODO: it does not merge, it inits only */
 
-    if (conf->listen.nelts == 0) {
-        ls = ngx_array_push(&conf->listen);
-        if (ls == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        ngx_memzero(ls, sizeof(ngx_http_listen_t));
-
-        sin = (struct sockaddr_in *) &ls->sockaddr;
-
-        sin->sin_family = AF_INET;
-#if (NGX_WIN32)
-        sin->sin_port = htons(80);
-#else
-        sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
-#endif
-        sin->sin_addr.s_addr = INADDR_ANY;
-
-        ls->socklen = sizeof(struct sockaddr_in);
-
-        ls->conf.backlog = NGX_LISTEN_BACKLOG;
-        ls->conf.rcvbuf = -1;
-        ls->conf.sndbuf = -1;
-        ls->conf.wildcard = 1;
-
-        (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr,
-                             NGX_SOCKADDR_STRLEN, 1);
-    }
-
-    if (conf->server_name.data == NULL) {
-        conf->server_name = cf->cycle->hostname;
-
-        sn = ngx_array_push(&conf->server_names);
-        if (sn == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-#if (NGX_PCRE)
-        sn->regex = NULL;
-        sn->captures = 0;
-#endif
-        sn->core_srv_conf = conf;
-        sn->name.len = conf->server_name.len;
-        sn->name.data = conf->server_name.data;
-    }
-
     ngx_conf_merge_size_value(conf->connection_pool_size,
                               prev->connection_pool_size, 256);
     ngx_conf_merge_size_value(conf->request_pool_size,
@@ -2892,7 +3009,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
                               prev->client_header_buffer_size, 1024);
     ngx_conf_merge_bufs_value(conf->large_client_header_buffers,
                               prev->large_client_header_buffers,
-                              4, ngx_pagesize);
+                              4, 8192);
 
     if (conf->large_client_header_buffers.size < conf->connection_pool_size) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -2909,6 +3026,37 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->underscores_in_headers,
                               prev->underscores_in_headers, 0);
 
+    if (conf->server_names.nelts == 0) {
+        /* the array has 4 empty preallocated elements, so push can not fail */
+        sn = ngx_array_push(&conf->server_names);
+#if (NGX_PCRE)
+        sn->regex = NULL;
+#endif
+        sn->server = conf;
+        ngx_str_set(&sn->name, "");
+    }
+
+    sn = conf->server_names.elts;
+    name = sn[0].name;
+
+#if (NGX_PCRE)
+    if (sn->regex) {
+        name.len++;
+        name.data--;
+    } else
+#endif
+
+    if (name.data[0] == '.') {
+        name.len--;
+        name.data++;
+    }
+
+    conf->server_name.len = name.len;
+    conf->server_name.data = ngx_pstrdup(cf->pool, &name);
+    if (conf->server_name.data == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
     return NGX_CONF_OK;
 }
 
@@ -2916,88 +3064,94 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
 static void *
 ngx_http_core_create_loc_conf(ngx_conf_t *cf)
 {
-    ngx_http_core_loc_conf_t  *lcf;
-
-    lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
-    if (lcf == NULL) {
+    ngx_http_core_loc_conf_t  *clcf;
+
+    clcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
+    if (clcf == NULL) {
         return NULL;
     }
 
     /*
      * set by ngx_pcalloc():
      *
-     *     lcf->root = { 0, NULL };
-     *     lcf->limit_except = 0;
-     *     lcf->post_action = { 0, NULL };
-     *     lcf->types = NULL;
-     *     lcf->default_type = { 0, NULL };
-     *     lcf->error_log = NULL;
-     *     lcf->error_pages = NULL;
-     *     lcf->try_files = NULL;
-     *     lcf->client_body_path = NULL;
-     *     lcf->regex = NULL;
-     *     lcf->exact_match = 0;
-     *     lcf->auto_redirect = 0;
-     *     lcf->alias = 0;
-     *     lcf->gzip_proxied = 0;
+     *     clcf->root = { 0, NULL };
+     *     clcf->limit_except = 0;
+     *     clcf->post_action = { 0, NULL };
+     *     clcf->types = NULL;
+     *     clcf->default_type = { 0, NULL };
+     *     clcf->error_log = NULL;
+     *     clcf->error_pages = NULL;
+     *     clcf->try_files = NULL;
+     *     clcf->client_body_path = NULL;
+     *     clcf->regex = NULL;
+     *     clcf->exact_match = 0;
+     *     clcf->auto_redirect = 0;
+     *     clcf->alias = 0;
+     *     clcf->gzip_proxied = 0;
      */
 
-    lcf->client_max_body_size = NGX_CONF_UNSET;
-    lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
-    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->sendfile = NGX_CONF_UNSET;
-    lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
+    clcf->client_max_body_size = NGX_CONF_UNSET;
+    clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
+    clcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->keepalive_disable = NGX_CONF_UNSET_UINT;
+    clcf->satisfy = NGX_CONF_UNSET_UINT;
+    clcf->if_modified_since = NGX_CONF_UNSET_UINT;
+    clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
+    clcf->client_body_in_single_buffer = NGX_CONF_UNSET;
+    clcf->internal = NGX_CONF_UNSET;
+    clcf->sendfile = NGX_CONF_UNSET;
+    clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
 #if (NGX_HAVE_FILE_AIO)
-    lcf->aio = NGX_CONF_UNSET;
+    clcf->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;
-    lcf->reset_timedout_connection = NGX_CONF_UNSET;
-    lcf->server_name_in_redirect = NGX_CONF_UNSET;
-    lcf->port_in_redirect = NGX_CONF_UNSET;
-    lcf->msie_padding = NGX_CONF_UNSET;
-    lcf->msie_refresh = NGX_CONF_UNSET;
-    lcf->log_not_found = NGX_CONF_UNSET;
-    lcf->log_subrequest = NGX_CONF_UNSET;
-    lcf->recursive_error_pages = NGX_CONF_UNSET;
-    lcf->server_tokens = NGX_CONF_UNSET;
-    lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
-    lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
-
-    lcf->open_file_cache = NGX_CONF_UNSET_PTR;
-    lcf->open_file_cache_valid = NGX_CONF_UNSET;
-    lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
-    lcf->open_file_cache_errors = NGX_CONF_UNSET;
-    lcf->open_file_cache_events = NGX_CONF_UNSET;
+    clcf->read_ahead = NGX_CONF_UNSET_SIZE;
+    clcf->directio = NGX_CONF_UNSET;
+    clcf->directio_alignment = NGX_CONF_UNSET;
+    clcf->tcp_nopush = NGX_CONF_UNSET;
+    clcf->tcp_nodelay = NGX_CONF_UNSET;
+    clcf->send_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->send_lowat = NGX_CONF_UNSET_SIZE;
+    clcf->postpone_output = NGX_CONF_UNSET_SIZE;
+    clcf->limit_rate = NGX_CONF_UNSET_SIZE;
+    clcf->limit_rate_after = NGX_CONF_UNSET_SIZE;
+    clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->keepalive_header = NGX_CONF_UNSET;
+    clcf->keepalive_requests = NGX_CONF_UNSET_UINT;
+    clcf->lingering_time = NGX_CONF_UNSET_MSEC;
+    clcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
+    clcf->reset_timedout_connection = NGX_CONF_UNSET;
+    clcf->server_name_in_redirect = NGX_CONF_UNSET;
+    clcf->port_in_redirect = NGX_CONF_UNSET;
+    clcf->msie_padding = NGX_CONF_UNSET;
+    clcf->msie_refresh = NGX_CONF_UNSET;
+    clcf->log_not_found = NGX_CONF_UNSET;
+    clcf->log_subrequest = NGX_CONF_UNSET;
+    clcf->recursive_error_pages = NGX_CONF_UNSET;
+    clcf->server_tokens = NGX_CONF_UNSET;
+    clcf->chunked_transfer_encoding = NGX_CONF_UNSET;
+    clcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
+    clcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
+
+    clcf->open_file_cache = NGX_CONF_UNSET_PTR;
+    clcf->open_file_cache_valid = NGX_CONF_UNSET;
+    clcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
+    clcf->open_file_cache_errors = NGX_CONF_UNSET;
+    clcf->open_file_cache_events = NGX_CONF_UNSET;
 
 #if (NGX_HTTP_GZIP)
-    lcf->gzip_vary = NGX_CONF_UNSET;
-    lcf->gzip_http_version = NGX_CONF_UNSET_UINT;
+    clcf->gzip_vary = NGX_CONF_UNSET;
+    clcf->gzip_http_version = NGX_CONF_UNSET_UINT;
 #if (NGX_PCRE)
-    lcf->gzip_disable = NGX_CONF_UNSET_PTR;
-    lcf->gzip_disable_msie6 = 3;
+    clcf->gzip_disable = NGX_CONF_UNSET_PTR;
+#endif
+    clcf->gzip_disable_msie6 = 3;
+#if (NGX_HTTP_DEGRADATION)
+    clcf->gzip_disable_degradation = 3;
 #endif
 #endif
 
-    return lcf;
+    return clcf;
 }
 
 
@@ -3031,8 +3185,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
         conf->root_values = prev->root_values;
 
         if (prev->root.data == NULL) {
-            conf->root.len = sizeof("html") - 1;
-            conf->root.data = (u_char *) "html";
+            ngx_str_set(&conf->root, "html");
 
             if (ngx_conf_full_name(cf->cycle, &conf->root, 0) != NGX_OK) {
                 return NGX_CONF_ERROR;
@@ -3141,6 +3294,9 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_msec_value(conf->client_body_timeout,
                               prev->client_body_timeout, 60000);
 
+    ngx_conf_merge_uint_value(conf->keepalive_disable, prev->keepalive_disable,
+                              NGX_HTTP_KEEPALIVE_DISABLE_MSIE6
+                              |NGX_HTTP_KEEPALIVE_DISABLE_SAFARI);
     ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
                               NGX_HTTP_SATISFY_ALL);
     ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
@@ -3156,6 +3312,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
 #if (NGX_HAVE_FILE_AIO)
     ngx_conf_merge_value(conf->aio, prev->aio, 0);
 #endif
+    ngx_conf_merge_size_value(conf->read_ahead, prev->read_ahead, 0);
     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,
@@ -3212,7 +3369,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->reset_timedout_connection,
                               prev->reset_timedout_connection, 0);
     ngx_conf_merge_value(conf->server_name_in_redirect,
-                              prev->server_name_in_redirect, 1);
+                              prev->server_name_in_redirect, 0);
     ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 1);
     ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
     ngx_conf_merge_value(conf->msie_refresh, prev->msie_refresh, 0);
@@ -3221,6 +3378,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->recursive_error_pages,
                               prev->recursive_error_pages, 0);
     ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1);
+    ngx_conf_merge_value(conf->chunked_transfer_encoding,
+                              prev->chunked_transfer_encoding, 1);
 
     ngx_conf_merge_ptr_value(conf->open_file_cache,
                               prev->open_file_cache, NULL);
@@ -3253,6 +3412,15 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
             (prev->gzip_disable_msie6 == 3) ? 0 : prev->gzip_disable_msie6;
     }
 
+#if (NGX_HTTP_DEGRADATION)
+
+    if (conf->gzip_disable_degradation == 3) {
+        conf->gzip_disable_degradation =
+            (prev->gzip_disable_degradation == 3) ?
+                 0 : prev->gzip_disable_degradation;
+    }
+
+#endif
 #endif
 
     return NGX_CONF_OK;
@@ -3262,17 +3430,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
 static char *
 ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_srv_conf_t *scf = conf;
-
-    ngx_str_t          *value, size;
-    ngx_url_t           u;
-    ngx_uint_t          n;
-    ngx_http_listen_t  *ls;
-
-    /*
-     * TODO: check duplicate 'listen' directives,
-     *       add resolved name to server names ???
-     */
+    ngx_http_core_srv_conf_t *cscf = conf;
+
+    ngx_str_t              *value, size;
+    ngx_url_t               u;
+    ngx_uint_t              n;
+    ngx_http_listen_opt_t   lsopt;
+
+    cscf->listen = 1;
 
     value = cf->args->elts;
 
@@ -3292,58 +3457,56 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    ls = ngx_array_push(&scf->listen);
-    if (ls == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memzero(ls, sizeof(ngx_http_listen_t));
-
-    ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);
-
-    ls->socklen = u.socklen;
-    ls->file_name = cf->conf_file->file.name.data;
-    ls->line = cf->conf_file->line;
-    ls->conf.backlog = NGX_LISTEN_BACKLOG;
-    ls->conf.rcvbuf = -1;
-    ls->conf.sndbuf = -1;
-    ls->conf.wildcard = u.wildcard;
-
-    (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr,
+    ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
+
+    ngx_memcpy(&lsopt.u.sockaddr, u.sockaddr, u.socklen);
+
+    lsopt.socklen = u.socklen;
+    lsopt.backlog = NGX_LISTEN_BACKLOG;
+    lsopt.rcvbuf = -1;
+    lsopt.sndbuf = -1;
+#if (NGX_HAVE_SETFIB)
+    lsopt.setfib = -1;
+#endif
+    lsopt.wildcard = u.wildcard;
+
+    (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,
                          NGX_SOCKADDR_STRLEN, 1);
 
-    if (cf->args->nelts == 2) {
-        return NGX_CONF_OK;
-    }
-
-    if (ngx_strcmp(value[2].data, "default") == 0) {
-        ls->conf.default_server = 1;
-        n = 3;
-
-    } else {
-        n = 2;
-    }
-
-    for ( /* void */ ; n < cf->args->nelts; n++) {
-
-        if (ls->conf.default_server == 0) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "\"%V\" parameter can be specified for "
-                               "the default \"listen\" directive only",
-                               &value[n]);
-            return NGX_CONF_ERROR;
+    for (n = 2; n < cf->args->nelts; n++) {
+
+        if (ngx_strcmp(value[n].data, "default_server") == 0
+            || ngx_strcmp(value[n].data, "default") == 0)
+        {
+            lsopt.default_server = 1;
+            continue;
         }
 
         if (ngx_strcmp(value[n].data, "bind") == 0) {
-            ls->conf.bind = 1;
+            lsopt.set = 1;
+            lsopt.bind = 1;
             continue;
         }
 
+#if (NGX_HAVE_SETFIB)
+        if (ngx_strncmp(value[n].data, "setfib=", 7) == 0) {
+            lsopt.setfib = ngx_atoi(value[n].data + 7, value[n].len - 7);
+
+            if (lsopt.setfib == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid setfib \"%V\"", &value[n]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+#endif
         if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {
-            ls->conf.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
-            ls->conf.bind = 1;
-
-            if (ls->conf.backlog == NGX_ERROR || ls->conf.backlog == 0) {
+            lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
+            lsopt.set = 1;
+            lsopt.bind = 1;
+
+            if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "invalid backlog \"%V\"", &value[n]);
                 return NGX_CONF_ERROR;
@@ -3356,10 +3519,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             size.len = value[n].len - 7;
             size.data = value[n].data + 7;
 
-            ls->conf.rcvbuf = ngx_parse_size(&size);
-            ls->conf.bind = 1;
-
-            if (ls->conf.rcvbuf == NGX_ERROR) {
+            lsopt.rcvbuf = ngx_parse_size(&size);
+            lsopt.set = 1;
+            lsopt.bind = 1;
+
+            if (lsopt.rcvbuf == NGX_ERROR) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "invalid rcvbuf \"%V\"", &value[n]);
                 return NGX_CONF_ERROR;
@@ -3372,10 +3536,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             size.len = value[n].len - 7;
             size.data = value[n].data + 7;
 
-            ls->conf.sndbuf = ngx_parse_size(&size);
-            ls->conf.bind = 1;
-
-            if (ls->conf.sndbuf == NGX_ERROR) {
+            lsopt.sndbuf = ngx_parse_size(&size);
+            lsopt.set = 1;
+            lsopt.bind = 1;
+
+            if (lsopt.sndbuf == NGX_ERROR) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "invalid sndbuf \"%V\"", &value[n]);
                 return NGX_CONF_ERROR;
@@ -3386,8 +3551,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strncmp(value[n].data, "accept_filter=", 14) == 0) {
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-            ls->conf.accept_filter = (char *) &value[n].data[14];
-            ls->conf.bind = 1;
+            lsopt.accept_filter = (char *) &value[n].data[14];
+            lsopt.set = 1;
+            lsopt.bind = 1;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "accept filters \"%V\" are not supported "
@@ -3399,8 +3565,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strcmp(value[n].data, "deferred") == 0) {
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-            ls->conf.deferred_accept = 1;
-            ls->conf.bind = 1;
+            lsopt.deferred_accept = 1;
+            lsopt.set = 1;
+            lsopt.bind = 1;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "the deferred accept is not supported "
@@ -3413,15 +3580,15 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
             struct sockaddr  *sa;
 
-            sa = (struct sockaddr *) ls->sockaddr;
+            sa = &lsopt.u.sockaddr;
 
             if (sa->sa_family == AF_INET6) {
 
                 if (ngx_strcmp(&value[n].data[10], "n") == 0) {
-                    ls->conf.ipv6only = 1;
+                    lsopt.ipv6only = 1;
 
                 } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) {
-                    ls->conf.ipv6only = 2;
+                    lsopt.ipv6only = 2;
 
                 } else {
                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3430,13 +3597,13 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
                     return NGX_CONF_ERROR;
                 }
 
-                ls->conf.bind = 1;
+                lsopt.set = 1;
+                lsopt.bind = 1;
 
             } else {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "ipv6only is not supported "
-                                   "on addr \"%s\", ignored",
-                                   ls->conf.addr);
+                                   "on addr \"%s\", ignored", lsopt.addr);
             }
 
             continue;
@@ -3450,7 +3617,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strcmp(value[n].data, "ssl") == 0) {
 #if (NGX_HTTP_SSL)
-            ls->conf.ssl = 1;
+            lsopt.ssl = 1;
             continue;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3465,7 +3632,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    return NGX_CONF_OK;
+    if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) {
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_ERROR;
 }
 
 
@@ -3475,36 +3646,12 @@ ngx_http_core_server_name(ngx_conf_t *cf
     ngx_http_core_srv_conf_t *cscf = conf;
 
     u_char                   ch;
-    ngx_str_t               *value, name;
+    ngx_str_t               *value;
     ngx_uint_t               i;
     ngx_http_server_name_t  *sn;
 
     value = cf->args->elts;
 
-    ch = value[1].data[0];
-
-    if (cscf->server_name.data == NULL) {
-        if (value[1].len) {
-            name = value[1];
-
-            if (ch == '.') {
-                name.len--;
-                name.data++;
-            }
-
-            cscf->server_name.len = name.len;
-            cscf->server_name.data = ngx_pstrdup(cf->pool, &name);
-            if (cscf->server_name.data == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-        } else {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "the first server name must not be empty");
-            return NGX_CONF_ERROR;
-        }
-    }
-
     for (i = 1; i < cf->args->nelts; i++) {
 
         ch = value[i].data[0];
@@ -3537,19 +3684,26 @@ ngx_http_core_server_name(ngx_conf_t *cf
 
 #if (NGX_PCRE)
         sn->regex = NULL;
-        sn->captures = 0;
 #endif
-        sn->core_srv_conf = cscf;
-        sn->name = value[i];
+        sn->server = cscf;
+
+        if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
+            sn->name = cf->cycle->hostname;
+
+        } else {
+            sn->name = value[i];
+        }
 
         if (value[i].data[0] != '~') {
+            ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
             continue;
         }
 
 #if (NGX_PCRE)
         {
-        ngx_str_t  err;
-        u_char     errstr[NGX_MAX_CONF_ERRSTR];
+        u_char               *p;
+        ngx_regex_compile_t   rc;
+        u_char                errstr[NGX_MAX_CONF_ERRSTR];
 
         if (value[i].len == 1) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3557,21 +3711,29 @@ ngx_http_core_server_name(ngx_conf_t *cf
             return NGX_CONF_ERROR;
         }
 
-        err.len = NGX_MAX_CONF_ERRSTR;
-        err.data = errstr;
-
         value[i].len--;
         value[i].data++;
 
-        sn->regex = ngx_regex_compile(&value[i], 0, cf->pool, &err);
-
+        ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+        rc.pattern = value[i];
+        rc.err.len = NGX_MAX_CONF_ERRSTR;
+        rc.err.data = errstr;
+
+        for (p = value[i].data; p < value[i].data + value[i].len; p++) {
+            if (*p >= 'A' && *p <= 'Z') {
+                rc.options = NGX_REGEX_CASELESS;
+                break;
+            }
+        }
+
+        sn->regex = ngx_http_regex_compile(cf, &rc);
         if (sn->regex == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
             return NGX_CONF_ERROR;
         }
 
-        sn->captures = (ngx_regex_capture_count(sn->regex) > 0);
         sn->name = value[i];
+        cscf->captures = (rc.captures > 0);
         }
 #else
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3589,19 +3751,18 @@ ngx_http_core_server_name(ngx_conf_t *cf
 static char *
 ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t                  *value;
-    ngx_uint_t                  alias, n;
+    ngx_int_t                   alias;
+    ngx_uint_t                  n;
     ngx_http_script_compile_t   sc;
 
     alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0;
 
-    if (lcf->root.data) {
-
-        /* the (ngx_uint_t) cast is required by gcc 2.7.2.3 */
-
-        if ((ngx_uint_t) lcf->alias == alias) {
+    if (clcf->root.data) {
+
+        if ((clcf->alias != 0) == alias) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"%V\" directive is duplicate",
                                &cmd->name);
@@ -3609,13 +3770,13 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"%V\" directive is duplicate, "
                                "\"%s\" directive is specified before",
-                               &cmd->name, lcf->alias ? "alias" : "root");
+                               &cmd->name, clcf->alias ? "alias" : "root");
         }
 
         return NGX_CONF_ERROR;
     }
 
-    if (lcf->named && alias) {
+    if (clcf->named && alias) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "the \"alias\" directive may not be used "
                            "inside named location");
@@ -3647,29 +3808,35 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
-    lcf->alias = alias;
-    lcf->root = value[1];
-
-    if (!alias && lcf->root.data[lcf->root.len - 1] == '/') {
-        lcf->root.len--;
+    clcf->alias = alias ? clcf->name.len : 0;
+    clcf->root = value[1];
+
+    if (!alias && clcf->root.data[clcf->root.len - 1] == '/') {
+        clcf->root.len--;
     }
 
-    if (lcf->root.data[0] != '$') {
-        if (ngx_conf_full_name(cf->cycle, &lcf->root, 0) != NGX_OK) {
+    if (clcf->root.data[0] != '$') {
+        if (ngx_conf_full_name(cf->cycle, &clcf->root, 0) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
     }
 
-    n = ngx_http_script_variables_count(&lcf->root);
+    n = ngx_http_script_variables_count(&clcf->root);
 
     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+    sc.variables = n;
+
+#if (NGX_PCRE)
+    if (alias && clcf->regex) {
+        n = 1;
+    }
+#endif
 
     if (n) {
         sc.cf = cf;
-        sc.source = &lcf->root;
-        sc.lengths = &lcf->root_lengths;
-        sc.values = &lcf->root_values;
-        sc.variables = n;
+        sc.source = &clcf->root;
+        sc.lengths = &clcf->root_lengths;
+        sc.values = &clcf->root_values;
         sc.complete_lengths = 1;
         sc.complete_values = 1;
 
@@ -3678,20 +3845,6 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         }
     }
 
-#if (NGX_PCRE)
-
-    if (alias && lcf->regex
-        && (ngx_regex_capture_count(lcf->regex) <= 0 || sc.ncaptures == 0))
-    {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "the \"alias\" directive must use captures "
-                           "inside location given by regular expression");
-
-        return NGX_CONF_ERROR;
-    }
-
-#endif
-
     return NGX_CONF_OK;
 }
 
@@ -3710,6 +3863,7 @@ static ngx_http_method_name_t  ngx_metho
    { (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH },
    { (u_char *) "LOCK",      (uint32_t) ~NGX_HTTP_LOCK },
    { (u_char *) "UNLOCK",    (uint32_t) ~NGX_HTTP_UNLOCK },
+   { (u_char *) "PATCH",     (uint32_t) ~NGX_HTTP_PATCH },
    { NULL, 0 }
 };
 
@@ -3796,6 +3950,7 @@ ngx_http_core_limit_except(ngx_conf_t *c
     clcf->loc_conf = ctx->loc_conf;
     clcf->name = pclcf->name;
     clcf->noname = 1;
+    clcf->lmt_excpt = 1;
 
     if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
         return NGX_CONF_ERROR;
@@ -3843,7 +3998,7 @@ ngx_http_core_directio(ngx_conf_t *cf, n
 static char *
 ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     u_char                            *p;
     ngx_int_t                          overwrite;
@@ -3853,10 +4008,10 @@ ngx_http_core_error_page(ngx_conf_t *cf,
     ngx_http_complex_value_t           cv;
     ngx_http_compile_complex_value_t   ccv;
 
-    if (lcf->error_pages == NULL) {
-        lcf->error_pages = ngx_array_create(cf->pool, 4,
-                                            sizeof(ngx_http_err_page_t));
-        if (lcf->error_pages == NULL) {
+    if (clcf->error_pages == NULL) {
+        clcf->error_pages = ngx_array_create(cf->pool, 4,
+                                             sizeof(ngx_http_err_page_t));
+        if (clcf->error_pages == NULL) {
             return NGX_CONF_ERROR;
         }
     }
@@ -3904,8 +4059,7 @@ ngx_http_core_error_page(ngx_conf_t *cf,
         return NGX_CONF_ERROR;
     }
 
-    args.len = 0;
-    args.data = NULL;
+    ngx_str_null(&args);
 
     if (cv.lengths == NULL && uri.data[0] == '/') {
         p = (u_char *) ngx_strchr(uri.data, '?');
@@ -3920,7 +4074,7 @@ ngx_http_core_error_page(ngx_conf_t *cf,
     }
 
     for (i = 1; i < cf->args->nelts - n; i++) {
-        err = ngx_array_push(lcf->error_pages);
+        err = ngx_array_push(clcf->error_pages);
         if (err == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -3933,26 +4087,22 @@ ngx_http_core_error_page(ngx_conf_t *cf,
             return NGX_CONF_ERROR;
         }
 
-        if (err->status < 400 || err->status > 599) {
+        if (err->status < 300 || err->status > 599) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "value \"%V\" must be between 400 and 599",
+                               "value \"%V\" must be between 300 and 599",
                                &value[i]);
             return NGX_CONF_ERROR;
         }
 
-        if (overwrite >= 0) {
-            err->overwrite = overwrite;
-
-        } else {
+        err->overwrite = overwrite;
+
+        if (overwrite == -1) {
             switch (err->status) {
                 case NGX_HTTP_TO_HTTPS:
                 case NGX_HTTPS_CERT_ERROR:
                 case NGX_HTTPS_NO_CERT:
                     err->overwrite = NGX_HTTP_BAD_REQUEST;
-                    break;
-
                 default:
-                    err->overwrite = err->status;
                     break;
             }
         }
@@ -4048,14 +4198,14 @@ ngx_http_core_try_files(ngx_conf_t *cf, 
 static char *
 ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     time_t       inactive;
     ngx_str_t   *value, s;
     ngx_int_t    max;
     ngx_uint_t   i;
 
-    if (lcf->open_file_cache != NGX_CONF_UNSET_PTR) {
+    if (clcf->open_file_cache != NGX_CONF_UNSET_PTR) {
         return "is duplicate";
     }
 
@@ -4091,7 +4241,7 @@ ngx_http_core_open_file_cache(ngx_conf_t
 
         if (ngx_strcmp(value[i].data, "off") == 0) {
 
-            lcf->open_file_cache = NULL;
+            clcf->open_file_cache = NULL;
 
             continue;
         }
@@ -4104,7 +4254,7 @@ ngx_http_core_open_file_cache(ngx_conf_t
         return NGX_CONF_ERROR;
     }
 
-    if (lcf->open_file_cache == NULL) {
+    if (clcf->open_file_cache == NULL) {
         return NGX_CONF_OK;
     }
 
@@ -4114,8 +4264,8 @@ ngx_http_core_open_file_cache(ngx_conf_t
         return NGX_CONF_ERROR;
     }
 
-    lcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
-    if (lcf->open_file_cache) {
+    clcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
+    if (clcf->open_file_cache) {
         return NGX_CONF_OK;
     }
 
@@ -4126,50 +4276,50 @@ ngx_http_core_open_file_cache(ngx_conf_t
 static char *
 ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t  *value;
 
-    if (lcf->error_log) {
+    if (clcf->error_log) {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    lcf->error_log = ngx_log_create(cf->cycle, &value[1]);
-    if (lcf->error_log == NULL) {
+    clcf->error_log = ngx_log_create(cf->cycle, &value[1]);
+    if (clcf->error_log == NULL) {
         return NGX_CONF_ERROR;
     }
 
     if (cf->args->nelts == 2) {
-        lcf->error_log->log_level = NGX_LOG_ERR;
+        clcf->error_log->log_level = NGX_LOG_ERR;
         return NGX_CONF_OK;
     }
 
-    return ngx_log_set_levels(cf, lcf->error_log);
+    return ngx_log_set_levels(cf, clcf->error_log);
 }
 
 
 static char *
 ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
+    ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t  *value;
 
-    if (lcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) {
+    if (clcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) {
         return "is duplicate";
     }
 
     value = cf->args->elts;
 
-    lcf->keepalive_timeout = ngx_parse_time(&value[1], 0);
-
-    if (lcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) {
+    clcf->keepalive_timeout = ngx_parse_time(&value[1], 0);
+
+    if (clcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) {
         return "invalid value";
     }
 
-    if (lcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
+    if (clcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
         return "value must be less than 597 hours";
     }
 
@@ -4177,13 +4327,13 @@ ngx_http_core_keepalive(ngx_conf_t *cf, 
         return NGX_CONF_OK;
     }
 
-    lcf->keepalive_header = ngx_parse_time(&value[2], 1);
-
-    if (lcf->keepalive_header == NGX_ERROR) {
+    clcf->keepalive_header = ngx_parse_time(&value[2], 1);
+
+    if (clcf->keepalive_header == NGX_ERROR) {
         return "invalid value";
     }
 
-    if (lcf->keepalive_header == NGX_PARSE_LARGE_TIME) {
+    if (clcf->keepalive_header == NGX_PARSE_LARGE_TIME) {
         return "value must be less than 68 years";
     }
 
@@ -4194,13 +4344,13 @@ ngx_http_core_keepalive(ngx_conf_t *cf, 
 static char *
 ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *lcf = conf;
-
-    if (lcf->internal != NGX_CONF_UNSET) {
+    ngx_http_core_loc_conf_t *clcf = conf;
+
+    if (clcf->internal != NGX_CONF_UNSET) {
         return "is duplicate";
     }
 
-    lcf->internal = 1;
+    clcf->internal = 1;
 
     return NGX_CONF_OK;
 }
@@ -4248,10 +4398,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
 
 #if (NGX_PCRE)
 
-    ngx_str_t         err, *value;
-    ngx_uint_t        i;
-    ngx_regex_elt_t  *re;
-    u_char            errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t            *value;
+    ngx_uint_t            i;
+    ngx_regex_elt_t      *re;
+    ngx_regex_compile_t   rc;
+    u_char                errstr[NGX_MAX_CONF_ERRSTR];
 
     if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) {
         clcf->gzip_disable = ngx_array_create(cf->pool, 2,
@@ -4263,49 +4414,77 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
 
     value = cf->args->elts;
 
-    err.len = NGX_MAX_CONF_ERRSTR;
-    err.data = errstr;
+    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+    rc.pool = cf->pool;
+    rc.err.len = NGX_MAX_CONF_ERRSTR;
+    rc.err.data = errstr;
 
     for (i = 1; i < cf->args->nelts; i++) {
 
-        if (ngx_strcmp(value[1].data, "msie6") == 0) {
+        if (ngx_strcmp(value[i].data, "msie6") == 0) {
             clcf->gzip_disable_msie6 = 1;
             continue;
         }
 
+#if (NGX_HTTP_DEGRADATION)
+
+        if (ngx_strcmp(value[i].data, "degradation") == 0) {
+            clcf->gzip_disable_degradation = 1;
+            continue;
+        }
+
+#endif
+
         re = ngx_array_push(clcf->gzip_disable);
         if (re == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool,
-                                      &err);
-
-        if (re->regex == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+        rc.pattern = value[i];
+        rc.options = NGX_REGEX_CASELESS;
+
+        if (ngx_regex_compile(&rc) != NGX_OK) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
             return NGX_CONF_ERROR;
         }
 
+        re->regex = rc.regex;
         re->name = value[i].data;
     }
 
     return NGX_CONF_OK;
 
 #else
-    ngx_str_t  *value;
+    ngx_str_t   *value;
+    ngx_uint_t   i;
 
     value = cf->args->elts;
 
-    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "msie6") == 0) {
-        clcf->gzip_disable_msie6 = 1;
-        return NGX_CONF_OK;
+    for (i = 1; i < cf->args->nelts; i++) {
+        if (ngx_strcmp(value[i].data, "msie6") == 0) {
+            clcf->gzip_disable_msie6 = 1;
+            continue;
+        }
+
+#if (NGX_HTTP_DEGRADATION)
+
+        if (ngx_strcmp(value[i].data, "degradation") == 0) {
+            clcf->gzip_disable_degradation = 1;
+            continue;
+        }
+
+#endif
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "without PCRE library \"gzip_disable\" supports "
+                           "builtin \"msie6\" and \"degradation\" mask only");
+
+        return NGX_CONF_ERROR;
     }
 
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "without PCRE library \"gzip_disable\" supports "
-                       "builtin \"msie6\" mask only");
-
-    return NGX_CONF_ERROR;
+    return NGX_CONF_OK;
+
 #endif
 }
 
@@ -4348,8 +4527,15 @@ ngx_http_core_pool_size(ngx_conf_t *cf, 
 
     if (*sp < NGX_MIN_POOL_SIZE) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "pool must be no less than %uz", NGX_MIN_POOL_SIZE);
-
+                           "the pool size must be no less than %uz",
+                           NGX_MIN_POOL_SIZE);
+        return NGX_CONF_ERROR;
+    }
+
+    if (*sp % NGX_POOL_ALIGNMENT) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the pool size must be a multiple of %uz",
+                           NGX_POOL_ALIGNMENT);
         return NGX_CONF_ERROR;
     }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -38,11 +38,31 @@
 #define NGX_HTTP_IMS_BEFORE             2
 
 
+#define NGX_HTTP_KEEPALIVE_DISABLE_NONE    0x0002
+#define NGX_HTTP_KEEPALIVE_DISABLE_MSIE6   0x0004
+#define NGX_HTTP_KEEPALIVE_DISABLE_SAFARI  0x0008
+
+
 typedef struct ngx_http_location_tree_node_s  ngx_http_location_tree_node_t;
 typedef struct ngx_http_core_loc_conf_s  ngx_http_core_loc_conf_t;
 
 
 typedef struct {
+    union {
+        struct sockaddr        sockaddr;
+        struct sockaddr_in     sockaddr_in;
+#if (NGX_HAVE_INET6)
+        struct sockaddr_in6    sockaddr_in6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+        struct sockaddr_un     sockaddr_un;
+#endif
+        u_char                 sockaddr_data[NGX_SOCKADDRLEN];
+    } u;
+
+    socklen_t                  socklen;
+
+    unsigned                   set:1;
     unsigned                   default_server:1;
     unsigned                   bind:1;
     unsigned                   wildcard:1;
@@ -56,6 +76,9 @@ typedef struct {
     int                        backlog;
     int                        rcvbuf;
     int                        sndbuf;
+#if (NGX_HAVE_SETFIB)
+    int                        setfib;
+#endif
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
     char                      *accept_filter;
@@ -65,18 +88,7 @@ typedef struct {
 #endif
 
     u_char                     addr[NGX_SOCKADDR_STRLEN + 1];
-} ngx_http_listen_conf_t;
-
-
-typedef struct {
-    u_char                     sockaddr[NGX_SOCKADDRLEN];
-    socklen_t                  socklen;
-
-    u_char                    *file_name;
-    ngx_uint_t                 line;
-
-    ngx_http_listen_conf_t     conf;
-} ngx_http_listen_t;
+} ngx_http_listen_opt_t;
 
 
 typedef enum {
@@ -133,6 +145,7 @@ typedef struct {
     ngx_hash_t                 variables_hash;
 
     ngx_array_t                variables;       /* ngx_http_variable_t */
+    ngx_uint_t                 ncaptures;
 
     ngx_uint_t                 server_names_hash_max_size;
     ngx_uint_t                 server_names_hash_bucket_size;
@@ -142,6 +155,8 @@ typedef struct {
 
     ngx_hash_keys_arrays_t    *variables_keys;
 
+    ngx_array_t               *ports;
+
     ngx_uint_t                 try_files;       /* unsigned  try_files:1 */
 
     ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
@@ -149,9 +164,6 @@ typedef struct {
 
 
 typedef struct {
-    /* array of the ngx_http_listen_t, "listen" directive */
-    ngx_array_t                 listen;
-
     /* array of the ngx_http_server_name_t, "server_name" directive */
     ngx_array_t                 server_names;
 
@@ -172,6 +184,11 @@ typedef struct {
     ngx_flag_t                  merge_slashes;
     ngx_flag_t                  underscores_in_headers;
 
+    unsigned                    listen:1;
+#if (NGX_PCRE)
+    unsigned                    captures:1;
+#endif
+
     ngx_http_core_loc_conf_t  **named_locations;
 } ngx_http_core_srv_conf_t;
 
@@ -181,7 +198,7 @@ typedef struct {
 
 typedef struct {
     /* the default server configuration for this address:port */
-    ngx_http_core_srv_conf_t  *core_srv_conf;
+    ngx_http_core_srv_conf_t  *default_server;
 
     ngx_http_virtual_names_t  *virtual_names;
 
@@ -222,40 +239,28 @@ typedef struct {
 
 
 typedef struct {
-    struct sockaddr           *sockaddr;
-    socklen_t                  socklen;
+    ngx_http_listen_opt_t      opt;
 
     ngx_hash_t                 hash;
     ngx_hash_wildcard_t       *wc_head;
     ngx_hash_wildcard_t       *wc_tail;
 
-    ngx_array_t                names;      /* array of ngx_http_server_name_t */
-
 #if (NGX_PCRE)
     ngx_uint_t                 nregex;
     ngx_http_server_name_t    *regex;
 #endif
 
     /* the default server configuration for this address:port */
-    ngx_http_core_srv_conf_t  *core_srv_conf;
-
-    unsigned                   default_server:1;
-    unsigned                   bind:1;
-    unsigned                   wildcard:1;
-#if (NGX_HTTP_SSL)
-    unsigned                   ssl:1;
-#endif
-
-    ngx_http_listen_conf_t    *listen_conf;
+    ngx_http_core_srv_conf_t  *default_server;
+    ngx_array_t                servers;  /* array of ngx_http_core_srv_conf_t */
 } ngx_http_conf_addr_t;
 
 
 struct ngx_http_server_name_s {
 #if (NGX_PCRE)
-    ngx_regex_t               *regex;
-    ngx_uint_t                 captures;      /* unsigned  captures:1; */
+    ngx_http_regex_t          *regex;
 #endif
-    ngx_http_core_srv_conf_t  *core_srv_conf; /* virtual name server conf */
+    ngx_http_core_srv_conf_t  *server;   /* virtual name server conf */
     ngx_str_t                  name;
 };
 
@@ -282,21 +287,22 @@ struct ngx_http_core_loc_conf_s {
     ngx_str_t     name;          /* location name */
 
 #if (NGX_PCRE)
-    ngx_regex_t  *regex;
-
-    unsigned      captures:1;
+    ngx_http_regex_t  *regex;
 #endif
 
     unsigned      noname:1;   /* "if () {}" block or limit_except */
+    unsigned      lmt_excpt:1;
     unsigned      named:1;
 
     unsigned      exact_match:1;
     unsigned      noregex:1;
 
     unsigned      auto_redirect:1;
-    unsigned      alias:1;
 #if (NGX_HTTP_GZIP)
     unsigned      gzip_disable_msie6:2;
+#if (NGX_HTTP_DEGRADATION)
+    unsigned      gzip_disable_degradation:2;
+#endif
 #endif
 
     ngx_http_location_tree_node_t   *static_locations;
@@ -312,6 +318,8 @@ struct ngx_http_core_loc_conf_s {
 
     ngx_http_handler_pt  handler;
 
+    /* location name length for inclusive location with inherited alias */
+    size_t        alias;
     ngx_str_t     root;                    /* root, alias */
     ngx_str_t     post_action;
 
@@ -332,6 +340,7 @@ struct ngx_http_core_loc_conf_s {
     size_t        limit_rate;              /* limit_rate */
     size_t        limit_rate_after;        /* limit_rate_after */
     size_t        sendfile_max_chunk;      /* sendfile_max_chunk */
+    size_t        read_ahead;              /* read_ahead */
 
     ngx_msec_t    client_body_timeout;     /* client_body_timeout */
     ngx_msec_t    send_timeout;            /* send_timeout */
@@ -345,6 +354,7 @@ struct ngx_http_core_loc_conf_s {
     time_t        keepalive_header;        /* keepalive_timeout */
 
     ngx_uint_t    keepalive_requests;      /* keepalive_requests */
+    ngx_uint_t    keepalive_disable;       /* keepalive_disable */
     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 */
@@ -367,6 +377,7 @@ struct ngx_http_core_loc_conf_s {
     ngx_flag_t    log_subrequest;          /* log_subrequest */
     ngx_flag_t    recursive_error_pages;   /* recursive_error_pages */
     ngx_flag_t    server_tokens;           /* server_tokens */
+    ngx_flag_t    chunked_transfer_encoding; /* chunked_transfer_encoding */
 
 #if (NGX_HTTP_GZIP)
     ngx_flag_t    gzip_vary;               /* gzip_vary */
@@ -431,6 +442,8 @@ struct ngx_http_location_tree_node_s {
 void ngx_http_core_run_phases(ngx_http_request_t *r);
 ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph);
+ngx_int_t ngx_http_core_rewrite_phase(ngx_http_request_t *r,
+    ngx_http_phase_handler_t *ph);
 ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph);
 ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
@@ -448,6 +461,8 @@ 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);
 void ngx_http_set_exten(ngx_http_request_t *r);
+ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
+    ngx_str_t *ct, ngx_http_complex_value_t *cv);
 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);
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -12,11 +12,15 @@
 
 static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
     ngx_http_cache_t *c);
+static ssize_t ngx_http_file_cache_aio_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_int_t ngx_http_file_cache_name(ngx_http_request_t *r,
+    ngx_path_t *path);
 static ngx_http_file_cache_node_t *
     ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
@@ -42,6 +46,7 @@ static ngx_int_t ngx_http_file_cache_del
 
 ngx_str_t  ngx_http_cache_status[] = {
     ngx_string("MISS"),
+    ngx_string("BYPASS"),
     ngx_string("EXPIRED"),
     ngx_string("STALE"),
     ngx_string("UPDATING"),
@@ -140,6 +145,60 @@ ngx_http_file_cache_init(ngx_shm_zone_t 
 }
 
 
+ngx_int_t
+ngx_http_file_cache_new(ngx_http_request_t *r)
+{
+    ngx_http_cache_t  *c;
+
+    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;
+    c->file.fd = NGX_INVALID_FILE;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_file_cache_create(ngx_http_request_t *r)
+{
+    ngx_http_cache_t       *c;
+    ngx_pool_cleanup_t     *cln;
+    ngx_http_file_cache_t  *cache;
+
+    ngx_http_file_cache_create_key(r);
+
+    c = r->cache;
+    cache = c->file_cache;
+
+    cln = ngx_pool_cleanup_add(r->pool, 0);
+    if (cln == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
+        return NGX_ERROR;
+    }
+
+    cln->handler = ngx_http_file_cache_cleanup;
+    cln->data = c;
+
+    if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
 void
 ngx_http_file_cache_create_key(ngx_http_request_t *r)
 {
@@ -178,10 +237,8 @@ ngx_http_file_cache_create_key(ngx_http_
 ngx_int_t
 ngx_http_file_cache_open(ngx_http_request_t *r)
 {
-    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;
@@ -247,27 +304,10 @@ ngx_http_file_cache_open(ngx_http_reques
         }
     }
 
-    path = cache->path;
-
-    c->file.name.len = path->name.len + 1 + path->len
-                       + 2 * NGX_HTTP_CACHE_KEY_LEN;
-
-    c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
-    if (c->file.name.data == NULL) {
+    if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
         return NGX_ERROR;
     }
 
-    ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
-
-    p = c->file.name.data + path->name.len + 1 + path->len;
-    p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
-    *p = '\0';
-
-    ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
-                   "cache file: \"%s\"", c->file.name.data);
-
     if (!test) {
         return NGX_DECLINED;
     }
@@ -281,6 +321,7 @@ ngx_http_file_cache_open(ngx_http_reques
     of.min_uses = clcf->open_file_cache_min_uses;
     of.events = clcf->open_file_cache_events;
     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
+    of.read_ahead = clcf->read_ahead;
 
     if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
         != NGX_OK)
@@ -327,42 +368,13 @@ ngx_http_file_cache_read(ngx_http_reques
     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;
+    n = ngx_http_file_cache_aio_read(r, c);
 
-            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) {
+    if (n < 0) {
         return n;
     }
 
-    if ((size_t) n <= c->header_start) {
+    if ((size_t) n < c->header_start) {
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
                       "cache file \"%s\" is too small", c->file.name.data);
         return NGX_ERROR;
@@ -370,7 +382,7 @@ ngx_http_file_cache_read(ngx_http_reques
 
     h = (ngx_http_file_cache_header_t *) c->buf->pos;
 
-    if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) {
+    if (h->crc32 != c->crc32) {
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
                       "cache file \"%s\" has md5 collision", c->file.name.data);
         return NGX_DECLINED;
@@ -382,6 +394,7 @@ ngx_http_file_cache_read(ngx_http_reques
     c->last_modified = h->last_modified;
     c->date = h->date;
     c->valid_msec = h->valid_msec;
+    c->header_start = h->header_start;
     c->body_start = h->body_start;
 
     r->cached = 1;
@@ -415,6 +428,7 @@ ngx_http_file_cache_read(ngx_http_reques
 
         } else {
             c->node->updating = 1;
+            c->updating = 1;
             rc = NGX_HTTP_CACHE_STALE;
         }
 
@@ -431,8 +445,46 @@ ngx_http_file_cache_read(ngx_http_reques
 }
 
 
+static ssize_t
+ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
 #if (NGX_HAVE_FILE_AIO)
+    ssize_t                    n;
+    ngx_http_core_loc_conf_t  *clcf;
 
+    if (!ngx_file_aio) {
+        goto noaio;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (!clcf->aio) {
+        goto noaio;
+    }
+
+    n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
+
+    if (n != NGX_AGAIN) {
+        return n;
+    }
+
+    c->file.aio->data = r;
+    c->file.aio->handler = ngx_http_cache_aio_event_handler;
+
+    r->main->blocked++;
+    r->aio = 1;
+
+    return NGX_AGAIN;
+
+noaio:
+
+#endif
+
+    return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
+}
+
+
+#if (NGX_HAVE_FILE_AIO)
 
 static void
 ngx_http_cache_aio_event_handler(ngx_event_t *ev)
@@ -465,6 +517,9 @@ ngx_http_file_cache_exists(ngx_http_file
     if (fcn) {
         ngx_queue_remove(&fcn->queue);
 
+        fcn->uses++;
+        fcn->count++;
+
         if (fcn->error) {
 
             if (fcn->valid_sec < ngx_time()) {
@@ -476,9 +531,6 @@ ngx_http_file_cache_exists(ngx_http_file
             goto done;
         }
 
-        fcn->uses++;
-        fcn->count++;
-
         if (fcn->exists) {
 
             c->exists = fcn->exists;
@@ -527,12 +579,15 @@ ngx_http_file_cache_exists(ngx_http_file
 
     ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
 
+    fcn->uses = 1;
+    fcn->count = 1;
+    fcn->updating = 0;
+    fcn->deleting = 0;
+
 renew:
 
     rc = NGX_DECLINED;
 
-    fcn->uses = 1;
-    fcn->count = 1;
     fcn->valid_msec = 0;
     fcn->error = 0;
     fcn->exists = 0;
@@ -559,6 +614,37 @@ failed:
 }
 
 
+static ngx_int_t
+ngx_http_file_cache_name(ngx_http_request_t *r, ngx_path_t *path)
+{
+    u_char            *p;
+    ngx_http_cache_t  *c;
+
+    c = r->cache;
+
+    c->file.name.len = path->name.len + 1 + path->len
+                       + 2 * NGX_HTTP_CACHE_KEY_LEN;
+
+    c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
+    if (c->file.name.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
+
+    p = c->file.name.data + path->name.len + 1 + path->len;
+    p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
+    *p = '\0';
+
+    ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "cache file: \"%s\"", c->file.name.data);
+
+    return NGX_OK;
+}
+
+
 static ngx_http_file_cache_node_t *
 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key)
 {
@@ -691,7 +777,7 @@ ngx_http_file_cache_set_header(ngx_http_
 void
 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
 {
-    off_t                   size;
+    off_t                   size, length;
     ngx_int_t               rc;
     ngx_file_uniq_t         uniq;
     ngx_file_info_t         fi;
@@ -709,10 +795,12 @@ ngx_http_file_cache_update(ngx_http_requ
                    "http file cache update");
 
     c->updated = 1;
+    c->updating = 0;
 
     cache = c->file_cache;
 
     uniq = 0;
+    length = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http file cache rename: \"%s\" to \"%s\"",
@@ -737,10 +825,11 @@ ngx_http_file_cache_update(ngx_http_requ
 
         } else {
             uniq = ngx_file_uniq(&fi);
+            length = ngx_file_size(&fi);
         }
     }
 
-    size = (c->length + cache->bsize - 1) / cache->bsize;
+    size = (length + cache->bsize - 1) / cache->bsize;
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -750,7 +839,7 @@ ngx_http_file_cache_update(ngx_http_requ
 
     size = size - (c->node->length + cache->bsize - 1) / cache->bsize;
 
-    c->node->length = c->length;
+    c->node->length = length;
 
     cache->sh->size += size;
 
@@ -767,7 +856,6 @@ 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;
@@ -790,21 +878,18 @@ ngx_http_cache_send(ngx_http_request_t *
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    r->header_only = (c->length - c->body_start) == 0;
+
     rc = ngx_http_send_header(r);
 
     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
         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 = size ? 1: 0;
+    b->in_file = 1;
     b->last_buf = (r == r->main) ? 1: 0;
     b->last_in_chain = 1;
 
@@ -820,46 +905,57 @@ ngx_http_cache_send(ngx_http_request_t *
 
 
 void
-ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
+ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf)
 {
-    ngx_http_cache_t       *c;
-    ngx_http_file_cache_t  *cache;
-
-    c = r->cache;
+    ngx_http_file_cache_t       *cache;
+    ngx_http_file_cache_node_t  *fcn;
 
     if (c->updated) {
         return;
     }
 
-    c->updated = 1;
-
     cache = c->file_cache;
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http file cache free");
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
+                   "http file cache free, fd: %d", c->file.fd);
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
-    c->node->count--;
+    fcn = c->node;
+    fcn->count--;
+
+    if (c->updating) {
+        fcn->updating = 0;
+    }
 
     if (c->error) {
-        c->node->valid_sec = c->valid_sec;
-        c->node->valid_msec = c->valid_msec;
-        c->node->error = c->error;
+        fcn->error = c->error;
+
+        if (c->valid_sec) {
+            fcn->valid_sec = c->valid_sec;
+            fcn->valid_msec = c->valid_msec;
+        }
+
+    } else if (!fcn->exists && fcn->count == 0 && c->min_uses == 1) {
+        ngx_queue_remove(&fcn->queue);
+        ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
+        ngx_slab_free_locked(cache->shpool, fcn);
+        c->node = NULL;
     }
 
-    c->node->updating = 0;
-
     ngx_shmtx_unlock(&cache->shpool->mutex);
 
+    c->updated = 1;
+    c->updating = 0;
+
     if (c->temp_file) {
         if (tf && tf->file.fd != NGX_INVALID_FILE) {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
                            "http file cache incomplete: \"%s\"",
                            tf->file.name.data);
 
             if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                ngx_log_error(NGX_LOG_CRIT, c->file.log, ngx_errno,
                               ngx_delete_file_n " \"%s\" failed",
                               tf->file.name.data);
             }
@@ -873,28 +969,19 @@ ngx_http_file_cache_cleanup(void *data)
 {
     ngx_http_cache_t  *c = data;
 
-    ngx_http_file_cache_t  *cache;
-
     if (c->updated) {
         return;
     }
 
-    c->updated = 1;
-
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
                    "http file cache cleanup");
 
-    if (c->error) {
-        return;
+    if (c->updating) {
+        ngx_log_error(NGX_LOG_ALERT, c->file.log, 0,
+                      "stalled cache updating, error:%ui", c->error);
     }
 
-    cache = c->file_cache;
-
-    ngx_shmtx_lock(&cache->shpool->mutex);
-
-    c->node->count--;
-
-    ngx_shmtx_unlock(&cache->shpool->mutex);
+    ngx_http_file_cache_free(c, NULL);
 }
 
 
@@ -923,7 +1010,7 @@ ngx_http_file_cache_forced_expire(ngx_ht
     ngx_memcpy(name, path->name.data, path->name.len);
 
     wait = 10;
-    tries = 0;
+    tries = 20;
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -938,28 +1025,18 @@ ngx_http_file_cache_forced_expire(ngx_ht
                   fcn->count, fcn->exists,
                   fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
 
-        if (fcn->count) {
+        if (fcn->count == 0) {
+            ngx_http_file_cache_delete(cache, q, name);
+            wait = 0;
 
-            if (tries++ < 20) {
+        } else {
+            if (--tries) {
                 continue;
             }
 
             wait = 1;
-
-            break;
         }
 
-        if (!fcn->exists) {
-
-            ngx_queue_remove(q);
-            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
-            ngx_slab_free_locked(cache->shpool, fcn);
-
-            break;
-        }
-
-        ngx_http_file_cache_delete(cache, q, name);
-
         break;
     }
 
@@ -1022,41 +1099,33 @@ ngx_http_file_cache_expire(ngx_http_file
                        fcn->count, fcn->exists,
                        fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
 
-        if (fcn->count) {
-
-            p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
-                             sizeof(ngx_rbtree_key_t));
-
-            len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
-            (void) ngx_hex_dump(p, fcn->key, len);
+        if (fcn->count == 0) {
+            ngx_http_file_cache_delete(cache, q, name);
+            continue;
+        }
 
-            /*
-             * abnormally exited workers may leave locked cache entries,
-             * and although it may be safe to remove them completely,
-             * we prefer to remove them from inactive queue and rbtree
-             * only, and to allow other leaks
-             */
-
-            ngx_queue_remove(q);
-            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",
-                       2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
-
+        if (fcn->deleting) {
             continue;
         }
 
-        if (!fcn->exists) {
+        p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
+                         sizeof(ngx_rbtree_key_t));
+        len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
+        (void) ngx_hex_dump(p, fcn->key, len);
 
-            ngx_queue_remove(q);
-            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
-            ngx_slab_free_locked(cache->shpool, fcn);
+        /*
+         * abnormally exited workers may leave locked cache entries,
+         * and although it may be safe to remove them completely,
+         * we prefer to remove them from inactive queue and rbtree
+         * only, and to allow other leaks
+         */
 
-            continue;
-        }
+        ngx_queue_remove(q);
+        ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
 
-        ngx_http_file_cache_delete(cache, q, name);
+        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+                      "ignore long locked inactive cache entry %*s, count:%d",
+                      2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
     }
 
     ngx_shmtx_unlock(&cache->shpool->mutex);
@@ -1078,39 +1147,42 @@ ngx_http_file_cache_delete(ngx_http_file
 
     fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
 
-    cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
-
-    path = cache->path;
-
-    p = name + path->name.len + 1 + path->len;
+    if (fcn->exists) {
+        cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
 
-    p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t));
+        path = cache->path;
+        p = name + path->name.len + 1 + path->len;
+        p = ngx_hex_dump(p, (u_char *) &fcn->node.key,
+                         sizeof(ngx_rbtree_key_t));
+        len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
+        p = ngx_hex_dump(p, fcn->key, len);
+        *p = '\0';
 
-    len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
-    p = ngx_hex_dump(p, fcn->key, len);
-    *p = '\0';
-
-    ngx_queue_remove(q);
+        fcn->count++;
+        fcn->deleting = 1;
+        ngx_shmtx_unlock(&cache->shpool->mutex);
 
-    ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
-
-    ngx_slab_free_locked(cache->shpool, fcn);
+        len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
+        ngx_create_hashed_filename(path, name, len);
 
-    ngx_shmtx_unlock(&cache->shpool->mutex);
-
-    len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+                       "http file cache expire: \"%s\"", name);
 
-    ngx_create_hashed_filename(path, name, len);
+        if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
+                          ngx_delete_file_n " \"%s\" failed", name);
+        }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
-                   "http file cache expire: \"%s\"", name);
-
-    if (ngx_delete_file(name) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
-                      ngx_delete_file_n " \"%s\" failed", name);
+        ngx_shmtx_lock(&cache->shpool->mutex);
+        fcn->count--;
+        fcn->deleting = 0;
     }
 
-    ngx_shmtx_lock(&cache->shpool->mutex);
+    if (fcn->count == 0) {
+        ngx_queue_remove(q);
+        ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
+        ngx_slab_free_locked(cache->shpool, fcn);
+    }
 }
 
 
@@ -1120,7 +1192,7 @@ ngx_http_file_cache_manager(void *data)
     ngx_http_file_cache_t  *cache = data;
 
     off_t   size;
-    time_t  next;
+    time_t  next, wait;
 
     next = ngx_http_file_cache_expire(cache);
 
@@ -1141,7 +1213,11 @@ ngx_http_file_cache_manager(void *data)
             return next;
         }
 
-        next = ngx_http_file_cache_forced_expire(cache);
+        wait = ngx_http_file_cache_forced_expire(cache);
+
+        if (wait > 0) {
+            return wait;
+        }
 
         if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) {
             return next;
@@ -1203,7 +1279,7 @@ ngx_http_file_cache_manager_sleep(ngx_ht
 
     if (cache->files++ > 100) {
 
-        ngx_time_update(0, 0);
+        ngx_time_update();
 
         elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
 
@@ -1220,7 +1296,7 @@ ngx_http_file_cache_manager_sleep(ngx_ht
 
             ngx_msleep(200);
 
-            ngx_time_update(0, 0);
+            ngx_time_update();
         }
 
         cache->last = ngx_current_msec;
@@ -1366,6 +1442,8 @@ ngx_http_file_cache_add(ngx_http_file_ca
         fcn->valid_msec = c->valid_msec;
         fcn->error = 0;
         fcn->exists = 1;
+        fcn->updating = 0;
+        fcn->deleting = 0;
         fcn->uniq = c->uniq;
         fcn->valid_sec = c->valid_sec;
         fcn->body_start = c->body_start;
@@ -1679,3 +1757,69 @@ ngx_http_file_cache_valid_set_slot(ngx_c
 
     return NGX_CONF_OK;
 }
+
+
+ngx_int_t
+ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache)
+{
+    ngx_str_t                  val;
+    ngx_uint_t                 i;
+    ngx_http_complex_value_t  *cv;
+
+    cv = no_cache->elts;
+
+    for (i = 0; i < no_cache->nelts; i++) {
+        if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        if (val.len && val.data[0] != '0') {
+            return NGX_DECLINED;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+char *
+ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_str_t                          *value;
+    ngx_uint_t                          i;
+    ngx_array_t                       **a;
+    ngx_http_complex_value_t           *cv;
+    ngx_http_compile_complex_value_t    ccv;
+
+    a = (ngx_array_t **) (p + cmd->offset);
+
+    if (*a == NGX_CONF_UNSET_PTR) {
+        *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
+        if (*a == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        cv = ngx_array_push(*a);
+        if (cv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        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;
+        }
+    }
+
+    return NGX_CONF_OK;
+}
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -53,7 +53,7 @@ static ngx_str_t ngx_http_status_lines[]
 
     ngx_string("200 OK"),
     ngx_string("201 Created"),
-    ngx_null_string,  /* "202 Accepted" */
+    ngx_string("202 Accepted"),
     ngx_null_string,  /* "203 Non-Authoritative Information" */
     ngx_string("204 No Content"),
     ngx_null_string,  /* "205 Reset Content" */
@@ -68,7 +68,7 @@ static ngx_str_t ngx_http_status_lines[]
 
     ngx_string("301 Moved Permanently"),
     ngx_string("302 Moved Temporarily"),
-    ngx_null_string,  /* "303 See Other" */
+    ngx_string("303 See Other"),
     ngx_string("304 Not Modified"),
 
     /* ngx_null_string, */  /* "305 Use Proxy" */
@@ -132,10 +132,6 @@ static ngx_str_t ngx_http_status_lines[]
 ngx_http_header_out_t  ngx_http_headers_out[] = {
     { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) },
     { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) },
-#if 0
-    { ngx_string("Content-Type"),
-                 offsetof(ngx_http_headers_out_t, content_type) },
-#endif
     { ngx_string("Content-Length"),
                  offsetof(ngx_http_headers_out_t, content_length) },
     { ngx_string("Content-Encoding"),
@@ -174,6 +170,10 @@ ngx_http_header_filter(ngx_http_request_
 #endif
     u_char                     addr[NGX_SOCKADDR_STRLEN];
 
+    if (r->header_sent) {
+        return NGX_OK;
+    }
+
     r->header_sent = 1;
 
     if (r != r->main) {
@@ -222,8 +222,7 @@ ngx_http_header_filter(ngx_http_request_
 
             if (status == NGX_HTTP_NO_CONTENT) {
                 r->header_only = 1;
-                r->headers_out.content_type.len = 0;
-                r->headers_out.content_type.data = NULL;
+                ngx_str_null(&r->headers_out.content_type);
                 r->headers_out.last_modified_time = -1;
                 r->headers_out.last_modified = NULL;
                 r->headers_out.content_length = NULL;
@@ -342,6 +341,11 @@ ngx_http_header_filter(ngx_http_request_
             port = ntohs(sin6->sin6_port);
             break;
 #endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+        case AF_UNIX:
+            port = 0;
+            break;
+#endif
         default: /* AF_INET */
             sin = (struct sockaddr_in *) c->local_sockaddr;
             port = ntohs(sin->sin_port);
@@ -370,8 +374,7 @@ ngx_http_header_filter(ngx_http_request_
         }
 
     } else {
-        host.len = 0;
-        host.data = NULL;
+        ngx_str_null(&host);
         port = 0;
     }
 
@@ -399,8 +402,13 @@ ngx_http_header_filter(ngx_http_request_
     }
 
 #if (NGX_HTTP_GZIP)
-    if (r->gzip && clcf->gzip_vary) {
-        len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
+    if (r->gzip_vary) {
+        if (clcf->gzip_vary) {
+            len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
+
+        } else {
+            r->gzip_vary = 0;
+        }
     }
 #endif
 
@@ -533,8 +541,7 @@ ngx_http_header_filter(ngx_http_request_
 
         r->headers_out.location->value.len = b->last - p;
         r->headers_out.location->value.data = p;
-        r->headers_out.location->key.len = sizeof("Location: ") - 1;
-        r->headers_out.location->key.data = (u_char *) "Location: ";
+        ngx_str_set(&r->headers_out.location->key, "Location");
 
         *b->last++ = CR; *b->last++ = LF;
     }
@@ -559,7 +566,7 @@ ngx_http_header_filter(ngx_http_request_
     }
 
 #if (NGX_HTTP_GZIP)
-    if (r->gzip && clcf->gzip_vary) {
+    if (r->gzip_vary) {
         b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
                              sizeof("Vary: Accept-Encoding" CRLF) - 1);
     }
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -112,8 +112,10 @@ ngx_http_parse_request_line(ngx_http_req
         sw_schema_slash_slash,
         sw_host,
         sw_port,
+        sw_host_http_09,
         sw_after_slash_in_uri,
         sw_check_uri,
+        sw_check_uri_http_09,
         sw_uri,
         sw_http_09,
         sw_http_H,
@@ -208,6 +210,10 @@ ngx_http_parse_request_line(ngx_http_req
                         r->method = NGX_HTTP_MKCOL;
                     }
 
+                    if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
+                        r->method = NGX_HTTP_PATCH;
+                    }
+
                     if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
                         r->method = NGX_HTTP_TRACE;
                     }
@@ -266,7 +272,7 @@ ngx_http_parse_request_line(ngx_http_req
         /* space* before URI */
         case sw_spaces_before_uri:
 
-            if (ch == '/' ){
+            if (ch == '/') {
                 r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
@@ -353,7 +359,7 @@ ngx_http_parse_request_line(ngx_http_req
                  */
                 r->uri_start = r->schema_end + 1;
                 r->uri_end = r->schema_end + 2;
-                state = sw_http_09;
+                state = sw_host_http_09;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
@@ -379,13 +385,35 @@ ngx_http_parse_request_line(ngx_http_req
                  */
                 r->uri_start = r->schema_end + 1;
                 r->uri_end = r->schema_end + 2;
-                state = sw_http_09;
+                state = sw_host_http_09;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
+        /* space+ after "http://host[:port] " */
+        case sw_host_http_09:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                r->http_minor = 9;
+                state = sw_almost_done;
+                break;
+            case LF:
+                r->http_minor = 9;
+                goto done;
+            case 'H':
+                r->http_protocol.data = p;
+                state = sw_http_H;
+                break;
+            default:
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+
         /* check "/.", "//", "%", and "\" (Win32) in URI */
         case sw_after_slash_in_uri:
 
@@ -397,7 +425,7 @@ ngx_http_parse_request_line(ngx_http_req
             switch (ch) {
             case ' ':
                 r->uri_end = p;
-                state = sw_http_09;
+                state = sw_check_uri_http_09;
                 break;
             case CR:
                 r->uri_end = p;
@@ -438,8 +466,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->plus_in_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             default:
                 state = sw_check_uri;
                 break;
@@ -463,7 +490,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             case ' ':
                 r->uri_end = p;
-                state = sw_http_09;
+                state = sw_check_uri_http_09;
                 break;
             case CR:
                 r->uri_end = p;
@@ -496,11 +523,34 @@ ngx_http_parse_request_line(ngx_http_req
                 r->plus_in_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        /* space+ after URI */
+        case sw_check_uri_http_09:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                r->http_minor = 9;
+                state = sw_almost_done;
+                break;
+            case LF:
+                r->http_minor = 9;
+                goto done;
+            case 'H':
+                r->http_protocol.data = p;
+                state = sw_http_H;
+                break;
+            default:
+                r->space_in_uri = 1;
+                state = sw_check_uri;
                 break;
             }
             break;
 
+
         /* URI */
         case sw_uri:
 
@@ -526,8 +576,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->complex_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
@@ -548,7 +597,9 @@ ngx_http_parse_request_line(ngx_http_req
                 state = sw_http_H;
                 break;
             default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
+                r->space_in_uri = 1;
+                state = sw_uri;
+                break;
             }
             break;
 
@@ -1190,19 +1241,14 @@ ngx_http_parse_complex_uri(ngx_http_requ
             if (ch >= '0' && ch <= '9') {
                 ch = (u_char) ((decoded << 4) + ch - '0');
 
-                if (ch == '%') {
+                if (ch == '%' || ch == '#') {
                     state = sw_usual;
                     *u++ = ch;
                     ch = *p++;
                     break;
-                }
-
-                if (ch == '#') {
-                    *u++ = ch;
-                    ch = *p++;
 
                 } else if (ch == '\0') {
-                    r->zero_in_uri = 1;
+                    return NGX_HTTP_PARSE_INVALID_REQUEST;
                 }
 
                 state = quoted_state;
@@ -1214,8 +1260,10 @@ ngx_http_parse_complex_uri(ngx_http_requ
                 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
 
                 if (ch == '?') {
+                    state = sw_usual;
                     *u++ = ch;
                     ch = *p++;
+                    break;
 
                 } else if (ch == '+') {
                     r->plus_in_uri = 1;
@@ -1270,6 +1318,211 @@ args:
 
 
 ngx_int_t
+ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
+    ngx_http_status_t *status)
+{
+    u_char   ch;
+    u_char  *p;
+    enum {
+        sw_start = 0,
+        sw_H,
+        sw_HT,
+        sw_HTT,
+        sw_HTTP,
+        sw_first_major_digit,
+        sw_major_digit,
+        sw_first_minor_digit,
+        sw_minor_digit,
+        sw_status,
+        sw_space_after_status,
+        sw_status_text,
+        sw_almost_done
+    } state;
+
+    state = r->state;
+
+    for (p = b->pos; p < b->last; p++) {
+        ch = *p;
+
+        switch (state) {
+
+        /* "HTTP/" */
+        case sw_start:
+            switch (ch) {
+            case 'H':
+                state = sw_H;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_H:
+            switch (ch) {
+            case 'T':
+                state = sw_HT;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_HT:
+            switch (ch) {
+            case 'T':
+                state = sw_HTT;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_HTT:
+            switch (ch) {
+            case 'P':
+                state = sw_HTTP;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_HTTP:
+            switch (ch) {
+            case '/':
+                state = sw_first_major_digit;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        /* the first digit of major HTTP version */
+        case sw_first_major_digit:
+            if (ch < '1' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            state = sw_major_digit;
+            break;
+
+        /* the major HTTP version or dot */
+        case sw_major_digit:
+            if (ch == '.') {
+                state = sw_first_minor_digit;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            break;
+
+        /* the first digit of minor HTTP version */
+        case sw_first_minor_digit:
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            state = sw_minor_digit;
+            break;
+
+        /* the minor HTTP version or the end of the request line */
+        case sw_minor_digit:
+            if (ch == ' ') {
+                state = sw_status;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            break;
+
+        /* HTTP status code */
+        case sw_status:
+            if (ch == ' ') {
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            status->code = status->code * 10 + ch - '0';
+
+            if (++status->count == 3) {
+                state = sw_space_after_status;
+                status->start = p - 2;
+            }
+
+            break;
+
+        /* space or end of line */
+        case sw_space_after_status:
+            switch (ch) {
+            case ' ':
+                state = sw_status_text;
+                break;
+            case '.':                    /* IIS may send 403.1, 403.2, etc */
+                state = sw_status_text;
+                break;
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                goto done;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        /* any text until end of line */
+        case sw_status_text:
+            switch (ch) {
+            case CR:
+                state = sw_almost_done;
+
+                break;
+            case LF:
+                goto done;
+            }
+            break;
+
+        /* end of status line */
+        case sw_almost_done:
+            status->end = p - 1;
+            switch (ch) {
+            case LF:
+                goto done;
+            default:
+                return NGX_ERROR;
+            }
+        }
+    }
+
+    b->pos = p;
+    r->state = state;
+
+    return NGX_AGAIN;
+
+done:
+
+    b->pos = p + 1;
+
+    if (status->end == NULL) {
+        status->end = p;
+    }
+
+    r->state = sw_start;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
     ngx_str_t *args, ngx_uint_t *flags)
 {
@@ -1304,8 +1557,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
         }
 
         if (ch == '\0') {
-            *flags |= NGX_HTTP_ZERO_IN_URI;
-            continue;
+            goto unsafe;
         }
 
         if (ngx_path_separator(ch) && len > 2) {
@@ -1322,8 +1574,10 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
 
 unsafe:
 
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "unsafe URI \"%V\" was detected", uri);
+    if (*flags & NGX_HTTP_LOG_UNSAFE) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "unsafe URI \"%V\" was detected", uri);
+    }
 
     return NGX_ERROR;
 }
@@ -1447,34 +1701,19 @@ ngx_http_arg(ngx_http_request_t *r, u_ch
 void
 ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
 {
-    u_char  ch, *p, *last;
-
-    p = uri->data;
-
-    last = p + uri->len;
+    u_char  *p, *last;
 
-    args->len = 0;
+    last = uri->data + uri->len;
 
-    while (p < last) {
-
-        ch = *p++;
+    p = ngx_strlchr(uri->data, last, '?');
 
-        if (ch == '?') {
-            args->len = last - p;
-            args->data = p;
-
-            uri->len = p - 1 - uri->data;
+    if (p) {
+        uri->len = p - uri->data;
+        p++;
+        args->len = last - p;
+        args->data = p;
 
-            if (ngx_strlchr(p, last, '\0') != NULL) {
-                r->zero_in_uri = 1;
-            }
-
-            return;
-        }
-
-        if (ch == '\0') {
-            r->zero_in_uri = 1;
-            continue;
-        }
+    } else {
+        args->len = 0;
     }
 }
--- a/src/http/ngx_http_parse_time.c
+++ b/src/http/ngx_http_parse_time.c
@@ -8,13 +8,15 @@
 #include <ngx_core.h>
 
 
-static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static ngx_uint_t  mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 
 time_t
 ngx_http_parse_time(u_char *value, size_t len)
 {
-    u_char  *p, *end;
-    int      day, month, year, hour, min, sec;
+    u_char      *p, *end;
+    ngx_int_t    month;
+    ngx_uint_t   day, year, hour, min, sec;
+    uint64_t     time;
     enum {
         no = 0,
         rfc822,   /* Tue, 10 Nov 2002 23:50:13   */
@@ -229,14 +231,6 @@ ngx_http_parse_time(u_char *value, size_
         return NGX_ERROR;
     }
 
-#if (NGX_TIME_T_SIZE <= 4)
-
-    if (year >= 2038) {
-        return NGX_ERROR;
-    }
-
-#endif
-
     /*
      * shift new year to March 1 and start months from 1 (not 0),
      * it is needed for Gauss' formula
@@ -249,7 +243,7 @@ ngx_http_parse_time(u_char *value, size_
 
     /* Gauss' formula for Grigorian days since March 1, 1 BC */
 
-    return (
+    time = (uint64_t) (
             /* days in years including leap years since March 1, 1 BC */
 
             365 * year + year / 4 - year / 100 + year / 400
@@ -268,4 +262,14 @@ ngx_http_parse_time(u_char *value, size_
              */
 
             - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
+
+#if (NGX_TIME_T_SIZE <= 4)
+
+    if (time > 0x7fffffff) {
+        return NGX_ERROR;
+    }
+
+#endif
+
+    return (time_t) time;
 }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -31,7 +31,8 @@ static ngx_int_t ngx_http_process_cookie
 
 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
 static void ngx_http_process_request(ngx_http_request_t *r);
-static ssize_t ngx_http_validate_host(u_char *host, size_t len);
+static ssize_t ngx_http_validate_host(ngx_http_request_t *r, u_char **host,
+    size_t len, ngx_uint_t alloc);
 static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r,
     u_char *host, size_t len);
 
@@ -87,6 +88,10 @@ ngx_http_header_t  ngx_http_headers_in[]
                  offsetof(ngx_http_headers_in_t, if_modified_since),
                  ngx_http_process_unique_header_line },
 
+    { ngx_string("If-Unmodified-Since"),
+                 offsetof(ngx_http_headers_in_t, if_unmodified_since),
+                 ngx_http_process_unique_header_line },
+
     { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent),
                  ngx_http_process_user_agent },
 
@@ -380,7 +385,7 @@ 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;
+    cscf = addr_conf->default_server;
 
     r->main_conf = cscf->ctx->main_conf;
     r->srv_conf = cscf->ctx->srv_conf;
@@ -554,7 +559,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
     }
 
     if (n == 1) {
-        if (buf[0] == 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {
+        if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                            "https ssl handshake: 0x%02Xd", buf[0]);
 
@@ -627,6 +632,7 @@ int
 ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
 {
     size_t                    len;
+    u_char                   *host;
     const char               *servername;
     ngx_connection_t         *c;
     ngx_http_request_t       *r;
@@ -651,7 +657,15 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
 
     r = c->data;
 
-    if (ngx_http_find_virtual_server(r, (u_char *) servername, len) != NGX_OK) {
+    host = (u_char *) servername;
+
+    len = ngx_http_validate_host(r, &host, len, 1);
+
+    if (len <= 0) {
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    if (ngx_http_find_virtual_server(r, host, len) != NGX_OK) {
         return SSL_TLSEXT_ERR_NOACK;
     }
 
@@ -670,6 +684,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
 static void
 ngx_http_process_request_line(ngx_event_t *rev)
 {
+    u_char                    *host;
     ssize_t                    n;
     ngx_int_t                  rc, rv;
     ngx_connection_t          *c;
@@ -745,6 +760,7 @@ ngx_http_process_request_line(ngx_event_
             r->unparsed_uri.len = r->uri_end - r->uri_start;
             r->unparsed_uri.data = r->uri_start;
 
+            r->valid_unparsed_uri = r->space_in_uri ? 0 : 1;
 
             r->method_name.len = r->method_end - r->request_start + 1;
             r->method_name.data = r->request_line.data;
@@ -777,14 +793,31 @@ ngx_http_process_request_line(ngx_event_
 
             p = r->uri.data + r->uri.len - 1;
 
-            if (*p == '.') {
-
-                while (--p > r->uri.data && *p == '.') { /* void */ }
-
+            while (p > r->uri.data) {
+
+                if (*p == ' ') {
+                    p--;
+                    continue;
+                }
+
+                if (*p == '.') {
+                    p--;
+                    continue;
+                }
+
+                if (ngx_strncasecmp(p - 6, (u_char *) "::$data", 7) == 0) {
+                    p -= 7;
+                    continue;
+                }
+
+                break;
+            }
+
+            if (p != r->uri.data + r->uri.len - 1) {
                 r->uri.len = p + 1 - r->uri.data;
-
                 ngx_http_set_exten(r);
             }
+
             }
 #endif
 
@@ -801,18 +834,25 @@ ngx_http_process_request_line(ngx_event_
                            "http exten: \"%V\"", &r->exten);
 
             if (r->host_start && r->host_end) {
-                n = ngx_http_validate_host(r->host_start,
-                                           r->host_end - r->host_start);
-
-                if (n <= 0) {
+
+                host = r->host_start;
+                n = ngx_http_validate_host(r, &host,
+                                           r->host_end - r->host_start, 0);
+
+                if (n == 0) {
                     ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                   "client sent invalid host in request line");
                     ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                     return;
                 }
 
+                if (n < 0) {
+                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                    return;
+                }
+
                 r->headers_in.server.len = n;
-                r->headers_in.server.data = r->host_start;
+                r->headers_in.server.data = host;
             }
 
             if (r->http_version < NGX_HTTP_VERSION_10) {
@@ -936,9 +976,20 @@ ngx_http_process_request_headers(ngx_eve
                 }
 
                 if (rv == NGX_DECLINED) {
-                    len = r->header_in->end - r->header_name_start;
                     p = r->header_name_start;
 
+                    r->lingering_close = 1;
+
+                    if (p == NULL) {
+                        ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                                      "client sent too large request");
+                        ngx_http_finalize_request(r,
+                                            NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
+                        return;
+                    }
+
+                    len = r->header_in->end - p;
+
                     if (len > NGX_MAX_ERROR_STR - 300) {
                         len = NGX_MAX_ERROR_STR - 300;
                         p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
@@ -947,7 +998,9 @@ ngx_http_process_request_headers(ngx_eve
                     ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                   "client sent too long header line: \"%*s\"",
                                   len, r->header_name_start);
-                    ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+
+                    ngx_http_finalize_request(r,
+                                            NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
                     return;
                 }
             }
@@ -1312,27 +1365,34 @@ static ngx_int_t
 ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    ssize_t  len;
+    u_char   *host;
+    ssize_t   len;
 
     if (r->headers_in.host == NULL) {
         r->headers_in.host = h;
     }
 
-    len = ngx_http_validate_host(h->value.data, h->value.len);
-
-    if (len <= 0) {
+    host = h->value.data;
+    len = ngx_http_validate_host(r, &host, h->value.len, 0);
+
+    if (len == 0) {
         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                       "client sent invalid host header");
         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
         return NGX_ERROR;
     }
 
+    if (len < 0) {
+        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return NGX_ERROR;
+    }
+
     if (r->headers_in.server.len) {
         return NGX_OK;
     }
 
     r->headers_in.server.len = len;
-    r->headers_in.server.data = h->value.data;
+    r->headers_in.server.data = host;
 
     return NGX_OK;
 }
@@ -1412,6 +1472,12 @@ ngx_http_process_user_agent(ngx_http_req
         if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
             r->headers_in.gecko = 1;
 
+        } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) {
+            r->headers_in.chrome = 1;
+
+        } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1)) {
+            r->headers_in.safari = 1;
+
         } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
             r->headers_in.konqueror = 1;
         }
@@ -1588,21 +1654,23 @@ ngx_http_process_request(ngx_http_reques
 
 
 static ssize_t
-ngx_http_validate_host(u_char *host, size_t len)
+ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len,
+    ngx_uint_t alloc)
 {
-    u_char      ch;
-    size_t      i, last;
-    ngx_uint_t  dot;
+    u_char      *h, ch;
+    size_t       i, last;
+    ngx_uint_t   dot;
 
     last = len;
+    h = *host;
     dot = 0;
 
     for (i = 0; i < len; i++) {
-        ch = host[i];
+        ch = h[i];
 
         if (ch == '.') {
             if (dot) {
-                return -1;
+                return 0;
             }
 
             dot = 1;
@@ -1617,7 +1685,11 @@ ngx_http_validate_host(u_char *host, siz
         }
 
         if (ngx_path_separator(ch) || ch == '\0') {
-            return -1;
+            return 0;
+        }
+
+        if (ch >= 'A' || ch < 'Z') {
+            alloc = 1;
         }
     }
 
@@ -1625,6 +1697,15 @@ ngx_http_validate_host(u_char *host, siz
         last--;
     }
 
+    if (alloc) {
+        *host = ngx_pnalloc(r->pool, last) ;
+        if (*host == NULL) {
+            return -1;
+        }
+
+        ngx_strlow(*host, h, last);
+    }
+
     return last;
 }
 
@@ -1632,29 +1713,15 @@ ngx_http_validate_host(u_char *host, siz
 static ngx_int_t
 ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
 {
-    u_char                    *server;
-    ngx_uint_t                 hash;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
-    u_char                     buf[32];
 
     if (r->virtual_names == NULL) {
         return NGX_DECLINED;
     }
 
-    if (len <= 32) {
-        server = buf;
-
-    } else {
-        server = ngx_pnalloc(r->pool, len);
-        if (server == NULL) {
-            return NGX_ERROR;
-        }
-    }
-
-    hash = ngx_hash_strlow(server, host, len);
-
-    cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len);
+    cscf = ngx_hash_find_combined(&r->virtual_names->names,
+                                  ngx_hash_key(host, len), host, len);
 
     if (cscf) {
         goto found;
@@ -1662,64 +1729,31 @@ ngx_http_find_virtual_server(ngx_http_re
 
 #if (NGX_PCRE)
 
-    if (r->virtual_names->nregex) {
-        size_t                   ncaptures;
+    if (len && r->virtual_names->nregex) {
         ngx_int_t                n;
         ngx_uint_t               i;
         ngx_str_t                name;
         ngx_http_server_name_t  *sn;
 
         name.len = len;
-        name.data = server;
-
-        ncaptures = 0;
+        name.data = host;
 
         sn = r->virtual_names->regex;
 
         for (i = 0; i < r->virtual_names->nregex; i++) {
 
-            if (sn[i].captures && r->captures == NULL) {
-
-                ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3;
-
-                r->captures = ngx_palloc(r->pool, ncaptures * sizeof(int));
-                if (r->captures == NULL) {
-                    return NGX_ERROR;
-                }
-
-                if (server == buf) {
-                    server = ngx_pnalloc(r->pool, len);
-                    if (server == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    ngx_memcpy(server, buf, len);
-                    name.data = server;
-                }
+            n = ngx_http_regex_exec(r, sn[i].regex, &name);
+
+            if (n == NGX_OK) {
+                cscf = sn[i].server;
+                goto found;
             }
 
-            n = ngx_regex_exec(sn[i].regex, &name, r->captures, ncaptures);
-
-            if (n == NGX_REGEX_NO_MATCHED) {
+            if (n == NGX_DECLINED) {
                 continue;
             }
 
-            if (n < 0) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                              ngx_regex_exec_n
-                              " failed: %d on \"%V\" using \"%V\"",
-                              n, &name, &sn[i].name);
-                return NGX_ERROR;
-            }
-
-            /* match */
-
-            cscf = sn[i].core_srv_conf;
-
-            r->ncaptures = ncaptures;
-            r->captures_data = server;
-
-            goto found;
+            return NGX_ERROR;
         }
     }
 
@@ -1993,6 +2027,7 @@ ngx_http_finalize_request(ngx_http_reque
     }
 
     r->done = 1;
+    r->write_event_handler = ngx_http_request_empty_handler;
 
     if (!r->post_action) {
         r->request_complete = 1;
@@ -2032,6 +2067,10 @@ ngx_http_terminate_request(ngx_http_requ
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http terminate request count:%d", mr->count);
 
+    if (rc > 0 && (mr->headers_out.status == 0 || mr->connection->sent == 0)) {
+        mr->headers_out.status = rc;
+    }
+
     cln = mr->cleanup;
     mr->cleanup = NULL;
 
@@ -2081,13 +2120,24 @@ ngx_http_finalize_connection(ngx_http_re
 {
     ngx_http_core_loc_conf_t  *clcf;
 
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
     if (r->main->count != 1) {
+
+        if (r->discard_body) {
+            r->read_event_handler = ngx_http_discarded_request_body_handler;
+
+            if (r->lingering_time == 0) {
+                r->lingering_time = ngx_time()
+                                      + (time_t) (clcf->lingering_time / 1000);
+                ngx_add_timer(r->connection->read, clcf->lingering_timeout);
+            }
+        }
+
         ngx_http_close_request(r, 0);
         return;
     }
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     if (!ngx_terminate
          && !ngx_exiting
          && r->keepalive
@@ -2113,7 +2163,9 @@ ngx_http_set_write_handler(ngx_http_requ
 
     r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
 
-    r->read_event_handler = ngx_http_test_reading;
+    r->read_event_handler = r->discard_body ?
+                                ngx_http_discarded_request_body_handler:
+                                ngx_http_test_reading;
     r->write_event_handler = ngx_http_writer;
 
     wev = r->connection->write;
@@ -2215,6 +2267,8 @@ ngx_http_writer(ngx_http_request_t *r)
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0,
                    "http writer done: \"%V?%V\"", &r->uri, &r->args);
 
+    r->write_event_handler = ngx_http_request_empty_handler;
+
     ngx_http_finalize_request(r, rc);
 }
 
@@ -2391,6 +2445,8 @@ ngx_http_set_keepalive(ngx_http_request_
         }
     }
 
+    r->keepalive = 0;
+
     ngx_http_free_request(r, 0);
 
     c->data = hc;
@@ -2538,6 +2594,7 @@ ngx_http_set_keepalive(ngx_http_request_
 #endif
 
     c->idle = 1;
+    ngx_reusable_connection(c, 1);
 
     if (rev->ready) {
         ngx_post_event(rev, &ngx_posted_events);
@@ -2647,6 +2704,7 @@ ngx_http_keepalive_handler(ngx_event_t *
     c->log->action = "reading client request line";
 
     c->idle = 0;
+    ngx_reusable_connection(c, 0);
 
     ngx_http_init_request(rev);
 }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -10,7 +10,6 @@
 
 #define NGX_HTTP_MAX_URI_CHANGES           10
 #define NGX_HTTP_MAX_SUBREQUESTS           50
-#define NGX_HTTP_MAX_CAPTURES              9
 
 /* must be 2^n */
 #define NGX_HTTP_LC_HEADER_LEN             32
@@ -38,7 +37,8 @@
 #define NGX_HTTP_PROPPATCH                 0x0800
 #define NGX_HTTP_LOCK                      0x1000
 #define NGX_HTTP_UNLOCK                    0x2000
-#define NGX_HTTP_TRACE                     0x4000
+#define NGX_HTTP_PATCH                     0x4000
+#define NGX_HTTP_TRACE                     0x8000
 
 #define NGX_HTTP_CONNECTION_CLOSE          1
 #define NGX_HTTP_CONNECTION_KEEP_ALIVE     2
@@ -57,19 +57,22 @@
 #define NGX_HTTP_PARSE_INVALID_HEADER      13
 
 
-#define NGX_HTTP_ZERO_IN_URI               1
+/* unused                                  1 */
 #define NGX_HTTP_SUBREQUEST_IN_MEMORY      2
 #define NGX_HTTP_SUBREQUEST_WAITED         4
+#define NGX_HTTP_LOG_UNSAFE                8
 
 
 #define NGX_HTTP_OK                        200
 #define NGX_HTTP_CREATED                   201
+#define NGX_HTTP_ACCEPTED                  202
 #define NGX_HTTP_NO_CONTENT                204
 #define NGX_HTTP_PARTIAL_CONTENT           206
 
 #define NGX_HTTP_SPECIAL_RESPONSE          300
 #define NGX_HTTP_MOVED_PERMANENTLY         301
 #define NGX_HTTP_MOVED_TEMPORARILY         302
+#define NGX_HTTP_SEE_OTHER                 303
 #define NGX_HTTP_NOT_MODIFIED              304
 
 #define NGX_HTTP_BAD_REQUEST               400
@@ -92,7 +95,9 @@
 /* The special code to close connection without any response */
 #define NGX_HTTP_CLOSE                     444
 
-#define NGX_HTTP_OWN_CODES                 495
+#define NGX_HTTP_NGINX_CODES               494
+
+#define NGX_HTTP_REQUEST_HEADER_TOO_LARGE  494
 
 #define NGX_HTTPS_CERT_ERROR               495
 #define NGX_HTTPS_NO_CERT                  496
@@ -164,6 +169,7 @@ typedef struct {
     ngx_table_elt_t                  *host;
     ngx_table_elt_t                  *connection;
     ngx_table_elt_t                  *if_modified_since;
+    ngx_table_elt_t                  *if_unmodified_since;
     ngx_table_elt_t                  *user_agent;
     ngx_table_elt_t                  *referer;
     ngx_table_elt_t                  *content_length;
@@ -219,6 +225,8 @@ typedef struct {
     unsigned                          msie6:1;
     unsigned                          opera:1;
     unsigned                          gecko:1;
+    unsigned                          chrome:1;
+    unsigned                          safari:1;
     unsigned                          konqueror:1;
 } ngx_http_headers_in_t;
 
@@ -433,11 +441,12 @@ struct ngx_http_request_s {
     /* URI with "+" */
     unsigned                          plus_in_uri:1;
 
-    /* URI with "\0" or "%00" */
-    unsigned                          zero_in_uri:1;
+    /* URI with " " */
+    unsigned                          space_in_uri:1;
 
     unsigned                          invalid_header:1;
 
+    unsigned                          add_uri_to_alias:1;
     unsigned                          valid_location:1;
     unsigned                          valid_unparsed_uri:1;
     unsigned                          uri_changed:1;
@@ -456,7 +465,12 @@ struct ngx_http_request_s {
 #if (NGX_HTTP_CACHE)
     unsigned                          cached:1;
 #endif
-    unsigned                          gzip:2;
+
+#if (NGX_HTTP_GZIP)
+    unsigned                          gzip_tested:1;
+    unsigned                          gzip_ok:1;
+    unsigned                          gzip_vary:1;
+#endif
 
     unsigned                          proxy:1;
     unsigned                          bypass_cache:1;
@@ -478,7 +492,6 @@ struct ngx_http_request_s {
     unsigned                          plain_http:1;
     unsigned                          chunked:1;
     unsigned                          header_only:1;
-    unsigned                          zero_body:1;
     unsigned                          keepalive:1;
     unsigned                          lingering_close:1;
     unsigned                          discard_body:1;
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -13,7 +13,6 @@ static void ngx_http_read_client_request
 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
     ngx_chain_t *body);
-static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r);
 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
 
@@ -460,6 +459,7 @@ ngx_http_discard_request_body(ngx_http_r
 
     if (size) {
         if (r->headers_in.content_length_n > size) {
+            r->header_in->pos += size;
             r->headers_in.content_length_n -= size;
 
         } else {
@@ -469,23 +469,26 @@ ngx_http_discard_request_body(ngx_http_r
         }
     }
 
-    r->discard_body = 1;
-
-    r->read_event_handler = ngx_http_read_discarded_request_body_handler;
+    r->read_event_handler = ngx_http_discarded_request_body_handler;
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->count++;
-    (void) ngx_http_read_discarded_request_body(r);
+    if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
+        r->lingering_close = 0;
+
+    } else {
+        r->count++;
+        r->discard_body = 1;
+    }
 
     return NGX_OK;
 }
 
 
-static void
-ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r)
+void
+ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
 {
     ngx_int_t                  rc;
     ngx_msec_t                 timer;
@@ -499,7 +502,7 @@ ngx_http_read_discarded_request_body_han
     if (rev->timedout) {
         c->timedout = 1;
         c->error = 1;
-        ngx_http_finalize_request(r, 0);
+        ngx_http_finalize_request(r, NGX_ERROR);
         return;
     }
 
@@ -508,7 +511,8 @@ ngx_http_read_discarded_request_body_han
 
         if (timer <= 0) {
             r->discard_body = 0;
-            ngx_http_finalize_request(r, 0);
+            r->lingering_close = 0;
+            ngx_http_finalize_request(r, NGX_ERROR);
             return;
         }
 
@@ -519,13 +523,9 @@ ngx_http_read_discarded_request_body_han
     rc = ngx_http_read_discarded_request_body(r);
 
     if (rc == NGX_OK) {
-
         r->discard_body = 0;
-
-        if (r->done) {
-            ngx_http_finalize_request(r, 0);
-        }
-
+        r->lingering_close = 0;
+        ngx_http_finalize_request(r, NGX_DONE);
         return;
     }
 
@@ -533,7 +533,7 @@ ngx_http_read_discarded_request_body_han
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
         c->error = 1;
-        ngx_http_finalize_request(r, rc);
+        ngx_http_finalize_request(r, NGX_ERROR);
         return;
     }
 
@@ -562,12 +562,16 @@ ngx_http_read_discarded_request_body(ngx
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http read discarded body");
 
-    do {
+    for ( ;; ) {
         if (r->headers_in.content_length_n == 0) {
             r->read_event_handler = ngx_http_block_reading;
             return NGX_OK;
         }
 
+        if (!r->connection->read->ready) {
+            return NGX_AGAIN;
+        }
+
         size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ?
                    NGX_HTTP_DISCARD_BUFFER_SIZE:
                    (size_t) r->headers_in.content_length_n;
@@ -588,10 +592,7 @@ ngx_http_read_discarded_request_body(ngx
         }
 
         r->headers_in.content_length_n -= n;
-
-    } while (r->connection->read->ready);
-
-    return NGX_AGAIN;
+    }
 }
 
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -211,6 +211,112 @@ ngx_http_compile_complex_value(ngx_http_
 }
 
 
+char *
+ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_str_t                          *value;
+    ngx_http_complex_value_t          **cv;
+    ngx_http_compile_complex_value_t    ccv;
+
+    cv = (ngx_http_complex_value_t **) (p + cmd->offset);
+
+    if (*cv != NULL) {
+        return "duplicate";
+    }
+
+    *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+    if (*cv == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = *cv;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+ngx_int_t
+ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
+{
+    ngx_str_t                  val;
+    ngx_uint_t                 i;
+    ngx_http_complex_value_t  *cv;
+
+    if (predicates == NULL) {
+        return NGX_OK;
+    }
+
+    cv = predicates->elts;
+
+    for (i = 0; i < predicates->nelts; i++) {
+        if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        if (val.len && val.data[0] != '0') {
+            return NGX_DECLINED;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+char *
+ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_str_t                          *value;
+    ngx_uint_t                          i;
+    ngx_array_t                       **a;
+    ngx_http_complex_value_t           *cv;
+    ngx_http_compile_complex_value_t    ccv;
+
+    a = (ngx_array_t **) (p + cmd->offset);
+
+    if (*a == NGX_CONF_UNSET_PTR) {
+        *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
+        if (*a == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        cv = ngx_array_push(*a);
+        if (cv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        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;
+        }
+    }
+
+    return NGX_CONF_OK;
+}
+
+
 ngx_uint_t
 ngx_http_script_variables_count(ngx_str_t *value)
 {
@@ -251,8 +357,6 @@ ngx_http_script_compile(ngx_http_script_
             {
             ngx_uint_t  n;
 
-            /* NGX_HTTP_MAX_CAPTURES is 9 */
-
             if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
 
                 n = sc->source->data[i] - '0';
@@ -828,20 +932,9 @@ ngx_http_script_regex_start_code(ngx_htt
         e->line.data = e->sp->data;
     }
 
-    if (code->ncaptures && r->captures == NULL) {
+    rc = ngx_http_regex_exec(r, code->regex, &e->line);
 
-        r->captures = ngx_palloc(r->pool,
-                                 (NGX_HTTP_MAX_CAPTURES + 1) * 3 * sizeof(int));
-        if (r->captures == NULL) {
-            e->ip = ngx_http_script_exit;
-            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            return;
-        }
-    }
-
-    rc = ngx_regex_exec(code->regex, &e->line, r->captures, code->ncaptures);
-
-    if (rc == NGX_REGEX_NO_MATCHED) {
+    if (rc == NGX_DECLINED) {
         if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
             ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
                           "\"%V\" does not match \"%V\"",
@@ -870,11 +963,7 @@ ngx_http_script_regex_start_code(ngx_htt
         return;
     }
 
-    if (rc < 0) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
-                      rc, &e->line, &code->name);
-
+    if (rc == NGX_ERROR) {
         e->ip = ngx_http_script_exit;
         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
         return;
@@ -885,9 +974,6 @@ ngx_http_script_regex_start_code(ngx_htt
                       "\"%V\" matches \"%V\"", &code->name, &e->line);
     }
 
-    r->ncaptures = code->ncaptures;
-    r->captures_data = e->line.data;
-
     if (code->test) {
         if (code->negative_test) {
             e->sp->len = 0;
@@ -930,14 +1016,14 @@ ngx_http_script_regex_start_code(ngx_htt
         e->buf.len = code->size;
 
         if (code->uri) {
-            if (rc && (r->quoted_uri || r->plus_in_uri)) {
+            if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
                 e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
                                                  NGX_ESCAPE_ARGS);
             }
         }
 
-        for (n = 1; n < (ngx_uint_t) rc; n++) {
-            e->buf.len += r->captures[2 * n + 1] - r->captures[2 * n];
+        for (n = 2; n < r->ncaptures; n += 2) {
+            e->buf.len += r->captures[n + 1] - r->captures[n];
         }
 
     } else {
@@ -1003,7 +1089,7 @@ ngx_http_script_regex_end_code(ngx_http_
                          NGX_UNESCAPE_REDIRECT);
 
         if (src < e->pos) {
-            dst = ngx_copy(dst, src, e->pos - src);
+            dst = ngx_movemem(dst, src, e->pos - src);
         }
 
         e->pos = dst;
@@ -1028,8 +1114,7 @@ ngx_http_script_regex_end_code(ngx_http_
         }
 
         r->headers_out.location->hash = 1;
-        r->headers_out.location->key.len = sizeof("Location") - 1;
-        r->headers_out.location->key.data = (u_char *) "Location";
+        ngx_str_set(&r->headers_out.location->key, "Location");
         r->headers_out.location->value = e->buf;
 
         e->ip += sizeof(ngx_http_script_regex_end_code_t);
@@ -1275,14 +1360,17 @@ ngx_http_script_return_code(ngx_http_scr
 
     code = (ngx_http_script_return_code_t *) e->ip;
 
-    e->status = code->status;
-
-    if (code->status == NGX_HTTP_NO_CONTENT) {
-        e->request->header_only = 1;
-        e->request->zero_body = 1;
+    if (code->status < NGX_HTTP_BAD_REQUEST
+        || code->text.value.len
+        || code->text.lengths)
+    {
+        e->status = ngx_http_send_response(e->request, code->status, NULL,
+                                           &code->text);
+    } else {
+        e->status = code->status;
     }
 
-    e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t);
+    e->ip = ngx_http_script_exit;
 }
 
 
@@ -1407,6 +1495,7 @@ ngx_http_script_file_code(ngx_http_scrip
 
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
+    of.read_ahead = clcf->read_ahead;
     of.directio = clcf->directio;
     of.valid = clcf->open_file_cache_valid;
     of.min_uses = clcf->open_file_cache_min_uses;
@@ -1417,7 +1506,10 @@ ngx_http_script_file_code(ngx_http_scrip
     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
         != NGX_OK)
     {
-        if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+        if (of.err != NGX_ENOENT
+            && of.err != NGX_ENOTDIR
+            && of.err != NGX_ENAMETOOLONG)
+        {
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
                           "%s \"%s\" failed", of.failed, value->data);
         }
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -114,10 +114,9 @@ typedef struct {
 
 typedef struct {
     ngx_http_script_code_pt     code;
-    ngx_regex_t                *regex;
+    ngx_http_regex_t           *regex;
     ngx_array_t                *lengths;
     uintptr_t                   size;
-    uintptr_t                   ncaptures;
     uintptr_t                   status;
     uintptr_t                   next;
 
@@ -160,7 +159,7 @@ typedef struct {
 typedef struct {
     ngx_http_script_code_pt     code;
     uintptr_t                   status;
-    uintptr_t                   null;
+    ngx_http_complex_value_t    text;
 } ngx_http_script_return_code_t;
 
 
@@ -208,6 +207,14 @@ void ngx_http_script_flush_complex_value
 ngx_int_t ngx_http_complex_value(ngx_http_request_t *r,
     ngx_http_complex_value_t *val, ngx_str_t *value);
 ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv);
+char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+
+
+ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r,
+    ngx_array_t *predicates);
+char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 
 ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value);
 ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc);
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -31,13 +31,13 @@ static u_char ngx_http_error_tail[] =
 ;
 
 
-static u_char ngx_http_msie_stub[] =
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
-"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+static u_char ngx_http_msie_padding[] =
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
+"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
 ;
 
 
@@ -65,6 +65,14 @@ static char ngx_http_error_302_page[] =
 ;
 
 
+static char ngx_http_error_303_page[] =
+"<html>" CRLF
+"<head><title>303 See Other</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>303 See Other</h1></center>" CRLF
+;
+
+
 static char ngx_http_error_400_page[] =
 "<html>" CRLF
 "<head><title>400 Bad Request</title></head>" CRLF
@@ -193,6 +201,16 @@ static char ngx_http_error_416_page[] =
 ;
 
 
+static char ngx_http_error_494_page[] =
+"<html>" CRLF
+"<head><title>400 Request Header Or Cookie Too Large</title></head>"
+CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>400 Bad Request</h1></center>" CRLF
+"<center>Request Header Or Cookie Too Large</center>" CRLF
+;
+
+
 static char ngx_http_error_495_page[] =
 "<html>" CRLF
 "<head><title>400 The SSL certificate error</title></head>"
@@ -281,7 +299,7 @@ static ngx_str_t ngx_http_error_pages[] 
     /* ngx_null_string, */               /* 300 */
     ngx_string(ngx_http_error_301_page),
     ngx_string(ngx_http_error_302_page),
-    ngx_null_string,                     /* 303 */
+    ngx_string(ngx_http_error_303_page),
 
 #define NGX_HTTP_LAST_LEVEL_300  304
 #define NGX_HTTP_LEVEL_300       (NGX_HTTP_LAST_LEVEL_300 - 301)
@@ -307,6 +325,7 @@ static ngx_str_t ngx_http_error_pages[] 
 #define NGX_HTTP_LAST_LEVEL_400  417
 #define NGX_HTTP_LEVEL_400       (NGX_HTTP_LAST_LEVEL_400 - 400)
 
+    ngx_string(ngx_http_error_494_page), /* 494, request header too large */
     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
     ngx_string(ngx_http_error_497_page), /* 497, http to https */
@@ -421,17 +440,18 @@ ngx_http_special_response_handler(ngx_ht
         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200
                                            + NGX_HTTP_LEVEL_300;
 
-    } else if (error >= NGX_HTTP_OWN_CODES
+    } else if (error >= NGX_HTTP_NGINX_CODES
                && error < NGX_HTTP_LAST_LEVEL_500)
     {
         /* 49X, 5XX */
-        err = error - NGX_HTTP_OWN_CODES + NGX_HTTP_LEVEL_200
-                                         + NGX_HTTP_LEVEL_300
-                                         + NGX_HTTP_LEVEL_400;
+        err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_LEVEL_200
+                                           + NGX_HTTP_LEVEL_300
+                                           + NGX_HTTP_LEVEL_400;
         switch (error) {
             case NGX_HTTP_TO_HTTPS:
             case NGX_HTTPS_CERT_ERROR:
             case NGX_HTTPS_NO_CERT:
+            case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
                 r->err_status = NGX_HTTP_BAD_REQUEST;
                 break;
         }
@@ -515,9 +535,9 @@ ngx_http_send_error_page(ngx_http_reques
         r->expect_tested = 1;
     }
 
-    r->err_status = overwrite;
-
-    r->zero_in_uri = 0;
+    if (overwrite >= 0) {
+        r->err_status = overwrite;
+    }
 
     if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
         return NGX_ERROR;
@@ -550,11 +570,17 @@ ngx_http_send_error_page(ngx_http_reques
         return NGX_ERROR;
     }
 
-    r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
+    if (overwrite >= NGX_HTTP_MOVED_PERMANENTLY
+        && overwrite <= NGX_HTTP_SEE_OTHER)
+    {
+        r->err_status = overwrite;
+
+    } else {
+        r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
+    }
 
     location->hash = 1;
-    location->key.len = sizeof("Location") - 1;
-    location->key.data = (u_char *) "Location";
+    ngx_str_set(&location->key, "Location");
     location->value = uri;
 
     r->headers_out.location = location;
@@ -565,7 +591,7 @@ ngx_http_send_error_page(ngx_http_reques
         return ngx_http_send_refresh(r);
     }
 
-    return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY
+    return ngx_http_send_special_response(r, clcf, r->err_status
                                                    - NGX_HTTP_MOVED_PERMANENTLY
                                                    + NGX_HTTP_LEVEL_200);
 }
@@ -593,32 +619,24 @@ ngx_http_send_special_response(ngx_http_
 
     msie_padding = 0;
 
-    if (!r->zero_body) {
-        if (ngx_http_error_pages[err].len) {
-            r->headers_out.content_length_n = ngx_http_error_pages[err].len
-                                              + len;
-            if (clcf->msie_padding
-                && r->headers_in.msie
-                && r->http_version >= NGX_HTTP_VERSION_10
-                && err >= NGX_HTTP_LEVEL_300)
-            {
-                r->headers_out.content_length_n +=
-                                                sizeof(ngx_http_msie_stub) - 1;
-                msie_padding = 1;
-            }
-
-            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;
+    if (ngx_http_error_pages[err].len) {
+        r->headers_out.content_length_n = ngx_http_error_pages[err].len + len;
+        if (clcf->msie_padding
+            && (r->headers_in.msie || r->headers_in.chrome)
+            && r->http_version >= NGX_HTTP_VERSION_10
+            && err >= NGX_HTTP_LEVEL_300)
+        {
+            r->headers_out.content_length_n +=
+                                         sizeof(ngx_http_msie_padding) - 1;
+            msie_padding = 1;
         }
 
+        r->headers_out.content_type_len = sizeof("text/html") - 1;
+        ngx_str_set(&r->headers_out.content_type, "text/html");
+        r->headers_out.content_type_lowcase = NULL;
+
     } else {
-        r->headers_out.content_length_n = 0;
-        err = 0;
+        r->headers_out.content_length_n = -1;
     }
 
     if (r->headers_out.content_length) {
@@ -671,8 +689,8 @@ ngx_http_send_special_response(ngx_http_
         }
 
         b->memory = 1;
-        b->pos = ngx_http_msie_stub;
-        b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1;
+        b->pos = ngx_http_msie_padding;
+        b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;
 
         out[1].next = &out[2];
         out[2].buf = b;
@@ -711,8 +729,7 @@ ngx_http_send_refresh(ngx_http_request_t
     r->err_status = NGX_HTTP_OK;
 
     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";
+    ngx_str_set(&r->headers_out.content_type, "text/html");
     r->headers_out.content_type_lowcase = NULL;
 
     r->headers_out.location->hash = 0;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -72,6 +72,8 @@ 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_set_cookie(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t
     ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
@@ -189,7 +191,7 @@ ngx_http_upstream_header_t  ngx_http_ups
                  ngx_http_upstream_rewrite_refresh, 0, 0 },
 
     { ngx_string("Set-Cookie"),
-                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_process_set_cookie, 0,
                  ngx_http_upstream_copy_header_line, 0, 1 },
 
     { ngx_string("Content-Disposition"),
@@ -355,6 +357,16 @@ ngx_conf_bitmask_t  ngx_http_upstream_ca
 };
 
 
+ngx_conf_bitmask_t  ngx_http_upstream_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_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE },
+    { ngx_null_string, 0 }
+};
+
+
 ngx_int_t
 ngx_http_upstream_create(ngx_http_request_t *r)
 {
@@ -365,7 +377,6 @@ ngx_http_upstream_create(ngx_http_reques
     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));
@@ -479,6 +490,8 @@ ngx_http_upstream_init_request(ngx_http_
         return;
     }
 
+    u->peer.local = u->conf->local;
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     u->output.alignment = clcf->directio_alignment;
@@ -532,7 +545,8 @@ ngx_http_upstream_init_request(ngx_http_
             if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
                 != NGX_OK)
             {
-                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
                 return;
             }
 
@@ -560,11 +574,20 @@ ngx_http_upstream_init_request(ngx_http_
             }
         }
 
+        if (u->resolved->port == 0) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "no port in upstream \"%V\"", host);
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
         temp.name = *host;
 
         ctx = ngx_resolve_start(clcf->resolver, &temp);
         if (ctx == NULL) {
-            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
 
@@ -572,7 +595,7 @@ ngx_http_upstream_init_request(ngx_http_
             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);
+            ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
             return;
         }
 
@@ -586,7 +609,8 @@ ngx_http_upstream_init_request(ngx_http_
 
         if (ngx_resolve_name(ctx) != NGX_OK) {
             u->resolved->ctx = NULL;
-            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
 
@@ -596,7 +620,8 @@ ngx_http_upstream_init_request(ngx_http_
 found:
 
     if (uscf->peer.init(r, uscf) != NGX_OK) {
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
 
@@ -616,6 +641,19 @@ ngx_http_upstream_cache(ngx_http_request
 
     if (c == NULL) {
 
+        switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {
+
+        case NGX_ERROR:
+            return NGX_ERROR;
+
+        case NGX_DECLINED:
+            u->cache_status = NGX_HTTP_CACHE_BYPASS;
+            return NGX_DECLINED;
+
+        default: /* NGX_OK */
+            break;
+        }
+
         if (!(r->method & u->conf->cache_methods)) {
             return NGX_DECLINED;
         }
@@ -624,18 +662,10 @@ ngx_http_upstream_cache(ngx_http_request
             u->method = ngx_http_core_get_method;
         }
 
-        c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
-        if (c == NULL) {
+        if (ngx_http_file_cache_new(r) != NGX_OK) {
             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;
         }
@@ -646,6 +676,8 @@ ngx_http_upstream_cache(ngx_http_request
 
         u->cacheable = 1;
 
+        c = r->cache;
+
         c->min_uses = u->conf->cache_min_uses;
         c->body_start = u->conf->buffer_size;
         c->file_cache = u->conf->cache->data;
@@ -746,6 +778,11 @@ ngx_http_upstream_cache_send(ngx_http_re
     r->cached = 1;
     c = r->cache;
 
+    if (c->header_start == c->body_start) {
+        r->http_version = NGX_HTTP_VERSION_9;
+        return ngx_http_cache_send(r);
+    }
+
     /* TODO: cache stack */
 
     u->buffer = *c->buf;
@@ -789,11 +826,13 @@ static void
 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
 {
     ngx_http_request_t            *r;
+    ngx_http_upstream_t           *u;
     ngx_http_upstream_resolved_t  *ur;
 
     r = ctx->data;
 
-    r->upstream->resolved->ctx = NULL;
+    u = r->upstream;
+    ur = u->resolved;
 
     if (ctx->state) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -801,12 +840,10 @@ ngx_http_upstream_resolve_handler(ngx_re
                       &ctx->name, ctx->state,
                       ngx_resolver_strerror(ctx->state));
 
-        ngx_resolve_name_done(ctx);
-        ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
+        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
         return;
     }
 
-    ur = r->upstream->resolved;
     ur->naddrs = ctx->naddrs;
     ur->addrs = ctx->addrs;
 
@@ -827,14 +864,15 @@ ngx_http_upstream_resolve_handler(ngx_re
 #endif
 
     if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
-        ngx_resolve_name_done(ctx);
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
 
     ngx_resolve_name_done(ctx);
-
-    ngx_http_upstream_connect(r, r->upstream);
+    ur->ctx = NULL;
+
+    ngx_http_upstream_connect(r, u);
 }
 
 
@@ -921,10 +959,6 @@ ngx_http_upstream_check_broken_connectio
         return;
     }
 
-    if (u->peer.connection == NULL) {
-        return;
-    }
-
 #if (NGX_HAVE_KQUEUE)
 
     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
@@ -956,7 +990,6 @@ ngx_http_upstream_check_broken_connectio
         if (u->peer.connection == NULL) {
             ngx_http_upstream_finalize_request(r, u,
                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
-            return;
         }
 
         return;
@@ -1019,7 +1052,6 @@ ngx_http_upstream_check_broken_connectio
     if (u->peer.connection == NULL) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
     }
 }
 
@@ -1542,7 +1574,7 @@ ngx_http_upstream_process_header(ngx_htt
 
     /* rc == NGX_OK */
 
-    if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST) {
+    if (u->headers_in.status_n > NGX_HTTP_SPECIAL_RESPONSE) {
 
         if (r->subrequest_in_memory) {
             u->buffer.last = u->buffer.pos;
@@ -1696,6 +1728,21 @@ ngx_http_upstream_intercept_errors(ngx_h
                 r->headers_out.www_authenticate = h;
             }
 
+#if (NGX_HTTP_CACHE)
+
+            if (r->cache) {
+                time_t  valid;
+
+                valid = ngx_http_file_cache_valid(u->conf->cache_valid, status);
+
+                if (valid) {
+                    r->cache->valid_sec = ngx_time() + valid;
+                    r->cache->error = status;
+                }
+
+                ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
+            }
+#endif
             ngx_http_upstream_finalize_request(r, u, status);
 
             return NGX_OK;
@@ -1795,19 +1842,14 @@ ngx_http_upstream_process_headers(ngx_ht
         }
 
         uri = &u->headers_in.x_accel_redirect->value;
-        args.len = 0;
-        args.data = NULL;
-        flags = 0;
+        ngx_str_null(&args);
+        flags = NGX_HTTP_LOG_UNSAFE;
 
         if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
             return NGX_DONE;
         }
 
-        if (flags & NGX_HTTP_ZERO_IN_URI) {
-            r->zero_in_uri = 1;
-        }
-
         if (r->method != NGX_HTTP_HEAD) {
             r->method = NGX_HTTP_GET;
         }
@@ -1914,7 +1956,7 @@ ngx_http_upstream_process_body_in_memory
 
         if (size == 0) {
             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
-                          "upstream buffer is too small to read repsonse");
+                          "upstream buffer is too small to read response");
             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
             return;
         }
@@ -2079,6 +2121,47 @@ ngx_http_upstream_send_response(ngx_http
         r->cache->file.fd = NGX_INVALID_FILE;
     }
 
+    switch (ngx_http_test_predicates(r, u->conf->no_cache)) {
+
+    case NGX_ERROR:
+        ngx_http_upstream_finalize_request(r, u, 0);
+        return;
+
+    case NGX_DECLINED:
+        u->cacheable = 0;
+        break;
+
+    default: /* NGX_OK */
+
+        if (u->cache_status == NGX_HTTP_CACHE_BYPASS) {
+
+            if (ngx_http_file_cache_new(r) != NGX_OK) {
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+            if (u->create_key(r) != NGX_OK) {
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+            /* TODO: add keys */
+
+            r->cache->min_uses = u->conf->cache_min_uses;
+            r->cache->body_start = u->conf->buffer_size;
+            r->cache->file_cache = u->conf->cache->data;
+
+            if (ngx_http_file_cache_create(r) != NGX_OK) {
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+            u->cacheable = 1;
+        }
+
+        break;
+    }
+
     if (u->cacheable) {
         time_t  now, valid;
 
@@ -2099,11 +2182,6 @@ ngx_http_upstream_send_response(ngx_http
             r->cache->date = now;
             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
 
-            if (r->headers_out.content_length_n != -1) {
-                r->cache->length = r->cache->body_start
-                                   + r->headers_out.content_length_n;
-            }
-
             ngx_http_file_cache_set_header(r, u->buffer.start);
 
         } else {
@@ -2116,7 +2194,7 @@ ngx_http_upstream_send_response(ngx_http
                    "http cacheable: %d", u->cacheable);
 
     if (u->cacheable == 0 && r->cache) {
-        ngx_http_file_cache_free(r, u->pipe->temp_file);
+        ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
     }
 
 #endif
@@ -2591,7 +2669,7 @@ ngx_http_upstream_process_request(ngx_ht
                 ngx_http_file_cache_update(r, u->pipe->temp_file);
 
             } else if (p->upstream_error) {
-                ngx_http_file_cache_free(r, u->pipe->temp_file);
+                ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
             }
         }
 
@@ -2837,6 +2915,7 @@ ngx_http_upstream_cleanup(void *data)
 
     if (u->resolved && u->resolved->ctx) {
         ngx_resolve_name_done(u->resolved->ctx);
+        u->resolved->ctx = NULL;
     }
 
     ngx_http_upstream_finalize_request(r, u, NGX_DONE);
@@ -2854,6 +2933,12 @@ ngx_http_upstream_finalize_request(ngx_h
 
     if (u->cleanup) {
         *u->cleanup = NULL;
+        u->cleanup = NULL;
+    }
+
+    if (u->resolved && u->resolved->ctx) {
+        ngx_resolve_name_done(u->resolved->ctx);
+        u->resolved->ctx = NULL;
     }
 
     if (u->state && u->state->response_sec) {
@@ -2912,10 +2997,6 @@ ngx_http_upstream_finalize_request(ngx_h
     if (u->cacheable && r->cache) {
         time_t  valid;
 
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http upstream cache fd: %d",
-                       r->cache->file.fd);
-
         if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
 
             valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
@@ -2926,7 +3007,7 @@ ngx_http_upstream_finalize_request(ngx_h
             }
         }
 
-        ngx_http_file_cache_free(r, u->pipe->temp_file);
+        ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
     }
 
 #endif
@@ -2976,6 +3057,24 @@ ngx_http_upstream_ignore_header_line(ngx
 
 
 static ngx_int_t
+ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+#if (NGX_HTTP_CACHE)
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+
+    if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
+        u->cacheable = 0;
+    }
+#endif
+
+    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)
 {
@@ -3017,16 +3116,18 @@ ngx_http_upstream_process_cache_control(
         return NGX_OK;
     }
 
-    last = h->value.data + h->value.len;
-
-    if (ngx_strlcasestrn(h->value.data, last, (u_char *) "no-cache", 8 - 1)
-        != NULL)
+    p = h->value.data;
+    last = p + h->value.len;
+
+    if (ngx_strlcasestrn(p, last, (u_char *) "no-cache", 8 - 1) != NULL
+        || ngx_strlcasestrn(p, last, (u_char *) "no-store", 8 - 1) != NULL
+        || ngx_strlcasestrn(p, last, (u_char *) "private", 7 - 1) != NULL)
     {
         u->cacheable = 0;
         return NGX_OK;
     }
 
-    p = ngx_strlcasestrn(h->value.data, last, (u_char *) "max-age=", 8 - 1);
+    p = ngx_strlcasestrn(p, last, (u_char *) "max-age=", 8 - 1);
 
     if (p == NULL) {
         return NGX_OK;
@@ -3035,7 +3136,7 @@ ngx_http_upstream_process_cache_control(
     n = 0;
 
     for (p += 8; p < last; p++) {
-        if (*p == ';' || *p == ' ') {
+        if (*p == ',' || *p == ';' || *p == ' ') {
             break;
         }
 
@@ -3703,7 +3804,7 @@ ngx_http_upstream_response_time_variable
         if (state[i].status) {
             ms = (ngx_msec_int_t)
                      (state[i].response_sec * 1000 + state[i].response_msec);
-            ms = (ms >= 0) ? ms : 0;
+            ms = ngx_max(ms, 0);
             p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
 
         } else {
@@ -4196,6 +4297,41 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
 }
 
 
+char *
+ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf)
+{
+    char  *p = conf;
+
+    ngx_int_t     rc;
+    ngx_str_t    *value;
+    ngx_addr_t  **paddr;
+
+    paddr = (ngx_addr_t **) (p + cmd->offset);
+
+    *paddr = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
+    if (*paddr == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    rc = ngx_parse_addr(cf->pool, *paddr, value[1].data, value[1].len);
+
+    switch (rc) {
+    case NGX_OK:
+        (*paddr)->name = value[1];
+        return NGX_CONF_OK;
+
+    case NGX_DECLINED:
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid address \"%V\"", &value[1]);
+    default:
+        return NGX_CONF_ERROR;
+    }
+}
+
+
 ngx_int_t
 ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -43,6 +43,7 @@
 #define NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES     0x00000004
 #define NGX_HTTP_UPSTREAM_IGN_EXPIRES        0x00000008
 #define NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL  0x00000010
+#define NGX_HTTP_UPSTREAM_IGN_SET_COOKIE     0x00000020
 
 
 typedef struct {
@@ -52,7 +53,7 @@ typedef struct {
     ngx_uint_t                       status;
     time_t                           response_sec;
     ngx_uint_t                       response_msec;
-    off_t                           response_length;
+    off_t                            response_length;
 
     ngx_str_t                       *peer;
 } ngx_http_upstream_state_t;
@@ -80,7 +81,7 @@ typedef struct {
 
 
 typedef struct {
-    ngx_peer_addr_t                 *addrs;
+    ngx_addr_t                      *addrs;
     ngx_uint_t                       naddrs;
     ngx_uint_t                       weight;
     ngx_uint_t                       max_fails;
@@ -152,6 +153,8 @@ typedef struct {
     ngx_array_t                     *hide_headers;
     ngx_array_t                     *pass_headers;
 
+    ngx_addr_t                      *local;
+
 #if (NGX_HTTP_CACHE)
     ngx_shm_zone_t                  *cache;
 
@@ -160,6 +163,8 @@ typedef struct {
     ngx_uint_t                       cache_methods;
 
     ngx_array_t                     *cache_valid;
+    ngx_array_t                     *cache_bypass;
+    ngx_array_t                     *no_cache;
 #endif
 
     ngx_array_t                     *store_lengths;
@@ -321,6 +326,8 @@ ngx_int_t ngx_http_upstream_create(ngx_h
 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);
+char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
     ngx_str_t *default_hide_headers, ngx_hash_init_t *hash);
@@ -332,7 +339,7 @@ ngx_int_t ngx_http_upstream_hide_headers
 
 extern ngx_module_t        ngx_http_upstream_module;
 extern ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[];
-
+extern ngx_conf_bitmask_t  ngx_http_upstream_ignore_headers_masks[];
 
 
 #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -81,5 +81,4 @@ void ngx_http_upstream_save_round_robin_
 #endif
 
 
-
 #endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -14,6 +14,8 @@ static ngx_int_t ngx_http_variable_reque
     ngx_http_variable_value_t *v, uintptr_t data);
 static void ngx_http_variable_request_set(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
@@ -194,7 +196,8 @@ static ngx_http_variable_t  ngx_http_cor
     { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
 
     { ngx_string("request_method"), NULL,
-      ngx_http_variable_request_method, 0, 0, 0 },
+      ngx_http_variable_request_method, 0,
+      NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
     { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
 
@@ -238,7 +241,7 @@ static ngx_http_variable_t  ngx_http_cor
       offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
 
     { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
-      ngx_http_variable_request,
+      ngx_http_variable_request_get_size,
       offsetof(ngx_http_request_t, limit_rate),
       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
@@ -438,8 +441,7 @@ ngx_http_get_flushed_variable(ngx_http_r
 
 
 ngx_http_variable_value_t *
-ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
-    ngx_uint_t nowarn)
+ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
 {
     ngx_http_variable_t        *v;
     ngx_http_variable_value_t  *vv;
@@ -451,7 +453,7 @@ ngx_http_get_variable(ngx_http_request_t
 
     if (v) {
         if (v->flags & NGX_HTTP_VAR_INDEXED) {
-            return ngx_http_get_indexed_variable(r, v->index);
+            return ngx_http_get_flushed_variable(r, v->index);
 
         } else {
 
@@ -492,7 +494,7 @@ ngx_http_get_variable(ngx_http_request_t
         return NULL;
     }
 
-    if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) {
+    if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) {
 
         if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
             == NGX_OK)
@@ -523,11 +525,6 @@ ngx_http_get_variable(ngx_http_request_t
 
     vv->not_found = 1;
 
-    if (nowarn == 0) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "unknown \"%V\" variable", name);
-    }
-
     return vv;
 }
 
@@ -568,6 +565,28 @@ ngx_http_variable_request_set(ngx_http_r
 }
 
 
+static ngx_int_t
+ngx_http_variable_request_get_size(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    size_t  *sp;
+
+    sp = (size_t *) ((char *) r + data);
+
+    v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);
+    if (v->data == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    return NGX_OK;
+}
+
+
 static void
 ngx_http_variable_request_set_size(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
@@ -887,7 +906,7 @@ ngx_http_variable_binary_remote_addr(ngx
         v->valid = 1;
         v->no_cacheable = 0;
         v->not_found = 0;
-        v->data = (u_char *) &sin6->sin6_addr;
+        v->data = sin6->sin6_addr.s6_addr;
 
         break;
 #endif
@@ -1371,8 +1390,7 @@ ngx_http_variable_sent_location(ngx_http
         return NGX_OK;
     }
 
-    name.len = sizeof("sent_http_location") - 1;
-    name.data = (u_char *) "sent_http_location";
+    ngx_str_set(&name, "sent_http_location");
 
     return ngx_http_variable_unknown_header(v, &name,
                                             &r->headers_out.headers.part,
@@ -1642,6 +1660,205 @@ ngx_http_variable_pid(ngx_http_request_t
 }
 
 
+void *
+ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map, ngx_uint_t key,
+    u_char *text, size_t len, ngx_str_t *match)
+{
+    void  *p;
+
+    p = ngx_hash_find_combined(&map->hash, key, text, len);
+    if (p) {
+        return p;
+    }
+
+#if (NGX_PCRE)
+
+    if (len && map->nregex) {
+        ngx_int_t              n;
+        ngx_uint_t             i;
+        ngx_http_map_regex_t  *reg;
+
+        reg = map->regex;
+
+        for (i = 0; i < map->nregex; i++) {
+
+            n = ngx_http_regex_exec(r, reg[i].regex, match);
+
+            if (n == NGX_OK) {
+                return reg[i].value;
+            }
+
+            if (n == NGX_DECLINED) {
+                continue;
+            }
+
+            /* NGX_ERROR */
+
+            return NULL;
+        }
+    }
+
+#endif
+
+    return NULL;
+}
+
+
+#if (NGX_PCRE)
+
+static ngx_int_t
+ngx_http_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v,
+    uintptr_t data)
+{
+    v->not_found = 1;
+    return NGX_OK;
+}
+
+
+ngx_http_regex_t *
+ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
+{
+    u_char                     *p;
+    size_t                      size;
+    ngx_str_t                   name;
+    ngx_uint_t                  i, n;
+    ngx_http_variable_t        *v;
+    ngx_http_regex_t           *re;
+    ngx_http_regex_variable_t  *rv;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    rc->pool = cf->pool;
+
+    if (ngx_regex_compile(rc) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
+        return NULL;
+    }
+
+    re = ngx_pcalloc(cf->pool, sizeof(ngx_http_regex_t));
+    if (re == NULL) {
+        return NULL;
+    }
+
+    re->regex = rc->regex;
+    re->ncaptures = rc->captures;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+    cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
+
+    n = (ngx_uint_t) rc->named_captures;
+
+    if (n == 0) {
+        return re;
+    }
+
+    rv = ngx_palloc(rc->pool, n * sizeof(ngx_http_regex_variable_t));
+    if (rv == NULL) {
+        return NULL;
+    }
+
+    re->variables = rv;
+    re->nvariables = n;
+    re->name = rc->pattern;
+
+    size = rc->name_size;
+    p = rc->names;
+
+    for (i = 0; i < n; i++) {
+        rv[i].capture = 2 * ((p[0] << 8) + p[1]);
+
+        name.data = &p[2];
+        name.len = ngx_strlen(name.data);
+
+        v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
+        if (v == NULL) {
+            return NULL;
+        }
+
+        rv[i].index = ngx_http_get_variable_index(cf, &name);
+        if (rv[i].index == NGX_ERROR) {
+            return NULL;
+        }
+
+        v->get_handler = ngx_http_variable_not_found;
+
+        p += size;
+    }
+
+    return re;
+}
+
+
+ngx_int_t
+ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s)
+{
+    ngx_int_t                   rc, index;
+    ngx_uint_t                  i, n, len;
+    ngx_http_variable_value_t  *vv;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    if (re->ncaptures) {
+        len = cmcf->ncaptures;
+
+        if (r->captures == NULL) {
+            r->captures = ngx_palloc(r->pool, len * sizeof(int));
+            if (r->captures == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
+    } else {
+        len = 0;
+    }
+
+    rc = ngx_regex_exec(re->regex, s, r->captures, len);
+
+    if (rc == NGX_REGEX_NO_MATCHED) {
+        return NGX_DECLINED;
+    }
+
+    if (rc < 0) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
+                      rc, s, &re->name);
+        return NGX_ERROR;
+    }
+
+    for (i = 0; i < re->nvariables; i++) {
+
+        n = re->variables[i].capture;
+        index = re->variables[i].index;
+        vv = &r->variables[index];
+
+        vv->len = r->captures[n + 1] - r->captures[n];
+        vv->valid = 1;
+        vv->no_cacheable = 0;
+        vv->not_found = 0;
+        vv->data = &s->data[r->captures[n]];
+
+#if (NGX_DEBUG)
+        {
+        ngx_http_variable_t  *v;
+
+        v = cmcf->variables.elts;
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http regex set $%V to \"%*s\"",
+                       &v[index].name, vv->len, vv->data);
+        }
+#endif
+    }
+
+    r->ncaptures = rc * 2;
+    r->captures_data = s->data;
+
+    return NGX_OK;
+}
+
+#endif
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
@@ -1757,6 +1974,7 @@ ngx_http_variables_init_vars(ngx_conf_t 
         if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
             v[i].get_handler = ngx_http_variable_argument;
             v[i].data = (uintptr_t) &v[i].name;
+            v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
 
             continue;
         }
@@ -1799,87 +2017,3 @@ ngx_http_variables_init_vars(ngx_conf_t 
 
     return NGX_OK;
 }
-
-
-void
-ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp,
-    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
-{
-    ngx_rbtree_node_t               **p;
-    ngx_http_variable_value_node_t   *vvn, *vvt;
-
-    for ( ;; ) {
-
-        vvn = (ngx_http_variable_value_node_t *) node;
-        vvt = (ngx_http_variable_value_node_t *) temp;
-
-        if (node->key != temp->key) {
-
-            p = (node->key < temp->key) ? &temp->left : &temp->right;
-
-        } else if (vvn->len != vvt->len) {
-
-            p = (vvn->len < vvt->len) ? &temp->left : &temp->right;
-
-        } else {
-            p = (ngx_memcmp(vvn->value->data, vvt->value->data, vvn->len) < 0)
-                 ? &temp->left : &temp->right;
-        }
-
-        if (*p == sentinel) {
-            break;
-        }
-
-        temp = *p;
-    }
-
-    *p = node;
-    node->parent = temp;
-    node->left = sentinel;
-    node->right = sentinel;
-    ngx_rbt_red(node);
-}
-
-
-ngx_http_variable_value_t *
-ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val,
-    uint32_t hash)
-{
-    ngx_int_t                        rc;
-    ngx_rbtree_node_t               *node, *sentinel;
-    ngx_http_variable_value_node_t  *vvn;
-
-    node = rbtree->root;
-    sentinel = rbtree->sentinel;
-
-    while (node != sentinel) {
-
-        vvn = (ngx_http_variable_value_node_t *) node;
-
-        if (hash != node->key) {
-            node = (hash < node->key) ? node->left : node->right;
-            continue;
-        }
-
-        if (val->len != vvn->len) {
-            node = (val->len < vvn->len) ? node->left : node->right;
-            continue;
-        }
-
-        rc = ngx_memcmp(val->data, vvn->value->data, val->len);
-
-        if (rc < 0) {
-            node = node->left;
-            continue;
-        }
-
-        if (rc > 0) {
-            node = node->right;
-            continue;
-        }
-
-        return vvn->value;
-    }
-
-    return NULL;
-}
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -50,7 +50,7 @@ ngx_http_variable_value_t *ngx_http_get_
     ngx_uint_t index);
 
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
-    ngx_str_t *name, ngx_uint_t key, ngx_uint_t nowarn);
+    ngx_str_t *name, ngx_uint_t key);
 
 ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v,
     ngx_str_t *var, ngx_list_part_t *part, size_t prefix);
@@ -59,21 +59,52 @@ ngx_int_t ngx_http_variable_unknown_head
 #define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL;
 
 
-ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf);
-ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf);
+#if (NGX_PCRE)
+
+typedef struct {
+    ngx_uint_t                    capture;
+    ngx_int_t                     index;
+} ngx_http_regex_variable_t;
+
+
+typedef struct {
+    ngx_regex_t                  *regex;
+    ngx_uint_t                    ncaptures;
+    ngx_http_regex_variable_t    *variables;
+    ngx_uint_t                    nvariables;
+    ngx_str_t                     name;
+} ngx_http_regex_t;
 
 
 typedef struct {
-    ngx_rbtree_node_t             node;
-    size_t                        len;
-    ngx_http_variable_value_t    *value;
-} ngx_http_variable_value_node_t;
+    ngx_http_regex_t             *regex;
+    void                         *value;
+} ngx_http_map_regex_t;
+
+
+ngx_http_regex_t *ngx_http_regex_compile(ngx_conf_t *cf,
+    ngx_regex_compile_t *rc);
+ngx_int_t ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re,
+    ngx_str_t *s);
+
+#endif
 
 
-void ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp,
-    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
-ngx_http_variable_value_t *ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree,
-    ngx_str_t *name, uint32_t hash);
+typedef struct {
+    ngx_hash_combined_t           hash;
+#if (NGX_PCRE)
+    ngx_http_map_regex_t         *regex;
+    ngx_uint_t                    nregex;
+#endif
+} ngx_http_map_t;
+
+
+void *ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map,
+    ngx_uint_t key, u_char *text, size_t len, ngx_str_t *match);
+
+
+ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf);
+ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf);
 
 
 extern ngx_http_variable_value_t  ngx_http_variable_null_value;
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -395,7 +395,7 @@ char *ngx_mail_capabilities(ngx_conf_t *
 
 
 /* STUB */
-void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer);
+void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer);
 void ngx_mail_auth_http_init(ngx_mail_session_t *s);
 /**/
 
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -12,7 +12,7 @@
 
 
 typedef struct {
-    ngx_peer_addr_t                *peer;
+    ngx_addr_t                     *peer;
 
     ngx_msec_t                      timeout;
 
@@ -457,7 +457,7 @@ ngx_mail_auth_http_process_headers(ngx_m
     time_t               timer;
     size_t               len, size;
     ngx_int_t            rc, port, n;
-    ngx_peer_addr_t     *peer;
+    ngx_addr_t          *peer;
     struct sockaddr_in  *sin;
 
     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
@@ -764,7 +764,7 @@ ngx_mail_auth_http_process_headers(ngx_m
                 return;
             }
 
-            peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
+            peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t));
             if (peer == NULL) {
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
@@ -795,8 +795,7 @@ ngx_mail_auth_http_process_headers(ngx_m
 
             sin->sin_port = htons((in_port_t) port);
 
-            ctx->addr.data[ctx->addr.len] = '\0';
-            sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
+            sin->sin_addr.s_addr = ngx_inet_addr(ctx->addr.data, ctx->addr.len);
             if (sin->sin_addr.s_addr == INADDR_NONE) {
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V sent invalid server "
@@ -1406,12 +1405,17 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c
 
     ahcf->peer = u.addrs;
 
-    ahcf->host_header = u.host;
+    if (u.family != AF_UNIX) {
+        ahcf->host_header = u.host;
+
+    } else {
+        ngx_str_set(&ahcf->host_header, "localhost");
+    }
+
     ahcf->uri = u.uri;
 
     if (ahcf->uri.len == 0) {
-        ahcf->uri.len = sizeof("/") - 1;
-        ahcf->uri.data = (u_char *) "/";
+        ngx_str_set(&ahcf->uri, "/");
     }
 
     return NGX_CONF_OK;
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -346,7 +346,7 @@ ngx_mail_auth_plain(ngx_mail_session_t *
 #endif
 
     plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
-    if (plain.data == NULL){
+    if (plain.data == NULL) {
         return NGX_ERROR;
     }
 
@@ -403,7 +403,7 @@ ngx_mail_auth_login_username(ngx_mail_se
                    "mail auth login username: \"%V\"", &arg[n]);
 
     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
-    if (s->login.data == NULL){
+    if (s->login.data == NULL) {
         return NGX_ERROR;
     }
 
@@ -434,7 +434,7 @@ ngx_mail_auth_login_password(ngx_mail_se
 
     s->passwd.data = ngx_pnalloc(c->pool,
                                  ngx_base64_decoded_length(arg[0].len));
-    if (s->passwd.data == NULL){
+    if (s->passwd.data == NULL) {
         return NGX_ERROR;
     }
 
@@ -494,7 +494,7 @@ ngx_mail_auth_cram_md5(ngx_mail_session_
                    "mail auth cram-md5: \"%V\"", &arg[0]);
 
     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len));
-    if (s->login.data == NULL){
+    if (s->login.data == NULL) {
         return NGX_ERROR;
     }
 
--- a/src/mail/ngx_mail_imap_handler.c
+++ b/src/mail/ngx_mail_imap_handler.c
@@ -39,8 +39,7 @@ ngx_mail_imap_init_session(ngx_mail_sess
 
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
 
-    s->out.len = sizeof(imap_greeting) - 1;
-    s->out.data = imap_greeting;
+    ngx_str_set(&s->out, imap_greeting);
 
     c->read->handler = ngx_mail_imap_init_protocol;
 
@@ -136,8 +135,7 @@ ngx_mail_imap_auth_state(ngx_event_t *re
 
     tag = 1;
     s->text.len = 0;
-    s->out.len = sizeof(imap_ok) - 1;
-    s->out.data = imap_ok;
+    ngx_str_set(&s->out, imap_ok);
 
     if (rc == NGX_OK) {
 
@@ -186,8 +184,7 @@ ngx_mail_imap_auth_state(ngx_event_t *re
 
             case NGX_IMAP_LOGOUT:
                 s->quit = 1;
-                s->text.len = sizeof(imap_bye) - 1;
-                s->text.data = imap_bye;
+                ngx_str_set(&s->text, imap_bye);
                 break;
 
             case NGX_IMAP_NOOP:
@@ -208,8 +205,7 @@ ngx_mail_imap_auth_state(ngx_event_t *re
             rc = ngx_mail_auth_login_username(s, c, 0);
 
             tag = 0;
-            s->out.len = sizeof(imap_password) - 1;
-            s->out.data = imap_password;
+            ngx_str_set(&s->out, imap_password);
             s->mail_state = ngx_imap_auth_login_password;
 
             break;
@@ -229,8 +225,7 @@ ngx_mail_imap_auth_state(ngx_event_t *re
 
     } else if (rc == NGX_IMAP_NEXT) {
         tag = 0;
-        s->out.len = sizeof(imap_next) - 1;
-        s->out.data = imap_next;
+        ngx_str_set(&s->out, imap_next);
     }
 
     switch (rc) {
@@ -245,16 +240,14 @@ ngx_mail_imap_auth_state(ngx_event_t *re
 
     case NGX_MAIL_PARSE_INVALID_COMMAND:
         s->state = 0;
-        s->out.len = sizeof(imap_invalid_command) - 1;
-        s->out.data = imap_invalid_command;
+        ngx_str_set(&s->out, imap_invalid_command);
         s->mail_state = ngx_imap_start;
         break;
     }
 
     if (tag) {
         if (s->tag.len == 0) {
-            s->tag.len = sizeof(imap_star) - 1;
-            s->tag.data = (u_char *) imap_star;
+            ngx_str_set(&s->tag, imap_star);
         }
 
         if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) {
@@ -364,24 +357,21 @@ ngx_mail_imap_authenticate(ngx_mail_sess
 
     case NGX_MAIL_AUTH_LOGIN:
 
-        s->out.len = sizeof(imap_username) - 1;
-        s->out.data = imap_username;
+        ngx_str_set(&s->out, imap_username);
         s->mail_state = ngx_imap_auth_login_username;
 
         return NGX_OK;
 
     case NGX_MAIL_AUTH_LOGIN_USERNAME:
 
-        s->out.len = sizeof(imap_password) - 1;
-        s->out.data = imap_password;
+        ngx_str_set(&s->out, imap_password);
         s->mail_state = ngx_imap_auth_login_password;
 
         return ngx_mail_auth_login_username(s, c, 1);
 
     case NGX_MAIL_AUTH_PLAIN:
 
-        s->out.len = sizeof(imap_plain_next) - 1;
-        s->out.data = imap_plain_next;
+        ngx_str_set(&s->out, imap_plain_next);
         s->mail_state = ngx_imap_auth_plain;
 
         return NGX_OK;
--- a/src/mail/ngx_mail_pop3_handler.c
+++ b/src/mail/ngx_mail_pop3_handler.c
@@ -59,8 +59,7 @@ ngx_mail_pop3_init_session(ngx_mail_sess
         s->out.len = p - s->out.data;
 
     } else {
-        s->out.len = sizeof(pop3_greeting) - 1;
-        s->out.data = pop3_greeting;
+        ngx_str_set(&s->out, pop3_greeting);
     }
 
     c->read->handler = ngx_mail_pop3_init_protocol;
@@ -149,8 +148,7 @@ ngx_mail_pop3_auth_state(ngx_event_t *re
         return;
     }
 
-    s->out.len = sizeof(pop3_ok) - 1;
-    s->out.data = pop3_ok;
+    ngx_str_set(&s->out, pop3_ok);
 
     if (rc == NGX_OK) {
         switch (s->mail_state) {
@@ -188,7 +186,6 @@ ngx_mail_pop3_auth_state(ngx_event_t *re
 
             default:
                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
-                s->mail_state = ngx_pop3_start;
                 break;
             }
 
@@ -215,7 +212,6 @@ ngx_mail_pop3_auth_state(ngx_event_t *re
 
             default:
                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
-                s->mail_state = ngx_pop3_start;
                 break;
             }
 
@@ -228,8 +224,7 @@ ngx_mail_pop3_auth_state(ngx_event_t *re
         case ngx_pop3_auth_login_username:
             rc = ngx_mail_auth_login_username(s, c, 0);
 
-            s->out.len = sizeof(pop3_password) - 1;
-            s->out.data = pop3_password;
+            ngx_str_set(&s->out, pop3_password);
             s->mail_state = ngx_pop3_auth_login_password;
             break;
 
@@ -261,8 +256,7 @@ ngx_mail_pop3_auth_state(ngx_event_t *re
         s->mail_state = ngx_pop3_start;
         s->state = 0;
 
-        s->out.len = sizeof(pop3_invalid_command) - 1;
-        s->out.data = pop3_invalid_command;
+        ngx_str_set(&s->out, pop3_invalid_command);
 
         /* fall through */
 
@@ -468,24 +462,21 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
 
     case NGX_MAIL_AUTH_LOGIN:
 
-        s->out.len = sizeof(pop3_username) - 1;
-        s->out.data = pop3_username;
+        ngx_str_set(&s->out, pop3_username);
         s->mail_state = ngx_pop3_auth_login_username;
 
         return NGX_OK;
 
     case NGX_MAIL_AUTH_LOGIN_USERNAME:
 
-        s->out.len = sizeof(pop3_password) - 1;
-        s->out.data = pop3_password;
+        ngx_str_set(&s->out, pop3_password);
         s->mail_state = ngx_pop3_auth_login_password;
 
         return ngx_mail_auth_login_username(s, c, 1);
 
     case NGX_MAIL_AUTH_PLAIN:
 
-        s->out.len = sizeof(pop3_next) - 1;
-        s->out.data = pop3_next;
+        ngx_str_set(&s->out, pop3_next);
         s->mail_state = ngx_pop3_auth_plain;
 
         return NGX_OK;
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -108,7 +108,7 @@ static u_char  smtp_auth_ok[] = "235 2.0
 
 
 void
-ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer)
+ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)
 {
     int                        keepalive;
     ngx_int_t                  rc;
@@ -304,8 +304,7 @@ ngx_mail_proxy_pop3_handler(ngx_event_t 
 
     default:
 #if (NGX_SUPPRESS_WARN)
-        line.len = 0;
-        line.data = NULL;
+        ngx_str_null(&line);
 #endif
         break;
     }
@@ -439,8 +438,7 @@ ngx_mail_proxy_imap_handler(ngx_event_t 
 
     default:
 #if (NGX_SUPPRESS_WARN)
-        line.len = 0;
-        line.data = NULL;
+        ngx_str_null(&line);
 #endif
         break;
     }
@@ -669,8 +667,7 @@ ngx_mail_proxy_smtp_handler(ngx_event_t 
 
     default:
 #if (NGX_SUPPRESS_WARN)
-        line.len = 0;
-        line.data = NULL;
+        ngx_str_null(&line);
 #endif
         break;
     }
@@ -731,7 +728,7 @@ ngx_mail_proxy_read_response(ngx_mail_se
 
     b->last += n;
 
-    if (b->last - b->pos < 5) {
+    if (b->last - b->pos < 4) {
         return NGX_AGAIN;
     }
 
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -191,7 +191,7 @@ ngx_mail_smtp_resolve_name_handler(ngx_r
 
     if (ctx->state) {
         ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                      "%V could not be resolved (%i: %s)",
+                      "\"%V\" could not be resolved (%i: %s)",
                       &ctx->name, ctx->state,
                       ngx_resolver_strerror(ctx->state));
 
@@ -319,8 +319,7 @@ ngx_mail_smtp_invalid_pipelining(ngx_eve
             return;
         }
 
-        s->out.len = sizeof(smtp_invalid_pipelining) - 1;
-        s->out.data = smtp_invalid_pipelining;
+        ngx_str_set(&s->out, smtp_invalid_pipelining);
         s->quit = 1;
     }
 
@@ -415,8 +414,7 @@ ngx_mail_smtp_auth_state(ngx_event_t *re
         return;
     }
 
-    s->out.len = sizeof(smtp_ok) - 1;
-    s->out.data = smtp_ok;
+    ngx_str_set(&s->out, smtp_ok);
 
     if (rc == NGX_OK) {
         switch (s->mail_state) {
@@ -436,8 +434,7 @@ ngx_mail_smtp_auth_state(ngx_event_t *re
 
             case NGX_SMTP_QUIT:
                 s->quit = 1;
-                s->out.len = sizeof(smtp_bye) - 1;
-                s->out.data = smtp_bye;
+                ngx_str_set(&s->out, smtp_bye);
                 break;
 
             case NGX_SMTP_MAIL:
@@ -457,8 +454,7 @@ ngx_mail_smtp_auth_state(ngx_event_t *re
 
             case NGX_SMTP_STARTTLS:
                 rc = ngx_mail_smtp_starttls(s, c);
-                s->out.len = sizeof(smtp_starttls) - 1;
-                s->out.data = smtp_starttls;
+                ngx_str_set(&s->out, smtp_starttls);
                 break;
 
             default:
@@ -471,8 +467,7 @@ ngx_mail_smtp_auth_state(ngx_event_t *re
         case ngx_smtp_auth_login_username:
             rc = ngx_mail_auth_login_username(s, c, 0);
 
-            s->out.len = sizeof(smtp_password) - 1;
-            s->out.data = smtp_password;
+            ngx_str_set(&s->out, smtp_password);
             s->mail_state = ngx_smtp_auth_login_password;
             break;
 
@@ -507,9 +502,7 @@ ngx_mail_smtp_auth_state(ngx_event_t *re
     case NGX_MAIL_PARSE_INVALID_COMMAND:
         s->mail_state = ngx_smtp_start;
         s->state = 0;
-
-        s->out.len = sizeof(smtp_invalid_command) - 1;
-        s->out.data = smtp_invalid_command;
+        ngx_str_set(&s->out, smtp_invalid_command);
 
         /* fall through */
 
@@ -537,8 +530,7 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s
     ngx_mail_smtp_srv_conf_t  *sscf;
 
     if (s->args.nelts != 2) {
-        s->out.len = sizeof(smtp_invalid_argument) - 1;
-        s->out.data = smtp_invalid_argument;
+        ngx_str_set(&s->out, smtp_invalid_argument);
         s->state = 0;
         return NGX_OK;
     }
@@ -554,10 +546,8 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s
 
     ngx_memcpy(s->smtp_helo.data, arg[1].data, arg[1].len);
 
-    s->smtp_from.len = 0;
-    s->smtp_from.data = NULL;
-    s->smtp_to.len = 0;
-    s->smtp_to.data = NULL;
+    ngx_str_null(&s->smtp_from);
+    ngx_str_null(&s->smtp_to);
 
     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
 
@@ -607,8 +597,7 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s
 #endif
 
     if (s->args.nelts < 2) {
-        s->out.len = sizeof(smtp_invalid_argument) - 1;
-        s->out.data = smtp_invalid_argument;
+        ngx_str_set(&s->out, smtp_invalid_argument);
         s->state = 0;
         return NGX_OK;
     }
@@ -619,24 +608,21 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s
 
     case NGX_MAIL_AUTH_LOGIN:
 
-        s->out.len = sizeof(smtp_username) - 1;
-        s->out.data = smtp_username;
+        ngx_str_set(&s->out, smtp_username);
         s->mail_state = ngx_smtp_auth_login_username;
 
         return NGX_OK;
 
     case NGX_MAIL_AUTH_LOGIN_USERNAME:
 
-        s->out.len = sizeof(smtp_password) - 1;
-        s->out.data = smtp_password;
+        ngx_str_set(&s->out, smtp_password);
         s->mail_state = ngx_smtp_auth_login_password;
 
         return ngx_mail_auth_login_username(s, c, 2);
 
     case NGX_MAIL_AUTH_PLAIN:
 
-        s->out.len = sizeof(smtp_next) - 1;
-        s->out.data = smtp_next;
+        ngx_str_set(&s->out, smtp_next);
         s->mail_state = ngx_smtp_auth_plain;
 
         return NGX_OK;
@@ -679,18 +665,14 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s
 
     if (!(sscf->auth_methods & NGX_MAIL_AUTH_NONE_ENABLED)) {
         ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
-
-        s->out.len = sizeof(smtp_auth_required) - 1;
-        s->out.data = smtp_auth_required;
-
+        ngx_str_set(&s->out, smtp_auth_required);
         return NGX_OK;
     }
 
     /* auth none */
 
     if (s->smtp_from.len) {
-        s->out.len = sizeof(smtp_bad_sequence) - 1;
-        s->out.data = smtp_bad_sequence;
+        ngx_str_set(&s->out, smtp_bad_sequence);
         return NGX_OK;
     }
 
@@ -712,8 +694,7 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s
     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    "smtp mail from:\"%V\"", &s->smtp_from);
 
-    s->out.len = sizeof(smtp_ok) - 1;
-    s->out.data = smtp_ok;
+    ngx_str_set(&s->out, smtp_ok);
 
     return NGX_OK;
 }
@@ -725,8 +706,7 @@ ngx_mail_smtp_rcpt(ngx_mail_session_t *s
     ngx_str_t  *arg, *end, cmd;
 
     if (s->smtp_from.len == 0) {
-        s->out.len = sizeof(smtp_bad_sequence) - 1;
-        s->out.data = smtp_bad_sequence;
+        ngx_str_set(&s->out, smtp_bad_sequence);
         return NGX_OK;
     }
 
@@ -757,13 +737,9 @@ ngx_mail_smtp_rcpt(ngx_mail_session_t *s
 static ngx_int_t
 ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    s->smtp_from.len = 0;
-    s->smtp_from.data = NULL;
-    s->smtp_to.len = 0;
-    s->smtp_to.data = NULL;
-
-    s->out.len = sizeof(smtp_ok) - 1;
-    s->out.data = smtp_ok;
+    ngx_str_null(&s->smtp_from);
+    ngx_str_null(&s->smtp_to);
+    ngx_str_set(&s->out, smtp_ok);
 
     return NGX_OK;
 }
@@ -784,12 +760,9 @@ ngx_mail_smtp_starttls(ngx_mail_session_
              * obtained from client before STARTTLS.
              */
 
-            s->smtp_helo.len = 0;
-            s->smtp_helo.data = NULL;
-            s->smtp_from.len = 0;
-            s->smtp_from.data = NULL;
-            s->smtp_to.len = 0;
-            s->smtp_to.data = NULL;
+            ngx_str_null(&s->smtp_helo);
+            ngx_str_null(&s->smtp_from);
+            ngx_str_null(&s->smtp_to);
 
             c->read->handler = ngx_mail_starttls_handler;
             return NGX_OK;
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -9,7 +9,7 @@
 #include <ngx_mail.h>
 
 
-#define NGX_DEFAULT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
+#define NGX_DEFAULT_CIPHERS  "HIGH:!ADH:!MD5"
 
 
 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf);
@@ -163,8 +163,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
      *     scf->certificate = { 0, NULL };
      *     scf->certificate_key = { 0, NULL };
      *     scf->dhparam = { 0, NULL };
-     *     scf->ciphers.len = 0;
-     *     scf->ciphers.data = NULL;
+     *     scf->ciphers = { 0, NULL };
      *     scf->shm_zone = NULL;
      */
 
@@ -198,8 +197,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
                          prev->prefer_server_ciphers, 0);
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
-                         (NGX_CONF_BITMASK_SET
-                          |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
+                         (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
 
     ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
     ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
--- a/src/misc/ngx_google_perftools_module.c
+++ b/src/misc/ngx_google_perftools_module.c
@@ -8,7 +8,7 @@
 #include <ngx_core.h>
 
 /*
- * declare Profiler here interface because
+ * declare Profiler interface here because
  * <google/profiler.h> is C++ header file
  */
 
@@ -73,7 +73,7 @@ ngx_google_perftools_create_conf(ngx_cyc
     }
 
     /*
-     * set by pcalloc()
+     * set by ngx_pcalloc()
      *
      *     gptcf->profiles = { 0, NULL };
      */
@@ -101,7 +101,6 @@ ngx_google_perftools_worker(ngx_cycle_t 
     }
 
     if (getenv("CPUPROFILE")) {
-
         /* disable inherited Profiler enabled in master process */
         ProfilerStop();
     }
@@ -109,7 +108,6 @@ ngx_google_perftools_worker(ngx_cycle_t 
     ngx_sprintf(profile, "%V.%d%Z", &gptcf->profiles, ngx_pid);
 
     if (ProfilerStart(profile)) {
-
         /* start ITIMER_PROF timer */
         ProfilerRegisterThread();
 
--- a/src/os/unix/ngx_alloc.c
+++ b/src/os/unix/ngx_alloc.c
@@ -21,7 +21,7 @@ ngx_alloc(size_t size, ngx_log_t *log)
     p = malloc(size);
     if (p == NULL) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "malloc() %uz bytes failed", size);
+                      "malloc(%uz) failed", size);
     }
 
     ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);
@@ -51,15 +51,18 @@ void *
 ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
 {
     void  *p;
+    int    err;
 
-    if (posix_memalign(&p, alignment, size) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "posix_memalign() %uz bytes aligned to %uz failed",
-                      size, alignment);
+    err = posix_memalign(&p, alignment, size);
+
+    if (err) {
+        ngx_log_error(NGX_LOG_EMERG, log, err,
+                      "posix_memalign(%uz, %uz) failed", alignment, size);
+        p = NULL;
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0,
-                   "posix_memalign: %p:%uz", p, size);
+    ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
+                   "posix_memalign: %p:%uz @%uz", p, size, alignment);
 
     return p;
 }
@@ -74,12 +77,11 @@ ngx_memalign(size_t alignment, size_t si
     p = memalign(alignment, size);
     if (p == NULL) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "memalign() %uz bytes aligned to %uz failed",
-                      size, alignment);
+                      "memalign(%uz, %uz) failed", alignment, size);
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0,
-                   "memalign: %p:%uz", p, size);
+    ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
+                   "memalign: %p:%uz @%uz", p, size, alignment);
 
     return p;
 }
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -12,7 +12,32 @@
 #include <ngx_core.h>
 
 
-#if (NGX_DARWIN_ATOMIC)
+#if (NGX_HAVE_LIBATOMIC)
+
+#define AO_REQUIRE_CAS
+#include <atomic_ops.h>
+
+#define NGX_HAVE_ATOMIC_OPS  1
+
+typedef long                        ngx_atomic_int_t;
+typedef AO_t                        ngx_atomic_uint_t;
+typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
+
+#if (NGX_PTR_SIZE == 8)
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
+#else
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
+#endif
+
+#define ngx_atomic_cmp_set(lock, old, new)                                    \
+    AO_compare_and_swap(lock, old, new)
+#define ngx_atomic_fetch_add(value, add)                                      \
+    AO_fetch_and_add(value, add)
+#define ngx_memory_barrier()        AO_nop()
+#define ngx_cpu_pause()
+
+
+#elif (NGX_DARWIN_ATOMIC)
 
 /*
  * use Darwin 8 atomic(3) and barrier(3) operations
@@ -31,7 +56,7 @@
 
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 #define ngx_atomic_cmp_set(lock, old, new)                                    \
     OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock)
@@ -43,7 +68,7 @@ typedef uint64_t                    ngx_
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 #define ngx_atomic_cmp_set(lock, old, new)                                    \
     OSAtomicCompareAndSwap32Barrier(old, new, (int32_t *) lock)
@@ -60,15 +85,45 @@ typedef uint32_t                    ngx_
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
 
 
-#else /* !(NGX_DARWIN) */
+#elif (NGX_HAVE_GCC_ATOMIC)
+
+/* GCC 4.1 builtin atomic operations */
+
+#define NGX_HAVE_ATOMIC_OPS  1
+
+typedef long                        ngx_atomic_int_t;
+typedef unsigned long               ngx_atomic_uint_t;
+
+#if (NGX_PTR_SIZE == 8)
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
+#else
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
+#endif
+
+typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
 
 
-#if ( __i386__ || __i386 )
+#define ngx_atomic_cmp_set(lock, old, set)                                    \
+    __sync_bool_compare_and_swap(lock, old, set)
+
+#define ngx_atomic_fetch_add(value, add)                                      \
+    __sync_fetch_and_add(value, add)
+
+#define ngx_memory_barrier()        __sync_synchronize()
+
+#if ( __i386__ || __i386 || __amd64__ || __amd64 )
+#define ngx_cpu_pause()             __asm__ ("pause")
+#else
+#define ngx_cpu_pause()
+#endif
+
+
+#elif ( __i386__ || __i386 )
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 
 #if ( __SUNPRO_C )
@@ -109,7 +164,7 @@ ngx_cpu_pause(void);
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 
 #if ( __SUNPRO_C )
@@ -151,13 +206,13 @@ ngx_cpu_pause(void);
 
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 #else
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 #endif
 
@@ -188,13 +243,13 @@ typedef volatile ngx_atomic_uint_t  ngx_
 
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 #else
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 #endif
 
@@ -203,9 +258,6 @@ typedef volatile ngx_atomic_uint_t  ngx_
 
 #include "ngx_gcc_atomic_ppc.h"
 
-
-#endif
-
 #endif
 
 
@@ -216,7 +268,7 @@ typedef volatile ngx_atomic_uint_t  ngx_
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 
 static ngx_inline ngx_atomic_uint_t
--- a/src/os/unix/ngx_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -36,7 +36,18 @@ ngx_write_channel(ngx_socket_t s, ngx_ch
         cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
         cmsg.cm.cmsg_level = SOL_SOCKET;
         cmsg.cm.cmsg_type = SCM_RIGHTS;
-        *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
+
+        /*
+         * We have to use ngx_memcpy() instead of simple
+         *   *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
+         * because some gcc 4.4 with -O2/3/s optimization issues the warning:
+         *   dereferencing type-punned pointer will break strict-aliasing rules
+         *
+         * Fortunately, gcc with -O1 compiles this ngx_memcpy()
+         * in the same simple assignment as in the code above
+         */
+
+        ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int));
     }
 
     msg.msg_flags = 0;
@@ -153,7 +164,9 @@ ngx_read_channel(ngx_socket_t s, ngx_cha
             return NGX_ERROR;
         }
 
-        ch->fd = *(int *) CMSG_DATA(&cmsg.cm);
+        /* ch->fd = *(int *) CMSG_DATA(&cmsg.cm); */
+
+        ngx_memcpy(&ch->fd, CMSG_DATA(&cmsg.cm), sizeof(int));
     }
 
     if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
--- a/src/os/unix/ngx_errno.c
+++ b/src/os/unix/ngx_errno.c
@@ -8,54 +8,79 @@
 #include <ngx_core.h>
 
 
-#if (NGX_HAVE_STRERROR_R)
-
-u_char *
-ngx_strerror_r(int err, u_char *errstr, size_t size)
-{
-    if (size == 0) {
-        return errstr;
-    }
-
-    errstr[0] = '\0';
+/*
+ * The strerror() messages are copied because:
+ *
+ * 1) strerror() and strerror_r() functions are not Async-Signal-Safe,
+ *    therefore, they can not be used in signal handlers;
+ *
+ * 2) a direct sys_errlist[] array may be used instead of these functions,
+ *    but Linux linker warns about its usage:
+ *
+ * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
+ * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
+ *
+ *    causing false bug reports.
+ */
 
-    strerror_r(err, (char *) errstr, size);
-
-    while (*errstr && size) {
-        errstr++;
-        size--;
-    }
 
-    return errstr;
-}
+static ngx_str_t  *ngx_sys_errlist;
+static ngx_str_t   ngx_unknown_error = ngx_string("Unknown error");
 
-#elif (NGX_HAVE_GNU_STRERROR_R)
-
-/* Linux strerror_r() */
 
 u_char *
-ngx_strerror_r(int err, u_char *errstr, size_t size)
+ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
+{
+    ngx_str_t  *msg;
+
+    msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]:
+                                              &ngx_unknown_error;
+    size = ngx_min(size, msg->len);
+
+    return ngx_cpymem(errstr, msg->data, size);
+}
+
+
+ngx_uint_t
+ngx_strerror_init(void)
 {
-    char  *str;
+    char       *msg;
+    u_char     *p;
+    size_t      len;
+    ngx_err_t   err;
 
-    if (size == 0) {
-        return errstr;
+    /*
+     * ngx_strerror() is not ready to work at this stage, therefore,
+     * malloc() is used and possible errors are logged using strerror().
+     */
+
+    len = NGX_SYS_NERR * sizeof(ngx_str_t);
+
+    ngx_sys_errlist = malloc(len);
+    if (ngx_sys_errlist == NULL) {
+        goto failed;
     }
 
-    errstr[0] = '\0';
+    for (err = 0; err < NGX_SYS_NERR; err++) {
+        msg = strerror(err);
+        len = ngx_strlen(msg);
 
-    str = strerror_r(err, (char *) errstr, size);
+        p = malloc(len);
+        if (p == NULL) {
+            goto failed;
+        }
 
-    if (str != (char *) errstr) {
-        return ngx_cpystrn(errstr, (u_char *) str, size);
+        ngx_memcpy(p, msg, len);
+        ngx_sys_errlist[err].len = len;
+        ngx_sys_errlist[err].data = p;
     }
 
-    while (*errstr && size) {
-        errstr++;
-        size--;
-    }
+    return NGX_OK;
+
+failed:
 
-    return errstr;
+    err = errno;
+    ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
+
+    return NGX_ERROR;
 }
-
-#endif
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -30,7 +30,6 @@ typedef int               ngx_err_t;
 #define NGX_EINVAL        EINVAL
 #define NGX_ENOSPC        ENOSPC
 #define NGX_EPIPE         EPIPE
-#define NGX_EAGAIN        EAGAIN
 #define NGX_EINPROGRESS   EINPROGRESS
 #define NGX_EADDRINUSE    EADDRINUSE
 #define NGX_ECONNABORTED  ECONNABORTED
@@ -48,6 +47,11 @@ typedef int               ngx_err_t;
 #define NGX_EILSEQ        EILSEQ
 #define NGX_ENOMOREFILES  0
 
+#if (__hpux__)
+#define NGX_EAGAIN        EWOULDBLOCK
+#else
+#define NGX_EAGAIN        EAGAIN
+#endif
 
 
 #define ngx_errno                  errno
@@ -56,18 +60,8 @@ typedef int               ngx_err_t;
 #define ngx_set_socket_errno(err)  errno = err
 
 
-#if (NGX_HAVE_STRERROR_R || NGX_HAVE_GNU_STRERROR_R)
-
-u_char *ngx_strerror_r(int err, u_char *errstr, size_t size);
-
-#else
-
-/* Solaris and Tru64 UNIX have thread-safe strerror() */
-
-#define ngx_strerror_r(err, errstr, size)  \
-    ngx_cpystrn(errstr, (u_char *) strerror(err), size)
-
-#endif
+u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size);
+ngx_uint_t ngx_strerror_init(void);
 
 
 #endif /* _NGX_ERRNO_H_INCLUDED_ */
--- a/src/os/unix/ngx_file_aio_read.c
+++ b/src/os/unix/ngx_file_aio_read.c
@@ -39,12 +39,11 @@ 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;
+    int               n;
+    ngx_event_t      *ev;
+    ngx_event_aio_t  *aio;
 
-    if (enosys) {
+    if (!ngx_file_aio) {
         return ngx_read_file(file, buf, size, offset);
     }
 
@@ -116,7 +115,7 @@ ngx_file_aio_read(ngx_file_t *file, u_ch
                       "aio_read(\"%V\") failed", &file->name);
 
         if (n == NGX_ENOSYS) {
-            enosys = 1;
+            ngx_file_aio = 0;
             return ngx_read_file(file, buf, size, offset);
         }
 
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -8,6 +8,13 @@
 #include <ngx_core.h>
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+ngx_uint_t  ngx_file_aio = 1;
+
+#endif
+
+
 ssize_t
 ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
@@ -22,7 +29,7 @@ ngx_read_file(ngx_file_t *file, u_char *
 
     if (n == -1) {
         ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                      "pread() failed, file \"%s\"", file->name.data);
+                      "pread() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -30,7 +37,8 @@ ngx_read_file(ngx_file_t *file, u_char *
 
     if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "lseek() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
@@ -40,7 +48,8 @@ ngx_read_file(ngx_file_t *file, u_char *
     n = read(file->fd, buf, size);
 
     if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "read() failed");
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                      "read() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -57,57 +66,66 @@ ngx_read_file(ngx_file_t *file, u_char *
 ssize_t
 ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
-    ssize_t  n;
+    ssize_t  n, written;
 
     ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
                    "write: %d, %p, %uz, %O", file->fd, buf, size, offset);
 
+    written = 0;
+
 #if (NGX_HAVE_PWRITE)
 
-    n = pwrite(file->fd, buf, size, offset);
+    for ( ;; ) {
+        n = pwrite(file->fd, buf + written, size, offset);
+
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "pwrite() \"%s\" failed", file->name.data);
+            return NGX_ERROR;
+        }
 
-    if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pwrite() failed");
-        return NGX_ERROR;
-    }
+        file->offset += n;
+        written += n;
 
-    if ((size_t) n != size) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                      "pwrite() has written only %z of %uz", n, size);
-        return NGX_ERROR;
+        if ((size_t) n == size) {
+            return written;
+        }
+
+        offset += n;
+        size -= n;
     }
 
 #else
 
     if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "lseek() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
         file->sys_offset = offset;
     }
 
-    n = write(file->fd, buf, size);
+    for ( ;; ) {
+        n = write(file->fd, buf + written, size);
 
-    if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "write() failed");
-        return NGX_ERROR;
-    }
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "write() \"%s\" failed", file->name.data);
+            return NGX_ERROR;
+        }
 
-    if ((size_t) n != size) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                      "write() has written only %z of %uz", n, size);
-        return NGX_ERROR;
-    }
+        file->offset += n;
+        written += n;
 
-    file->sys_offset += n;
-
-#endif
+        if ((size_t) n == size) {
+            return written;
+        }
 
-    file->offset += n;
-
-    return n;
+        size -= n;
+    }
+#endif
 }
 
 
@@ -191,7 +209,7 @@ ngx_write_chain_to_file(ngx_file_t *file
         if (file->sys_offset != offset) {
             if (lseek(file->fd, offset, SEEK_SET) == -1) {
                 ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                              "lseek() failed");
+                              "lseek() \"%s\" failed", file->name.data);
                 return NGX_ERROR;
             }
 
@@ -202,13 +220,14 @@ ngx_write_chain_to_file(ngx_file_t *file
 
         if (n == -1) {
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                          "writev() failed");
+                          "writev() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
         if ((size_t) n != size) {
             ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                          "writev() has written only %z of %uz", n, size);
+                          "writev() \"%s\" has written only %z of %uz",
+                          file->name.data, n, size);
             return NGX_ERROR;
         }
 
@@ -226,7 +245,7 @@ ngx_set_file_time(u_char *name, ngx_fd_t
 {
     struct timeval  tv[2];
 
-    tv[0].tv_sec = s;
+    tv[0].tv_sec = ngx_time();
     tv[0].tv_usec = 0;
     tv[1].tv_sec = s;
     tv[1].tv_usec = 0;
@@ -240,6 +259,58 @@ ngx_set_file_time(u_char *name, ngx_fd_t
 
 
 ngx_int_t
+ngx_create_file_mapping(ngx_file_mapping_t *fm)
+{
+    fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
+                           NGX_FILE_DEFAULT_ACCESS);
+    if (fm->fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", fm->name);
+        return NGX_ERROR;
+    }
+
+    if (ftruncate(fm->fd, fm->size) == -1) {
+        ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+                      "ftruncate() \"%s\" failed", fm->name);
+        goto failed;
+    }
+
+    fm->addr = mmap(NULL, fm->size, PROT_READ|PROT_WRITE, MAP_SHARED,
+                    fm->fd, 0);
+    if (fm->addr != MAP_FAILED) {
+        return NGX_OK;
+    }
+
+    ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+                  "mmap(%uz) \"%s\" failed", fm->size, fm->name);
+
+failed:
+
+    if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", fm->name);
+    }
+
+    return NGX_ERROR;
+}
+
+
+void
+ngx_close_file_mapping(ngx_file_mapping_t *fm)
+{
+    if (munmap(fm->addr, fm->size) == -1) {
+        ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+                      "munmap(%uz) \"%s\" failed", fm->size, fm->name);
+    }
+
+    if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", fm->name);
+    }
+}
+
+
+ngx_int_t
 ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir)
 {
     dir->dir = opendir((const char *) name->data);
@@ -262,9 +333,8 @@ ngx_read_dir(ngx_dir_t *dir)
     if (dir->de) {
 #if (NGX_HAVE_D_TYPE)
         dir->type = dir->de->d_type;
-        dir->valid_type = dir->type ? 1 : 0;
 #else
-        dir->valid_type = 0;
+        dir->type = 0;
 #endif
         return NGX_OK;
     }
@@ -384,6 +454,26 @@ ngx_unlock_fd(ngx_fd_t fd)
 }
 
 
+#if (NGX_HAVE_POSIX_FADVISE)
+
+ngx_int_t
+ngx_read_ahead(ngx_fd_t fd, size_t n)
+{
+    int  err;
+
+    err = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+
+    if (err == 0) {
+        return 0;
+    }
+
+    ngx_set_errno(err);
+    return NGX_FILE_ERROR;
+}
+
+#endif
+
+
 #if (NGX_HAVE_O_DIRECT)
 
 ngx_int_t
@@ -394,7 +484,7 @@ ngx_directio_on(ngx_fd_t fd)
     flags = fcntl(fd, F_GETFL);
 
     if (flags == -1) {
-        return -1;
+        return NGX_FILE_ERROR;
     }
 
     return fcntl(fd, F_SETFL, flags | O_DIRECT);
@@ -409,7 +499,7 @@ ngx_directio_off(ngx_fd_t fd)
     flags = fcntl(fd, F_GETFL);
 
     if (flags == -1) {
-        return -1;
+        return NGX_FILE_ERROR;
     }
 
     return fcntl(fd, F_SETFL, flags & ~O_DIRECT);
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -18,13 +18,21 @@ typedef ino_t                    ngx_fil
 
 
 typedef struct {
+    u_char                      *name;
+    size_t                       size;
+    void                        *addr;
+    ngx_fd_t                     fd;
+    ngx_log_t                   *log;
+} ngx_file_mapping_t;
+
+
+typedef struct {
     DIR                         *dir;
     struct dirent               *de;
     struct stat                  info;
 
     unsigned                     type:8;
     unsigned                     valid_info:1;
-    unsigned                     valid_type:1;
 } ngx_dir_t;
 
 
@@ -65,6 +73,7 @@ typedef struct {
 #define NGX_FILE_OPEN            0
 #define NGX_FILE_TRUNCATE        O_CREAT|O_TRUNC
 #define NGX_FILE_APPEND          O_WRONLY|O_APPEND
+#define NGX_FILE_NONBLOCK        O_NONBLOCK
 
 #define NGX_FILE_DEFAULT_ACCESS  0644
 #define NGX_FILE_OWNER_ACCESS    0600
@@ -139,16 +148,23 @@ ngx_int_t ngx_set_file_time(u_char *name
 #define ngx_fd_info(fd, sb)      fstat(fd, sb)
 #define ngx_fd_info_n            "fstat()"
 
+#define ngx_link_info(file, sb)  lstat((const char *) file, sb)
+#define ngx_link_info_n          "lstat()"
+
 #define ngx_is_dir(sb)           (S_ISDIR((sb)->st_mode))
 #define ngx_is_file(sb)          (S_ISREG((sb)->st_mode))
 #define ngx_is_link(sb)          (S_ISLNK((sb)->st_mode))
-#define ngx_is_exec(sb)          ((sb)->st_mode & S_IXUSR)
+#define ngx_is_exec(sb)          (((sb)->st_mode & S_IXUSR) == S_IXUSR)
 #define ngx_file_access(sb)      ((sb)->st_mode & 0777)
 #define ngx_file_size(sb)        (sb)->st_size
 #define ngx_file_mtime(sb)       (sb)->st_mtime
 #define ngx_file_uniq(sb)        (sb)->st_ino
 
 
+ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm);
+void ngx_close_file_mapping(ngx_file_mapping_t *fm);
+
+
 #if (NGX_HAVE_CASELESS_FILESYSTEM)
 
 #define ngx_filename_cmp(s1, s2, n)  strncasecmp((char *) s1, (char *) s2, n)
@@ -200,31 +216,31 @@ ngx_int_t ngx_read_dir(ngx_dir_t *dir);
 #else
 #define ngx_de_namelen(dir)      ngx_strlen((dir)->de->d_name)
 #endif
-#define ngx_de_info(name, dir)   stat((const char *) name, &(dir)->info)
+
+static ngx_inline ngx_int_t
+ngx_de_info(u_char *name, ngx_dir_t *dir)
+{
+    dir->type = 0;
+    return stat((const char *) name, &dir->info);
+}
+
 #define ngx_de_info_n            "stat()"
 #define ngx_de_link_info(name, dir)  lstat((const char *) name, &(dir)->info)
 #define ngx_de_link_info_n       "lstat()"
 
 #if (NGX_HAVE_D_TYPE)
 
-#if (NGX_LINUX)
-
-/* XFS on Linux does not set dirent.d_type */
+/*
+ * some file systems (e.g. XFS on Linux and CD9660 on FreeBSD)
+ * do not set dirent.d_type
+ */
 
 #define ngx_de_is_dir(dir)                                                   \
     (((dir)->type) ? ((dir)->type == DT_DIR) : (S_ISDIR((dir)->info.st_mode)))
 #define ngx_de_is_file(dir)                                                  \
     (((dir)->type) ? ((dir)->type == DT_REG) : (S_ISREG((dir)->info.st_mode)))
 #define ngx_de_is_link(dir)                                                  \
-    (((dir)->type) ? ((dir)->type == DT_LINK) : (S_ISLNK((dir)->info.st_mode)))
-
-#else
-
-#define ngx_de_is_dir(dir)       ((dir)->type == DT_DIR)
-#define ngx_de_is_file(dir)      ((dir)->type == DT_REG)
-#define ngx_de_is_link(dir)      ((dir)->type == DT_LINK)
-
-#endif /* NGX_LINUX */
+    (((dir)->type) ? ((dir)->type == DT_LNK) : (S_ISLNK((dir)->info.st_mode)))
 
 #else
 
@@ -254,6 +270,28 @@ ngx_err_t ngx_unlock_fd(ngx_fd_t fd);
 #define ngx_unlock_fd_n          "fcntl(F_SETLK, F_UNLCK)"
 
 
+#if (NGX_HAVE_F_READAHEAD)
+
+#define NGX_HAVE_READ_AHEAD      1
+
+#define ngx_read_ahead(fd, n)    fcntl(fd, F_READAHEAD, (int) n)
+#define ngx_read_ahead_n         "fcntl(fd, F_READAHEAD)"
+
+#elif (NGX_HAVE_POSIX_FADVISE)
+
+#define NGX_HAVE_READ_AHEAD      1
+
+ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n);
+#define ngx_read_ahead_n         "posix_fadvise(POSIX_FADV_SEQUENTIAL)"
+
+#else
+
+#define ngx_read_ahead(fd, n)    0
+#define ngx_read_ahead_n         "ngx_read_ahead_n"
+
+#endif
+
+
 #if (NGX_HAVE_O_DIRECT)
 
 ngx_int_t ngx_directio_on(ngx_fd_t fd);
@@ -292,6 +330,8 @@ size_t ngx_fs_bsize(u_char *name);
 ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
     off_t offset, ngx_pool_t *pool);
 
+extern ngx_uint_t  ngx_file_aio;
+
 #endif
 
 
--- a/src/os/unix/ngx_freebsd_rfork_thread.h
+++ b/src/os/unix/ngx_freebsd_rfork_thread.h
@@ -118,5 +118,4 @@ void ngx_mutex_unlock(ngx_mutex_t *m);
 typedef int (*ngx_rfork_thread_func_pt)(void *arg);
 
 
-
 #endif /* _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ */
--- a/src/os/unix/ngx_gcc_atomic_x86.h
+++ b/src/os/unix/ngx_gcc_atomic_x86.h
@@ -122,5 +122,5 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 
 #define ngx_memory_barrier()    __asm__ volatile ("" ::: "memory")
 
-/* old as does not support "pause" opcode */
+/* old "as" does not support "pause" opcode */
 #define ngx_cpu_pause()         __asm__ (".byte 0xf3, 0x90")
--- a/src/os/unix/ngx_linux_aio_read.c
+++ b/src/os/unix/ngx_linux_aio_read.c
@@ -27,13 +27,12 @@ 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;
+    long              n;
+    struct iocb      *piocb[1];
+    ngx_event_t      *ev;
+    ngx_event_aio_t  *aio;
 
-    if (enosys) {
+    if (!ngx_file_aio) {
         return ngx_read_file(file, buf, size, offset);
     }
 
@@ -96,6 +95,10 @@ ngx_file_aio_read(ngx_file_t *file, u_ch
     n = io_submit(ngx_aio_ctx, 1, piocb);
 
     if (n == 1) {
+        ev->active = 1;
+        ev->ready = 0;
+        ev->complete = 0;
+
         return NGX_AGAIN;
     }
 
@@ -109,7 +112,7 @@ ngx_file_aio_read(ngx_file_t *file, u_ch
                   "io_submit(\"%V\") failed", &file->name);
 
     if (n == NGX_ENOSYS) {
-        enosys = 1;
+        ngx_file_aio = 0;
         return ngx_read_file(file, buf, size, offset);
     }
 
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -88,7 +88,7 @@ typedef struct iocb  ngx_aiocb_t;
 #endif
 
 
-#define NGX_LISTEN_BACKLOG        511
+#define NGX_LISTEN_BACKLOG        -1
 
 
 #if defined TCP_DEFER_ACCEPT && !defined NGX_HAVE_DEFERRED_ACCEPT
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -44,8 +44,6 @@ ngx_os_init(ngx_log_t *log)
     ngx_pagesize = getpagesize();
     ngx_cacheline_size = NGX_CPU_CACHE_LINE;
 
-    n = ngx_pagesize;
-
     for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }
 
     if (ngx_ncpu == 0) {
@@ -62,7 +60,7 @@ ngx_os_init(ngx_log_t *log)
 
     ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur;
 
-#if (NGX_HAVE_INHERITED_NONBLOCK)
+#if (NGX_HAVE_INHERITED_NONBLOCK || NGX_HAVE_ACCEPT4)
     ngx_inherited_nonblocking = 1;
 #else
     ngx_inherited_nonblocking = 0;
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -11,10 +11,10 @@
 
 
 typedef struct {
-     int     signo;
-     char   *signame;
-     char   *name;
-     void  (*handler)(int signo);
+    int     signo;
+    char   *signame;
+    char   *name;
+    void  (*handler)(int signo);
 } ngx_signal_t;
 
 
@@ -317,7 +317,7 @@ ngx_signal_handler(int signo)
         }
     }
 
-    ngx_time_update(0, 0);
+    ngx_time_sigsafe_update();
 
     action = "";
 
@@ -388,6 +388,7 @@ ngx_signal_handler(int signo)
         break;
 
     case NGX_PROCESS_WORKER:
+    case NGX_PROCESS_HELPER:
         switch (signo) {
 
         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
@@ -478,16 +479,15 @@ ngx_process_get_status(void)
              */
 
             if (err == NGX_ECHILD) {
-                ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
+                ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
                               "waitpid() failed");
                 return;
             }
 
 #endif
 
-            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
+            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
                           "waitpid() failed");
-
             return;
         }
 
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -86,7 +86,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
     u_char            *p;
     size_t             size;
     ngx_int_t          i;
-    ngx_uint_t         n;
+    ngx_uint_t         n, sigio;
     sigset_t           set;
     struct itimerval   itv;
     ngx_uint_t         live;
@@ -139,11 +139,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
     ngx_new_binary = 0;
     delay = 0;
+    sigio = 0;
     live = 1;
 
     for ( ;; ) {
         if (delay) {
             if (ngx_sigalrm) {
+                sigio = 0;
                 delay *= 2;
                 ngx_sigalrm = 0;
             }
@@ -166,9 +168,10 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
         sigsuspend(&set);
 
-        ngx_time_update(0, 0);
+        ngx_time_update();
 
-        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up");
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                       "wake up, sigio %i", sigio);
 
         if (ngx_reap) {
             ngx_reap = 0;
@@ -186,6 +189,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy
                 delay = 50;
             }
 
+            if (sigio) {
+                sigio--;
+                continue;
+            }
+
+            sigio = ccf->worker_processes + 2 /* cache processes */;
+
             if (delay > 1000) {
                 ngx_signal_worker_processes(cycle, SIGKILL);
             } else {
@@ -281,6 +291,11 @@ ngx_single_process_cycle(ngx_cycle_t *cy
 {
     ngx_uint_t  i;
 
+    if (ngx_set_environment(cycle, NULL) == NULL) {
+        /* fatal */
+        exit(2);
+    }
+
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->init_process) {
             if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
@@ -675,6 +690,8 @@ ngx_master_process_exit(ngx_cycle_t *cyc
         }
     }
 
+    ngx_close_listening_sockets(cycle);
+
     /*
      * Copy ngx_cycle->log related data to the special static exit cycle,
      * log, and log file structures enough to allow a signal handler to log.
@@ -702,6 +719,8 @@ ngx_worker_process_cycle(ngx_cycle_t *cy
     ngx_uint_t         i;
     ngx_connection_t  *c;
 
+    ngx_process = NGX_PROCESS_WORKER;
+
     ngx_worker_process_init(cycle, 1);
 
     ngx_setproctitle("worker process");
@@ -817,8 +836,6 @@ ngx_worker_process_init(ngx_cycle_t *cyc
     ngx_core_conf_t  *ccf;
     ngx_listening_t  *ls;
 
-    ngx_process = NGX_PROCESS_WORKER;
-
     if (ngx_set_environment(cycle, NULL) == NULL) {
         /* fatal */
         exit(2);
@@ -844,13 +861,13 @@ ngx_worker_process_init(ngx_cycle_t *cyc
         }
     }
 
-    if (ccf->rlimit_core != NGX_CONF_UNSET_SIZE) {
+    if (ccf->rlimit_core != NGX_CONF_UNSET) {
         rlmt.rlim_cur = (rlim_t) ccf->rlimit_core;
         rlmt.rlim_max = (rlim_t) ccf->rlimit_core;
 
         if (setrlimit(RLIMIT_CORE, &rlmt) == -1) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
-                          "setrlimit(RLIMIT_CORE, %i) failed",
+                          "setrlimit(RLIMIT_CORE, %O) failed",
                           ccf->rlimit_core);
         }
     }
@@ -1277,6 +1294,8 @@ ngx_cache_manager_process_cycle(ngx_cycl
 
     cycle->connection_n = 512;
 
+    ngx_process = NGX_PROCESS_HELPER;
+
     ngx_worker_process_init(cycle, 0);
 
     ngx_close_listening_sockets(cycle);
@@ -1328,7 +1347,7 @@ ngx_cache_manager_process_handler(ngx_ev
 
             next = (n <= next) ? n : next;
 
-            ngx_time_update(0, 0);
+            ngx_time_update();
         }
     }
 
@@ -1358,7 +1377,7 @@ ngx_cache_loader_process_handler(ngx_eve
 
         if (path[i]->loader) {
             path[i]->loader(path[i]->data);
-            ngx_time_update(0, 0);
+            ngx_time_update();
         }
     }
 
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -21,8 +21,9 @@
 
 #define NGX_PROCESS_SINGLE     0
 #define NGX_PROCESS_MASTER     1
-#define NGX_PROCESS_WORKER     2
-#define NGX_PROCESS_SIGNALLER  3
+#define NGX_PROCESS_SIGNALLER  2
+#define NGX_PROCESS_WORKER     3
+#define NGX_PROCESS_HELPER     4
 
 
 typedef struct {
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -158,7 +158,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx
 
     rev->ready = 0;
 
-    if (n == NGX_ERROR){
+    if (n == NGX_ERROR) {
         c->read->error = 1;
     }
 
@@ -247,7 +247,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx
 
     rev->ready = 0;
 
-    if (n == NGX_ERROR){
+    if (n == NGX_ERROR) {
         c->read->error = 1;
     }
 
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -113,7 +113,7 @@ ngx_unix_recv(ngx_connection_t *c, u_cha
 
     rev->ready = 0;
 
-    if (n == NGX_ERROR){
+    if (n == NGX_ERROR) {
         rev->error = 1;
     }
 
@@ -169,7 +169,7 @@ ngx_unix_recv(ngx_connection_t *c, u_cha
 
     rev->ready = 0;
 
-    if (n == NGX_ERROR){
+    if (n == NGX_ERROR) {
         rev->error = 1;
     }
 
--- a/src/os/unix/ngx_setproctitle.h
+++ b/src/os/unix/ngx_setproctitle.h
@@ -13,7 +13,7 @@
 /* FreeBSD, NetBSD, OpenBSD */
 
 #define ngx_init_setproctitle(log)
-#define ngx_setproctitle           setproctitle
+#define ngx_setproctitle(title)    setproctitle("%s", title)
 
 
 #else /* !NGX_HAVE_SETPROCTITLE */
--- a/src/os/unix/ngx_sunpro_amd64.il
+++ b/src/os/unix/ngx_sunpro_amd64.il
@@ -31,7 +31,12 @@
 
 
 / ngx_cpu_pause()
+/
+/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware
+/ capability added by linker because Solaris/amd64 does not know about it:
+/
+/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ]
 
        .inline ngx_cpu_pause,0
-       pause
+       rep; nop
        .end
--- a/src/os/unix/ngx_thread.h
+++ b/src/os/unix/ngx_thread.h
@@ -124,5 +124,4 @@ ngx_int_t ngx_cond_signal(ngx_cond_t *cv
 #endif
 
 
-
 #endif /* _NGX_THREAD_H_INCLUDED_ */
--- a/src/os/unix/ngx_udp_recv.c
+++ b/src/os/unix/ngx_udp_recv.c
@@ -60,7 +60,7 @@ ngx_udp_unix_recv(ngx_connection_t *c, u
 
     rev->ready = 0;
 
-    if (n == NGX_ERROR){
+    if (n == NGX_ERROR) {
         rev->error = 1;
     }
 
@@ -104,7 +104,7 @@ ngx_udp_unix_recv(ngx_connection_t *c, u
 
     rev->ready = 0;
 
-    if (n == NGX_ERROR){
+    if (n == NGX_ERROR) {
         rev->error = 1;
     }
 
--- a/src/os/unix/ngx_user.c
+++ b/src/os/unix/ngx_user.c
@@ -41,11 +41,11 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
     err = ngx_errno;
 
     if (err == 0) {
-        len = ngx_strlen(value);
+        len = ngx_strlen(value) + 1;
 
         *encrypted = ngx_pnalloc(pool, len);
         if (*encrypted) {
-            ngx_memcpy(*encrypted, value, len + 1);
+            ngx_memcpy(*encrypted, value, len);
             return NGX_OK;
         }
     }
@@ -79,11 +79,11 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
     value = crypt((char *) key, (char *) salt);
 
     if (value) {
-        len = ngx_strlen(value);
+        len = ngx_strlen(value) + 1;
 
         *encrypted = ngx_pnalloc(pool, len);
         if (*encrypted) {
-            ngx_memcpy(*encrypted, value, len + 1);
+            ngx_memcpy(*encrypted, value, len);
         }
 
 #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
--- a/src/os/unix/ngx_user.h
+++ b/src/os/unix/ngx_user.h
@@ -20,5 +20,4 @@ ngx_int_t ngx_crypt(ngx_pool_t *pool, u_
     u_char **encrypted);
 
 
-
 #endif /* _NGX_USER_H_INCLUDED_ */