changeset 635:e67b227c8dbb default tip

Merge with current.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 25 Apr 2011 04:07:55 +0400
parents f3a9e57d2e17 (current diff) 00d13b6d4ebd (diff)
children
files auto/modules auto/sources src/http/modules/ngx_http_range_filter_module.c src/http/ngx_http_request.h
diffstat 139 files changed, 9297 insertions(+), 2595 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -281,3 +281,31 @@ 2da4537168f879f528f09d0e0ce80abe68adf05e
 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,447 @@
 
+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 
@@ -11,7 +454,7 @@ Changes with nginx 0.8.34               
     *) 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.34.
+       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.
@@ -882,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.
 
@@ -1236,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.
@@ -4645,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,451 @@
 
+éÚÍÅÎÅÎÉÑ × 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 ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ×ÓÅ ÛÉÆÒÙ, ÉÓÐÏÌØÚÕÅÍÙÅ × 
@@ -11,7 +458,7 @@
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ HTTPS-ÒÅÆÅÒÅÒÙ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÍÏÇ ÎÅ ÎÁÈÏÄÉÔØ ÆÁÊÌÙ, ÅÓÌÉ ÐÕÔØ × 
-       ËÏÎÆÉÇÕÒÁÃÉÉ ÂÙÌ ÚÁÄÁÎ × ÄÒÕÇÏÍ ÒÅÇÉÓÔÒÅ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.34.
+       ËÏÎÆÉÇÕÒÁÃÉÉ ÂÙÌ ÚÁÄÁÎ × ÄÒÕÇÏÍ ÒÅÇÉÓÔÒÅ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.8.33.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $date_local ×ÙÄÁ×ÁÌÁ ÎÅ×ÅÒÎÏÅ ×ÒÅÍÑ, ÅÓÌÉ 
        ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÆÏÒÍÁÔ "%s".
@@ -218,7 +665,7 @@
     *) âÅÚÏÐÁÓÎÏÓÔØ: ÔÅÐÅÒØ SSL/TLS renegotiation ÚÁÐÒÅÝ£Î.
        óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
 
-    *) éÓÐÒÁ×ÌÅÎÉÅ: listen unix domain ÓÏËÅÔ ÎÅ ÎÁÓÌÅÄÏ×ÁÌÉÓØ ×Ï ×ÒÅÍÑ 
+    *) éÓÐÒÁ×ÌÅÎÉÅ: listen unix domain ÓÏËÅÔ ÎÅ ÎÁÓÌÅÄÏ×ÁÌÓÑ ×Ï ×ÒÅÍÑ 
        ÏÂÎÏ×ÌÅÎÉÑ ÂÅÚ ÐÅÒÅÒÙ×Á.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ "unix:" × ÄÉÒÅËÔÉ×Å set_real_ip_from ÎÅ 
@@ -294,7 +741,7 @@
        --error-log-path; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.53.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÞÉÔÁÌ ÚÁÐÑÔÕÀ ÒÁÚÄÅÌÉÔÅÌÅÍ × ÓÔÒÏËÅ 
-       "Cache-Control" × ÓÔÒÏËÅ ÚÁÇÏÌÏ×ËÁ ÂÜËÅÎÄÁ.
+       "Cache-Control" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx/Windows ÍÏÇ ÎÅ ÓÏÚÄÁÔØ ×ÒÅÍÅÎÎÙÊ ÆÁÊÌ, ÆÁÊÌ × 
        ËÜÛÅ ÉÌÉ ÆÁÊÌ Ó ÐÏÍÏÝØÀ ÄÉÒÅËÔÉ× proxy/fastcgi_store, ÅÓÌÉ ÒÁÂÏÞÉÊ 
@@ -328,7 +775,7 @@
 
     *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù limit_req_log_level É limit_conn_log_level.
 
-    *) éÓÐÒÁ×ÌÅÎÉÅ: ôÅÐÅÒØ ÄÉÒÅËÔÉ×Á limit_req ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÁÌÇÏÒÉÔÍÕ 
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á limit_req ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÁÌÇÏÒÉÔÍÕ 
        leaky bucket.
        óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
 
@@ -1694,7 +2141,7 @@
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ×ÅÒÎÏ ÏÐÒÅÄÅÌÑÌ ÄÌÉÎÕ ÓÔÒÏËÉ ËÜÛÁ ÎÁ 
        Pentium 4.
-       óÐÁÓÉÂÏ Gena Makhomed.
+       óÐÁÓÉÂÏ çÅÎÎÁÄÉÀ íÁÈÏÍÅÄÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÒÏËÓÉÒÏ×ÁÎÎÙÈ ÐÏÄÚÁÐÒÏÓÁÈ É ÐÏÄÚÁÐÒÏÓÁÈ Ë 
        FastCGI-ÓÅÒ×ÅÒÕ ×ÍÅÓÔÏ ÍÅÔÏÄÁ GET ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÏÒÉÇÉÎÁÌØÎÙÊ ÍÅÔÏÄ 
@@ -1962,7 +2409,7 @@
        óÐÁÓÉÂÏ áÎÄÒÅÀ îÉÇÍÁÔÕÌÉÎÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ngx_http_memcached_module ÎÅ ÕÓÔÁÎÁ×ÌÉ×ÁÌ 
-       upstream_response_time.
+       $upstream_response_time.
        óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ.
 
     *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÁÂÏÞÉÊ ÐÒÏÃÅÓÓ ÍÏÇ ÚÁÃÉËÌÉÔØÓÑ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ 
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2002-2010 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
@@ -143,19 +143,6 @@ if [ "$NGX_PLATFORM" != win32 ]; then
     . auto/feature
 
 
-    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
-
-
     if [ "$NGX_CC_NAME" = "ccc" ]; then
         echo "checking for C99 variadic macros ... disabled"
     else
@@ -173,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/feature
+++ b/auto/feature
@@ -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'
@@ -105,6 +112,16 @@ install:	$NGX_OBJS${ngx_dirsep}nginx${ng
 		|| 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'
@@ -136,6 +153,7 @@ cat << END >> Makefile
 
 build:
 	\$(MAKE) -f $NGX_MAKEFILE
+	\$(MAKE) -f $NGX_MAKEFILE manpage
 
 install:
 	\$(MAKE) -f $NGX_MAKEFILE install
--- 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,6 +19,8 @@ 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"
         ;;
 
         *)
@@ -35,38 +37,27 @@ if [ $OPENSSL != NONE ]; then
 
 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
@@ -57,7 +57,7 @@ END
 	&& \$(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
@@ -133,12 +133,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"
@@ -146,6 +140,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"
@@ -188,7 +187,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
@@ -196,13 +194,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"
@@ -210,7 +206,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
@@ -232,7 +227,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
@@ -244,24 +238,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"
@@ -288,9 +284,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"
@@ -319,6 +324,7 @@ if [ $HTTP_SECURE_LINK = YES ]; then
 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
--- 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
@@ -184,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            ;;
@@ -209,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         ;;
@@ -341,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
@@ -363,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
@@ -452,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
@@ -295,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/sources
+++ b/auto/sources
@@ -388,6 +388,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
 
@@ -409,6 +413,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
--- 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,7 +64,6 @@ 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
 
@@ -97,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()"
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -32,7 +32,6 @@ 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;
@@ -50,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;
@@ -61,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
@@ -332,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;
     }
 
@@ -685,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;
@@ -859,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
     }
@@ -876,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) {
@@ -919,7 +928,7 @@ ngx_core_module_create_conf(ngx_cycle_t 
     }
 
     /*
-     * set by pcalloc()
+     * set by ngx_pcalloc()
      *
      *     ccf->pid = NULL;
      *     ccf->oldpid = NULL;
@@ -936,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;
@@ -993,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) {
@@ -1042,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         8034
-#define NGINX_VERSION      "0.8.34"
+#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
@@ -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) {
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -12,6 +12,9 @@
 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)
 {
@@ -74,6 +77,10 @@ ngx_create_listening(ngx_conf_t *cf, voi
     ls->rcvbuf = -1;
     ls->sndbuf = -1;
 
+#if (NGX_HAVE_SETFIB)
+    ls->setfib = -1;
+#endif
+
     return ls;
 }
 
@@ -96,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 "
@@ -181,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));
@@ -475,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;
@@ -685,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);
@@ -827,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);
@@ -866,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)
--- 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
 
 };
 
@@ -132,6 +135,8 @@ struct ngx_connection_s {
 
     ngx_buf_t          *buffer;
 
+    ngx_queue_t         queue;
+
     ngx_atomic_uint_t   number;
 
     ngx_uint_t          requests;
@@ -147,6 +152,7 @@ struct ngx_connection_s {
     unsigned            destroyed:1;
 
     unsigned            idle:1;
+    unsigned            reusable:1;
     unsigned            close:1;
 
     unsigned            sendfile:1;
@@ -183,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_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);
@@ -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
@@ -762,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;
@@ -823,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
@@ -943,7 +943,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
 
         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) {
--- 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
@@ -490,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,
--- 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;
 
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -138,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);
@@ -1836,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;
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -10,6 +10,8 @@
 
 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
@@ -75,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
@@ -143,7 +145,7 @@ 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;
@@ -229,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++;
 
@@ -240,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++;
 
@@ -257,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);
                 }
 
@@ -359,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++ = '-';
@@ -386,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);
                 }
@@ -877,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)
 {
@@ -1050,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,
@@ -1072,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;
         }
     }
@@ -1090,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;
@@ -1278,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 */
@@ -1593,6 +1675,89 @@ ngx_escape_html(u_char *dst, u_char *src
 }
 
 
+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
@@ -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
@@ -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
@@ -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) {
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -155,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 */
 
@@ -561,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);
@@ -1309,7 +1311,8 @@ 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 */
@@ -2231,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);
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -190,7 +190,7 @@ ngx_http_access_inet6(ngx_http_request_t
         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_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+        ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "access: %*s %*s %*s", cl, ct, ml, mt, al, at);
         }
 #endif
--- 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_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -50,6 +50,8 @@ 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 != r->main
@@ -63,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);
@@ -539,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) {
@@ -685,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);
         }
 
@@ -719,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);
     }
 
--- a/src/http/modules/ngx_http_degradation_module.c
+++ b/src/http/modules/ngx_http_degradation_module.c
@@ -89,22 +89,32 @@ ngx_module_t  ngx_http_degradation_modul
 static ngx_int_t
 ngx_http_degradation_handler(ngx_http_request_t *r)
 {
-    time_t                             now;
-    static size_t                      sbrk_size;
-    static time_t                      sbrk_time;
-    ngx_http_degradation_loc_conf_t   *dlcf;
-    ngx_http_degradation_main_conf_t  *dmcf;
+    ngx_http_degradation_loc_conf_t  *dlcf;
 
     dlcf = ngx_http_get_module_loc_conf(r, ngx_http_degradation_module);
 
-    if (dlcf->degrade == 0) {
-        return NGX_DECLINED;
+    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 */
@@ -120,19 +130,23 @@ ngx_http_degradation_handler(ngx_http_re
 
             sbrk_size = (size_t) sbrk(0) - ((uintptr_t) ngx_palloc & ~0x3FFFFF);
             sbrk_time = now;
+            log = 1;
         }
 
         /* unlock mutex */
 
         if (sbrk_size >= dmcf->sbrk_size) {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "degradation sbrk: %uz", sbrk_size);
+            if (log) {
+                ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                              "degradation sbrk:%uzM",
+                              sbrk_size / (1024 * 1024));
+            }
 
-            return dlcf->degrade;
+            return 1;
         }
     }
 
-    return NGX_DECLINED;
+    return 0;
 }
 
 
--- 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
@@ -162,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 };
@@ -185,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;
 
 
@@ -321,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,
@@ -341,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,
@@ -399,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,
@@ -421,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),
@@ -439,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,
@@ -533,16 +522,14 @@ static ngx_str_t  ngx_http_fastcgi_hide_
 
 #if (NGX_HTTP_CACHE)
 
-static ngx_str_t  ngx_http_fastcgi_hide_cache_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_string("Set-Cookie"),
-    ngx_string("P3P"),
-    ngx_null_string
+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
@@ -589,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;
@@ -628,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;
@@ -706,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;
@@ -720,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);
 
@@ -748,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;
 
@@ -763,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;
         }
     }
 
@@ -885,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);
@@ -922,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;
         }
     }
 
@@ -1101,7 +1144,6 @@ ngx_http_fastcgi_process_header(ngx_http
     ngx_table_elt_t                *h;
     ngx_http_upstream_t            *u;
     ngx_http_fastcgi_ctx_t         *f;
-    ngx_http_fastcgi_header_t      *fh;
     ngx_http_upstream_header_t     *hh;
     ngx_http_fastcgi_loc_conf_t    *flcf;
     ngx_http_fastcgi_split_part_t  *part;
@@ -1233,8 +1275,9 @@ ngx_http_fastcgi_process_header(ngx_http
                         } else {
                             u->buffer.pos = u->buffer.start;
                         }
+#else
+                        u->buffer.pos = u->buffer.start;
 #endif
-
                         u->buffer.last = u->buffer.pos;
                         f->large_stderr = 1;
                     }
@@ -1254,9 +1297,10 @@ ngx_http_fastcgi_process_header(ngx_http
 
 #if (NGX_HTTP_CACHE)
 
-        if (f->large_stderr) {
-            u_char   *start;
-            ssize_t   len;
+        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;
 
@@ -1449,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) {
@@ -1922,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;
@@ -1948,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
 
@@ -1974,10 +2016,12 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     u_char                       *p;
     size_t                        size;
     uintptr_t                    *code;
-    ngx_str_t                    *h;
     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;
 
@@ -2169,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);
 
@@ -2195,18 +2251,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
     hash.name = "fastcgi_hide_headers_hash";
 
-#if (NGX_HTTP_CACHE)
-
-    h = conf->upstream.cache ? ngx_http_fastcgi_hide_cache_headers:
-                               ngx_http_fastcgi_hide_headers;
-#else
-
-    h = ngx_http_fastcgi_hide_headers;
-
-#endif
-
     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
-                                            &prev->upstream, h, &hash)
+             &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -2221,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;
@@ -2233,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);
@@ -2249,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));
@@ -2357,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;
 }
 
@@ -2460,10 +2562,10 @@ ngx_http_fastcgi_split(ngx_http_request_
 
     if (n >= 0) { /* match */
         f->script_name.len = captures[3] - captures[2];
-        f->script_name.data = r->uri.data;
+        f->script_name.data = r->uri.data + captures[2];
 
         f->path_info.len = captures[5] - captures[4];
-        f->path_info.data = r->uri.data + f->script_name.len;
+        f->path_info.data = r->uri.data + captures[4];
 
         return f;
     }
@@ -2755,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) {
--- 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;
@@ -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,8 +30,12 @@ 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);
@@ -46,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,
@@ -128,6 +132,10 @@ static ngx_http_variable_t  ngx_http_geo
       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 },
@@ -144,6 +152,14 @@ static ngx_http_variable_t  ngx_http_geo
       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 }
 };
 
@@ -215,7 +231,6 @@ ngx_http_geoip_city_variable(ngx_http_re
 
     len = ngx_strlen(val);
     v->data = ngx_pnalloc(r->pool, len);
-
     if (v->data == NULL) {
         GeoIPRecord_delete(gr);
         return NGX_ERROR;
@@ -245,6 +260,50 @@ 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)
 {
@@ -273,6 +332,35 @@ ngx_http_geoip_city_float_variable(ngx_h
 }
 
 
+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)
 {
@@ -358,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:
@@ -397,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
@@ -258,6 +258,18 @@ ngx_http_gzip_header_filter(ngx_http_req
 
     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);
@@ -285,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;
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -89,10 +89,6 @@ 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) {
@@ -180,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;
@@ -212,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;
     }
 
@@ -292,9 +280,7 @@ ngx_http_set_expires(ngx_http_request_t 
     ngx_http_time(expires->value.data, expires_time);
 
     if (conf->expires_time < 0 || max_age < 0) {
-        cc->value.len = sizeof("no-cache") - 1;
-        cc->value.data = (u_char *) "no-cache";
-
+        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,9 +61,9 @@ 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;
@@ -99,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,
@@ -113,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"),
@@ -228,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) {
@@ -489,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;
@@ -503,6 +520,7 @@ ngx_http_image_process(ngx_http_request_
     if (rc == NGX_OK
         && ctx->width <= ctx->max_width
         && ctx->height <= ctx->max_height
+        && ctx->angle == 0
         && !ctx->force)
     {
         return ngx_http_image_asis(r, ctx);
@@ -529,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) {
@@ -708,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;
@@ -728,6 +745,7 @@ ngx_http_image_resize(ngx_http_request_t
     conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
 
     if (!ctx->force
+        && ctx->angle == 0
         && (ngx_uint_t) sx <= ctx->max_width
         && (ngx_uint_t) sy <= ctx->max_height)
     {
@@ -779,6 +797,10 @@ transparent:
 
         resize = 1;
 
+    } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
+
+        resize = 0;
+
     } else { /* NGX_HTTP_IMAGE_CROP */
 
         resize = 0;
@@ -827,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;
@@ -990,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;
@@ -998,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;
 
@@ -1080,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;
 
@@ -1109,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);
 
@@ -1150,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) {
@@ -1229,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);
 
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -51,7 +51,7 @@ typedef struct {
 
 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);
 
@@ -186,25 +186,56 @@ 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);
 
+        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);
@@ -212,70 +243,26 @@ ngx_http_limit_req_handler(ngx_http_requ
         return NGX_HTTP_SERVICE_UNAVAILABLE;
     }
 
-    if (rc == NGX_AGAIN) {
-        ngx_shmtx_unlock(&ctx->shpool->mutex);
-
-        if (lrcf->nodelay) {
-            return NGX_DECLINED;
-        }
-
-        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);
+    /* 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;
 }
 
 
@@ -355,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;
@@ -390,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();
 
@@ -402,16 +391,15 @@ ngx_http_limit_req_lookup(ngx_http_limit
                     excess = 0;
                 }
 
+                *ep = excess;
+
                 if ((ngx_uint_t) excess > lrcf->burst) {
-                    *lrp = lr;
                     return NGX_BUSY;
                 }
 
                 lr->excess = excess;
                 lr->last = now;
 
-                *lrp = lr;
-
                 if (excess) {
                     return NGX_AGAIN;
                 }
@@ -426,7 +414,7 @@ ngx_http_limit_req_lookup(ngx_http_limit
         break;
     }
 
-    *lrp = NULL;
+    *ep = 0;
 
     return NGX_DECLINED;
 }
--- 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);
 }
@@ -747,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;
 
@@ -922,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 },
@@ -105,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
 };
 
@@ -189,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);
@@ -432,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;
     }
@@ -637,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) {
--- 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;
 
 
@@ -344,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,
@@ -364,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,
@@ -422,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),
@@ -455,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)
 
@@ -544,21 +519,6 @@ static ngx_keyval_t  ngx_http_proxy_cach
     { 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
 
 
@@ -612,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)
@@ -637,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;
@@ -923,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);
         }
@@ -1192,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;
 }
@@ -1206,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;
@@ -1216,15 +1179,15 @@ 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)
 
@@ -1251,20 +1214,20 @@ ngx_http_proxy_process_status_line(ngx_h
     }
 
     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\"",
@@ -1277,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;
@@ -1566,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";
             }
 
@@ -1581,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";
             }
 
@@ -1780,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);
@@ -1827,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;
@@ -1839,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;
@@ -1913,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;
@@ -1938,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
 
@@ -1968,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;
 
@@ -2162,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);
 
@@ -2214,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;
@@ -2251,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;
@@ -2273,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;
@@ -2309,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) {
@@ -2331,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;
@@ -2355,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;
     }
 
@@ -2417,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;
         }
@@ -2565,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);
 }
 
 
@@ -2707,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;
@@ -2754,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;
@@ -2958,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
@@ -3029,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 {
@@ -3046,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;
     }
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -259,10 +259,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);
 }
@@ -390,8 +388,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);
@@ -555,8 +552,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_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -363,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);
@@ -407,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) {
 
--- 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,
@@ -341,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;
@@ -436,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));
@@ -447,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;
     }
 
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,8 +1910,7 @@ 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;
+    ngx_str_null(&args);
     flags = NGX_HTTP_LOG_UNSAFE;
 
     if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
@@ -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);
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -314,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;
      */
 
--- 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;
 
     /*
@@ -189,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;
 
--- 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;
--- 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.34';
+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,7 +642,7 @@ 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);
 
@@ -848,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;
     }
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -168,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);
@@ -481,8 +477,7 @@ ngx_http_perl_init_interpreter(ngx_conf_
             return NGX_CONF_ERROR;
         }
 
-        m->len = sizeof(NGX_PERL_MODULES) - 1;
-        m->data = NGX_PERL_MODULES;
+        ngx_str_set(m, NGX_PERL_MODULES);
     }
 #endif
 
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -26,6 +26,9 @@ static ngx_int_t ngx_http_add_address(ng
 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);
@@ -263,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;
         }
     }
 
@@ -509,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;
 
@@ -526,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;
 
@@ -586,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;
 
@@ -598,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))
@@ -605,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]);
@@ -619,6 +659,8 @@ ngx_http_merge_locations(ngx_conf_t *cf,
         }
     }
 
+    *ctx = saved;
+
     return NGX_CONF_OK;
 }
 
@@ -1179,6 +1221,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 #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
@@ -1228,6 +1273,10 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
         /* 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) {
@@ -1254,6 +1303,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
         }
 
         addr[i].opt.default_server = default_server;
+#if (NGX_HTTP_SSL)
+        addr[i].opt.ssl = ssl;
+#endif
 
         return NGX_OK;
     }
@@ -1450,7 +1502,7 @@ ngx_http_server_names(ngx_conf_t *cf, ng
             }
 
             if (rc == NGX_BUSY) {
-            ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+                ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                               "conflicting server name \"%V\" on %s, ignored",
                               &name[n].name, addr->opt.addr);
             }
@@ -1720,6 +1772,10 @@ ngx_http_add_listening(ngx_conf_t *cf, n
     ls->ipv6only = addr->opt.ipv6only;
 #endif
 
+#if (NGX_HAVE_SETFIB)
+    ls->setfib = addr->opt.setfib;
+#endif
+
     return ls;
 }
 
@@ -1814,8 +1870,12 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_
         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;
         }
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -51,6 +51,14 @@ 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;
 
@@ -70,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,
@@ -132,6 +142,10 @@ char *ngx_http_merge_types(ngx_conf_t *c
 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 (ngx_file_aio && 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 }
 };
@@ -494,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,
@@ -599,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,
@@ -767,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:
@@ -783,33 +801,7 @@ ngx_http_handler(ngx_http_request_t *r)
             break;
         }
 
-        if (r->keepalive) {
-
-            if (r->headers_in.msie6) {
-                if (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;
-                }
-
-            } else if (r->headers_in.safari) {
-                /*
-                 * Safari may send a POST request to a closed keepalive
-                 * connection and stalls for some time
-                 */
-                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 {
@@ -817,10 +809,6 @@ 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;
 #if (NGX_HTTP_GZIP)
     r->gzip_tested = 0;
@@ -862,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,
@@ -893,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)
 {
@@ -1093,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;
     }
 
@@ -1145,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 ( ;; ) {
 
@@ -1206,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;
             }
         }
@@ -1215,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) {
 
@@ -1274,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);
@@ -1334,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,
@@ -1398,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;
         }
     }
 
@@ -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 */
@@ -1678,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] != '/') {
@@ -1699,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) {
@@ -1742,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,
@@ -1770,7 +1897,9 @@ ngx_http_map_uri_to_path(ngx_http_reques
         ngx_uint_t  captures;
 
         captures = alias && clcf->regex;
-        reserved += captures ? 1 : r->uri.len - alias + 1;
+
+        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
@@ -1791,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
     }
@@ -2034,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;
@@ -2098,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;
 
@@ -2147,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++;
 
@@ -2180,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,
@@ -2202,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);
@@ -2305,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;
 
@@ -2384,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;
 }
 
@@ -2824,8 +2994,7 @@ 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;
 
-    struct sockaddr_in      *sin;
-    ngx_http_listen_opt_t    lsopt;
+    ngx_str_t                name;
     ngx_http_server_name_t  *sn;
 
     /* TODO: it does not merge, it inits only */
@@ -2857,48 +3026,35 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->underscores_in_headers,
                               prev->underscores_in_headers, 0);
 
-    if (!conf->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;
-        lsopt.wildcard = 1;
-
-        (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,
-                             NGX_SOCKADDR_STRLEN, 1);
-
-        if (ngx_http_add_listen(cf, conf, &lsopt) == NGX_OK) {
-            return NGX_CONF_OK;
-        }
-    }
-
-    if (conf->server_name.data == NULL) {
-        conf->server_name = cf->cycle->hostname;
-
+    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 (sn == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
 #if (NGX_PCRE)
         sn->regex = NULL;
 #endif
         sn->server = conf;
-        sn->name.len = conf->server_name.len;
-        sn->name.data = conf->server_name.data;
+        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;
@@ -2937,6 +3093,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     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;
@@ -2972,6 +3129,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     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;
 
@@ -2986,7 +3144,10 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     clcf->gzip_http_version = NGX_CONF_UNSET_UINT;
 #if (NGX_PCRE)
     clcf->gzip_disable = NGX_CONF_UNSET_PTR;
+#endif
     clcf->gzip_disable_msie6 = 3;
+#if (NGX_HTTP_DEGRADATION)
+    clcf->gzip_disable_degradation = 3;
 #endif
 #endif
 
@@ -3024,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;
@@ -3134,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,
@@ -3206,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);
@@ -3215,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);
@@ -3247,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;
@@ -3291,6 +3465,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
     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,
@@ -3311,6 +3488,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             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) {
             lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
             lsopt.set = 1;
@@ -3427,7 +3617,6 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strcmp(value[n].data, "ssl") == 0) {
 #if (NGX_HTTP_SSL)
-            lsopt.set = 1;
             lsopt.ssl = 1;
             continue;
 #else
@@ -3457,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];
@@ -3521,7 +3686,13 @@ ngx_http_core_server_name(ngx_conf_t *cf
         sn->regex = NULL;
 #endif
         sn->server = cscf;
-        sn->name = value[i];
+
+        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);
@@ -3583,16 +3754,15 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
     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 (clcf->root.data) {
 
-        /* the (ngx_uint_t) cast is required by gcc 2.7.2.3 */
-
-        if ((ngx_uint_t) clcf->alias == alias) {
+        if ((clcf->alias != 0) == alias) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"%V\" directive is duplicate",
                                &cmd->name);
@@ -3638,7 +3808,7 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
-    clcf->alias = alias;
+    clcf->alias = alias ? clcf->name.len : 0;
     clcf->root = value[1];
 
     if (!alias && clcf->root.data[clcf->root.len - 1] == '/') {
@@ -3654,13 +3824,19 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
     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 = &clcf->root;
         sc.lengths = &clcf->root_lengths;
         sc.values = &clcf->root_values;
-        sc.variables = n;
         sc.complete_lengths = 1;
         sc.complete_values = 1;
 
@@ -3687,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 }
 };
 
@@ -3773,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;
@@ -3881,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, '?');
@@ -3917,19 +4094,15 @@ ngx_http_core_error_page(ngx_conf_t *cf,
             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;
             }
         }
@@ -4249,17 +4422,26 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
 
     for (i = 1; i < cf->args->nelts; i++) {
 
-        if (ngx_strcmp(value[1].data, "msie6") == 0) {
+        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;
         }
 
-        rc.pattern = value[1];
+        rc.pattern = value[i];
         rc.options = NGX_REGEX_CASELESS;
 
         if (ngx_regex_compile(&rc) != NGX_OK) {
@@ -4274,20 +4456,35 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng
     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
 }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -38,6 +38,11 @@
 #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;
 
@@ -71,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;
@@ -283,15 +291,18 @@ struct ngx_http_core_loc_conf_s {
 #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;
@@ -307,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;
 
@@ -341,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 */
@@ -363,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 */
@@ -427,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,
@@ -444,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
@@ -19,6 +19,8 @@ static void ngx_http_cache_aio_event_han
 #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,
@@ -44,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"),
@@ -142,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)
 {
@@ -180,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;
@@ -249,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;
     }
@@ -330,8 +368,6 @@ ngx_http_file_cache_read(ngx_http_reques
     ngx_http_file_cache_t         *cache;
     ngx_http_file_cache_header_t  *h;
 
-    c = r->cache;
-
     n = ngx_http_file_cache_aio_read(r, c);
 
     if (n < 0) {
@@ -392,6 +428,7 @@ ngx_http_file_cache_read(ngx_http_reques
 
         } else {
             c->node->updating = 1;
+            c->updating = 1;
             rc = NGX_HTTP_CACHE_STALE;
         }
 
@@ -480,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()) {
@@ -491,9 +531,6 @@ ngx_http_file_cache_exists(ngx_http_file
             goto done;
         }
 
-        fcn->uses++;
-        fcn->count++;
-
         if (fcn->exists) {
 
             c->exists = fcn->exists;
@@ -542,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;
@@ -574,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)
 {
@@ -724,6 +795,7 @@ ngx_http_file_cache_update(ngx_http_requ
                    "http file cache update");
 
     c->updated = 1;
+    c->updating = 0;
 
     cache = c->file_cache;
 
@@ -833,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);
             }
@@ -886,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);
 }
 
 
@@ -936,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);
 
@@ -951,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;
     }
 
@@ -1035,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);
@@ -1091,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);
+    }
 }
 
 
@@ -1133,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);
 
@@ -1154,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;
@@ -1216,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));
 
@@ -1233,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;
@@ -1379,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;
@@ -1692,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" */
@@ -170,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) {
@@ -218,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;
@@ -338,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);
@@ -366,8 +374,7 @@ ngx_http_header_filter(ngx_http_request_
         }
 
     } else {
-        host.len = 0;
-        host.data = NULL;
+        ngx_str_null(&host);
         port = 0;
     }
 
@@ -534,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;
     }
--- 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) {
@@ -1449,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_request.c
+++ b/src/http/ngx_http_request.c
@@ -88,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 },
 
@@ -555,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]);
 
@@ -756,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;
@@ -788,16 +793,31 @@ ngx_http_process_request_line(ngx_event_
 
             p = r->uri.data + r->uri.len - 1;
 
-            if (*p == '.' || *p == ' ') {
-
-                while (--p > r->uri.data && (*p == '.' || *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
 
@@ -958,10 +978,13 @@ ngx_http_process_request_headers(ngx_eve
                 if (rv == NGX_DECLINED) {
                     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_BAD_REQUEST);
+                        ngx_http_finalize_request(r,
+                                            NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
                         return;
                     }
 
@@ -975,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;
                 }
             }
@@ -2569,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);
@@ -2678,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
@@ -37,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
@@ -56,7 +57,7 @@
 #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
@@ -64,12 +65,14 @@
 
 #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;
@@ -435,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;
@@ -485,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_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)
 {
@@ -983,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;
@@ -1008,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);
@@ -1255,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;
 }
 
 
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -159,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;
 
 
@@ -207,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
@@ -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->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;
-            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) {
@@ -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,8 +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->cleanup = NULL;
     }
 
     u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
@@ -564,6 +574,14 @@ 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);
@@ -623,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;
         }
@@ -631,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;
         }
@@ -653,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;
@@ -1703,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;
@@ -1802,8 +1842,7 @@ ngx_http_upstream_process_headers(ngx_ht
         }
 
         uri = &u->headers_in.x_accel_redirect->value;
-        args.len = 0;
-        args.data = NULL;
+        ngx_str_null(&args);
         flags = NGX_HTTP_LOG_UNSAFE;
 
         if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
@@ -1811,10 +1850,6 @@ ngx_http_upstream_process_headers(ngx_ht
             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;
         }
@@ -1921,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;
         }
@@ -2086,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;
 
@@ -2118,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
@@ -2593,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);
             }
         }
 
@@ -2921,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);
@@ -2935,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
@@ -2985,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)
 {
@@ -3026,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;
@@ -3712,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 {
--- 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;
@@ -162,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;
@@ -336,6 +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_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -441,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;
@@ -454,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 {
 
@@ -526,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;
 }
 
@@ -1396,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,
@@ -1667,6 +1660,50 @@ 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
@@ -1937,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;
         }
@@ -1979,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);
@@ -76,6 +76,12 @@ typedef struct {
 } ngx_http_regex_t;
 
 
+typedef struct {
+    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,
@@ -84,21 +90,21 @@ ngx_int_t ngx_http_regex_exec(ngx_http_r
 #endif
 
 
-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);
+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;
 
 
-typedef struct {
-    ngx_rbtree_node_t             node;
-    size_t                        len;
-    ngx_http_variable_value_t    *value;
-} ngx_http_variable_value_node_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 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);
+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_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1409,15 +1409,13 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c
         ahcf->host_header = u.host;
 
     } else {
-        ahcf->host_header.len = sizeof("localhost") - 1;
-        ahcf->host_header.data = (u_char *) "localhost";
+        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) {
@@ -226,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;
 
@@ -259,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 */
 
@@ -466,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
@@ -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;
     }
@@ -664,8 +662,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;
     }
@@ -726,7 +723,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
@@ -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);
     }
 
     ngx_mail_send(c->write);
@@ -414,8 +413,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) {
@@ -435,8 +433,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:
@@ -456,8 +453,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:
@@ -470,8 +466,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;
 
@@ -502,9 +497,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 */
 
@@ -529,8 +522,7 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s
     ngx_mail_smtp_srv_conf_t  *sscf;
 
     if (s->args.nelts != 1) {
-        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;
     }
@@ -546,10 +538,8 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s
 
     ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].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);
 
@@ -599,8 +589,7 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s
 #endif
 
     if (s->args.nelts == 0) {
-        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;
     }
@@ -611,24 +600,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, 1);
 
     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;
@@ -673,18 +659,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;
     }
 
@@ -723,8 +705,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;
 }
@@ -738,8 +719,7 @@ ngx_mail_smtp_rcpt(ngx_mail_session_t *s
     ngx_uint_t  i;
 
     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;
     }
 
@@ -787,13 +767,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;
 }
@@ -814,12 +790,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
@@ -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;
      */
 
--- 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_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -44,7 +44,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch
          *   dereferencing type-punned pointer will break strict-aliasing rules
          *
          * Fortunately, gcc with -O1 compiles this ngx_memcpy()
-         * in the same simple assigment as in the code above
+         * in the same simple assignment as in the code above
          */
 
         ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int));
--- 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_files.c
+++ b/src/os/unix/ngx_files.c
@@ -76,7 +76,7 @@ ngx_write_file(ngx_file_t *file, u_char 
 #if (NGX_HAVE_PWRITE)
 
     for ( ;; ) {
-        n = pwrite(file->fd, buf, size, offset);
+        n = pwrite(file->fd, buf + written, size, offset);
 
         if (n == -1) {
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
@@ -108,7 +108,7 @@ ngx_write_file(ngx_file_t *file, u_char 
     }
 
     for ( ;; ) {
-        n = write(file->fd, buf, size);
+        n = write(file->fd, buf + written, size);
 
         if (n == -1) {
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
@@ -245,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;
@@ -259,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);
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -18,6 +18,15 @@ 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;
@@ -64,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
@@ -138,6 +148,9 @@ 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))
@@ -148,6 +161,10 @@ ngx_int_t ngx_set_file_time(u_char *name
 #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)
--- a/src/os/unix/ngx_linux_aio_read.c
+++ b/src/os/unix/ngx_linux_aio_read.c
@@ -95,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;
     }
 
--- 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
@@ -60,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 = "";
 
@@ -479,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
@@ -168,7 +168,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
         sigsuspend(&set);
 
-        ngx_time_update(0, 0);
+        ngx_time_update();
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "wake up, sigio %i", sigio);
@@ -291,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) {
@@ -856,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);
         }
     }
@@ -1342,7 +1347,7 @@ ngx_cache_manager_process_handler(ngx_ev
 
             next = (n <= next) ? n : next;
 
-            ngx_time_update(0, 0);
+            ngx_time_update();
         }
     }
 
@@ -1372,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_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_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_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)