# HG changeset patch # User Maxim Dounin # Date 1218478026 -14400 # Node ID cd9cb7a3ff9e83c821d7dd07fbe736ae78329c76 # Parent 52b28d322d76312e9a2601db900c02779fe0253a# Parent 040b8c84d040db5be92f1d9aef30c4a34e102418 Merge with nginx 0.7.8. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -170,3 +170,32 @@ 390b8f8309d6eb6771fec2467145bb42b6b71868 5e3b425174f6aea903cfd1b7b5eb8d21bb780847 NGINX_0_6_9 3a91bfeffabaa2cd1a89dab846803bc595d79460 NGINX_0_6_10 3f511163d90862acd9a0d46304e910b515d6c52f NGINX_0_6_11 +1c519aff5c0cc50bbc6db813f93767d6cf4569bc NGINX_0_6_12 +cac46d125dc7c11ce3b7b5c2be0eb634d2e513a6 NGINX_0_6_13 +10cc350ed8a1a0c1a9f0c093f5bec0032ea9eac4 NGINX_0_6_14 +4276c2f1f434d6e7e350d9675b2fcc6efb99f79c NGINX_0_6_15 +eae74a780a84a4f89a835e17a840657cb6b1c556 NGINX_0_6_16 +05693816539c8788ed0060c52a94df2f0975a8bb NGINX_0_6_17 +e10168d6e371c8c2bf687eda4beba01ce6ae3684 NGINX_0_6_18 +5a1bb0129dff4d4fd697de3d70c119967618f0f9 NGINX_0_6_19 +84b8345f70d5c2c37e869f1b269c12bd0f55bc90 NGINX_0_6_20 +583decdb82a458bd5dd2e11c8accbb6ca30c6bd6 NGINX_0_6_21 +b743d290eb3bdec9f8f8ccdcaea8e899b5d781bc NGINX_0_6_22 +9121a0a91f470755095d53c8691d1c3ea58784b8 NGINX_0_6_23 +2b41fbc2e39e1d6c9ab4bd7c5de0191e4d27f574 NGINX_0_6_24 +54fad6c4b555ce02d963e0bc98c867301affb883 NGINX_0_6_25 +a39aab45a53f467d05443d25208b5d893de8f867 NGINX_0_6_26 +babd3d9efb625a2afe53f106195370bd9d5467ca NGINX_0_6_27 +6aeb6e11b9e796d06e1079cecf514d5c3bf5b47f NGINX_0_6_28 +9a242235a80a93be37aa0694220d9c11c27dda64 NGINX_0_6_29 +6639b93e81b2bd6a016b310953215108aad0c379 NGINX_0_6_30 +67fa3851697b2c2940bd437b00e576a2f1706568 NGINX_0_6_31 +edf1cb6c328eb13c27880d1f4cb5ea068f7aec37 NGINX_0_7_0 +820f6378fc007b8682ab891f6b793f7ebe97208a NGINX_0_7_1 +bc21d9cd9c5427ba2c8e096ca20a33ce4aa50d7c NGINX_0_7_2 +984bb0b1399bffe332ad1fe5cd8d4d7862fa18d8 NGINX_0_7_3 +12defd37f57883e4d59ef36837d03c9b68c3c3ad NGINX_0_7_4 +1172e6d6f40f26a5130a15f5b7adbd902216faf2 NGINX_0_7_5 +6de24473fa708acc3b2f13611f5c44b0e3a292c9 NGINX_0_7_6 +0b6053502c552a3021db417cb2dc6caac7ba1bdd NGINX_0_7_7 +34fb3a5735483bd22e77f90f305103307a813fc4 NGINX_0_7_8 diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,537 @@ +Changes with nginx 0.7.7 30 Jul 2008 + + *) Change: now the EAGAIN error returned by connect() is not considered + as temporary error. + + *) Change: now the $ssl_client_cert variable value is a certificate + with TAB character intended before each line except first one; an + unchanged certificate is available in the $ssl_client_raw_cert + variable. + + *) Feature: the "ask" parameter in the "ssl_verify_client" directive. + + *) Feature: byte-range processing improvements. + Thanks to Maxim Dounin. + + *) Feature: the "directio" directive. + + *) Feature: MacOSX 1.5 sendfile() support. + + *) Bugfix: now in MacOSX and Cygwin locations are tested in case + insensitive mode; however, the compare is provided by single-byte + locales only. + + *) Bugfix: mail proxy SSL connections hanged, if select, poll, or + /dev/poll methods were used. + + *) Bugfix: UTF-8 encoding usage in the ngx_http_autoindex_module. + + +Changes with nginx 0.7.6 07 Jul 2008 + + *) Bugfix: now if variables are used in the "access_log" directive a + request root existence is always tested. + + *) Bugfix: the ngx_http_flv_module did not support several values in a + query string. + + +Changes with nginx 0.7.5 01 Jul 2008 + + *) Bugfixes in variables support in the "access_log" directive; the + bugs had appeared in 0.7.4. + + *) Bugfix: nginx could not be built --without-http_gzip_module; the bug + had appeared in 0.7.3. + Thanks to Kirill A. Korinskiy. + + *) Bugfix: if sub_filter and SSI were used together, then responses + might were transferred incorrectly. + + +Changes with nginx 0.7.4 30 Jun 2008 + + *) Feature: variables support in the "access_log" directive. + + *) Feature: the "open_log_file_cache" directive. + + *) Feature: the -g switch. + + *) Feature: the "Expect" request header line support. + + *) Bugfix: large SSI inclusions might be truncated. + + +Changes with nginx 0.7.3 23 Jun 2008 + + *) Change: the "rss" extension MIME type has been changed to + "application/rss+xml". + + *) Change: now the "gzip_vary" directive turned on issues a + "Vary: Accept-Encoding" header line for uncompressed responses too. + + *) Feature: now the "rewrite" directive does a redirect automatically + if the "https://" protocol is used. + + *) Bugfix: the "proxy_pass" directive did not work with the HTTPS + protocol; the bug had appeared in 0.6.9. + + +Changes with nginx 0.7.2 16 Jun 2008 + + *) Feature: now nginx supports EDH key exchange ciphers. + + *) Feature: the "ssl_dhparam" directive. + + *) Feature: the $ssl_client_cert variable. + Thanks to Manlio Perillo. + + *) Bugfix: after changing URI via a "rewrite" directive nginx did not + search a new location; the bug had appeared in 0.7.1. + Thanks to Maxim Dounin. + + *) Bugfix: nginx could not be built without PCRE library; the bug had + appeared in 0.7.1. + + *) Bugfix: when a request to a directory was redirected with the slash + added, nginx dropped a query string from the original request. + + +Changes with nginx 0.7.1 26 May 2008 + + *) Change: now locations are searched in a tree. + + *) Change: the "optimize_server_names" directive was canceled due to + the "server_name_in_redirect" directive introduction. + + *) Change: some long deprecated directives are not supported anymore. + + *) Change: the "none" parameter in the "ssl_session_cache" directive; + now this is default parameter. + Thanks to Rob Mueller. + + *) Bugfix: worker processes might not catch reconfiguration and log + rotation signals. + + *) Bugfix: nginx could not be built on latest Fedora 9 Linux. + Thanks to Roxis. + + +Changes with nginx 0.7.0 19 May 2008 + + *) Change: now the 0x00-0x1F, '"' and '\' characters are escaped as + \xXX in an access_log. + Thanks to Maxim Dounin. + + *) Change: now nginx allows several "Host" request header line. + + *) Feature: the "modified" flag in the "expires" directive. + + *) Feature: the $uid_got and $uid_set variables may be used at any + request processing stage. + + *) Feature: the $hostname variable. + Thanks to Andrei Nigmatulin. + + *) Feature: DESTDIR support. + Thanks to Todd A. Fisher and Andras Voroskoi. + + *) Bugfix: a segmentation fault might occur in worker process on Linux, + if keepalive was enabled. + + +Changes with nginx 0.6.31 12 May 2008 + + *) Bugfix: nginx did not process FastCGI response if header was at the + end of FastCGI record; the bug had appeared in 0.6.2. + Thanks to Sergey Serov. + + *) Bugfix: a segmentation fault might occur in worker process if a file + was deleted and the "open_file_cache_errors" directive was off. + + +Changes with nginx 0.6.30 29 Apr 2008 + + *) Change: now if an "include" directive pattern does not match any + file, then nginx does not issue an error. + + *) Feature: now the time in directives may be specified without spaces, + for example, "1h50m". + + *) Bugfix: memory leaks if the "ssl_verify_client" directive was on. + Thanks to Chavelle Vincent. + + *) Bugfix: the "sub_filter" directive might set text to change into + output. + + *) Bugfix: the "error_page" directive did not take into account + arguments in redirected URI. + + *) Bugfix: now nginx always opens files in binary mode under Cygwin. + + *) Bugfix: nginx could not be built on OpenBSD; the bug had appeared in + 0.6.15. + + +Changes with nginx 0.6.29 18 Mar 2008 + + *) Feature: the ngx_google_perftools_module. + + *) Bugfix: the ngx_http_perl_module could not be built on 64-bit + platforms; the bug had appeared in 0.6.27. + + +Changes with nginx 0.6.28 13 Mar 2008 + + *) Bugfix: the rtsig method could not be built; the bug had appeared in + 0.6.27. + + +Changes with nginx 0.6.27 12 Mar 2008 + + *) Change: now by default the rtsig method is not built on + Linux 2.6.18+. + + *) Change: now a request method is not changed while redirection to a + named location via an "error_page" directive. + + *) Feature: the "resolver" and "resolver_timeout" directives in SMTP + proxy. + + *) Feature: the "post_action" directive supports named locations. + + *) Bugfix: a segmentation fault occurred in worker process, if a + request was redirected from proxy, FastCGI, or memcached location to + static named locations. + + *) Bugfix: browsers did not repeat SSL handshake if there is no valid + client certificate in first handshake. + Thanks to Alexander V. Inyukhin. + + *) Bugfix: if response code 495-497 was redirected via an "error_page" + directive without code change, then nginx tried to allocate too many + memory. + + *) Bugfix: memory leak in long-lived non buffered connections. + + *) Bugfix: memory leak in resolver. + + *) Bugfix: a segmentation fault occurred in worker process, if a + request was redirected from proxy, FastCGI, or memcached location to + static named locations. + + *) Bugfix: in the $proxy_host and $proxy_port variables caching. + Thanks to Sergey Bochenkov. + + *) Bugfix: a "proxy_pass" directive with variables used incorrectly the + same port as in another "proxy_pass" directive with the same host + name and without variables. + Thanks to Sergey Bochenkov. + + *) Bugfix: an alert "sendmsg() failed (9: Bad file descriptor)" on some + 64-bit platforms while reconfiguration. + + *) Bugfix: a segmentation fault occurred in worker process, if empty + stub block was used second time in SSI. + + *) Bugfix: in copying URI part contained escaped symbols into arguments. + + +Changes with nginx 0.6.26 11 Feb 2008 + + *) Bugfix: the "proxy_store" and "fastcgi_store" directives did not + check a response length. + + *) Bugfix: a segmentation fault occurred in worker process, if big + value was used in a "expires" directive. + Thanks to Joaquin Cuenca Abela. + + *) Bugfix: nginx incorrectly detected cache line size on Pentium 4. + Thanks to Gena Makhomed. + + *) Bugfix: in proxied or FastCGI subrequests a client original method + was used instead of the GET method. + + *) Bugfix: socket leak in HTTPS mode if deferred accept was used. + Thanks to Ben Maurer. + + *) Bugfix: nginx issued the bogus error message "SSL_shutdown() failed + (SSL: )"; the bug had appeared in 0.6.23. + + *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" + error; the bug had appeared in 0.6.23. + + +Changes with nginx 0.6.25 08 Jan 2008 + + *) Change: now the "server_name_in_redirect" directive is used instead + of the "server_name" directive's special "*" parameter. + + *) Change: now wildcard and regex names can be used as main name in a + "server_name" directive. + + *) Change: the "satisfy_any" directive was replaced by the "satisfy" + directive. + + *) Workaround: old worker processes might hog CPU after reconfiguration + if they was run under Linux OpenVZ. + + *) Feature: the "min_delete_depth" directive. + + *) Bugfix: the COPY and MOVE methods did not work with single files. + + *) Bugfix: the ngx_http_gzip_static_module did not allow the + ngx_http_dav_module to work; the bug had appeared in 0.6.23. + + *) Bugfix: socket leak in HTTPS mode if deferred accept was used. + Thanks to Ben Maurer. + + *) Bugfix: nginx could not be built without PCRE library; the bug had + appeared in 0.6.23. + + +Changes with nginx 0.6.24 27 Dec 2007 + + *) Bugfix: a segmentation fault might occur in worker process if HTTPS + was used; the bug had appeared in 0.6.23. + + +Changes with nginx 0.6.23 27 Dec 2007 + + *) Change: the "off" parameter in the "ssl_session_cache" directive; + now this is default parameter. + + *) Change: the "open_file_cache_retest" directive was renamed to the + "open_file_cache_valid". + + *) Feature: the "open_file_cache_min_uses" directive. + + *) Feature: the ngx_http_gzip_static_module. + + *) Feature: the "gzip_disable" directive. + + *) Feature: the "memcached_pass" directive may be used inside the "if" + block. + + *) Bugfix: a segmentation fault occurred in worker process, if the + "memcached_pass" and "if" directives were used in the same location. + + *) Bugfix: if a "satisfy_any on" directive was used and not all access + and auth modules directives were set, then other given access and + auth directives were not tested; + + *) Bugfix: regex parameters in a "valid_referers" directive were not + inherited from previous level. + + *) Bugfix: a "post_action" directive did run if a request was completed + with 499 status code. + + *) Bugfix: optimization of 16K buffer usage in a SSL connection. + Thanks to Ben Maurer. + + *) Bugfix: the STARTTLS in SMTP mode did not work. + Thanks to Oleg Motienko. + + *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" + error; the bug had appeared in 0.5.13. + + +Changes with nginx 0.6.22 19 Dec 2007 + + *) Change: now all ngx_http_perl_module methods return values copied to + perl's allocated memory. + + *) Bugfix: if nginx was built with ngx_http_perl_module, the perl + before 5.8.6 was used, and perl supported threads, then during + reconfiguration the master process aborted; the bug had appeared in + 0.5.9. + Thanks to Boris Zhmurov. + + *) Bugfix: the ngx_http_perl_module methods may get invalid values of + the regex captures. + + *) Bugfix: a segmentation fault occurred in worker process, if the + $r->has_request_body() method was called for a request whose small + request body was already received. + + *) Bugfix: large_client_header_buffers did not freed before going to + keep-alive state. + Thanks to Olexander Shtepa. + + *) Bugfix: the last address was missed in the $upstream_addr variable; + the bug had appeared in 0.6.18. + + *) Bugfix: the "fastcgi_catch_stderr" directive did return error code; + now it returns 502 code, that can be rerouted to a next server using + the "fastcgi_next_upstream invalid_header" directive. + + *) Bugfix: a segmentation fault occurred in master process if the + "fastcgi_catch_stderr" directive was used; the bug had appeared in + 0.6.10. + Thanks to Manlio Perillo. + + +Changes with nginx 0.6.21 03 Dec 2007 + + *) Change: if variable values used in a "proxy_pass" directive contain + IP-addresses only, then a "resolver" directive is not mandatory. + resolver + + *) Bugfix: a segmentation fault might occur in worker process if a + "proxy_pass" directive with URI-part was used; the bug had appeared + in 0.6.19. + + *) Bugfix: if resolver was used on platform that does not support + kqueue, then nginx issued an alert "name is out of response". + Thanks to Andrei Nigmatulin. + + *) Bugfix: if the $server_protocol was used in FastCGI parameters and a + request line length was near to the "client_header_buffer_size" + directive value, then nginx issued an alert "fastcgi: the request + record is too big". + + *) Bugfix: if a plain text HTTP/0.9 version request was made to HTTPS + server, then nginx returned usual response. + + +Changes with nginx 0.6.20 28 Nov 2007 + + *) Bugfix: a segmentation fault might occur in worker process if a + "proxy_pass" directive with URI-part was used; the bug had appeared + in 0.6.19. + + +Changes with nginx 0.6.19 27 Nov 2007 + + *) Bugfix: the 0.6.18 version could not be built. + + +Changes with nginx 0.6.18 27 Nov 2007 + + *) Change: now the ngx_http_userid_module adds start time microseconds + to the cookie field contains a pid value. + + *) Change: now the full request line instead of URI only is written to + error_log. + + *) Feature: variables support in the "proxy_pass" directive. + + *) Feature: the "resolver" and "resolver_timeout" directives. + + *) Feature: now the directive "add_header last-modified ''" deletes a + "Last-Modified" response header line. + + *) Bugfix: the "limit_rate" directive did not allow to use full + throughput, even if limit value was very high. + + +Changes with nginx 0.6.17 15 Nov 2007 + + *) Feature: the "If-Range" request header line support. + Thanks to Alexander V. Inyukhin. + + *) Bugfix: URL double escaping in a redirect of the "msie_refresh" + directive; the bug had appeared in 0.6.4. + + *) Bugfix: the "autoindex" directive did not work with the "alias /" + directive. + + *) Bugfix: a segmentation fault might occur in worker process if + subrequests were used. + + *) Bugfix: the big responses may be transferred truncated if SSL and + gzip were used. + + *) Bugfix: the $status variable was equal to 0 if a proxied server + returned response in HTTP/0.9 version. + + +Changes with nginx 0.6.16 29 Oct 2007 + + *) Change: now the uname(2) is used on Linux instead of procfs. + Thanks to Ilya Novikov. + + *) Bugfix: if the "?" character was in a "error_page" directive, then + it was escaped in a proxied request; the bug had appeared in 0.6.11. + + *) Bugfix: compatibility with mget. + + +Changes with nginx 0.6.15 22 Oct 2007 + + *) Feature: Cygwin compatibility. + Thanks to Vladimir Kutakov. + + *) Feature: the "merge_slashes" directive. + + *) Feature: the "gzip_vary" directive. + + *) Feature: the "server_tokens" directive. + + *) Bugfix: nginx did not unescape URI in the "include" SSI command. + + *) Bugfix: the segmentation fault was occurred on start or while + reconfiguration if variable was used in the "charset" or + "source_charset" directives. + + *) Bugfix: nginx returned the 400 response on requests like + "GET http://www.domain.com HTTP/1.0". + Thanks to James Oakley. + + *) Bugfix: if request with request body was redirected using the + "error_page" directive, then nginx tried to read the request body + again; the bug had appeared in 0.6.7. + + *) Bugfix: a segmentation fault occurred in worker process if no + server_name was explicitly defined for server processing request; + the bug had appeared in 0.6.7. + + +Changes with nginx 0.6.14 15 Oct 2007 + + *) Change: now by default the "echo" SSI command uses entity encoding. + + *) Feature: the "encoding" parameter in the "echo" SSI command. + + *) Feature: the "access_log" directive may be used inside the + "limit_except" block. + + *) Bugfix: if all upstream servers were failed, then all servers had + got weight the was equal one until servers became alive; the bug had + appeared in 0.6.6. + + *) Bugfix: a segmentation fault occurred in worker process if + $date_local and $date_gmt were used outside the + ngx_http_ssi_filter_module. + + *) Bugfix: a segmentation fault might occur in worker process if debug + log was enabled. + Thanks to Andrei Nigmatulin. + + *) Bugfix: ngx_http_memcached_module did not set + $upstream_response_time. + Thanks to Maxim Dounin. + + *) Bugfix: a worker process may got caught in an endless loop, if the + memcached was used. + + *) Bugfix: nginx supported low case only "close" and "keep-alive" + values in the "Connection" request header line; the bug had appeared + in 0.6.11. + + *) Bugfix: sub_filter did not work with empty substitution. + + *) Bugfix: in sub_filter parsing. + + +Changes with nginx 0.6.13 24 Sep 2007 + + *) Bugfix: nginx did not close directory file on HEAD request if + autoindex was used. + Thanks to Arkadiusz Patyk. + + Changes with nginx 0.6.12 21 Sep 2007 *) Change: mail proxy was split on three modules: pop3, imap and smtp. @@ -9,7 +542,8 @@ Changes with nginx 0.6.12 *) Feature: the "smtp_greeting_delay" and "smtp_client_buffer" directives of the ngx_mail_smtp_module. - *) Bugfix: the trailing wildcards did not work; bug appeared in 0.6.9. + *) Bugfix: the trailing wildcards did not work; the bug had appeared in + 0.6.9. *) Bugfix: nginx could not start on Solaris if the shared PCRE library located in non-standard place was used. @@ -32,7 +566,8 @@ Changes with nginx 0.6.11 lines. *) Bugfix: if the "max_fails" was set for upstream server, then after - first failure server weight was always one; bug appeared in 0.6.6. + first failure server weight was always one; the bug had appeared in + 0.6.6. Changes with nginx 0.6.10 03 Sep 2007 @@ -40,7 +575,7 @@ Changes with nginx 0.6.10 *) Feature: the "open_file_cache", "open_file_cache_retest", and "open_file_cache_errors" directives. - *) Bugfix: socket leak; bug appeared in 0.6.7. + *) Bugfix: socket leak; the bug had appeared in 0.6.7. *) Bugfix: a charset set by the "charset" directive was not appended to the "Content-Type" header set by $r->send_http_header(). @@ -52,7 +587,7 @@ Changes with nginx 0.6.10 Changes with nginx 0.6.9 28 Aug 2007 *) Bugfix: a worker process may got caught in an endless loop, if the - HTTPS protocol was used; bug appeared in 0.6.7. + HTTPS protocol was used; the bug had appeared in 0.6.7. *) Bugfix: if server listened on two addresses or ports and trailing wildcard was used, then nginx did not run. @@ -60,7 +595,8 @@ Changes with nginx 0.6.9 *) Bugfix: the "ip_hash" directive might incorrectly mark servers as down. - *) Bugfix: nginx could not be built on amd64; bug appeared in 0.6.8. + *) Bugfix: nginx could not be built on amd64; the bug had appeared in + 0.6.8. Changes with nginx 0.6.8 20 Aug 2007 @@ -75,8 +611,8 @@ Changes with nginx 0.6.8 *) Change: now nginx escapes "%" in $memcached_key variable. *) Bugfix: nginx used path relative to configuration prefix for - non-absolute configuration file path specified in the "-c" key; bug - appeared in 0.6.6. + non-absolute configuration file path specified in the "-c" key; the + bug had appeared in 0.6.6. *) Bugfix: nginx did not work on FreeBSD/sparc64. @@ -106,7 +642,7 @@ Changes with nginx 0.6.7 *) Feature: the "add_header Last-Modified ..." directive changes the "Last-Modified" response header line. - *) Bugfix: if an response different than 200 was returned to an request + *) Bugfix: if a response different than 200 was returned to a request with body and connection went to the keep-alive state after the request, then nginx returned 400 for the next request. @@ -117,9 +653,9 @@ Changes with nginx 0.6.7 platforms except FreeBSD. Thanks to Jiang Hong. - *) Bugfix: a worker process may got caught in an endless loop, if an - "server" inside "upstream" block was marked as "down"; bug appeared - in 0.6.6. + *) Bugfix: a worker process may got caught in an endless loop, if a + "server" inside "upstream" block was marked as "down"; the bug had + appeared in 0.6.6. *) Bugfix: now Solaris sendfilev() is not used to transfer the client request body to FastCGI-server via the unix domain socket. @@ -144,7 +680,7 @@ Changes with nginx 0.6.6 for HTTP and HTTPS, then nginx used only one port - 80 or 443. *) Bugfix: fix building on Solaris/amd64 by Sun Studio 11 and early - versions; bug appeared in 0.6.4. + versions; the bug had appeared in 0.6.4. Changes with nginx 0.6.5 23 Jul 2007 @@ -205,8 +741,8 @@ Changes with nginx 0.6.3 eventport method was used. *) Bugfix: the "proxy_ignore_client_abort" and - "fastcgi_ignore_client_abort" directives did not work; bug appeared - in 0.5.13. + "fastcgi_ignore_client_abort" directives did not work; the bug had + appeared in 0.5.13. Changes with nginx 0.6.2 09 Jul 2007 @@ -238,7 +774,8 @@ Changes with nginx 0.6.0 Changes with nginx 0.5.25 11 Jun 2007 *) Bugfix: nginx could not be built with the - --without-http_rewrite_module parameter; bug appeared in 0.5.24. + --without-http_rewrite_module parameter; the bug had appeared in + 0.5.24. Changes with nginx 0.5.24 06 Jun 2007 @@ -247,7 +784,7 @@ Changes with nginx 0.5.24 was made using HTTP/0.9. *) Bugfix: a part of response body might be passed uncompressed if gzip - was used; bug appeared in 0.5.23. + was used; the bug had appeared in 0.5.23. Changes with nginx 0.5.23 04 Jun 2007 @@ -270,8 +807,8 @@ Changes with nginx 0.5.23 Changes with nginx 0.5.22 29 May 2007 - *) Bugfix: a big request body might not be passed to backend; bug - appeared in 0.5.21. + *) Bugfix: a big request body might not be passed to backend; the bug + had appeared in 0.5.21. Changes with nginx 0.5.21 28 May 2007 @@ -308,7 +845,8 @@ Changes with nginx 0.5.20 Studio. Thanks to Andrei Nigmatulin. - *) Bugfix: the ngx_http_perl_module could not built by Solaris make. + *) Bugfix: the ngx_http_perl_module could not be built by Solaris + make. Thanks to Andrei Nigmatulin. @@ -343,11 +881,12 @@ Changes with nginx 0.5.18 *) Bugfix: a segmentation fault occurred in master process after first reconfiguration and receiving any signal if nginx was built with - ngx_http_perl_module and perl did not support multiplicity; bug - appeared in 0.5.9. + ngx_http_perl_module and perl did not support multiplicity; the bug + had appeared in 0.5.9. *) Bugfix: if perl did not support multiplicity, then after - reconfiguration perl code did not work; bug appeared in 0.3.38. + reconfiguration perl code did not work; the bug had appeared in + 0.3.38. Changes with nginx 0.5.17 02 Apr 2007 @@ -374,14 +913,14 @@ Changes with nginx 0.5.16 *) Bugfix: a segmentation fault might occur in worker process if a charset was set in the "Content-Type" header line and the line has - trailing ";"; bug appeared in 0.3.50. + trailing ";"; the bug had appeared in 0.3.50. *) Bugfix: the "[alert] zero size buf" error when FastCGI server was - used and an request body written in a temporary file was multiple of + used and a request body written in a temporary file was multiple of 32K. *) Bugfix: nginx could not be built on Solaris without the --with-debug - option; bug appeared in 0.5.15. + option; the bug had appeared in 0.5.15. Changes with nginx 0.5.15 19 Mar 2007 @@ -437,17 +976,17 @@ Changes with nginx 0.5.13 send timeout only. *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc and ppc; bug appeared in 0.5.8. + amd64, sparc, and ppc; the bug had appeared in 0.5.8. Changes with nginx 0.5.12 12 Feb 2007 *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc É ppc; bug appeared in 0.5.8. + amd64, sparc, and ppc; the bug had appeared in 0.5.8. *) Bugfix: a segmentation fault might occur in worker process if the - temporarily files were used while working with FastCGI server; bug - appeared in 0.5.8. + temporarily files were used while working with FastCGI server; the + bug had appeared in 0.5.8. *) Bugfix: a segmentation fault might occur in worker process if the $fastcgi_script_name variable was logged. @@ -461,7 +1000,7 @@ Changes with nginx 0.5.11 Thanks to Chris McGrath. *) Bugfix: the response was incorrect if several ranges were requested; - bug appeared in 0.5.6. + the bug had appeared in 0.5.6. *) Bugfix: the "create_full_put_path" directive could not create the intermediate directories if no "dav_access" directive was set. @@ -477,10 +1016,10 @@ Changes with nginx 0.5.11 Changes with nginx 0.5.10 26 Jan 2007 *) Bugfix: while online executable file upgrade the new master process - did not inherit the listening sockets; bug appeared in 0.5.9. + did not inherit the listening sockets; the bug had appeared in 0.5.9. *) Bugfix: a segmentation fault might occur in worker process if nginx - was built with -O2 optimization; bug appeared in 0.5.1. + was built with -O2 optimization; the bug had appeared in 0.5.1. Changes with nginx 0.5.9 25 Jan 2007 @@ -516,7 +1055,7 @@ Changes with nginx 0.5.8 *) Bugfix: if the "proxy_buffering off" directive was used and a client connection was non-active, then the connection was closed after send - timeout; bug appeared in 0.4.7. + timeout; the bug had appeared in 0.4.7. *) Bugfix: if the "epoll" method was used and a client closed a connection prematurely, then nginx closed the connection after a @@ -597,7 +1136,7 @@ Changes with nginx 0.5.4 directive, then nginx might report about configuration error. *) Bugfix: a segmentation fault might occur if the $host variable was - used; bug appeared in 0.4.14. + used; the bug had appeared in 0.4.14. Changes with nginx 0.5.3 13 Dec 2006 @@ -614,8 +1153,8 @@ Changes with nginx 0.5.3 Changes with nginx 0.5.2 11 Dec 2006 *) Bugfix: if the "proxy_pass" directive used the name of the - "upstream" block, then nginx tried to resolve the name; bug appeared - in 0.5.1. + "upstream" block, then nginx tried to resolve the name; the bug had + appeared in 0.5.1. Changes with nginx 0.5.1 11 Dec 2006 @@ -623,19 +1162,20 @@ Changes with nginx 0.5.1 *) Bugfix: the "post_action" directive might not run after a unsuccessful completion of a request. - *) Workaround: for Eudora for Mac; bug appeared in 0.4.11. + *) Workaround: for Eudora for Mac; the bug had appeared in 0.4.11. Thanks to Bron Gondwana. *) Bugfix: if the "upstream" name was used in the "fastcgi_pass", then - the message "no port in upstream" was issued; bug appeared in 0.5.0. + the message "no port in upstream" was issued; the bug had appeared + in 0.5.0. *) Bugfix: if the "proxy_pass" and "fastcgi_pass" directives used the same servers but different ports, then these directives uses the - first described port; bug appeared in 0.5.0. + first described port; the bug had appeared in 0.5.0. *) Bugfix: if the "proxy_pass" and "fastcgi_pass" directives used the unix domain sockets, then these directives used first described - socket; bug appeared in 0.5.0. + socket; the bug had appeared in 0.5.0. *) Bugfix: ngx_http_auth_basic_module ignored the user if it was in the last line in the password file and there was no the carriage return, @@ -664,8 +1204,8 @@ Changes with nginx 0.5.0 *) Feature: the WAIT status in the "Auth-Status" header line of the IMAP/POP3 proxy authentication server response. - *) Bugfix: nginx could not be built on 64-bit platforms; bug appeared - in 0.4.14. + *) Bugfix: nginx could not be built on 64-bit platforms; the bug had + appeared in 0.4.14. Changes with nginx 0.4.14 27 Nov 2006 @@ -676,12 +1216,12 @@ Changes with nginx 0.4.14 Linux, and NetBSD. *) Bugfix: ngx_http_perl_module did not work with perl built with the - threads support; bug appeared in 0.3.38. + threads support; the bug had appeared in 0.3.38. *) Bugfix: ngx_http_perl_module did not work if perl was called recursively. - *) Bugfix: nginx ignored a host name in an request line. + *) Bugfix: nginx ignored a host name in a request line. *) Bugfix: a worker process may got caught in an endless loop, if a FastCGI server sent too many data to the stderr. @@ -704,14 +1244,14 @@ Changes with nginx 0.4.13 *) Feature: the "limit_except" directive supports all WebDAV methods. *) Bugfix: if the "add_before_body" directive was used without the - "add_after_body" directive, then an response did not transferred + "add_after_body" directive, then a response did not transferred complete. *) Bugfix: a large request body did not receive if the epoll method and the deferred accept() were used. *) Bugfix: a charset could not be set for ngx_http_autoindex_module - responses; bug appeared in 0.3.50. + responses; the bug had appeared in 0.3.50. *) Bugfix: the "[alert] zero size buf" error when FastCGI server was used; @@ -719,8 +1259,8 @@ Changes with nginx 0.4.13 *) Bugfix: the --group= configuration parameter was ignored. Thanks to Thomas Moschny. - *) Bugfix: the 50th subrequest in SSI response did not work; bug - appeared in 0.3.50. + *) Bugfix: the 50th subrequest in SSI response did not work; the bug + had appeared in 0.3.50. Changes with nginx 0.4.12 31 Oct 2006 @@ -741,7 +1281,7 @@ Changes with nginx 0.4.11 method. *) Bugfix: if the APOP was enabled in the POP3 proxy, then the - USER/PASS commands might not work; bug appeared in 0.4.10. + USER/PASS commands might not work; the bug had appeared in 0.4.10. Changes with nginx 0.4.10 23 Oct 2006 @@ -756,10 +1296,10 @@ Changes with nginx 0.4.10 variable was used in the "map" directive. *) Bugfix: the ngx_http_flv_module did not support the byte ranges for - full responses; bug appeared in 0.4.7. - - *) Bugfix: nginx could not be built on Debian amd64; bug appeared in - 0.4.9. + full responses; the bug had appeared in 0.4.7. + + *) Bugfix: nginx could not be built on Debian amd64; the bug had + appeared in 0.4.9. Changes with nginx 0.4.9 13 Oct 2006 @@ -773,8 +1313,8 @@ Changes with nginx 0.4.9 Changes with nginx 0.4.8 11 Oct 2006 *) Bugfix: if an "include" SSI command were before another "include" - SSI command with an "wait" parameter, then the "wait" parameter - might not work. + SSI command with a "wait" parameter, then the "wait" parameter might + not work. *) Bugfix: the ngx_http_flv_module added the FLV header to the full responses. @@ -791,8 +1331,8 @@ Changes with nginx 0.4.7 variables. *) Bugfix: if an "include" SSI command were before another "include" - SSI command with an "wait" parameter, then the "wait" parameter - might not work. + SSI command with a "wait" parameter, then the "wait" parameter might + not work. *) Bugfix: if the "proxy_buffering off" directive was used or while working with memcached the connections might not be closed on @@ -812,14 +1352,14 @@ Changes with nginx 0.4.6 $r->headers_out("Content-Length", ...) method. *) Bugfix: after redirecting error by an "error_page" directive any - ngx_http_rewrite_module directive returned this error code; bug - appeared in 0.4.4. + ngx_http_rewrite_module directive returned this error code; the bug + had appeared in 0.4.4. Changes with nginx 0.4.5 02 Oct 2006 - *) Bugfix: nginx could not be built on Linux and Solaris; bug appeared - in 0.4.4. + *) Bugfix: nginx could not be built on Linux and Solaris; the bug had + appeared in 0.4.4. Changes with nginx 0.4.4 02 Oct 2006 @@ -851,10 +1391,10 @@ Changes with nginx 0.4.3 *) Feature: the ngx_http_browser_module. *) Bugfix: a segmentation fault may occur while redirecting the 400 - error to the proxied server using an "proxy_pass" directive. + error to the proxied server using a "proxy_pass" directive. *) Bugfix: a segmentation fault occurred if an unix domain socket was - used in an "proxy_pass" directive; bug appeared in 0.3.47. + used in a "proxy_pass" directive; the bug had appeared in 0.3.47. *) Bugfix: SSI did work with memcached and nonbuffered responses. @@ -863,8 +1403,8 @@ Changes with nginx 0.4.3 Changes with nginx 0.4.2 14 Sep 2006 - *) Bugfix: the O_NOATIME flag support on Linux was canceled; bug - appeared in 0.4.1. + *) Bugfix: the O_NOATIME flag support on Linux was canceled; the bug + had appeared in 0.4.1. Changes with nginx 0.4.1 14 Sep 2006 @@ -898,7 +1438,7 @@ Changes with nginx 0.4.0 *) Bugfix: a segmentation fault occurred if there was an "index" directive with variables and the first index name was without - variables; bug appeared in 0.1.29. + variables; the bug had appeared in 0.1.29. Changes with nginx 0.3.61 28 Aug 2006 @@ -916,7 +1456,7 @@ Changes with nginx 0.3.61 Changes with nginx 0.3.60 18 Aug 2006 *) Bugfix: a worker process may got caught in an endless loop while an - error redirection; bug appeared in 0.3.59. + error redirection; the bug had appeared in 0.3.59. Changes with nginx 0.3.59 16 Aug 2006 @@ -928,7 +1468,7 @@ Changes with nginx 0.3.59 *) Bugfix: the "error_page" directive did not changes the "Content-Type" header line after the "X-Accel-Redirect" was used; - bug appeared in 0.3.58. + the bug had appeared in 0.3.58. Changes with nginx 0.3.58 14 Aug 2006 @@ -969,7 +1509,7 @@ Changes with nginx 0.3.56 *) Feature: the "if" directive supports the "-d", "!-d", "-e", "!-e", "-x", and "!-x" operators. - *) Bugfix: a segmentation fault occurred if an request returned an + *) Bugfix: a segmentation fault occurred if a request returned a redirect and some sent to client header lines were logged in the access log. @@ -996,8 +1536,8 @@ Changes with nginx 0.3.55 upstream. *) Bugfix: on some condition while reconfiguration character codes - inside the "charset_map" may be treated invalid; bug appeared in - 0.3.50. + inside the "charset_map" may be treated invalid; the bug had + appeared in 0.3.50. Changes with nginx 0.3.54 11 Jul 2006 @@ -1016,8 +1556,8 @@ Changes with nginx 0.3.54 *) Bugfix: the $upstream_response_time variable had the time of the first request to a backend only. - *) Bugfix: nginx could not be built on amd64 platform; bug appeared in - 0.3.53. + *) Bugfix: nginx could not be built on amd64 platform; the bug had + appeared in 0.3.53. Changes with nginx 0.3.53 07 Jul 2006 @@ -1050,10 +1590,10 @@ Changes with nginx 0.3.52 return the 405 error. *) Bugfix: the worker process may got caught in an endless loop if the - limit rate was used; bug appeared in 0.3.37. + limit rate was used; the bug had appeared in 0.3.37. *) Bugfix: ngx_http_charset_module logged "unknown charset" alert, even - if the recoding was not needed; bug appeared in 0.3.50. + if the recoding was not needed; the bug had appeared in 0.3.50. *) Bugfix: if a code response of the PUT request was 409, then a temporary file was not removed. @@ -1062,7 +1602,7 @@ Changes with nginx 0.3.52 Changes with nginx 0.3.51 30 Jun 2006 *) Bugfix: the "<" symbols might disappeared some conditions in the - SSI; bug appeared in 0.3.50. + SSI; the bug had appeared in 0.3.50. Changes with nginx 0.3.50 28 Jun 2006 @@ -1107,10 +1647,11 @@ Changes with nginx 0.3.48 *) Bugfix: the internal redirect always transform client's HTTP method to GET, now the transformation is made for the "X-Accel-Redirect" - redirects only and if the method is not HEAD; bug appeared in 0.3.42. + redirects only and if the method is not HEAD; the bug had appeared + in 0.3.42. *) Bugfix: the ngx_http_perl_module could not be built, if the perl was - built with the threads support; bug appeared in 0.3.46. + built with the threads support; the bug had appeared in 0.3.46. Changes with nginx 0.3.47 23 May 2006 @@ -1147,7 +1688,8 @@ Changes with nginx 0.3.45 *) Change: the ° symbol codes were changed in koi-win conversion table. - *) Feature: the euro É N symbols were added to koi-win conversion table. + *) Feature: the euro and N symbols were added to koi-win conversion + table. *) Bugfix: if nginx distributed the requests among several backends and some backend failed, then requests intended for this backend was @@ -1224,9 +1766,9 @@ Changes with nginx 0.3.39 *) Bugfix: the active connection counter increased on the exceeding of the connection limit specified by the "worker_connections" - directive; bug appeared in 0.2.0. - - *) Bugfix: the limit rate might not work on some condition; bug + directive; the bug had appeared in 0.2.0. + + *) Bugfix: the limit rate might not work on some condition; the bug had appeared in 0.3.38. @@ -1300,7 +1842,7 @@ Changes with nginx 0.3.36 Changes with nginx 0.3.35 22 Mar 2006 *) Bugfix: the accept-filter and the TCP_DEFER_ACCEPT option were set - for first "listen" directive only; bug appeared in 0.3.31. + for first "listen" directive only; the bug had appeared in 0.3.31. *) Bugfix: in the "proxy_pass" directive without the URI part in a subrequest. @@ -1325,7 +1867,7 @@ Changes with nginx 0.3.33 Changes with nginx 0.3.32 11 Mar 2006 *) Bugfix: the debug logging on startup and reconfiguration time was - removed; bug appeared in 0.3.31. + removed; the bug had appeared in 0.3.31. Changes with nginx 0.3.31 10 Mar 2006 @@ -1343,7 +1885,8 @@ Changes with nginx 0.3.31 *) Bugfix: if there were several "listen" directives listening one various addresses inside one server, then server names like - "*.domain.tld" worked for first address only; bug appeared in 0.3.18. + "*.domain.tld" worked for first address only; the bug had appeared + in 0.3.18. *) Bugfix: if the HTTPS protocol was used in the "proxy_pass" directive and the request body was in temporarily file then the request was @@ -1361,7 +1904,7 @@ Changes with nginx 0.3.30 ngx_http_ssi_filter_module. *) Bugfix: nginx could not be built on i386 platform, if the PIC was - used; bug appeared in 0.3.27. + used; the bug had appeared in 0.3.27. Changes with nginx 0.3.29 20 Feb 2006 @@ -1437,8 +1980,8 @@ Changes with nginx 0.3.26 Changes with nginx 0.3.25 01 Feb 2006 *) Bugfix: the segmentation fault was occurred on start or while - reconfiguration if there was invalid configuration; bug appeared in - 0.3.24. + reconfiguration if there was invalid configuration; the bug had + appeared in 0.3.24. Changes with nginx 0.3.24 01 Feb 2006 @@ -1454,8 +1997,8 @@ Changes with nginx 0.3.24 location. *) Bugfix: on 64-bit platforms segmentation fault may occurred on start - if the many names were used in the "server_name" directives; bug - appeared in 0.3.18. + if the many names were used in the "server_name" directives; the bug + had appeared in 0.3.18. Changes with nginx 0.3.23 24 Jan 2006 @@ -1478,8 +2021,8 @@ Changes with nginx 0.3.22 canceled. *) Bugfix: segmentation fault was occurred if the "none" or "blocked" - values was specified in the "valid_referers" directive; bug appeared - in 0.3.18. + values was specified in the "valid_referers" directive; the bug had + appeared in 0.3.18. Changes with nginx 0.3.21 16 Jan 2006 @@ -1530,10 +2073,10 @@ Changes with nginx 0.3.18 ngx_http_map_module. *) Bugfix: segmentation fault was occurred if configuration file did - not exist; bug appeared in 0.3.12. + not exist; the bug had appeared in 0.3.12. *) Bugfix: on 64-bit platforms segmentation fault may occurred on - start; bug appeared in 0.3.16. + start; the bug had appeared in 0.3.16. Changes with nginx 0.3.17 18 Dec 2005 @@ -1544,8 +2087,8 @@ Changes with nginx 0.3.17 *) Feature: the "map" directive supports domain names in the ".domain.tld" form. - *) Bugfix: the timeouts were not used in SSL handshake; bug appeared in - 0.2.4. + *) Bugfix: the timeouts were not used in SSL handshake; the bug had + appeared in 0.2.4. *) Bugfix: in the HTTPS protocol in the "proxy_pass" directive. @@ -1571,11 +2114,11 @@ Changes with nginx 0.3.16 *) Bugfix: the "config timefmt" SSI command set incorrect time format. *) Bugfix: nginx did not close connection to IMAP/POP3 backend for the - SSL connections; bug appeared in 0.3.13. + SSL connections; the bug had appeared in 0.3.13. Thanks to Rob Mueller. - *) Bugfix: segmentation fault may occurred in at SSL shutdown; bug - appeared in 0.3.13. + *) Bugfix: segmentation fault may occurred in at SSL shutdown; the bug + had appeared in 0.3.13. Changes with nginx 0.3.15 07 Dec 2005 @@ -1591,8 +2134,8 @@ Changes with nginx 0.3.15 Changes with nginx 0.3.14 05 Dec 2005 - *) Bugfix: in the 304 response the body was transferred; bug appeared - in 0.3.13. + *) Bugfix: in the 304 response the body was transferred; the bug had + appeared in 0.3.13. Changes with nginx 0.3.13 05 Dec 2005 @@ -1608,7 +2151,7 @@ Changes with nginx 0.3.13 request body to FastCGI-server via the unix domain socket. *) Bugfix: the "auth_basic" directive did not disable the - authorization; bug appeared in 0.3.11. + authorization; the bug had appeared in 0.3.11. Changes with nginx 0.3.12 26 Nov 2005 @@ -1629,7 +2172,7 @@ Changes with nginx 0.3.12 *) Feature: the "proxy_buffering" directive. *) Bugfix: the changes in accept mutex handling when the "rtsig" method - was used; bug appeared in 0.3.0. + was used; the bug had appeared in 0.3.0. *) Bugfix: if the client sent the "Transfer-Encoding: chunked" header line, then nginx returns the 411 error. @@ -1640,7 +2183,7 @@ Changes with nginx 0.3.12 *) Bugfix: if the "combined" format was explicitly specified in the "access_log" directive, then the empty lines was written to the log; - bug appeared in 0.3.8. + the bug had appeared in 0.3.8. *) Bugfix: nginx did not run on the sparc platform under any OS except Solaris. @@ -1652,7 +2195,7 @@ Changes with nginx 0.3.12 Changes with nginx 0.3.11 15 Nov 2005 *) Bugfix: nginx did not pass the client request headers and body while - proxying; bug appeared in 0.3.10. + proxying; the bug had appeared in 0.3.10. Changes with nginx 0.3.10 15 Nov 2005 @@ -1691,7 +2234,7 @@ Changes with nginx 0.3.10 Changes with nginx 0.3.9 10 Nov 2005 *) Bugfix: nginx considered URI as unsafe if two any symbols was - between two slashes; bug appeared in 0.3.8. + between two slashes; the bug had appeared in 0.3.8. Changes with nginx 0.3.8 09 Nov 2005 @@ -1731,8 +2274,8 @@ Changes with nginx 0.3.8 *) Bugfix: if the request URI was changes by the "rewrite" directive and the request was proxied in location given by regular expression, - then the incorrect request was transferred to backend; bug appeared - in 0.2.6. + then the incorrect request was transferred to backend; the bug had + appeared in 0.2.6. *) Bugfix: the "expires" directive did not remove the previous "Expires" header. @@ -1753,7 +2296,7 @@ Changes with nginx 0.3.7 *) Feature: the "access_log" supports the "buffer=" parameter. *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc É ppc; bug appeared in 0.3.2. + amd64, sparc, and ppc; the bug had appeared in 0.3.2. Changes with nginx 0.3.6 24 Oct 2005 @@ -1764,7 +2307,8 @@ Changes with nginx 0.3.6 *) Feature: the "log_format" supports the variables in the $name form. *) Bugfix: if at least in one server was no the "listen" directive, - then nginx did not listen on the 80 port; bug appeared in 0.3.3. + then nginx did not listen on the 80 port; the bug had appeared in + 0.3.3. *) Bugfix: if the URI part is omitted in "proxy_pass" directive, the the 80 port was always used. @@ -1773,10 +2317,10 @@ Changes with nginx 0.3.6 Changes with nginx 0.3.5 21 Oct 2005 *) Bugfix: the segmentation fault may occurred if the IMAP/POP3 login - was changed by authorization server; bug appeared in 0.2.2. + was changed by authorization server; the bug had appeared in 0.2.2. *) Bugfix: the accept mutex did not work and all connections were - handled by one process; bug appeared in 0.3.3. + handled by one process; the bug had appeared in 0.3.3. *) Bugfix: the timeout did not work if the "rtsig" method and the "timer_resolution" directive were used. @@ -1784,8 +2328,8 @@ Changes with nginx 0.3.5 Changes with nginx 0.3.4 19 Oct 2005 - *) Bugfix: nginx could not be built on Linux 2.4+ and MacOS X; bug - appeared in 0.3.3. + *) Bugfix: nginx could not be built on Linux 2.4+ and MacOS X; the bug + had appeared in 0.3.3. Changes with nginx 0.3.3 19 Oct 2005 @@ -1806,7 +2350,7 @@ Changes with nginx 0.3.3 the CLOSED state. *) Bugfix: the mime type may be incorrectly set to default value for - index file with variable in the name; bug appeared in 0.3.0. + index file with variable in the name; the bug had appeared in 0.3.0. *) Feature: the "timer_resolution" directive. @@ -1838,7 +2382,8 @@ Changes with nginx 0.3.2 Changes with nginx 0.3.1 10 Oct 2005 *) Bugfix: the segmentation fault occurred when the signal queue - overflowed if the "rtsig" method was used; bug appeared in 0.2.0. + overflowed if the "rtsig" method was used; the bug had appeared in + 0.2.0. *) Change: correct handling of the "\\", "\"", "\'", and "\$" pairs in SSI. @@ -1872,7 +2417,7 @@ Changes with nginx 0.2.6 *) Bugfix: if the "set" directive set the ngx_http_geo_module variable in some configuration part, the this variable was not available in other configuration parts and the "using uninitialized variable" - error was occurred; bug appeared in 0.2.2. + error was occurred; the bug had appeared in 0.2.2. Changes with nginx 0.2.5 04 Oct 2005 @@ -1894,17 +2439,17 @@ Changes with nginx 0.2.4 *) Feature: the ngx_http_ssi_module supports "$var=text", "$var!=text", "$var=/text/", and "$var!=/text/" expressions in the "if" command. - *) Bugfix: in proxying location without trailing slash; bug appeared in - 0.1.44. + *) Bugfix: in proxying location without trailing slash; the bug had + appeared in 0.1.44. *) Bugfix: the segmentation fault may occurred if the "rtsig" method - was used; bug appeared in 0.2.0. + was used; the bug had appeared in 0.2.0. Changes with nginx 0.2.3 30 Sep 2005 *) Bugfix: nginx could not be built without the --with-debug option; - bug appeared in 0.2.2. + the bug had appeared in 0.2.2. Changes with nginx 0.2.2 30 Sep 2005 @@ -1933,8 +2478,8 @@ Changes with nginx 0.2.2 Changes with nginx 0.2.1 23 Sep 2005 *) Bugfix: if all backend using in load-balancing failed after one - error, then nginx may got caught in an endless loop; bug appeared in - 0.2.0. + error, then nginx may got caught in an endless loop; the bug had + appeared in 0.2.0. Changes with nginx 0.2.0 23 Sep 2005 @@ -2012,7 +2557,7 @@ Changes with nginx 0.1.43 *) Bugfix: the segmentation fault occurred or the worker process may got caught in an endless loop if the proxied or FastCGI server sent the "Cache-Control" header line and the "expires" directive was - used; in the proxied mode the bug appeared in 0.1.29. + used; in the proxied mode the the bug had appeared in 0.1.29. Changes with nginx 0.1.42 23 Aug 2005 @@ -2022,7 +2567,7 @@ Changes with nginx 0.1.42 occurred in the ngx_http_proxy_module. *) Bugfix: the "limit_rate" directive did not work inside the "if" - block; bug appeared in 0.1.38. + block; the bug had appeared in 0.1.38. Changes with nginx 0.1.41 25 Jul 2005 @@ -2037,7 +2582,7 @@ Changes with nginx 0.1.40 information did not logged in the error log. *) Bugfix: the "Set-Cookie" header line was not transferred when the - "X-Accel-Redirect" was used; bug appeared in 0.1.39. + "X-Accel-Redirect" was used; the bug had appeared in 0.1.39. *) Bugfix: the "Content-Disposition" header line was not transferred when the "X-Accel-Redirect" was used. @@ -2059,8 +2604,8 @@ Changes with nginx 0.1.39 transferred while the 401 response code redirecting. *) Bugfix: the ngx_http_proxy_module and ngx_http_fastcgi_module may - close a connection before anything was transferred to a client; bug - appeared in 0.1.38. + close a connection before anything was transferred to a client; the + bug had appeared in 0.1.38. *) Workaround: the Linux glibc crypt_r() initialization bug. @@ -2069,17 +2614,17 @@ Changes with nginx 0.1.39 *) Bugfix: if the backend response had the "Location" header line and nginx should not rewrite this line, then the 500 code response body - was transferred; bug appeared in 0.1.29. + was transferred; the bug had appeared in 0.1.29. *) Bugfix: some directives of the ngx_http_proxy_module and ngx_http_fastcgi_module were not inherited from the server to the - location level; bug appeared in 0.1.29. + location level; the bug had appeared in 0.1.29. *) Bugfix: the ngx_http_ssl_module did not support the certificate chain. *) Bugfix: the ngx_http_autoindex_module did not show correctly the - long file names; bug appeared in 0.1.38. + long file names; the bug had appeared in 0.1.38. *) Bugfixes in IMAP/POP3 proxy in interaction with a backend at the login state. @@ -2107,8 +2652,8 @@ Changes with nginx 0.1.38 than one remote subrequest. *) Bugfix: nginx treated the backend response as invalid if the status - line in the header was transferred in two packets; bug appeared in - 0.1.29. + line in the header was transferred in two packets; the bug had + appeared in 0.1.29. *) Feature: the "ssi_types" directive. @@ -2162,7 +2707,7 @@ Changes with nginx 0.1.35 *) Feature: the "port_in_redirect" directive. *) Bugfix: the segmentation fault was occurred if the backend response - header was in several packets; bug appeared in 0.1.29. + header was in several packets; the bug had appeared in 0.1.29. *) Bugfix: if more than 10 servers were configured or some server did not use the "listen" directive, then the segmentation fault was @@ -2172,7 +2717,8 @@ Changes with nginx 0.1.35 bigger than the temporary file. *) Bugfix: nginx returned the 400 response on requests like - "GET http://www.domain.com/uri HTTP/1.0"; bug appeared in 0.1.28. + "GET http://www.domain.com/uri HTTP/1.0"; the bug had appeared in + 0.1.28. Changes with nginx 0.1.34 26 May 2005 @@ -2192,7 +2738,7 @@ Changes with nginx 0.1.34 Changes with nginx 0.1.33 23 May 2005 *) Bugfix: nginx could not be built with the --without-pcre parameter; - bug appeared in 0.1.29. + the bug had appeared in 0.1.29. *) Bugfix: 3, 4, 7, and 8 the "proxy_set_header" directives in one level cause the bus fault on start up. @@ -2206,7 +2752,7 @@ Changes with nginx 0.1.33 Changes with nginx 0.1.32 19 May 2005 *) Bugfix: the arguments were omitted in the redirects, issued by the - "rewrite" directive; bug appeared in 0.1.29. + "rewrite" directive; the bug had appeared in 0.1.29. *) Feature: the "if" directive supports the captures in regular expressions. @@ -2227,7 +2773,7 @@ Changes with nginx 0.1.31 *) Bugfix: errors while using SSI and gzipping. *) Bugfix: the redirect with the 301 code was transferred without - response body; bug appeared in 0.1.30. + response body; the bug had appeared in 0.1.30. Changes with nginx 0.1.30 14 May 2005 @@ -2239,7 +2785,8 @@ Changes with nginx 0.1.30 *) Bugfix: if the length of the response part received at once from proxied or FastCGI server was equal to 500, then nginx returns the - 500 response code; in proxy mode the bug appeared in 0.1.29 only. + 500 response code; in proxy mode the the bug had appeared in 0.1.29 + only. *) Bugfix: nginx did not consider the directives with 8 or 9 parameters as invalid. @@ -2318,7 +2865,7 @@ Changes with nginx 0.1.29 returned the 408 response. *) Bugfix: the segmentation fault was occurred if the backend sent an - invalid line in response header; bug appeared in 0.1.26. + invalid line in response header; the bug had appeared in 0.1.26. *) Bugfix: the segmentation fault may occurred in FastCGI fault tolerance configuration. @@ -2438,7 +2985,7 @@ Changes with nginx 0.1.23 server name of the "server_name" directive. *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc É ppc; bug appeared in 0.1.22. + amd64, sparc, and ppc; the bug had appeared in 0.1.22. *) Bugfix: the ngx_http_autoindex_module now shows the information not about the symlink, but about file or directory it points to. @@ -2453,7 +3000,7 @@ Changes with nginx 0.1.22 connections statistics if the proxying or FastCGI server were used. *) Bugfix: the installation paths were incorrectly quoted on Linux and - Solaris; bug appeared in 0.1.21. + Solaris; the bug had appeared in 0.1.21. Changes with nginx 0.1.21 22 Feb 2005 @@ -2538,7 +3085,8 @@ Changes with nginx 0.1.17 static page, then the segmentation fault occurred. *) Bugfix: if in a proxied "Location" header was a relative URL, then a - host name and a slash were added to them; bug appeared in 0.1.14. + host name and a slash were added to them; the bug had appeared in + 0.1.14. *) Bugfix: the system error message was not logged on Linux. @@ -2563,7 +3111,7 @@ Changes with nginx 0.1.16 *) Feature: the rewrite directive supports the arguments rewriting. *) Bugfix: the response code 400 was returned for the POST request with - the "Content-Length: 0" header; bug appeared in 0.1.14. + the "Content-Length: 0" header; the bug had appeared in 0.1.14. Changes with nginx 0.1.15 19 Jan 2005 @@ -2584,8 +3132,8 @@ Changes with nginx 0.1.15 to use the regular expressions in locations. *) Bugfix: the directive "proxy_preserve_host on" adds port 80 to the - "Host" headers, if upstream listen on port 80; bug appeared in - 0.1.14. + "Host" headers, if upstream listen on port 80; the bug had appeared + in 0.1.14. *) Bugfix: the same paths in autoconfiguration parameters --http-client-body-temp-path=PATH and --http-proxy-temp-path=PATH, @@ -2611,7 +3159,8 @@ Changes with nginx 0.1.14 fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, fastcgi_next_upstream, and fastcgi_x_powered_by. - *) Bugfix: the "[alert] zero size buf" error; bug appeared in 0.1.3. + *) Bugfix: the "[alert] zero size buf" error; the bug had appeared in + 0.1.3. *) Change: the URI must be specified after the host name in the proxy_pass directive. @@ -2696,7 +3245,7 @@ Changes with nginx 0.1.10 *) Bugfix: if the request without arguments contains "//", "/./", "/../" or "%XX" then the lost character in the request line was - lost; bug appeared in 0.1.9. + 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 not work. @@ -2714,7 +3263,8 @@ Changes with nginx 0.1.9 does not support sendfile64(). *) Bugfix: while the build configuration on Linux the - --with-poll_module parameter was required; bug appeared in 0.1.8. + --with-poll_module parameter was required; the bug had appeared in + 0.1.8. Changes with nginx 0.1.8 20 Nov 2004 @@ -2730,7 +3280,7 @@ Changes with nginx 0.1.8 Changes with nginx 0.1.7 12 Nov 2004 *) Bugfix: on FreeBSD the segmentation fault may occur if the size of - the transferred file was changed; bug appeared in 0.1.5. + the transferred file was changed; the bug had appeared in 0.1.5. Changes with nginx 0.1.6 11 Nov 2004 @@ -2789,13 +3339,13 @@ Changes with nginx 0.1.2 *) Bugfix: the portability improvements. *) Bugfix: if configuration file was set in command line, the - reconfiguration was impossible; bug appeared in 0.1.1. + reconfiguration was impossible; the bug had appeared in 0.1.1. *) Bugfix: proxy module may get caught in an endless loop when sendfile is not used. *) Bugfix: with sendfile the response was not recoded according to the - charset module directives; bug appeared in 0.1.1. + charset module directives; the bug had appeared in 0.1.1. *) Bugfix: very seldom bug in the kqueue processing. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,556 @@ +éÚÍÅÎÅÎÉÑ × nginx 0.7.7 30.07.2008 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÏÛÉÂËÁ EAGAIN ÐÒÉ ×ÙÚÏ×Å connect() ÎÅ ÓÞÉÔÁÅÔÓÑ + ×ÒÅÍÅÎÎÏÊ. + + *) éÚÍÅÎÅÎÉÅ: ÚÎÁÞÅÎÉÅÍ ÐÅÒÅÍÅÎÎÏÊ $ssl_client_cert ÔÅÐÅÒØ Ñ×ÌÑÅÔÓÑ + ÓÅÒÔÉÆÉËÁÔ, ÐÅÒÅÄ ËÁÖÄÏÊ ÓÔÒÏËÏÊ ËÏÔÏÒÏÇÏ, ËÒÏÍÅ ÐÅÒ×ÏÊ, ×ÓÔÁ×ÌÑÅÔÓÑ + ÓÉÍ×ÏÌ ÔÁÂÕÌÑÃÉÉ; ÎÅÉÚÍÅΣÎÎÙÊ ÓÅÒÔÉÆÉËÁÔ ÄÏÓÔÕÐÅÎ ÞÅÒÅÚ ÐÅÒÅÍÅÎÎÕÀ + $ssl_client_raw_cert. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ ask ÄÉÒÅËÔÉ×Ù ssl_verify_client. + + *) äÏÂÁ×ÌÅÎÉÅ: ÕÌÕÞÛÅÎÉÑ × ÏÂÒÁÂÏÔËÅ byte-range. + óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á directio. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ sendfile() × MacOSX 1.5. + + *) éÓÐÒÁ×ÌÅÎÉÅ: × MacOSX É Cygwin ÐÒÉ ÐÒÏ×ÅÒËÅ location'Ï× ÔÅÐÅÒØ + ÄÅÌÁÅÔÓÑ ÓÒÁ×ÎÅÎÉÅ ÂÅÚ ÕÞ£ÔÁ ÒÅÇÉÓÔÒÁ ÓÉÍ×ÏÌÏ×; ÏÄÎÁËÏ, ÓÒÁ×ÎÅÎÉÅ + ÏÇÒÁÎÉÞÅÎÏ ÔÏÌØËÏ ÏÄÎÏÂÁÊÔÎÙÍÉ locale'ÑÍÉ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏÅÄÉÎÅÎÉÑ ÐÏÞÔÏ×ÏÇÏ ÐÒÏËÓÉ-ÓÅÒ×ÅÒÁ ÚÁ×ÉÓÁÌÉ × ÒÅÖÉÍÅ + SSL, ÅÓÌÉ ÉÓÐÏÌØÚÏ×ÁÌÉÓØ ÍÅÔÏÄÙ select, poll ÉÌÉ /dev/poll. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ËÏÄÉÒÏ×ËÉ UTF-8 × + ngx_http_autoindex_module. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.6 07.07.2008 + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÙÈ × ÄÉÒÅËÔÉ×Å + access_log ×ÓÅÇÄÁ ÐÒÏ×ÅÒÑÅÔÓÑ ÓÕÝÅÓÔ×Ï×ÁÎÉÉ root'Á ÄÌÑ ÚÁÐÒÏÓÁ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_flv_module ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ÎÅÓËÏÌØËÏ + ÚÎÁÞÅÎÉÊ × ÁÒÇÕÍÅÎÔÁÈ ÚÁÐÒÏÓÁ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.5 01.07.2008 + + *) éÓÐÒÁ×ÌÅÎÉÑ × ÐÏÄÄÅÒÖËÅ ÐÅÒÅÍÅÎÎÙÈ × ÄÉÒÅËÔÉ×Å access_log; ÏÛÉÂËÉ + ÐÏÑ×ÉÌÁÓØ × 0.7.4. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ Ó ÐÁÒÁÍÅÔÒÏÍ + --without-http_gzip_module; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.3. + óÐÁÓÉÂÏ ëÉÒÉÌÌÕ ëÏÒÉÎÓËÏÍÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÓÏ×ÍÅÓÔÎÏÍ ÉÓÐÏÌØÚÏ×ÁÎÉÉ sub_filter É SSI ÏÔ×ÅÔÙ + ÍÏÇÌÉ ÐÅÒÅÄÁ×ÁÔØÓÑ ÎÅ×ÅÒÎÏ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.4 30.06.2008 + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á access_log ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÅÒÅÍÅÎÎÙÅ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á open_log_file_cache. + + *) äÏÂÁ×ÌÅÎÉÅ: ËÌÀÞ -g. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ ÓÔÒÏËÉ "Expect" × ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÂÏÌØÛÉÅ ×ËÌÀÞÅÎÉÑ × SSI ÍÏÇÌÉ ÐÅÒÅÄÁ×ÁÌÉÓØ ÎÅ ÐÏÌÎÏÓÔØÀ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.3 23.06.2008 + + *) éÚÍÅÎÅÎÉÅ: MIME-ÔÉÐ ÄÌÑ ÒÁÓÛÉÒÅÎÉÑ rss ÉÚÍÅΣΠÎÁ + "application/rss+xml". + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á "gzip_vary on" ×ÙÄÁ£Ô ÓÔÒÏËÕ + "Vary: Accept-Encoding" × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ É ÄÌÑ ÎÅÓÖÁÔÙÈ ÏÔ×ÅÔÏ×. + + *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÒÏÔÏËÏÌÁ "https://" × + ÄÉÒÅËÔÉ×Å rewrite Á×ÔÏÍÁÔÉÞÅÓËÉ ÄÅÌÁÅÔÓÑ ÒÅÄÉÒÅËÔ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_pass ÎÅ ÒÁÂÏÔÁÌÁ Ó ÐÒÏÔÏËÏÌÏÍ HTTPS; + ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.9. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.2 16.06.2008 + + *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ nginx ÐÏÄÄÅÒÖÉ×ÁÅÔ ÛÉÆÒÙ Ó ÏÂÍÅÎÏÍ EDH-ËÌÀÞÁÍÉ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á ssl_dhparam. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $ssl_client_cert. + óÐÁÓÉÂÏ Manlio Perillo. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÏÓÌÅ ÉÚÍÅÎÅÎÉÑ URI Ó ÐÏÍÏÝØÀ ÄÉÒÅËÔÉ×Ù rewrite nginx + ÎÅ ÉÓËÁÌ ÎÏ×ÙÊ location; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.7.1. + óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÂÅÚ ÂÉÂÌÉÏÔÅËÉ PCRE; ÏÛÉÂËÁ + ÐÏÑ×ÉÌÁÓØ × 0.7.1. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÒÅÄÉÒÅËÔÅ ÚÁÐÒÏÓÁ Ë ËÁÔÁÌÏÇÕ Ó ÄÏÂÁ×ÌÅÎÉÅÍ ÓÌÜÛÁ + nginx ÎÅ ÄÏÂÁ×ÌÑÌ ÁÒÇÕÍÅÎÔÙ ÉÚ ÏÒÉÇÉÎÁÌØÎÏÇÏ ÚÁÐÒÏÓÁ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.1 26.05.2008 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏÉÓË location'Á ÄÅÌÁÅÔÓÑ Ó ÐÏÍÏÝØÀ ÄÅÒÅ×Á. + + *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á optimize_server_names ÕÐÒÁÚÄÎÅÎÁ × Ó×ÑÚÉ Ó + ÐÏÑ×ÌÅÎÉÅÍ ÄÉÒÅËÔÉ×Ù server_name_in_redirect. + + *) éÚÍÅÎÅÎÉÅ: ÎÅËÏÔÏÒÙÅ ÄÁ×ÎÏ ÕÓÔÁÒÅ×ÛÉÅ ÄÉÒÅËÔÉ×Ù ÂÏÌØÛÅ ÎÅ + ÐÏÄÄÅÒÖÉ×ÁÀÔÓÑ. + + *) éÚÍÅÎÅÎÉÅ: ÐÁÒÁÍÅÔÒ "none" × ÄÉÒÅËÔÉ×Å ssl_session_cache; ÔÅÐÅÒØ + ÜÔÏÔ ÐÁÒÁÍÅÔÒ ÉÓÐÏÌØÚÕÅÔÓÑ ÐÏ ÕÍÏÌÞÁÎÉÀ. + óÐÁÓÉÂÏ Rob Mueller. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÁÂÏÞÉÅ ÐÒÏÃÅÓÓÙ ÍÏÇÌÉ ÎÅ ÒÅÁÇÉÒÏ×ÁÔØ ÎÁ ÓÉÇÎÁÌÙ + ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ É ÒÏÔÁÃÉÉ ÌÏÇÏ×. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ ÐÏÓÌÅÄÎÉÈ Fedora 9 Linux. + óÐÁÓÉÂÏ Roxis. + + +éÚÍÅÎÅÎÉÑ × nginx 0.7.0 19.05.2008 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÓÉÍ×ÏÌÙ 0x00-0x1F, '"' É '\' × access_log + ÚÁÐÉÓÙ×ÁÀÔÓÑ × ×ÉÄÅ \xXX. + óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ. + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ nginx ÒÁÚÒÅÛÁÅÔ ÎÅÓËÏÌØËÏ ÓÔÒÏË "Host" × ÚÁÇÏÌÏ×ËÅ + ÚÁÐÒÏÓÁ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á expires ÐÏÄÄÅÒÖÉ×ÁÅÔ ÆÌÁÇ modified. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÙÅ $uid_got É $uid_set ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÎÁ + ÌÀÂÏÊ ÓÔÁÄÉÉ ÏÂÒÁÂÏÔËÉ ÚÁÐÒÏÓÁ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÁÑ $hostname. + óÐÁÓÉÂÏ áÎÄÒÅÀ îÉÇÍÁÔÕÌÉÎÕ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ DESTDIR. + óÐÁÓÉÂÏ Todd A. Fisher É Andras Voroskoi. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ keepalive ÎÁ Linux × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ + ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.31 12.05.2008 + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÏÂÒÁÂÁÔÙ×ÁÌ ÏÔ×ÅÔ FastCGI-ÓÅÒ×ÅÒÁ, ÅÓÌÉ ÓÔÒÏËÁ + ÚÁÇÏÌÏ×ËÁ ÏÔ×ÅÔ ÂÙÌÁ × ËÏÎÃÅ ÚÁÐÉÓÉ FastCGI; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × + 0.6.2. + óÐÁÓÉÂÏ óÅÒÇÅÀ óÅÒÏ×Õ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÕÄÁÌÅÎÉÉ ÆÁÊÌÁ É ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù + open_file_cache_errors off × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ + segmentation fault. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.30 29.04.2008 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ, ÅÓÌÉ ÍÁÓËÅ, ÚÁÄÁÎÎÏÊ × ÄÉÒÅËÔÉ×Å include, ÎÅ + ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÎÉ ÏÄÉÎ ÆÁÊÌ, ÔÏ nginx ÎÅ ×ÙÄÁ£Ô ÏÛÉÂËÕ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ×ÒÅÍÑ × ÄÉÒÅËÔÉ×ÁÈ ÍÏÖÎÏ ÚÁÄÁ×ÁÔØ ÂÅÚ ÐÒÏÂÅÌÁ, + ÎÁÐÒÉÍÅÒ, "1h50m". + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞÅË ÐÁÍÑÔÉ, ÅÓÌÉ ÄÉÒÅËÔÉ×Á ssl_verify_client ÉÍÅÌÁ + ÚÎÁÞÅÎÉÅ on. + óÐÁÓÉÂÏ Chavelle Vincent. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á sub_filter ÍÏÇÌÁ ×ÓÔÁ×ÌÑÔØ ÚÁÍÅÎÑÅÍÙÊ ÔÅËÓÔ × + ×Ù×ÏÄ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á error_page ÎÅ ×ÏÓÐÒÉÎÉÍÁÌÁ ÐÁÒÁÍÅÔÒÙ × + ÐÅÒÅÎÁÐÒÁ×ÌÑÅÍÏÍ URI. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÐÒÉ ÓÂÏÒËÅ Ó Cygwin nginx ×ÓÅÇÄÁ ÏÔËÒÙ×ÁÅÔ ÆÁÊÌÙ + × ÂÉÎÁÒÎÏÍ ÒÅÖÉÍÅ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÐÏÄ OpenBSD; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × + 0.6.15. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.29 18.03.2008 + + *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_google_perftools_module. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_perl_module ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ 64-ÂÉÔÎÙÈ + ÐÌÁÔÆÏÒÍÁÈ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.27. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.28 13.03.2008 + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÅÔÏÄ rtsig ÎÅ ÓÏÂÉÒÁÌÓÑ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.27. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.27 12.03.2008 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÎÁ Linux 2.6.18+ ÐÏ ÕÍÏÌÞÁÎÉÀ ÎÅ ÓÏÂÉÒÁÅÔÓÑ ÍÅÔÏÄ + rtsig. + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÒÉ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÉ ÚÁÐÒÏÓÁ × ÉÍÅÎÏ×ÁÎÎÙÊ location + Ó ÐÏÍÏÝØÀ ÄÉÒÅËÔÉ×Ù error_page ÍÅÔÏÄ ÚÁÐÒÏÓÁ ÎÅ ÉÚÍÅÎÑÅÔÓÑ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù resolver É resolver_timeout × SMTP + ÐÒÏËÓÉ-ÓÅÒ×ÅÒÅ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á post_action ÐÏÄÄÅÒÖÉ×ÁÅÔ ÉÍÅÎÏ×ÁÎÎÙÅ + location'Ù. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÉ ÚÁÐÒÏÓÁ ÉÚ location'Á c + ÏÂÒÁÂÏÔÞÉËÏÍ proxy, FastCGI ÉÌÉ memcached × ÉÍÅÎÏ×ÁÎÎÙÊ location ÓÏ + ÓÔÁÔÉÞÅÓËÉÍ ÏÂÒÁÂÏÔÞÉËÏÍ × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation + fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÂÒÁÕÚÅÒÙ ÎÅ ÐÏ×ÔÏÒÑÌÉ SSL handshake, ÅÓÌÉ ÐÒÉ ÐÅÒ×ÏÍ + handshake ÎÅ ÏËÁÚÁÌÏÓØ ÐÒÁ×ÉÌØÎÏÇÏ ËÌÉÅÎÔÓËÏÇÏ ÓÅÒÔÉÆÉËÁÔÁ. + óÐÁÓÉÂÏ áÌÅËÓÁÎÄÒÕ éÎÀÈÉÎÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÉ ÏÛÉÂÏË 495-497 Ó ÐÏÍÏÝØÀ ÄÉÒÅËÔÉ×Ù + error_page ÂÅÚ ÉÚÍÅÎÅÎÉÑ ËÏÄÁ ÏÛÉÂËÉ nginx ÐÙÔÁÌÓÑ ×ÙÄÅÌÉÔØ ÏÞÅÎØ + ÍÎÏÇÏ ÐÁÍÑÔÉ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÐÁÍÑÔÉ × ÄÏÌÇÏÖÉ×ÕÝÉÈ ÎÅÂÕÆÆÅÒÉÚÉÒÏ×ÁÎÎÙÈ + ÓÏÅÄÉÎÅÎÉÑÈ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÐÁÍÑÔÉ × resolver'Å. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÉ ÚÁÐÒÏÓÁ ÉÚ location'Á c + ÏÂÒÁÂÏÔÞÉËÏÍ proxy × ÄÒÕÇÏÊ location Ó ÏÂÒÁÂÏÔÞÉËÏÍ proxy × ÒÁÂÏÞÅÍ + ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ × ËÜÛÉÒÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÙÈ $proxy_host É + $proxy_port. + óÐÁÓÉÂÏ óÅÒÇÅÀ âÏÞÅÎËÏ×Õ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_pass Ó ÐÅÒÅÍÅÎÎÙÍÉ ÉÓÐÏÌØÚÏ×ÁÌÁ ÐÏÒÔ, + ÏÐÉÓÁÎÎÏÊ × ÄÒÕÇÏÊ ÄÉÒÅËÔÉ×Å proxy_pass ÂÅÚ ÐÅÒÅÍÅÎÎÙÈ, ÎÏ Ó ÔÁËÉÍ + ÖÅ ÉÍÅÎÅÍ ÈÏÓÔÁ. + óÐÁÓÉÂÏ óÅÒÇÅÀ âÏÞÅÎËÏ×Õ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ×Ï ×ÒÅÍÑ ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ ÎÁ ÎÅËÏÔÏÒÙÈ 64-ÂÉÔÎÏÍ + ÐÌÁÔÆÏÒÍÁÈ × ÌÏÇ ÚÁÐÉÓÙ×ÁÌÓÑ alert "sendmsg() failed (9: Bad file + descriptor)". + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÐÏ×ÔÏÒÎÏÍ ÉÓÐÏÌØÚÏ×ÁÎÉÉ × SSI ÐÕÓÔÏÇÏ block'Á × + ËÁÞÅÓÔ×Å ÚÁÇÌÕÛËÉ × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÛÉÂËÉ ÐÒÉ ËÏÐÉÒÏ×ÁÎÉÉ ÞÁÓÔÉ URI, ÓÏÄÅÒÖÁÝÅÇÏ + ÜËÒÁÎÉÒÏ×ÁÎÎÙÅ ÓÉÍ×ÏÌÙ, × ÁÒÇÕÍÅÎÔÙ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.26 11.02.2008 + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_store É fastcgi_store ÎÅ ÐÒÏ×ÅÒÑÌÉ + ÄÌÉÎÕ ÏÔ×ÅÔÁ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÂÏÌØÛÏÇÏ ÚÎÁÞÅÎÉÑ × ÄÉÒÅËÔÉ×Å expires + × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault. + óÐÁÓÉÂÏ Joaquin Cuenca Abela. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ×ÅÒÎÏ ÏÐÒÅÄÅÌÑÌ ÄÌÉÎÕ ÓÔÒÏËÉ ËÜÛÁ ÎÁ + Pentium 4. + óÐÁÓÉÂÏ Gena Makhomed. + + *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÒÏËÓÉÒÏ×ÁÎÎÙÈ ÐÏÄÚÁÐÒÏÓÁÈ É ÐÏÄÚÁÐÒÏÓÁÈ Ë + FastCGI-ÓÅÒ×ÅÒÕ ×ÍÅÓÔÏ ÍÅÔÏÄÁ GET ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÏÒÉÇÉÎÁÌØÎÙÊ ÍÅÔÏÄ + ËÌÉÅÎÔÁ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ× × ÒÅÖÉÍÅ HTTPS ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ + ÏÔÌÏÖÅÎÎÏÇÏ accept'Á. + óÐÁÓÉÂÏ Ben Maurer. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ×ÙÄÁ×ÁÌ ÏÛÉÂÏÞÎÏÅ ÓÏÏÂÝÅÎÉÅ "SSL_shutdown() + failed (SSL: )"; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.23. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ HTTPS ÚÁÐÒÏÓÙ ÍÏÇÌÉ ÚÁ×ÅÒÛÁÔØÓÑ Ó + ÏÛÉÂËÏÊ "bad write retry"; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.23. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.25 08.01.2008 + + *) éÚÍÅÎÅÎÉÅ: ×ÍÅÓÔÏ ÓÐÅÃÉÁÌØÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "*" × ÄÉÒÅËÔÉ×Å server_name + ÔÅÐÅÒØ ÉÓÐÏÌØÚÕÅÔÓÑ ÄÉÒÅËÔÉ×Á server_name_in_redirect. + + *) éÚÍÅÎÅÎÉÅ: × ËÁÞÅÓÔ×Å ÏÓÎÏ×ÎÏÇÏ ÉÍÅÎÉ × ÄÉÒÅËÔÉ×Å server_name ÔÅÐÅÒØ + ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÉÍÅÎÁ Ó ÍÁÓËÁÍÉ É ÒÅÇÕÌÑÒÎÙÍÉ ×ÙÒÁÖÅÎÉÑÍÉ. + + *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á satisfy_any ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ satisfy. + + *) éÚÍÅÎÅÎÉÅ: ÐÏÓÌÅ ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ ÓÔÁÒÙÅ ÒÁÂÏÞÉÅ ÐÒÏÃÅÓÓ ÍÏÇÌÉ + ÓÉÌØÎÏ ÎÁÇÒÕÖÁÔØ ÐÒÏÃÅÓÓÏÒ ÐÒÉ ÚÁÐÕÓËÅ ÐÏÄ Linux OpenVZ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á min_delete_depth. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÅÔÏÄÙ COPY É MOVE ÎÅ ÒÁÂÏÔÁÌÉ Ó ÏÄÉÎÏÞÎÙÍÉ ÆÁÊÌÁÍÉ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_gzip_static_module ÎÅ ÐÏÚ×ÏÌÑÌ ÒÁÂÏÔÁÔØ + ÍÏÄÕÌÀ ngx_http_dav_module; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.23. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÕÔÅÞËÉ ÓÏËÅÔÏ× × ÒÅÖÉÍÅ HTTPS ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ + ÏÔÌÏÖÅÎÎÏÇÏ accept'Á. + óÐÁÓÉÂÏ Ben Maurer. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÂÅÚ ÂÉÂÌÉÏÔÅËÉ PCRE; ÏÛÉÂËÁ + ÐÏÑ×ÉÌÁÓØ × 0.6.23. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.24 27.12.2007 + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ HTTPS × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ + ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.23. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.23 27.12.2007 + + *) éÚÍÅÎÅÎÉÅ: ÐÁÒÁÍÅÔÒ "off" × ÄÉÒÅËÔÉ×Å ssl_session_cache; ÔÅÐÅÒØ ÜÔÏÔ + ÐÁÒÁÍÅÔÒ ÉÓÐÏÌØÚÕÅÔÓÑ ÐÏ ÕÍÏÌÞÁÎÉÀ. + + *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á open_file_cache_retest ÐÅÒÅÉÍÅÎÏ×ÁÎÁ × + open_file_cache_valid. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á open_file_cache_min_uses. + + *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_gzip_static_module. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á gzip_disable. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Õ memcached_pass ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ×ÎÕÔÒÉ ÂÌÏËÁ + if. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ×ÎÕÔÒÉ ÏÄÎÏÇÏ location'Á ÉÓÐÏÌØÚÏ×ÁÌÉÓØ ÄÉÒÅËÔÉ×Ù + "memcached_pass" É "if", ÔÏ × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ + segmentation fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù satisfy_any on" ÂÙÌÉ + ÚÁÄÁÎÙ ÄÉÒÅËÔÉ×Ù ÎÅ ×ÓÅÈ ÍÏÄÕÌÅÊ ÄÏÓÔÕÐÁ, ÔÏ ÚÁÄÁÎÎÙÅ ÄÉÒÅËÔÉ×Ù ÎÅ + ÐÒÏ×ÅÒÑÌÉÓØ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒÙ, ÚÁÄÁÎÎÙÅ ÒÅÇÕÌÑÒÎÙÍ ×ÙÒÁÖÅÎÉÅÍ × ÄÉÒÅËÔÉ×Å + valid_referers, ÎÅ ÎÁÓÌÅÄÏ×ÁÌÁÓØ Ó ÐÒÅÄÙÄÕÝÅÇÏ ÕÒÏ×ÎÑ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á post_action ÎÅ ÒÁÂÏÔÁÌÁ, ÅÓÌÉ ÚÁÐÒÏÓ + ÚÁ×ÅÒÛÁÌÓÑ Ó ËÏÄÏÍ 499. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÏÐÔÉÍÉÚÁÃÉÑ ÉÓÐÏÌØÚÏ×ÁÎÉÑ 16K ÂÕÆÅÒÁ ÄÌÑ + SSL-ÓÏÅÄÉÎÅÎÉÑ. + óÐÁÓÉÂÏ Ben Maurer. + + *) éÓÐÒÁ×ÌÅÎÉÅ: STARTTLS × ÒÅÖÉÍÅ SMTP ÎÅ ÒÁÂÏÔÁÌ. + óÐÁÓÉÂÏ ïÌÅÇÕ íÏÔÉÅÎËÏ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ HTTPS ÚÁÐÒÏÓÙ ÍÏÇÌÉ ÚÁ×ÅÒÛÁÔØÓÑ Ó + ÏÛÉÂËÏÊ "bad write retry"; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.5.13. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.22 19.12.2007 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ×ÓÅ ÍÅÔÏÄÙ ÍÏÄÕÌÑ ngx_http_perl_module ×ÏÚ×ÒÁÝÁÀÔ + ÚÎÁÞÅÎÉÑ, ÓËÏÐÉÒÏ×ÁÎÎÙÅ × ÐÁÍÑÔØ, ×ÙÄÅÌÅÎÎÕÀ perl'ÏÍ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ nginx ÂÙÌ ÓÏÂÒÁÎ Ó ÍÏÄÕÌÅÍ ngx_http_perl_module, + ÉÓÐÏÌØÚÏ×ÁÌÓÑ perl ÄÏ ×ÅÒÓÉÉ 5.8.6 É perl ÐÏÄÄÅÒÖÉ×ÁÌ ÐÏÔÏËÉ, ÔÏ ×Ï + ×ÒÅÍÑ ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ ÏÓÎÏ×ÎÏÊ ÐÒÏÃÅÓÓ Á×ÁÒÉÊÎÏ ×ÙÈÏÄÉÌ; ÏÛÉÂËÁ + ÐÏÑ×ÉÌÁÓØ × 0.5.9. + óÐÁÓÉÂÏ âÏÒÉÓÕ öÍÕÒÏ×Õ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: × ÍÅÔÏÄÙ ÍÏÄÕÌÑ ngx_http_perl_module ÍÏÇÌÉ ÐÅÒÅÄÁ×ÁÔØÓÑ + ÎÅ×ÅÒÎÙÅ ÒÅÚÕÌØÔÁÔÙ ×ÙÄÅÌÅÎÉÑ × ÒÅÇÕÌÑÒÎÙÈ ×ÙÒÁÖÅÎÉÑÈ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÍÅÔÏÄ $r->has_request_body() ×ÙÚÙ×ÁÌÓÑ ÄÌÑ + ÚÁÐÒÏÓÁ, Õ ËÏÔÏÒÏÇÏ ÎÅÂÏÌØÛÏÅ ÔÅÌÏ ÚÁÐÒÏÓÁ ÂÙÌÏ ÕÖÅ ÐÏÌÎÏÓÔØÀ + ÐÏÌÕÞÅÎÏ, ÔÏ × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: large_client_header_buffers ÎÅ ÏÓ×ÏÂÏÖÄÁÌÉÓØ ÐÅÒÅÄ + ÐÅÒÅÈÏÄÏÍ × ÓÏÓÔÏÑÎÉÅ keep-alive. + óÐÁÓÉÂÏ ïÌÅËÓÁÎÄÒÕ ûÔÅÐÅ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÅÒÅÍÅÎÎÏÊ $upstream_addr ÎÅ ÚÁÐÉÓÙ×ÁÌÓÑ ÐÏÓÌÅÄÎÉÊ + ÁÄÒÅÓ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.18. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á fastcgi_catch_stderr ÎÅ ×ÏÚ×ÒÁÝÁÌÁ ÏÛÉÂËÕ; + ÔÅÐÅÒØ ÏÎÁ ×ÏÚ×ÒÁÝÁÅÔ ÏÛÉÂËÕ 502, ËÏÔÏÒÕÀ ÍÏÖÎÏ ÎÁÐÒÁ×ÉÔØ ÎÁ + ÓÌÅÄÕÀÝÉÊ ÓÅÒ×ÅÒ Ó ÐÏÍÏÝØÀ "fastcgi_next_upstream invalid_header". + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù fastcgi_catch_stderr × + ÏÓÎÏ×ÎÏÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × + 0.6.10. + óÐÁÓÉÂÏ Manlio Perillo. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.21 03.12.2007 + + *) éÚÍÅÎÅÎÉÅ: ÅÓÌÉ × ÚÎÁÞÅÎÉÑÈ ÐÅÒÅÍÅÎÎÙÈ ÄÉÒÅËÔÉ×Ù proxy_pass + ÉÓÐÏÌØÚÕÀÔÓÑ ÔÏÌØËÏ IP-ÁÄÒÅÓÁ, ÔÏ ÕËÁÚÙ×ÁÔØ resolver ÎÅ ÎÕÖÎÏ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù proxy_pass c URI-ÞÁÓÔØÀ × + ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ + × 0.6.19. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ resolver ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÎÁ ÐÌÁÔÆÏÒÍÁÈ, ÎÅ + ÐÏÄÄÅÒÖÉ×ÁÀÝÉÈ ÍÅÔÏÄ kqueue, ÔÏ nginx ×ÙÄÁ×ÁÌ alert "name is out of + response". + óÐÁÓÉÂÏ áÎÄÒÅÀ îÉÇÍÁÔÕÌÉÎÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ðÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÏÊ $server_protocol × + FastCGI-ÐÁÒÁÍÅÔÒÁÈ É ÚÁÐÒÏÓÅ, ÄÌÉÎÁ ËÏÔÏÒÏÇÏ ÂÙÌÁ ÂÌÉÚËÁ Ë ÚÎÁÞÅÎÉÀ + ÄÉÒÅËÔÉ×Ù client_header_buffer_size, nginx ×ÙÄÁ×ÁÌ alert "fastcgi: + the request record is too big". + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÏÂÙÞÎÏÍ ÚÁÐÒÏÓÅ ×ÅÒÓÉÉ HTTP/0.9 Ë HTTPS ÓÅÒ×ÅÒÕ + nginx ×ÏÚ×ÒÁÝÁÌ ÏÂÙÞÎÙÊ ÏÔ×ÅÔ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.20 28.11.2007 + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù proxy_pass c URI-ÞÁÓÔØÀ × + ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ + × 0.6.19. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.19 27.11.2007 + + *) éÓÐÒÁ×ÌÅÎÉÅ: ×ÅÒÓÉÑ 0.6.18 ÎÅ ÓÏÂÉÒÁÌÁÓØ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.18 27.11.2007 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÍÏÄÕÌØ ngx_http_userid_module × ÐÏÌÅ ËÕËÉ Ó + ÎÏÍÅÒÏÍ ÐÒÏÃÅÓÓÁ ÄÏÂÁ×ÌÑÅÔ ÍÉËÒÏÓÅËÕÎÄÙ ÎÁ ×ÒÅÍÑ ÓÔÁÒÔÁ. + + *) éÚÍÅÎÅÎÉÅ: × error_log ÔÅÐÅÒØ ÚÁÐÉÓÙ×ÁÅÔÓÑ ÐÏÌÎÁÑ ÓÔÒÏËÁ ÚÁÐÒÏÓÁ + ×ÍÅÓÔÏ ÔÏÌØËÏ URI. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_pass ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÅÒÅÍÅÎÎÙÅ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù resolver É resolver_timeout. + + *) äÏÂÁ×ÌÅÎÉÅ: ÔÅÐÅÒØ ÄÉÒÅËÔÉ×Á "add_header last-modified ''" ÕÄÁÌÑÅÔ × + ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ ÓÔÒÏËÕ "Last-Modified". + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á limit_rate ÎÅ ÐÏÚ×ÏÌÑÌÁ ÐÅÒÅÄÁ×ÁÔØ ÎÁ ÐÏÌÎÏÊ + ÓËÏÒÏÓÔÉ, ÄÁÖÅ ÅÓÌÉ ÂÙÌ ÕËÁÚÁÎ ÏÞÅÎØ ÂÏÌØÛÏÊ ÌÉÍÉÔ. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.17 15.11.2007 + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÏÄÄÅÒÖËÁ ÓÔÒÏËÉ "If-Range" × ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ. + óÐÁÓÉÂÏ áÌÅËÓÁÎÄÒÕ éÎÀÈÉÎÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÄÉÒÅËÔÉ×Ù msie_refresh ÐÏ×ÔÏÒÎÏ + ÜËÒÁÎÉÒÏ×ÁÌÉÓØ ÕÖÅ ÜËÒÁÎÉÒÏ×ÁÎÎÙÅ ÓÉÍ×ÏÌÙ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.4. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á autoindex ÎÅ ÒÁÂÏÔÁÌÁ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ + "alias /". + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÏÄÚÁÐÒÏÓÏ× × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÍÏÇ + ÐÒÏÉÚÏÊÔÉ segmentation fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ SSL É gzip ÂÏÌØÛÉÅ ÏÔ×ÅÔÙ ÍÏÇÌÉ + ÐÅÒÅÄÁ×ÁÔØÓÑ ÎÅ ÐÏÌÎÏÓÔØÀ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÏÔ×ÅÔ ÐÒÏËÓÉÒÏ×ÁÎÎÏÇÏ ÓÅÒ×ÅÒÁ ÂÙÌ ×ÅÒÓÉÉ HTTP/0.9, + ÔÏ ÐÅÒÅÍÅÎÎÁÑ $status ÂÙÌÁ ÒÁ×ÎÁ 0. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.16 29.10.2007 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÎÁ Linux ÉÓÐÏÌØÚÕÅÔÓÑ uname(2) ×ÍÅÓÔÏ procfs. + óÐÁÓÉÂÏ éÌØÅ îÏ×ÉËÏ×Õ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ × ÄÉÒÅËÔÉ×Å error_page ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÓÉÍ×ÏÌ "?", + ÔÏ ÏÎ ÜËÒÁÎÉÒÏ×ÁÌÓÑ ÐÒÉ ÐÒÏËÓÉÒÏ×ÁÎÉÉ ÚÁÐÒÏÓÁ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × + 0.6.11. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÓÏ×ÍÅÓÔÉÍÏÓÔØ Ó mget. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.15 22.10.2007 + + *) äÏÂÁ×ÌÅÎÉÅ: ÓÏ×ÍÅÓÔÉÍÏÓÔØ Ó Cygwin. + óÐÁÓÉÂÏ ÷ÌÁÄÉÍÉÒÕ ëÕÔÁËÏ×Õ. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á merge_slashes. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á gzip_vary. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á server_tokens. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÒÁÓËÏÄÉÒÏ×ÁÌ URI × ËÏÍÁÎÄÅ SSI include. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÏÊ × ÄÉÒÅËÔÉ×ÁÈ charset ÉÌÉ + source_charset ÎÁ ÓÔÁÒÔÅ ÉÌÉ ×Ï ×ÒÅÍÑ ÐÅÒÅËÏÎÆÉÇÕÒÁÃÉÉ ÐÒÏÉÓÈÏÄÉÌ + segmentation fault, + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ×ÏÚ×ÒÁÝÁÌ ÏÛÉÂËÕ 400 ÎÁ ÚÁÐÒÏÓÙ ×ÉÄÁ + "GET http://www.domain.com HTTP/1.0". + óÐÁÓÉÂÏ James Oakley. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÏÓÌÅ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÑ ÚÁÐÒÏÓÁ Ó ÔÅÌÏÍ ÚÁÐÒÏÓÁ Ó ÐÏÍÏÝØÀ + ÄÉÒÅËÔÉ×Ù error_page nginx ÐÙÔÁÌÓÑ ÓÎÏ×Á ÐÒÏÞÉÔÁÔØ ÔÅÌÏ ÚÁÐÒÏÓÁ; + ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.7. + + *) éÓÐÒÁ×ÌÅÎÉÅ: × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ segmentation fault, ÅÓÌÉ + Õ ÓÅÒ×ÅÒÁ, ÏÂÒÁÂÁÔÙ×ÁÀÝÅÍÕ ÚÁÐÒÏÓ, ÎÅ ÂÙÌ Ñ×ÎÏ ÏÐÒÅÄẠ̊Π+ server_name; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.7. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.14 15.10.2007 + + *) éÚÍÅÎÅÎÉÅ: ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ËÏÍÁÎÄÁ SSI echo ÉÓÐÏÌØÚÕÅÔ + ËÏÄÉÒÏ×ÁÎÉÅ entity. + + *) äÏÂÁ×ÌÅÎÉÅ: ÐÁÒÁÍÅÔÒ encoding × ËÏÍÁÎÄÅ SSI echo. + + *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Õ access_log ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ×ÎÕÔÒÉ ÂÌÏËÁ + limit_except. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ×ÓÅ ÓÅÒ×ÅÒÁ ÁÐÓÔÒÉÍÁ ÏËÁÚÙ×ÁÌÉÓØ ÎÅÄÏÓÔÕÐÎÙÍÉ, ÔÏ + ÄÏ ×ÏÓÓÔÁÎÏ×ÌÅÎÉÑ ÒÁÂÏÔÏÓÐÏÓÏÂÎÏÓÔÉ Õ ×ÓÅÈ ÓÅÒ×ÅÒÏ× ×ÅÓ ÓÔÁÎÏ×ÉÌÓÑ + ÒÁ×ÎÙÍ ÏÄÎÏÍÕ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.6. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÐÅÒÅÍÅÎÎÙÈ $date_local É $date_gmt + ×ÎÅ ÍÏÄÕÌÑ ngx_http_ssi_filter_module × ÒÁÂÏÞÅÍ ÐÒÏÃÅÓÓÅ ÐÒÏÉÓÈÏÄÉÌ + segmentation fault. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ×ËÌÀÞ£ÎÎÏÍ ÏÔÌÁÄÏÞÎÏÍ ÌÏÇÅ × ÒÁÂÏÞÅÍ + ÐÒÏÃÅÓÓÅ ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault. + óÐÁÓÉÂÏ áÎÄÒÅÀ îÉÇÍÁÔÕÌÉÎÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ngx_http_memcached_module ÎÅ ÕÓÔÁÎÁ×ÌÉ×ÁÌ + upstream_response_time. + óÐÁÓÉÂÏ íÁËÓÉÍÕ äÕÎÉÎÕ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: ÒÁÂÏÞÉÊ ÐÒÏÃÅÓÓ ÍÏÇ ÚÁÃÉËÌÉÔØÓÑ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ + memcached. + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÒÁÓÐÏÚÎÁ×ÁÌ ÐÁÒÁÍÅÔÒÙ "close" É "keep-alive" × + ÓÔÒÏËÅ "Connection" × ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ ÔÏÌØËÏ, ÅÓÌÉ ÏÎÉ ÂÙÌÉ × + ÎÉÖÎÅÍ ÒÅÇÉÓÔÒÅ; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.6.11. + + *) éÓÐÒÁ×ÌÅÎÉÅ: sub_filter ÎÅ ÒÁÂÏÔÁÌ Ó ÐÕÓÔÏÊ ÓÔÒÏËÏÊ ÚÁÍÅÎÙ. + + *) éÓÐÒÁ×ÌÅÎÉÅ: × ÐÁÒÓÉÎÇÅ sub_filter. + + +éÚÍÅÎÅÎÉÑ × nginx 0.6.13 24.09.2007 + + *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÚÁËÒÙ×ÁÌ ÆÁÊÌ ËÁÔÁÌÏÇÁ ÄÌÑ ÚÁÐÒÏÓÁ HEAD, ÅÓÌÉ + ÉÓÐÏÌØÚÏ×ÁÌÓÑ autoindex + óÐÁÓÉÂÏ Arkadiusz Patyk. + + éÚÍÅÎÅÎÉÑ × nginx 0.6.12 21.09.2007 *) éÚÍÅÎÅÎÉÅ: ÐÏÞÔÏ×ÙÊ ÐÒÏËÓÉ-ÓÅÒ×ÅÒ ÒÁÚÄẠ̊ΠÎÁ ÔÒÉ ÍÏÄÕÌÑ: pop3, imap diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2007 Igor Sysoev + * Copyright (C) 2002-2008 Igor Sysoev * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -2,7 +2,7 @@ # Copyright (C) Igor Sysoev -# MSVC 6.0 SP2, MSVC Toolkit 2003 (7.1) +# MSVC 6.0 SP2, MSVC Toolkit 2003 (7.1), MSVC 2005 Express Edition SP1 (8.0) # optimizations @@ -91,17 +91,17 @@ CORE_LIBS="$CORE_LIBS kernel32.lib user3 CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" # debug -CFLAGS="$CFLAGS -Yd" -CORE_LINK="$CORE_LINK -debug -debugtype:coff" +if [ $NGX_CC_NAME != msvc8 ]; then + CFLAGS="$CFLAGS -Zi" + CORE_LINK="$CORE_LINK -debug" +fi # precompiled headers -if [ $NGX_CC_NAME != msvc7 ]; then - CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" - NGX_PCH="$NGX_OBJS/ngx_config.pch" - NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch" - NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch" -fi +CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" +NGX_PCH="$NGX_OBJS/ngx_config.pch" +NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch" +NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch" # the resource file diff --git a/auto/cc/name b/auto/cc/name --- a/auto/cc/name +++ b/auto/cc/name @@ -25,6 +25,13 @@ fi if [ "$CC" = cl ]; then if `$NGX_WINE $CC -v 2>&1 \ + | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14' \ + >/dev/null 2>&1`; then + + NGX_CC_NAME=msvc8 + echo " + using Microsoft Visual C++ 8 compiler" + + else if `$NGX_WINE $CC -v 2>&1 \ | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13' \ >/dev/null 2>&1`; then @@ -35,6 +42,7 @@ if [ "$CC" = cl ]; then NGX_CC_NAME=msvc echo " + using Microsoft Visual C++ compiler" fi + fi else if [ "$CC" = wcl386 ]; then diff --git a/auto/feature b/auto/feature --- a/auto/feature +++ b/auto/feature @@ -19,7 +19,9 @@ if test -n "$ngx_feature_name"; then fi if test -n "$ngx_feature_path"; then - ngx_feature_inc_path="-I $ngx_feature_path" + for ngx_temp in $ngx_feature_path; do + ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp" + done fi cat << END > $NGX_AUTOTEST.c diff --git a/auto/headers b/auto/headers --- a/auto/headers +++ b/auto/headers @@ -6,3 +6,4 @@ ngx_include="unistd.h"; . auto/includ ngx_include="inttypes.h"; . auto/include ngx_include="limits.h"; . auto/include ngx_include="sys/filio.h"; . auto/include +ngx_include="crypt.h"; . auto/include diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -17,47 +17,53 @@ fi cat << END >> $NGX_MAKEFILE -install: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \ +install: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \ $NGX_INSTALL_PERL_MODULES - test -d '$NGX_PREFIX' || mkdir -p '$NGX_PREFIX' + test -d '\$(DESTDIR)$NGX_PREFIX' || mkdir -p '\$(DESTDIR)$NGX_PREFIX' - test -d '`dirname "$NGX_SBIN_PATH"`' \ - || mkdir -p '`dirname "$NGX_SBIN_PATH"`' - test ! -f '$NGX_SBIN_PATH' || mv '$NGX_SBIN_PATH' '$NGX_SBIN_PATH.old' - cp $NGX_OBJS/nginx '$NGX_SBIN_PATH' + test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \ + || mkdir -p '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' + test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \ + || mv '\$(DESTDIR)$NGX_SBIN_PATH' \ + '\$(DESTDIR)$NGX_SBIN_PATH.old' + cp $NGX_OBJS/nginx '\$(DESTDIR)$NGX_SBIN_PATH' - test -d '$NGX_CONF_PREFIX' || mkdir -p '$NGX_CONF_PREFIX' + test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \ + || mkdir -p '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/koi-win '$NGX_CONF_PREFIX' - cp conf/koi-utf '$NGX_CONF_PREFIX' - cp conf/win-utf '$NGX_CONF_PREFIX' + cp conf/koi-win '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/koi-utf '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/win-utf '\$(DESTDIR)$NGX_CONF_PREFIX' - test -f '$NGX_CONF_PREFIX/mime.types' \ - || cp conf/mime.types '$NGX_CONF_PREFIX' - cp conf/mime.types '$NGX_CONF_PREFIX/mime.types.default' + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types' \ + || cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types.default' - test -f '$NGX_CONF_PREFIX/fastcgi_params' \ - || cp conf/fastcgi_params '$NGX_CONF_PREFIX' - cp conf/fastcgi_params '$NGX_CONF_PREFIX/fastcgi_params.default' + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params' \ + || cp conf/fastcgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/fastcgi_params \ + '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default' - test -f '$NGX_CONF_PATH' || cp conf/nginx.conf '$NGX_CONF_PREFIX' - cp conf/nginx.conf '$NGX_CONF_PREFIX/nginx.conf.default' + test -f '\$(DESTDIR)$NGX_CONF_PATH' \ + || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default' - test -d '`dirname "$NGX_PID_PATH"`' \ - || mkdir -p '`dirname "$NGX_PID_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \ + || mkdir -p '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' - test -d '`dirname "$NGX_HTTP_LOG_PATH"`' || \ - mkdir -p '`dirname "$NGX_HTTP_LOG_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' || \ + mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' - test -d '$NGX_PREFIX/html' || cp -r html '$NGX_PREFIX' + test -d '\$(DESTDIR)$NGX_PREFIX/html' \ + || cp -r html '\$(DESTDIR)$NGX_PREFIX' END -if test -n "$NGX_ERROR_LOG_PATH"; then +if test -n "\$(DESTDIR)$NGX_ERROR_LOG_PATH"; then cat << END >> $NGX_MAKEFILE - test -d '`dirname "$NGX_ERROR_LOG_PATH"`' || \ - mkdir -p '`dirname "$NGX_ERROR_LOG_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' || \ + mkdir -p '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' END fi diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -16,6 +16,7 @@ if [ $USE_MD5 = YES ]; then have=NGX_HAVE_OPENSSL_MD5_H . auto/have have=NGX_OPENSSL_MD5 . auto/have MD5=YES + MD5_LIB=OpenSSL else . auto/lib/md5/conf @@ -28,6 +29,7 @@ if [ $USE_SHA1 = YES ]; then if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then have=NGX_HAVE_OPENSSL_SHA1_H . auto/have SHA1=YES + SHA1_LIB=OpenSSL else . auto/lib/sha1/conf @@ -39,6 +41,14 @@ if [ $USE_ZLIB = YES ]; then . auto/lib/zlib/conf fi +if [ $USE_LIBXSLT = YES ]; then + . auto/lib/libxslt/conf +fi + if [ $USE_PERL = YES ]; then . auto/lib/perl/conf fi + +if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then + . auto/lib/google-perftools/conf +fi diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf new file mode 100644 --- /dev/null +++ b/auto/lib/google-perftools/conf @@ -0,0 +1,33 @@ + +# Copyright (C) Igor Sysoev + + + ngx_feature="Google perftools" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs="-lprofiler" + ngx_feature_test="ProfilerStop()" + . auto/feature + + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="Google perftools in /usr/local/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lprofiler" + else + ngx_feature_libs="-L/usr/local/lib -lprofiler" + fi + + . auto/feature +fi + + +if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" +fi diff --git a/auto/lib/libxslt/conf b/auto/lib/libxslt/conf new file mode 100644 --- /dev/null +++ b/auto/lib/libxslt/conf @@ -0,0 +1,78 @@ + +# Copyright (C) Igor Sysoev + + + ngx_feature="libxslt" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include + #include + #include + #include + #include + #include " + ngx_feature_path="/usr/include/libxml2" + ngx_feature_libs="-lxml2 -lxslt" + ngx_feature_test="xmlParserCtxtPtr ctxt = NULL; + xsltStylesheetPtr sheet = NULL; + xmlDocPtr doc; + doc = xmlParseChunk(ctxt, NULL, 0, 0); + xsltApplyStylesheet(sheet, doc, NULL);" + . auto/feature + + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="libxslt in /usr/local/" + ngx_feature_path="/usr/local/include/libxml2 /usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lxml2 -lxslt" + else + ngx_feature_libs="-L/usr/local/lib -lxml2 -lxslt" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="libxslt in /usr/pkg/" + ngx_feature_path="/usr/pkg/include/libxml2 /usr/pkg/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lxml2 -lxslt" + else + ngx_feature_libs="-L/usr/pkg/lib -lxml2 -lxslt" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="libxslt in /opt/local/" + ngx_feature_path="/opt/local/include/libxml2 /opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lxml2 -lxslt" + else + ngx_feature_libs="-L/opt/local/lib -lxml2 -lxslt" + fi + + . auto/feature +fi + + +if [ $ngx_found = yes ]; then + CORE_INCS="$CORE_INCS $ngx_feature_path" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" +fi diff --git a/auto/lib/md5/conf b/auto/lib/md5/conf --- a/auto/lib/md5/conf +++ b/auto/lib/md5/conf @@ -45,6 +45,7 @@ if [ $MD5 != NONE ]; then else if [ "$NGX_PLATFORM" != win32 ]; then + MD5=NO # Solaris 8/9 @@ -58,55 +59,43 @@ else ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" . auto/feature - if [ $ngx_found = yes ]; then - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - MD5=YES - MD5_LIB=md5 - ngx_found=no + ngx_md5_lib="system md5" - else + if [ $ngx_found = no ]; then + # FreeBSD ngx_feature="rsaref md library" - ngx_feature_name= - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= ngx_feature_libs="-lmd" - ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" . auto/feature + + ngx_md5_lib="system md" fi + if [ $ngx_found = no ]; then + + # OpenSSL crypto library + + ngx_feature="OpenSSL md5 crypto library" + ngx_feature_name="NGX_OPENSSL_MD5" + ngx_feature_incs="#include " + ngx_feature_libs="-lcrypto" + ngx_feature_test="MD5_CTX md5; MD5_Init(&md5)" + . auto/feature + + ngx_md5_lib="system crypto" + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_OPENSSL_MD5_H . auto/have + fi + fi if [ $ngx_found = yes ]; then CORE_LIBS="$CORE_LIBS $ngx_feature_libs" MD5=YES - MD5_LIB=md - ngx_found=no - - else - if [ $MD5 = NO ]; then - - # OpenSSL crypto library - - ngx_feature="OpenSSL md5 crypto library" - ngx_feature_name="NGX_OPENSSL_MD5" - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs="-lcrypto" - ngx_feature_test="MD5_CTX md5; MD5_Init(&md5)" - . auto/feature - fi + MD5_LIB=$ngx_md5_lib fi - - if [ $ngx_found = yes ]; then - have=NGX_HAVE_OPENSSL_MD5_H . auto/have - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - MD5=YES - MD5_LIB=crypto - fi fi fi diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -84,6 +84,7 @@ if [ $PCRE != NONE ]; then else if [ "$NGX_PLATFORM" != win32 ]; then + PCRE=NO ngx_feature="PCRE library" @@ -95,20 +96,11 @@ else ngx_feature_test="pcre *re; re = pcre_compile(NULL, 0, NULL, 0, NULL)" . auto/feature - if [ $ngx_found = yes ]; then - CORE_DEPS="$CORE_DEPS $REGEX_DEPS" - CORE_SRCS="$CORE_SRCS $REGEX_SRCS" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - PCRE=YES - ngx_found=no + if [ $ngx_found = no ]; then - else # FreeBSD port ngx_feature="PCRE library in /usr/local/" - ngx_feature_name="NGX_PCRE" - ngx_feature_run=no - ngx_feature_incs="#include " ngx_feature_path="/usr/local/include" if [ $NGX_RPATH = YES ]; then @@ -117,8 +109,49 @@ else ngx_feature_libs="-L/usr/local/lib -lpcre" fi - ngx_feature_test="pcre *re; - re = pcre_compile(NULL, 0, NULL, 0, NULL)" + . auto/feature + fi + + if [ $ngx_found = no ]; then + + # RedHat RPM, Solaris package + + ngx_feature="PCRE library in /usr/include/pcre/" + ngx_feature_path="/usr/include/pcre" + ngx_feature_libs="-lpcre" + + . auto/feature + fi + + if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="PCRE library in /usr/pkg/" + ngx_feature_path="/usr/pkg/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lpcre" + else + ngx_feature_libs="-L/usr/pkg/lib -lpcre" + fi + + . auto/feature + fi + + if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="PCRE library in /opt/local/" + ngx_feature_path="/opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lpcre" + else + ngx_feature_libs="-L/opt/local/lib -lpcre" + fi + . auto/feature fi @@ -128,94 +161,6 @@ else CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" PCRE=YES - ngx_found=no - - else - # Linux package - - if [ $PCRE = NO ]; then - - ngx_feature="PCRE library in /usr/include/pcre/" - ngx_feature_name="NGX_PCRE" - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path="/usr/include/pcre" - ngx_feature_libs="-lpcre" - ngx_feature_test="pcre *re; - re = pcre_compile(NULL, 0, NULL, 0, NULL)" - . auto/feature - fi - fi - - if [ $ngx_found = yes ]; then - CORE_DEPS="$CORE_DEPS $REGEX_DEPS" - CORE_SRCS="$CORE_SRCS $REGEX_SRCS" - CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - PCRE=YES - ngx_found=no - - else - # NetBSD port - - if [ $PCRE = NO ]; then - - ngx_feature="PCRE library in /usr/pkg/" - ngx_feature_name="NGX_PCRE" - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path="/usr/pkg/include" - - if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lpcre" - else - ngx_feature_libs="-L/usr/pkg/lib -lpcre" - fi - - ngx_feature_test="pcre *re; - re = pcre_compile(NULL, 0, NULL, 0, NULL)" - . auto/feature - fi - fi - - if [ $ngx_found = yes ]; then - CORE_DEPS="$CORE_DEPS $REGEX_DEPS" - CORE_SRCS="$CORE_SRCS $REGEX_SRCS" - CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - PCRE=YES - ngx_found=no - - else - # MacPorts - - if [ $PCRE = NO ]; then - - ngx_feature="PCRE library in /opt/local/" - ngx_feature_name="NGX_PCRE" - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path="/opt/local/include" - - if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lpcre" - else - ngx_feature_libs="-L/opt/local/lib -lpcre" - fi - - ngx_feature_test="pcre *re; - re = pcre_compile(NULL, 0, NULL, 0, NULL)" - . auto/feature - fi - fi - - if [ $ngx_found = yes ]; then - CORE_DEPS="$CORE_DEPS $REGEX_DEPS" - CORE_SRCS="$CORE_SRCS $REGEX_SRCS" - CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - PCRE=YES - ngx_found=no fi fi diff --git a/auto/lib/sha1/conf b/auto/lib/sha1/conf --- a/auto/lib/sha1/conf +++ b/auto/lib/sha1/conf @@ -35,6 +35,7 @@ if [ $SHA1 != NONE ]; then else if [ "$NGX_PLATFORM" != win32 ]; then + SHA1=NO # FreeBSD @@ -48,35 +49,28 @@ else ngx_feature_test="SHA_CTX sha1; SHA1_Init(&sha1)" . auto/feature + ngx_sha1_lib="system md" + + if [ $ngx_found = no ]; then + + # OpenSSL crypto library + + ngx_feature="OpenSSL sha1 crypto library" + ngx_feature_incs="#include " + ngx_feature_libs="-lcrypto" + . auto/feature + + ngx_sha1_lib="system crypto" + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_OPENSSL_SHA1_H . auto/have + fi + fi if [ $ngx_found = yes ]; then CORE_LIBS="$CORE_LIBS $ngx_feature_libs" SHA1=YES - SHA1_LIB=md - ngx_found=no - - else - if [ $SHA1 = NO ]; then - - # OpenSSL crypto library - - ngx_feature="OpenSSL sha1 crypto library" - ngx_feature_name= - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs="-lcrypto" - ngx_feature_test="SHA_CTX sha1; SHA1_Init(&sha1)" - . auto/feature - fi - fi - - - if [ $ngx_found = yes ]; then - have=NGX_HAVE_OPENSSL_SHA1_H . auto/have - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - SHA1=YES - SHA1_LIB=crypto + SHA1_LIB=$ngx_sha1_lib fi fi diff --git a/auto/make b/auto/make --- a/auto/make +++ b/auto/make @@ -6,7 +6,8 @@ mkdir -p $NGX_OBJS/src/core $NGX_OBJS/sr $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \ $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \ $NGX_OBJS/src/http/modules/perl \ - $NGX_OBJS/src/mail + $NGX_OBJS/src/mail \ + $NGX_OBJS/src/misc ngx_objs_dir=$NGX_OBJS$ngx_regex_dirsep @@ -127,6 +128,9 @@ END fi +ngx_all_srcs="$ngx_all_srcs $NGX_MISC_SRCS" + + if test -n "$NGX_ADDON_SRCS"; then cat << END >> $NGX_MAKEFILE @@ -309,6 +313,32 @@ END fi +# the misc sources + +if test -n "$NGX_MISC_SRCS"; then + + ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" + + for ngx_src in $NGX_MISC_SRCS + do + ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_obj=`echo $ngx_src \ + | sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"` + + cat << END >> $NGX_MAKEFILE + +$ngx_obj: \$(CORE_DEPS) $ngx_cont$ngx_src + $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX + +END + done + +fi + + # the addons sources if test -n "$NGX_ADDON_SRCS"; then diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -76,6 +76,9 @@ fi # the module order is important +# ngx_http_static_module +# ngx_http_gzip_static_module +# ngx_http_dav_module # ngx_http_autoindex_module # ngx_http_index_module # @@ -92,6 +95,8 @@ fi # ngx_http_postpone_filter # ngx_http_charset_filter # ngx_http_ssi_filter +# ngx_http_xslt_filter +# ngx_http_sub_filter # ngx_http_addition_filter # ngx_http_userid_filter # ngx_http_headers_filter @@ -113,7 +118,7 @@ fi if [ $HTTP_POSTPONE = YES ]; then HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTPP_POSTPONE_FILTER_SRCS" + HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS" fi if [ $HTTP_CHARSET = YES ]; then @@ -129,6 +134,12 @@ if [ $HTTP_SSI = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS" fi +if [ $HTTP_XSLT = YES ]; then + USE_LIBXSLT=YES + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_XSLT_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_XSLT_SRCS" +fi + if [ $HTTP_SUB = YES ]; then HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SUB_FILTER_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_SUB_SRCS" @@ -146,6 +157,12 @@ fi HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE" +if [ $HTTP_GZIP_STATIC = YES ]; then + have=NGX_HTTP_GZIP . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_GZIP_STATIC_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_STATIC_SRCS" +fi + if [ $HTTP_DAV = YES ]; then have=NGX_HTTP_DAV . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_DAV_MODULE" @@ -272,8 +289,8 @@ fi # STUB #USE_MD5=YES -#HTTP_SRCS="$HTTP_SRCS $HTPP_CACHE_SRCS" -#HTTP_SRCS="$HTTP_SRCS $HTPP_FILE_CACHE_SRCS" +#HTTP_SRCS="$HTTP_SRCS $HTTP_CACHE_SRCS" +#HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS" if [ $HTTP_STUB_STATUS = YES ]; then have=NGX_STAT_STUB . auto/have @@ -371,6 +388,12 @@ if [ $MAIL = YES ]; then fi +if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then + modules="$modules $NGX_GOOGLE_PERFTOOLS_MODULE" + NGX_MISC_SRCS="$NGX_MISC_SRCS $NGX_GOOGLE_PERFTOOLS_SRCS" +fi + + cat << END > $NGX_MODULES_C #include diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -56,6 +56,7 @@ HTTP_SSL=NO HTTP_SSI=YES HTTP_POSTPONE=NO HTTP_REALIP=NO +HTTP_XSLT=NO HTTP_SUB=NO HTTP_ADDITION=NO HTTP_DAV=NO @@ -76,6 +77,7 @@ HTTP_LIMIT_ZONE=YES HTTP_EMPTY_GIF=YES HTTP_BROWSER=YES HTTP_FLV=NO +HTTP_GZIP_STATIC=NO HTTP_UPSTREAM_IP_HASH=YES # STUB @@ -114,6 +116,10 @@ ZLIB_ASM=NO USE_PERL=NO NGX_PERL=perl +USE_LIBXSLT=NO + +NGX_GOOGLE_PERFTOOLS=NO + NGX_CPU_CACHE_LINE= @@ -147,8 +153,8 @@ do --without-poll_module) EVENT_POLL=NONE ;; --with-aio_module) EVENT_AIO=YES ;; - --with-threads=*) USE_THREADS="$value" ;; - --with-threads) USE_THREADS="pthreads" ;; + #--with-threads=*) USE_THREADS="$value" ;; + #--with-threads) USE_THREADS="pthreads" ;; --without-http) HTTP=NO ;; --http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;; @@ -159,9 +165,11 @@ do --with-http_ssl_module) HTTP_SSL=YES ;; --with-http_realip_module) HTTP_REALIP=YES ;; --with-http_addition_module) HTTP_ADDITION=YES ;; + --with-http_xslt_module) HTTP_XSLT=YES ;; --with-http_sub_module) HTTP_SUB=YES ;; --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; + --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; @@ -199,6 +207,8 @@ do --without-mail_imap_module) MAIL_IMAP=NO ;; --without-mail_smtp_module) MAIL_SMTP=NO ;; + --with-google_perftools_module) NGX_GOOGLE_PERFTOOLS=YES ;; + --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;; --with-cc=*) CC="$value" ;; @@ -270,9 +280,11 @@ cat << END --with-http_ssl_module enable ngx_http_ssl_module --with-http_realip_module enable ngx_http_realip_module --with-http_addition_module enable ngx_http_addition_module + --with-http_xslt_module enable ngx_http_xslt_module --with-http_sub_module enable ngx_http_sub_module --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module + --with-http_gzip_static_module enable ngx_http_gzip_static_module --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module @@ -308,8 +320,13 @@ cat << END --without-http disable HTTP server - --with-mail enable IMAP4/POP3/SMTP proxy module + --with-mail enable POP3/IMAP4/SMTP proxy module --with-mail_ssl_module enable ngx_mail_ssl_module + --without-mail_pop3_module disable ngx_mail_pop3_module + --without-mail_imap_module disable ngx_mail_imap_module + --without-mail_smtp_module disable ngx_mail_smtp_module + + --with-google_perftools_module enable ngx_google_perftools_module --add-module=PATH enable an external module diff --git a/auto/os/conf b/auto/os/conf --- a/auto/os/conf +++ b/auto/os/conf @@ -18,6 +18,10 @@ case "$NGX_PLATFORM" in . auto/os/solaris ;; + Darwin:*) + . auto/os/darwin + ;; + win32) . auto/os/win32 ;; @@ -36,24 +40,6 @@ case "$NGX_PLATFORM" in ' ;; - Darwin:*) - have=NGX_DARWIN . auto/have_headers - have=NGX_HAVE_INHERITED_NONBLOCK . auto/have - CORE_INCS="$UNIX_INCS" - CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" - CORE_SRCS="$UNIX_SRCS" - - ngx_feature="atomic(3)" - ngx_feature_name=NGX_DARWIN_ATOMIC - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test="int32_t lock, n; - n = OSAtomicCompareAndSwap32Barrier(0, 1, lock)" - . auto/feature - ;; - HP-UX:*) # HP/UX have=NGX_HPUX . auto/have_headers diff --git a/auto/os/darwin b/auto/os/darwin new file mode 100644 --- /dev/null +++ b/auto/os/darwin @@ -0,0 +1,115 @@ + +# Copyright (C) Igor Sysoev + + +have=NGX_DARWIN . auto/have_headers + +CORE_INCS="$UNIX_INCS" +CORE_DEPS="$UNIX_DEPS $DARWIN_DEPS" +CORE_SRCS="$UNIX_SRCS $DARWIN_SRCS" + + + +ngx_spacer=' +' + +# kqueue + +echo " + kqueue found" +have=NGX_HAVE_KQUEUE . auto/have +have=NGX_HAVE_CLEAR_EVENT . auto/have +EVENT_MODULES="$EVENT_MODULES $KQUEUE_MODULE" +CORE_SRCS="$CORE_SRCS $KQUEUE_SRCS" +EVENT_FOUND=YES +NGX_KQUEUE_CHECKED=YES + +ngx_feature="kqueue's EVFILT_TIMER" +ngx_feature_name="NGX_HAVE_TIMER_EVENT" +ngx_feature_run=yes +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int kq; + struct kevent kev; + struct timespec ts; + + if ((kq = kqueue()) == -1) return 1; + + kev.ident = 0; + kev.filter = EVFILT_TIMER; + kev.flags = EV_ADD|EV_ENABLE; + kev.fflags = 0; + kev.data = 1000; + kev.udata = 0; + + ts.tv_sec = 0; + ts.tv_nsec = 0; + + if (kevent(kq, &kev, 1, &kev, 1, &ts) == -1) return 1; + + if (kev.flags & EV_ERROR) return 1;" + +. auto/feature + + +ngx_feature="Darwin 64-bit kqueue millisecond timeout bug" +ngx_feature_name=NGX_DARWIN_KEVENT_BUG +ngx_feature_run=bug +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int kq; + struct kevent kev; + struct timespec ts; + struct timeval tv, tv0; + + kq = kqueue(); + + ts.tv_sec = 0; + ts.tv_nsec = 999000000; + + gettimeofday(&tv, 0); + kevent(kq, NULL, 0, &kev, 1, &ts); + gettimeofday(&tv0, 0); + timersub(&tv0, &tv, &tv); + + if (tv.tv_sec * 1000000 + tv.tv_usec < 900000) return 1;" + +. auto/feature + + +# sendfile() + +CC_AUX_FLAGS="$CC_AUX_FLAGS" +ngx_feature="sendfile()" +ngx_feature_name="NGX_HAVE_SENDFILE" +ngx_feature_run=yes +ngx_feature_incs="#include + #include + #include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int s = 0, fd = 1; + off_t n; off_t off = 0; + n = sendfile(s, fd, off, &n, NULL, 0); + if (n == -1 && errno == ENOSYS) return 1" +. auto/feature + +if [ $ngx_found = yes ]; then + have=NGX_HAVE_SENDFILE . auto/have + CORE_SRCS="$CORE_SRCS $DARWIN_SENDFILE_SRCS" +fi + + +ngx_feature="atomic(3)" +ngx_feature_name=NGX_DARWIN_ATOMIC +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int32_t lock, n; + n = OSAtomicCompareAndSwap32Barrier(0, 1, lock)" +. auto/feature diff --git a/auto/os/features b/auto/os/features --- a/auto/os/features +++ b/auto/os/features @@ -122,36 +122,6 @@ if test -z "$NGX_KQUEUE_CHECKED"; then if (kev.flags & EV_ERROR) return 1;" . auto/feature - - - if [ "$NGX_SYSTEM" = "Darwin" ]; then - - ngx_feature="Darwin 64-bit kqueue millisecond timeout bug" - ngx_feature_name=NGX_DARWIN_KEVENT_BUG - ngx_feature_run=bug - ngx_feature_incs="#include -#include " - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test="int kq; - struct kevent kev; - struct timespec ts; - struct timeval tv, tv0; - - kq = kqueue(); - - ts.tv_sec = 0; - ts.tv_nsec = 999000000; - - gettimeofday(&tv, 0); - kevent(kq, NULL, 0, &kev, 1, &ts); - gettimeofday(&tv0, 0); - timersub(&tv0, &tv, &tv); - - if (tv.tv_sec * 1000000 + tv.tv_usec < 900000) return 1;" - - . auto/feature - fi fi fi @@ -200,3 +170,34 @@ if [ $ngx_found = no ]; then CRYPT_LIB="-lcrypt" fi fi + + +ngx_feature="O_DIRECT" +ngx_feature_name="NGX_HAVE_O_DIRECT" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="fcntl(0, F_SETFL, O_DIRECT);" +. auto/feature + + +ngx_feature="F_NOCACHE" +ngx_feature_name="NGX_HAVE_F_NOCACHE" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="fcntl(0, F_NOCACHE, 1);" +. auto/feature + + +ngx_feature="directio()" +ngx_feature_name="NGX_HAVE_DIRECTIO" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="directio(0, DIRECTIO_ON);" +. auto/feature diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -16,18 +16,18 @@ CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURC # Linux kernel version -version=`grep "#define LINUX_VERSION_CODE" /usr/include/linux/version.h \ - | sed -e 's/^.* \(.*\)$/\1/'` +version=$((`uname -r \ + | sed 's/^\([^.]*\)\.\([^.]*\)\.\([^.-]*\).*/\1*256*256+\2*256+\3/'`)) version=${version:-0} -# enable the rt signals on Linux 2.2.19 and onward +# enable the rt signals on Linux between 2.2.19 and 2.6.17 -if [ $version -ge 131609 -o $EVENT_RTSIG = YES ]; then +if [ \( $version -ge 131603 -a $version -lt 132626 \) -o $EVENT_RTSIG = YES ] +then echo " + rt signals found" have=NGX_HAVE_RTSIG . auto/have - have=NGX_HAVE_POLL . auto/have EVENT_MODULES="$EVENT_MODULES $RTSIG_MODULE" CORE_SRCS="$CORE_SRCS $RTSIG_SRCS" EVENT_FOUND=YES diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -15,12 +15,15 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_list.h \ src/core/ngx_hash.h \ src/core/ngx_buf.h \ + src/core/ngx_queue.h \ src/core/ngx_string.h \ src/core/ngx_parse.h \ src/core/ngx_inet.h \ src/core/ngx_file.h \ src/core/ngx_crc.h \ src/core/ngx_crc32.h \ + src/core/ngx_md5.h \ + src/core/ngx_sha1.h \ src/core/ngx_rbtree.h \ src/core/ngx_radix_tree.h \ src/core/ngx_slab.h \ @@ -29,6 +32,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_connection.h \ src/core/ngx_cycle.h \ src/core/ngx_conf_file.h \ + src/core/ngx_resolver.h \ src/core/ngx_open_file_cache.h \ src/core/ngx_garbage_collector.h" @@ -40,6 +44,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_list.c \ src/core/ngx_hash.c \ src/core/ngx_buf.c \ + src/core/ngx_queue.c \ src/core/ngx_output_chain.c \ src/core/ngx_string.c \ src/core/ngx_parse.c \ @@ -56,6 +61,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_spinlock.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ + src/core/ngx_resolver.c \ src/core/ngx_open_file_cache.c \ src/core/ngx_garbage_collector.c" @@ -159,6 +165,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/unix/ngx_socket.c \ src/os/unix/ngx_recv.c \ src/os/unix/ngx_readv_chain.c \ + src/os/unix/ngx_udp_recv.c \ src/os/unix/ngx_send.c \ src/os/unix/ngx_writev_chain.c \ src/os/unix/ngx_channel.c \ @@ -172,7 +179,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ POSIX_DEPS=src/os/unix/ngx_posix_config.h -FREEBSD_DEPS=src/os/unix/ngx_freebsd_config.h +FREEBSD_DEPS="src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd.h" FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c FREEBSD_RFORK_DEPS="src/os/unix/ngx_freebsd_rfork_thread.h" @@ -181,16 +188,21 @@ FREEBSD_RFORK_THREAD_SRCS="src/os/unix/r PTHREAD_SRCS="src/os/unix/ngx_pthread_thread.c" -LINUX_DEPS=src/os/unix/ngx_linux_config.h +LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h" LINUX_SRCS=src/os/unix/ngx_linux_init.c LINUX_SENDFILE_SRCS=src/os/unix/ngx_linux_sendfile_chain.c -SOLARIS_DEPS=src/os/unix/ngx_solaris_config.h +SOLARIS_DEPS="src/os/unix/ngx_solaris_config.h src/os/unix/ngx_solaris.h" SOLARIS_SRCS=src/os/unix/ngx_solaris_init.c SOLARIS_SENDFILEV_SRCS=src/os/unix/ngx_solaris_sendfilev_chain.c +DARWIN_DEPS="src/os/unix/ngx_darwin_config.h src/os/unix/ngx_darwin.h" +DARWIN_SRCS=src/os/unix/ngx_darwin_init.c +DARWIN_SENDFILE_SRCS=src/os/unix/ngx_darwin_sendfile_chain.c + + WIN32_INCS="$CORE_INCS $EVENT_INCS src/os/win32" WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \ @@ -224,6 +236,7 @@ WIN32_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/win32/ngx_socket.c \ src/os/win32/ngx_wsarecv.c \ src/os/win32/ngx_wsarecv_chain.c \ + src/os/win32/ngx_udp_wsarecv.c \ src/os/win32/ngx_wsasend_chain.c \ src/os/win32/ngx_win32_init.c \ src/os/win32/ngx_user.c \ @@ -300,10 +313,10 @@ HTTP_SRCS="src/http/ngx_http.c \ # STUB HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c" -HTPP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c +HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c -HTPP_CACHE_SRCS=src/http/ngx_http_cache.c -HTPP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c +HTTP_CACHE_SRCS=src/http/ngx_http_cache.c +HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c HTTP_CHARSET_FILTER_MODULE=ngx_http_charset_filter_module @@ -319,6 +332,10 @@ HTTP_SSI_DEPS=src/http/modules/ngx_http_ HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter_module.c +HTTP_XSLT_FILTER_MODULE=ngx_http_xslt_filter_module +HTTP_XSLT_SRCS=src/http/modules/ngx_http_xslt_filter_module.c + + HTTP_SUB_FILTER_MODULE=ngx_http_sub_filter_module HTTP_SUB_SRCS=src/http/modules/ngx_http_sub_filter_module.c @@ -410,6 +427,10 @@ HTTP_FLV_MODULE=ngx_http_flv_module HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c +HTTP_GZIP_STATIC_MODULE=ngx_http_gzip_static_module +HTTP_GZIP_STATIC_SRCS=src/http/modules/ngx_http_gzip_static_module.c + + HTTP_UPSTREAM_IP_HASH_MODULE=ngx_http_upstream_ip_hash_module HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -449,3 +470,7 @@ MAIL_AUTH_HTTP_SRCS="src/mail/ngx_mail_a MAIL_PROXY_MODULE="ngx_mail_proxy_module" MAIL_PROXY_SRCS="src/mail/ngx_mail_proxy_module.c" + +NGX_GOOGLE_PERFTOOLS_MODULE=ngx_google_perftools_module +NGX_GOOGLE_PERFTOOLS_SRCS=src/misc/ngx_google_perftools_module.c + diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -21,15 +21,15 @@ echo echo "Configuration summary" -case $USE_THREADS in - rfork) echo " + using rfork()ed threads" ;; - pthreads) echo " + using libpthread threads library" ;; - libthr) echo " + using FreeBSD libthr threads library" ;; - libc_r) echo " + using FreeBSD libc_r threads library" ;; - linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; - NO) echo " + threads are not used" ;; - *) echo " + using lib$USE_THREADS threads library" ;; -esac +#case $USE_THREADS in +# rfork) echo " + using rfork()ed threads" ;; +# pthreads) echo " + using libpthread threads library" ;; +# libthr) echo " + using FreeBSD libthr threads library" ;; +# libc_r) echo " + using FreeBSD libc_r threads library" ;; +# linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; +# NO) echo " + threads are not used" ;; +# *) echo " + using lib$USE_THREADS threads library" ;; +#esac if [ $USE_PCRE = DISABLED ]; then echo " + PCRE library is disabled" @@ -51,26 +51,14 @@ case $OPENSSL in esac case $MD5 in - YES) - case $OPENSSL in - NONE|NO) echo " + md5: using system $MD5_LIB library" ;; - *) echo " + md5: using OpenSSL library" ;; - esac - ;; - + 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 case $SHA1 in - YES) - case $OPENSSL in - NONE|NO) echo " + sha1: using system $SHA1_LIB library" ;; - *) echo " + sha1: using OpenSSL library" ;; - esac - ;; - + YES) echo " + sha1: using $SHA1_LIB library" ;; NONE) echo " + sha1 library is not used" ;; NO) echo " + sha1 library is not found" ;; *) echo " + using sha1 library: $SHA1" ;; diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -2,11 +2,12 @@ types { text/html html htm shtml; text/css css; - text/xml xml rss; + text/xml xml; image/gif gif; image/jpeg jpeg jpg; application/x-javascript js; application/atom+xml atom; + application/rss+xml rss; text/mathml mml; text/plain txt; diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -63,6 +63,7 @@ http { # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { + # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -273,9 +273,11 @@ main(int argc, char *const *argv) return 1; } - /* ngx_crc32_init() requires ngx_cacheline_size set in ngx_os_init() */ + /* + * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init() + */ - if (ngx_crc32_init() != NGX_OK) { + if (ngx_crc32_table_init() != NGX_OK) { return 1; } @@ -635,8 +637,7 @@ ngx_getopt(ngx_cycle_t *cycle, int argc, case 'c': if (argv[i + 1] == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "the option: \"%s\" requires file name", - argv[i]); + "the option \"-c\" requires file name"); return NGX_ERROR; } @@ -644,6 +645,17 @@ ngx_getopt(ngx_cycle_t *cycle, int argc, cycle->conf_file.len = ngx_strlen(cycle->conf_file.data); break; + case 'g': + if (argv[i + 1] == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "the option \"-g\" requires parameter"); + return NGX_ERROR; + } + + cycle->conf_param.data = (u_char *) argv[++i]; + cycle->conf_param.len = ngx_strlen(cycle->conf_param.data); + break; + default: ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "invalid option: \"%s\"", argv[i]); @@ -756,12 +768,6 @@ ngx_core_module_init_conf(ngx_cycle_t *c { ngx_core_conf_t *ccf = conf; -#if !(NGX_WIN32) - ngx_str_t lock_file; - struct group *grp; - struct passwd *pwd; -#endif - ngx_conf_init_value(ccf->daemon, 1); ngx_conf_init_value(ccf->master, 1); ngx_conf_init_msec_value(ccf->timer_resolution, 0); @@ -794,6 +800,8 @@ ngx_core_module_init_conf(ngx_cycle_t *c #if !(NGX_WIN32) if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) { + struct group *grp; + struct passwd *pwd; ngx_set_errno(0); pwd = getpwnam(NGX_USER); @@ -828,7 +836,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); - ccf->oldpid.data = ngx_palloc(cycle->pool, ccf->oldpid.len); + ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); if (ccf->oldpid.data == NULL) { return NGX_CONF_ERROR; } @@ -846,6 +854,9 @@ ngx_core_module_init_conf(ngx_cycle_t *c return NGX_CONF_ERROR; } + { + ngx_str_t lock_file; + lock_file = cycle->old_cycle->lock_file; if (lock_file.len) { @@ -869,7 +880,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c } else { cycle->lock_file.len = ccf->lock_file.len + 1; - cycle->lock_file.data = ngx_palloc(cycle->pool, + cycle->lock_file.data = ngx_pnalloc(cycle->pool, ccf->lock_file.len + sizeof(".accept")); if (cycle->lock_file.data == NULL) { return NGX_CONF_ERROR; @@ -879,6 +890,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->lock_file.len), ".accept", sizeof(".accept")); } + } #endif @@ -1076,7 +1088,7 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character \"%c\" in \"worker_cpu_affinity\"", ch); - return NGX_CONF_ERROR ; + return NGX_CONF_ERROR; } } diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.6.12" +#define NGINX_VERSION "0.7.8" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_array.c b/src/core/ngx_array.c --- a/src/core/ngx_array.c +++ b/src/core/ngx_array.c @@ -39,12 +39,12 @@ ngx_array_destroy(ngx_array_t *a) p = a->pool; - if ((u_char *) a->elts + a->size * a->nalloc == p->last) { - p->last -= a->size * a->nalloc; + if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) { + p->d.last -= a->size * a->nalloc; } - if ((u_char *) a + sizeof(ngx_array_t) == p->last) { - p->last = (u_char *) a; + if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) { + p->d.last = (u_char *) a; } } @@ -64,14 +64,15 @@ ngx_array_push(ngx_array_t *a) p = a->pool; - if ((u_char *) a->elts + size == p->last && p->last + a->size <= p->end) + if ((u_char *) a->elts + size == p->d.last + && p->d.last + a->size <= p->d.end) { /* * the array allocation is the last in the pool * and there is space for new allocation */ - p->last += a->size; + p->d.last += a->size; a->nalloc++; } else { @@ -111,15 +112,15 @@ ngx_array_push_n(ngx_array_t *a, ngx_uin p = a->pool; - if ((u_char *) a->elts + a->size * a->nalloc == p->last - && p->last + size <= p->end) + if ((u_char *) a->elts + a->size * a->nalloc == p->d.last + && p->d.last + size <= p->d.end) { /* * the array allocation is the last in the pool * and there is space for new allocation */ - p->last += size; + p->d.last += size; a->nalloc += n; } else { diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -58,14 +58,52 @@ static int argument_number[] = { char * +ngx_conf_param(ngx_conf_t *cf) +{ + ngx_str_t *param; + ngx_buf_t b; + ngx_conf_file_t conf_file; + + param = &cf->cycle->conf_param; + + if (param->len == 0) { + return NGX_CONF_OK; + } + + ngx_memzero(&conf_file, sizeof(ngx_conf_file_t)); + + ngx_memzero(&b, sizeof(ngx_buf_t)); + + b.start = param->data; + b.pos = param->data; + b.last = param->data + param->len; + b.end = b.last; + b.temporary = 1; + + conf_file.file.fd = NGX_INVALID_FILE; + conf_file.file.name.data = (u_char *) "command line"; + conf_file.line = 1; + + cf->conf_file = &conf_file; + cf->conf_file->buffer = &b; + + return ngx_conf_parse(cf, NULL); +} + + +char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t *b; - ngx_uint_t block; ngx_conf_file_t *prev; + enum { + parse_file = 0, + parse_block, + parse_param + } type; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; @@ -117,13 +155,17 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; cf->conf_file->file.offset = 0; - cf->conf_file->file.log = cf->log;; + cf->conf_file->file.log = cf->log; cf->conf_file->line = 1; - block = 0; + type = parse_file; + + } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { + + type = parse_block; } else { - block = 1; + type = parse_param; } @@ -145,24 +187,38 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t } if (rc == NGX_CONF_BLOCK_DONE) { - if (!block) { + + if (type != parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } - block = 0; + goto done; } - if (rc == NGX_CONF_FILE_DONE && block) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unexpected end of file, expecting \"}\""); - goto failed; + if (rc == NGX_CONF_FILE_DONE) { + + if (type == parse_block) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected end of file, expecting \"}\""); + goto failed; + } + + goto done; } - if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) { - goto done; + if (rc == NGX_CONF_BLOCK_START) { + + if (type == parse_param) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "block directives are not supported " + "in -g option"); + goto failed; + } } + /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ + if (cf->handler) { /* @@ -398,10 +454,19 @@ ngx_conf_read_token(ngx_conf_t *cf) for ( ;; ) { if (b->pos >= b->last) { + if (cf->conf_file->file.offset >= ngx_file_size(&cf->conf_file->file.info)) { if (cf->args->nelts > 0) { + + if (cf->conf_file->file.fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected end of parameter, " + "expecting \";\""); + return NGX_ERROR; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, " "expecting \";\" or \"}\""); @@ -574,7 +639,7 @@ ngx_conf_read_token(ngx_conf_t *cf) return NGX_ERROR; } - word->data = ngx_palloc(cf->pool, b->pos - start + 1); + word->data = ngx_pnalloc(cf->pool, b->pos - start + 1); if (word->data == NULL) { return NGX_ERROR; } @@ -633,7 +698,7 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com { char *rv; ngx_int_t n; - ngx_str_t *value, file; + ngx_str_t *value, file, name; ngx_glob_t gl; value = cf->args->elts; @@ -645,10 +710,18 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com return NGX_CONF_ERROR; } + if (strpbrk((char *) file.data, "*?[") == NULL) { + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + return ngx_conf_parse(cf, &file); + } + ngx_memzero(&gl, sizeof(ngx_glob_t)); gl.pattern = file.data; gl.log = cf->log; + gl.test = 1; if (ngx_open_glob(&gl) != NGX_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, @@ -659,12 +732,15 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com rv = NGX_CONF_OK; for ( ;; ) { - n = ngx_read_glob(&gl, &file); + n = ngx_read_glob(&gl, &name); if (n != NGX_OK) { break; } + file.len = name.len++; + file.data = ngx_pstrdup(cf->pool, &name); + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); rv = ngx_conf_parse(cf, &file); @@ -715,7 +791,7 @@ ngx_conf_full_name(ngx_cycle_t *cycle, n } name->len = len + old.len; - name->data = ngx_palloc(cycle->pool, name->len + 1); + name->data = ngx_pnalloc(cycle->pool, name->len + 1); if (name->data == NULL) { return NGX_ERROR; } @@ -934,7 +1010,7 @@ ngx_conf_set_str_array_slot(ngx_conf_t * a = (ngx_array_t **) (p + cmd->offset); - if (*a == NULL) { + if (*a == NGX_CONF_UNSET_PTR) { *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); if (*a == NULL) { return NGX_CONF_ERROR; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -317,6 +317,7 @@ char *ngx_conf_check_num_bounds(ngx_conf #define addressof(addr) ((int) &addr) +char *ngx_conf_param(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -29,6 +29,10 @@ #include +#elif (NGX_DARWIN) +#include + + #elif (NGX_WIN32) #include @@ -116,10 +120,11 @@ typedef intptr_t ngx_flag_t; #define INET_ADDRSTRLEN 16 #endif -#define NGX_MAXHOSTNAMELEN 64 -/* -#define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN -*/ +#ifdef MAXHOSTNAMELEN +#define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN +#else +#define NGX_MAXHOSTNAMELEN 256 +#endif #if ((__GNU__ == 2) && (__GNUC_MINOR__ < 8)) diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -36,7 +36,7 @@ ngx_listening_inet_stream_socket(ngx_con sin->sin_port = htons(port); - ls->addr_text.data = ngx_palloc(cf->pool, + ls->addr_text.data = ngx_pnalloc(cf->pool, INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); if (ls->addr_text.data == NULL) { return NULL; @@ -106,8 +106,8 @@ ngx_set_inherited_sockets(ngx_cycle_t *c ls[i].addr_text_max_len = INET_ADDRSTRLEN; - ls[i].addr_text.data = ngx_palloc(cycle->pool, INET_ADDRSTRLEN - 1 - + sizeof(":65535") - 1); + ls[i].addr_text.data = ngx_pnalloc(cycle->pool, + INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); if (ls[i].addr_text.data == NULL) { return NGX_ERROR; } @@ -229,7 +229,7 @@ ngx_open_listening_sockets(ngx_cycle_t * /* TODO: configurable try number */ - for (tries = 5 ; tries; tries--) { + for (tries = 5; tries; tries--) { failed = 0; /* for each listening socket */ @@ -537,13 +537,21 @@ ngx_close_listening_sockets(ngx_cycle_t c = ls[i].connection; - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - if (c->read->active) { + if (c->read->active) { + if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { ngx_del_conn(c, NGX_CLOSE_EVENT); - } + + } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { - } else { - if (c->read->active) { + /* + * it seems that Linux-2.6.x OpenVZ sends events + * for closed shared listening sockets unless + * the events was explicity deleted + */ + + ngx_del_event(c->read, NGX_READ_EVENT, 0); + + } else { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } } @@ -653,6 +661,8 @@ ngx_free_connection(ngx_connection_t *c) void ngx_close_connection(ngx_connection_t *c) { + ngx_err_t err; + ngx_uint_t log_error, level; ngx_socket_t fd; if (c->fd == -1) { @@ -725,6 +735,8 @@ ngx_close_connection(ngx_connection_t *c #endif + log_error = c->log_error; + ngx_free_connection(c); fd = c->fd; @@ -732,9 +744,31 @@ ngx_close_connection(ngx_connection_t *c if (ngx_close_socket(fd) == -1) { + err = ngx_socket_errno; + + if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) { + + switch (log_error) { + + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + + default: + level = NGX_LOG_CRIT; + } + + } else { + level = NGX_LOG_CRIT; + } + /* we use ngx_cycle->log because c->log was in c->pool */ - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(level, ngx_cycle->log, err, ngx_close_socket_n " %d failed", fd); } } @@ -759,6 +793,9 @@ ngx_connection_error(ngx_connection_t *c || err == NGX_ENOTCONN || err == NGX_ETIMEDOUT || err == NGX_ECONNREFUSED + || err == NGX_ENETDOWN + || err == NGX_ENETUNREACH + || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { switch (c->log_error) { @@ -773,11 +810,11 @@ ngx_connection_error(ngx_connection_t *c break; default: - level = NGX_LOG_CRIT; + level = NGX_LOG_ALERT; } } else { - level = NGX_LOG_CRIT; + level = NGX_LOG_ALERT; } ngx_log_error(level, c->log, err, text); diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -50,6 +50,7 @@ typedef void (*ngx_connection_handler_pt #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ typedef void (*ngx_connection_handler_pt #endif #include #include +#include #include #include #include diff --git a/src/core/ngx_cpuinfo.c b/src/core/ngx_cpuinfo.c --- a/src/core/ngx_cpuinfo.c +++ b/src/core/ngx_cpuinfo.c @@ -92,13 +92,22 @@ ngx_cpuinfo(void) if (ngx_strcmp(vendor, "GenuineIntel") == 0) { - switch (cpu[0] & 0xf00) { + switch ((cpu[0] & 0xf00) >> 8) { /* Pentium */ case 5: + ngx_cacheline_size = 32; + break; + /* Pentium Pro, II, III */ case 6: ngx_cacheline_size = 32; + + if ((cpu[0] & 0xf0) >= 0xd0) { + /* Intel Core */ + ngx_cacheline_size = 64; + } + break; /* diff --git a/src/core/ngx_crc32.c b/src/core/ngx_crc32.c --- a/src/core/ngx_crc32.c +++ b/src/core/ngx_crc32.c @@ -102,7 +102,7 @@ uint32_t *ngx_crc32_table_short = ngx_cr ngx_int_t -ngx_crc32_init(void) +ngx_crc32_table_init(void) { void *p; diff --git a/src/core/ngx_crc32.h b/src/core/ngx_crc32.h --- a/src/core/ngx_crc32.h +++ b/src/core/ngx_crc32.h @@ -49,7 +49,30 @@ ngx_crc32_long(u_char *p, size_t len) } -ngx_int_t ngx_crc32_init(void); +#define ngx_crc32_init(crc) \ + crc = 0xffffffff + + +static ngx_inline void +ngx_crc32_update(uint32_t *crc, u_char *p, size_t len) +{ + uint32_t c; + + c = *crc; + + while (len--) { + c = ngx_crc32_table256[(c ^ *p++) & 0xff] ^ (c >> 8); + } + + *crc = c; +} + + +#define ngx_crc32_final(crc) \ + crc ^= 0xffffffff + + +ngx_int_t ngx_crc32_table_init(void); #endif /* _NGX_CRC32_H_INCLUDED_ */ diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -42,20 +42,22 @@ static ngx_str_t error_log = ngx_null_s ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { - void *rv; - u_char *lock_file; - ngx_uint_t i, n; - ngx_log_t *log; - ngx_conf_t conf; - ngx_pool_t *pool; - ngx_cycle_t *cycle, **old; - ngx_shm_zone_t *shm_zone, *oshm_zone; - ngx_slab_pool_t *shpool; - ngx_list_part_t *part, *opart; - ngx_open_file_t *file; - ngx_listening_t *ls, *nls; - ngx_core_conf_t *ccf, *old_ccf; - ngx_core_module_t *module; + void *rv; + char **senv, **env; + u_char *lock_file; + ngx_uint_t i, n; + ngx_log_t *log; + ngx_conf_t conf; + ngx_pool_t *pool; + ngx_cycle_t *cycle, **old; + ngx_shm_zone_t *shm_zone, *oshm_zone; + ngx_slab_pool_t *shpool; + ngx_list_part_t *part, *opart; + ngx_open_file_t *file; + ngx_listening_t *ls, *nls; + ngx_core_conf_t *ccf, *old_ccf; + ngx_core_module_t *module; + char hostname[NGX_MAXHOSTNAMELEN]; log = old_cycle->log; @@ -79,7 +81,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->conf_file.len = old_cycle->conf_file.len; - cycle->conf_file.data = ngx_palloc(pool, old_cycle->conf_file.len + 1); + cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); if (cycle->conf_file.data == NULL) { ngx_destroy_pool(pool); return NULL; @@ -88,6 +90,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) old_cycle->conf_file.len + 1); + cycle->conf_param.len = old_cycle->conf_param.len; + cycle->conf_param.data = ngx_pnalloc(pool, old_cycle->conf_param.len); + if (cycle->conf_param.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + ngx_memcpy(cycle->conf_param.data, old_cycle->conf_param.data, + old_cycle->conf_param.len); + + n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); @@ -169,6 +181,26 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } + if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed"); + ngx_destroy_pool(pool); + return NULL; + } + + /* on Linux gethostname() silently truncates name that does not fit */ + + hostname[NGX_MAXHOSTNAMELEN - 1] = '\0'; + cycle->hostname.len = ngx_strlen(hostname); + + cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len); + if (cycle->hostname.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + + ngx_memcpy(cycle->hostname.data, hostname, cycle->hostname.len); + + for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; @@ -187,6 +219,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } + senv = environ; + + ngx_memzero(&conf, sizeof(ngx_conf_t)); /* STUB: init array ? */ conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t)); @@ -213,6 +248,11 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) log->log_level = NGX_LOG_DEBUG_ALL; #endif + if (ngx_conf_param(&conf) != NGX_CONF_OK) { + ngx_destroy_cycle_pools(&conf); + return NULL; + } + if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { ngx_destroy_cycle_pools(&conf); return NULL; @@ -435,8 +475,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #else - lock_file = ngx_palloc(cycle->pool, - cycle->lock_file.len + shm_zone[i].name.len); + lock_file = ngx_pnalloc(cycle->pool, + cycle->lock_file.len + shm_zone[i].name.len); if (lock_file == NULL) { goto failed; @@ -694,9 +734,20 @@ old_shm_zone_done: if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { + /* + * perl_destruct() frees environ if it is not the same as it was at + * perl_construct() time. So we have saved an previous cycle + * environment before ngx_conf_parse() where it will be changed. + */ + + env = environ; + environ = senv; + ngx_destroy_pool(old_cycle->pool); cycle->old_cycle = NULL; + environ = env; + return cycle; } @@ -938,9 +989,6 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx ngx_uint_t i; ngx_list_part_t *part; ngx_open_file_t *file; -#if !(NGX_WIN32) - ngx_file_info_t fi; -#endif part = &cycle->open_files.part; file = part->elts; @@ -996,6 +1044,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx } #else if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) { + ngx_file_info_t fi; if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -60,8 +60,10 @@ struct ngx_cycle_s { ngx_cycle_t *old_cycle; ngx_str_t conf_file; + ngx_str_t conf_param; ngx_str_t root; ngx_str_t lock_file; + ngx_str_t hostname; }; diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -46,7 +46,7 @@ ngx_create_temp_file(ngx_file_t *file, n file->name.len = path->name.len + 1 + path->len + 10; - file->name.data = ngx_palloc(pool, file->name.len + 1); + file->name.data = ngx_pnalloc(pool, file->name.len + 1); if (file->name.data == NULL) { return NGX_ERROR; } @@ -61,16 +61,19 @@ ngx_create_temp_file(ngx_file_t *file, n n = (uint32_t) ngx_next_temp_number(0); + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + return NGX_ERROR; + } + for ( ;; ) { (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len, "%010uD%Z", n); - ngx_create_hashed_filename(file, path); + ngx_create_hashed_filename(path, file->name.data, file->name.len); - cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); - if (cln == NULL) { - return NGX_ERROR; - } + ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, + "hashed path: %s", file->name.data); file->fd = ngx_open_tempfile(file->name.data, persistent, access); @@ -117,31 +120,27 @@ ngx_create_temp_file(ngx_file_t *file, n void -ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path) +ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len) { - size_t name, pos, level; - ngx_uint_t i; + size_t i, level; + ngx_uint_t n; - name = file->name.len; - pos = path->name.len + 1; + i = path->name.len + 1; - file->name.data[path->name.len + path->len] = '/'; + file[path->name.len + path->len] = '/'; - for (i = 0; i < 3; i++) { - level = path->level[i]; + for (n = 0; n < 3; n++) { + level = path->level[n]; if (level == 0) { break; } - name -= level; - file->name.data[pos - 1] = '/'; - ngx_memcpy(&file->name.data[pos], &file->name.data[name], level); - pos += level + 1; + len -= level; + file[i - 1] = '/'; + ngx_memcpy(&file[i], &file[len], level); + i += level + 1; } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, - "hashed path: %s", file->name.data); } @@ -425,9 +424,6 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng ngx_err_t err; ngx_uint_t i; ngx_path_t **path; -#if !(NGX_WIN32) - ngx_file_info_t fi; -#endif path = cycle->pathes.elts; for (i = 0; i < cycle->pathes.nelts; i++) { @@ -447,6 +443,8 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng } #if !(NGX_WIN32) + { + ngx_file_info_t fi; if (ngx_file_info((const char *) path[i]->name.data, &fi) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, @@ -474,7 +472,7 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng return NGX_ERROR; } } - + } #endif } @@ -483,6 +481,115 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng ngx_int_t +ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) +{ + ngx_err_t err; + +#if !(NGX_WIN32) + + if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_change_file_access_n " \"%s\" failed", src->data); + err = 0; + goto failed; + } + +#endif + + if (ext->time != -1) { + if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", src->data); + err = 0; + goto failed; + } + } + + if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { + return NGX_OK; + } + + err = ngx_errno; + + if (err == NGX_ENOENT) { + + if (!ext->create_path) { + goto failed; + } + + err = ngx_create_full_path(to->data, ngx_dir_access(ext->access)); + + if (err) { + ngx_log_error(NGX_LOG_CRIT, ext->log, err, + ngx_create_dir_n " \"%s\" failed", to->data); + err = 0; + goto failed; + } + + if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { + return NGX_OK; + } + + err = ngx_errno; + goto failed; + } + +#if (NGX_WIN32) + + if (err == NGX_EEXIST) { + if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) { + + if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { + return NGX_OK; + } + + err = ngx_errno; + + } else { + err = 0; + } + } + +#endif + +failed: + + if (ext->delete_file) { + if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", src->data); + } + } + + if (err) { + ngx_log_error(NGX_LOG_CRIT, ext->log, err, + ngx_rename_file_n " \"%s\" to \"%s\" failed", + src->data, to->data); + } + + return NGX_ERROR; +} + + +/* + * ctx->init_handler() - see ctx->alloc + * ctx->file_handler() - file handler + * ctx->pre_tree_handler() - handler is called before entering directory + * ctx->post_tree_handler() - handler is called after leaving directory + * ctx->spec_handler() - special (socket, FIFO, etc.) file handler + * + * ctx->data - some data structure, it may be the same on all levels, or + * reallocated if ctx->alloc is nonzero + * + * ctx->alloc - a size of data structure that is allocated at every level + * and is initilialized by ctx->init_handler() + * + * ctx->log - a log + * + * on fatal (memory) error handler must return NGX_ABORT to stop walking tree + */ + +ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) { void *data, *prev; diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -57,6 +57,18 @@ typedef struct { } ngx_temp_file_t; +typedef struct { + ngx_uint_t access; + time_t time; + ngx_fd_t fd; + + unsigned create_path:1; + unsigned delete_file:1; + + ngx_log_t *log; +} ngx_ext_rename_file_t; + + typedef struct ngx_tree_ctx_s ngx_tree_ctx_t; typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev); @@ -84,11 +96,13 @@ ssize_t ngx_write_chain_to_temp_file(ngx ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access); -void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path); +void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len); ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path); ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access); ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot); ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); +ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, + ngx_ext_rename_file_t *ext); ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree); void ngx_init_temp_number(void); diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -390,9 +390,7 @@ found: elt->value = names[n].value; elt->len = (u_char) names[n].key.len; - for (i = 0; i < names[n].key.len; i++) { - elt->name[i] = ngx_tolower(names[n].key.data[i]); - } + ngx_strlow(elt->name, names[n].key.data, names[n].key.len); test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } @@ -622,6 +620,24 @@ ngx_hash_key_lc(u_char *data, size_t len } +ngx_uint_t +ngx_hash_strlow(u_char *dst, u_char *src, size_t n) +{ + ngx_uint_t key; + + key = 0; + + while (n--) { + *dst = ngx_tolower(*src); + key = ngx_hash(key, *dst); + dst++; + src++; + } + + return key; +} + + ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type) { @@ -796,12 +812,7 @@ wildcard: /* wildcard hash */ - k = 0; - - for (i = skip; i < last; i++) { - key->data[i] = ngx_tolower(key->data[i]); - k = ngx_hash(k, key->data[i]); - } + k = ngx_hash_strlow(&key->data[skip], &key->data[skip], last - skip); k %= ha->hsize; @@ -839,7 +850,7 @@ wildcard: } name->len = last - 1; - name->data = ngx_palloc(ha->temp_pool, name->len); + name->data = ngx_pnalloc(ha->temp_pool, name->len); if (name->data == NULL) { return NGX_ERROR; } @@ -855,7 +866,7 @@ wildcard: * and ".example.com" to "com.example\0" */ - p = ngx_palloc(ha->temp_pool, last); + p = ngx_pnalloc(ha->temp_pool, last); if (p == NULL) { return NGX_ERROR; } @@ -891,7 +902,7 @@ wildcard: last++; - p = ngx_palloc(ha->temp_pool, last); + p = ngx_pnalloc(ha->temp_pool, last); if (p == NULL) { return NGX_ERROR; } @@ -944,7 +955,7 @@ wildcard: } name->len = last - skip; - name->data = ngx_palloc(ha->temp_pool, name->len); + name->data = ngx_pnalloc(ha->temp_pool, name->len); if (name->data == NULL) { return NGX_ERROR; } diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h --- a/src/core/ngx_hash.h +++ b/src/core/ngx_hash.h @@ -110,6 +110,8 @@ ngx_int_t ngx_hash_wildcard_init(ngx_has #define ngx_hash(key, c) ((ngx_uint_t) key * 31 + c) ngx_uint_t ngx_hash_key(u_char *data, size_t len); ngx_uint_t ngx_hash_key_lc(u_char *data, size_t len); +ngx_uint_t ngx_hash_strlow(u_char *dst, u_char *src, size_t n); + ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type); ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -8,6 +8,54 @@ #include +static size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len); + + +/* AF_INET only */ + +in_addr_t +ngx_inet_addr(u_char *text, size_t len) +{ + u_char *p, c; + in_addr_t addr; + ngx_uint_t octet, n; + + addr = 0; + octet = 0; + n = 0; + + for (p = text; p < text + len; p++) { + + c = *p; + + if (c >= '0' && c <= '9') { + octet = octet * 10 + (c - '0'); + continue; + } + + if (c == '.' && octet < 256) { + addr = (addr << 8) + octet; + octet = 0; + n++; + continue; + } + + return INADDR_NONE; + } + + if (n != 3) { + return INADDR_NONE; + } + + if (octet < 256) { + addr = (addr << 8) + octet; + return htonl(addr); + } + + return INADDR_NONE; +} + + /* * ngx_sock_ntop() and ngx_inet_ntop() may be implemented as * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", however, @@ -18,50 +66,6 @@ * than using FreeBSD libc's snprintf(). */ - -static ngx_inline size_t -ngx_sprint_uchar(u_char *text, u_char c, size_t len) -{ - size_t n; - ngx_uint_t c1, c2; - - n = 0; - - if (len == n) { - return n; - } - - c1 = c / 100; - - if (c1) { - *text++ = (u_char) (c1 + '0'); - n++; - - if (len == n) { - return n; - } - } - - c2 = (c % 100) / 10; - - if (c1 || c2) { - *text++ = (u_char) (c2 + '0'); - n++; - - if (len == n) { - return n; - } - } - - c2 = c % 10; - - *text++ = (u_char) (c2 + '0'); - n++; - - return n; -} - - /* AF_INET only */ size_t @@ -118,6 +122,7 @@ ngx_sock_ntop(int family, struct sockadd return n; } + size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) { @@ -171,6 +176,49 @@ ngx_inet_ntop(int family, void *addr, u_ } +static size_t +ngx_sprint_uchar(u_char *text, u_char c, size_t len) +{ + size_t n; + ngx_uint_t c1, c2; + + n = 0; + + if (len == n) { + return n; + } + + c1 = c / 100; + + if (c1) { + *text++ = (u_char) (c1 + '0'); + n++; + + if (len == n) { + return n; + } + } + + c2 = (c % 100) / 10; + + if (c1 || c2) { + *text++ = (u_char) (c2 + '0'); + n++; + + if (len == n) { + return n; + } + } + + c2 = c % 10; + + *text = (u_char) (c2 + '0'); + n++; + + return n; +} + + /* AF_INET only */ ngx_int_t @@ -225,7 +273,7 @@ ngx_ptocidr(ngx_str_t *text, void *cidr) ngx_int_t -ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u) +ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host, *port_start; size_t len, port_len; @@ -273,12 +321,12 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t return NGX_ERROR; } - u->addrs = ngx_pcalloc(cf->pool, sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } - saun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)); + saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un)); if (saun == NULL) { return NGX_ERROR; } @@ -372,6 +420,9 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t return NGX_ERROR; } + u->port_text.len = port_len; + u->port_text.data = port_start; + } else { port = ngx_atoi(p, len); @@ -408,12 +459,12 @@ no_port: if (u->host.len) { - host = ngx_palloc(cf->temp_pool, u->host.len + 1); - if (host == NULL) { - return NGX_ERROR; - } + host = ngx_alloc(u->host.len + 1, pool->log); + if (host == NULL) { + return NGX_ERROR; + } - (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); u->addr.in_addr = inet_addr((const char *) host); @@ -421,6 +472,7 @@ no_port: h = gethostbyname((const char *) host); if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_free(host); u->err = "host not found"; return NGX_ERROR; } @@ -428,6 +480,8 @@ no_port: u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]); } + ngx_free(host); + } else { u->addr.in_addr = INADDR_ANY; } @@ -453,7 +507,7 @@ no_port: return NGX_ERROR; } - if (ngx_inet_resolve_host(cf, u) != NGX_OK) { + if (ngx_inet_resolve_host(pool, u) != NGX_OK) { return NGX_ERROR; } @@ -462,7 +516,7 @@ no_port: ngx_int_t -ngx_inet_resolve_host(ngx_conf_t *cf, ngx_url_t *u) +ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host; size_t len; @@ -471,7 +525,7 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng struct hostent *h; struct sockaddr_in *sin; - host = ngx_palloc(cf->temp_pool, u->host.len + 1); + host = ngx_alloc(u->host.len + 1, pool->log); if (host == NULL) { return NGX_ERROR; } @@ -485,6 +539,8 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng if (in_addr == INADDR_NONE) { h = gethostbyname((char *) host); + ngx_free(host); + if (h == NULL || h->h_addr_list[0] == NULL) { u->err = "host not found"; return NGX_ERROR; @@ -499,7 +555,7 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(cf->pool, i * sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_peer_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } @@ -508,7 +564,7 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng for (i = 0; h->h_addr_list[i] != NULL; i++) { - sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); if (sin == NULL) { return NGX_ERROR; } @@ -522,7 +578,7 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1; - p = ngx_palloc(cf->pool, len); + p = ngx_pnalloc(pool, len); if (p == NULL) { return NGX_ERROR; } @@ -535,14 +591,16 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng } else { + ngx_free(host); + /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(cf->pool, sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } - sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); if (sin == NULL) { return NGX_ERROR; } @@ -556,7 +614,7 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng u->addrs[0].sockaddr = (struct sockaddr *) sin; u->addrs[0].socklen = sizeof(struct sockaddr_in); - p = ngx_palloc(cf->pool, u->host.len + sizeof(":65536") - 1); + p = ngx_pnalloc(pool, u->host.len + sizeof(":65536") - 1); if (p == NULL) { return NGX_ERROR; } diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -35,6 +35,7 @@ typedef struct { ngx_str_t url; ngx_str_t host; + ngx_str_t port_text; ngx_str_t uri; in_port_t port; @@ -58,11 +59,12 @@ typedef struct { } ngx_url_t; +in_addr_t ngx_inet_addr(u_char *text, size_t len); size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); -ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u); -ngx_int_t ngx_inet_resolve_host(ngx_conf_t *cf, ngx_url_t *u); +ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); +ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u); diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -195,9 +195,6 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo /*********************************/ -#define ngx_log_alloc_log(pool, log) ngx_palloc(pool, log, sizeof(ngx_log_t)) -#define ngx_log_copy_log(new, old) ngx_memcpy(new, old, sizeof(ngx_log_t)) - ngx_log_t *ngx_log_init(void); ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args); char *ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log); diff --git a/src/core/ngx_md5.h b/src/core/ngx_md5.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_md5.h @@ -0,0 +1,40 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_MD5_H_INCLUDED_ +#define _NGX_MD5_H_INCLUDED_ + + +#include +#include + + +#if (NGX_HAVE_OPENSSL_MD5_H) +#include +#else +#include +#endif + + +typedef MD5_CTX ngx_md5_t; + + +#if (NGX_OPENSSL_MD5) + +#define ngx_md5_init MD5_Init +#define ngx_md5_update MD5_Update +#define ngx_md5_final MD5_Final + +#else + +#define ngx_md5_init MD5Init +#define ngx_md5_update MD5Update +#define ngx_md5_final MD5Final + +#endif + + +#endif /* _NGX_MD5_H_INCLUDED_ */ diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -18,22 +18,27 @@ static void ngx_open_file_cache_cleanup(void *data); +static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, + ngx_log_t *log); +static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, + ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_cleanup(void *data); static void ngx_close_cached_file(ngx_open_file_cache_t *cache, - ngx_cached_open_file_t *file, ngx_log_t *log); -static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, - ngx_log_t *log); + ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log); +static void ngx_open_file_del_event(ngx_cached_open_file_t *file); static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, ngx_log_t *log); static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static ngx_cached_open_file_t * + ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, + uint32_t hash); static void ngx_open_file_cache_remove(ngx_event_t *ev); ngx_open_file_cache_t * ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive) { - ngx_rbtree_node_t *sentinel; ngx_pool_cleanup_t *cln; ngx_open_file_cache_t *cache; @@ -42,22 +47,10 @@ ngx_open_file_cache_init(ngx_pool_t *poo return NULL; } - cache->list_head.prev = NULL; - cache->list_head.next = &cache->list_tail; - - cache->list_tail.prev = &cache->list_head; - cache->list_tail.next = NULL; + ngx_rbtree_init(&cache->rbtree, &cache->sentinel, + ngx_open_file_cache_rbtree_insert_value); - sentinel = ngx_palloc(pool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { - return NULL; - } - - ngx_rbtree_sentinel_init(sentinel); - - cache->rbtree.root = sentinel; - cache->rbtree.sentinel = sentinel; - cache->rbtree.insert = ngx_open_file_cache_rbtree_insert_value; + ngx_queue_init(&cache->expire_queue); cache->current = 0; cache->max = max; @@ -80,6 +73,7 @@ ngx_open_file_cache_cleanup(void *data) { ngx_open_file_cache_t *cache = data; + ngx_queue_t *q; ngx_cached_open_file_t *file; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, @@ -87,14 +81,15 @@ ngx_open_file_cache_cleanup(void *data) for ( ;; ) { - file = cache->list_tail.prev; - - if (file == &cache->list_head) { + if (ngx_queue_empty(&cache->expire_queue)) { break; } - file->next->prev = file->prev; - file->prev->next = file->next; + q = ngx_queue_last(&cache->expire_queue); + + file = ngx_queue_data(q, ngx_cached_open_file_t, queue); + + ngx_queue_remove(q); ngx_rbtree_delete(&cache->rbtree, &file->node); @@ -106,7 +101,7 @@ ngx_open_file_cache_cleanup(void *data) if (!file->err && !file->is_dir) { file->close = 1; file->count = 0; - ngx_close_cached_file(cache, file, ngx_cycle->log); + ngx_close_cached_file(cache, file, 0, ngx_cycle->log); } else { ngx_free(file->name); @@ -135,13 +130,12 @@ ngx_open_cached_file(ngx_open_file_cache time_t now; uint32_t hash; ngx_int_t rc; - ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; ngx_pool_cleanup_file_t *clnf; - ngx_open_file_cache_event_t *fev; ngx_open_file_cache_cleanup_t *ofcln; + of->fd = NGX_INVALID_FILE; of->err = 0; if (cache == NULL) { @@ -170,151 +164,144 @@ ngx_open_cached_file(ngx_open_file_cache return NGX_ERROR; } - hash = ngx_crc32_long(name->data, name->len); - - node = cache->rbtree.root; - sentinel = cache->rbtree.sentinel; - now = ngx_time(); - while (node != sentinel) { + hash = ngx_crc32_long(name->data, name->len); + + file = ngx_open_file_lookup(cache, name, hash); + + if (file) { + + file->uses++; + + ngx_queue_remove(&file->queue); - if (hash < node->key) { - node = node->left; - continue; - } + if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) { + + /* file was not used often enough to keep open */ + + rc = ngx_open_and_stat_file(name->data, of, pool->log); - if (hash > node->key) { - node = node->right; - continue; + if (rc != NGX_OK && (of->err == 0 || !of->errors)) { + goto failed; + } + + goto add_event; } - /* hash == node->key */ - - do { - file = (ngx_cached_open_file_t *) node; - - rc = ngx_strcmp(name->data, file->name); - - if (rc == 0) { - - file->next->prev = file->prev; - file->prev->next = file->next; - - if (file->event || now - file->created < of->retest) { - if (file->err == 0) { - of->fd = file->fd; - of->uniq = file->uniq; - of->mtime = file->mtime; - of->size = file->size; - - of->is_dir = file->is_dir; - of->is_file = file->is_file; - of->is_link = file->is_link; - of->is_exec = file->is_exec; + if (file->use_event + || (file->event == NULL + && (of->uniq == 0 || of->uniq == file->uniq) + && now - file->created < of->valid)) + { + if (file->err == 0) { - if (!file->is_dir) { - file->count++; - } - - } else { - of->err = file->err; - } - - goto found; - } + of->fd = file->fd; + of->uniq = file->uniq; + of->mtime = file->mtime; + of->size = file->size; - ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, - "retest open file: %s, fd:%d, c:%d, e:%d", - file->name, file->fd, file->count, file->err); - - if (file->is_dir) { + of->is_dir = file->is_dir; + of->is_file = file->is_file; + of->is_link = file->is_link; + of->is_exec = file->is_exec; - /* - * chances that directory became file are very small - * so test_dir flag allows to use a single ngx_file_info() - * syscall instead of three syscalls - */ - - of->test_dir = 1; + if (!file->is_dir) { + file->count++; + ngx_open_file_add_event(cache, file, of, pool->log); } - rc = ngx_open_and_stat_file(name->data, of, pool->log); + } else { + of->err = file->err; + } + + goto found; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, + "retest open file: %s, fd:%d, c:%d, e:%d", + file->name, file->fd, file->count, file->err); + + if (file->is_dir) { + + /* + * chances that directory became file are very small + * so test_dir flag allows to use a single syscall + * in ngx_file_info() instead of three syscalls + */ + + of->test_dir = 1; + } + + of->fd = file->fd; + of->uniq = file->uniq; - if (rc != NGX_OK && (of->err == 0 || !of->errors)) { - goto failed; + rc = ngx_open_and_stat_file(name->data, of, pool->log); + + if (rc != NGX_OK && (of->err == 0 || !of->errors)) { + goto failed; + } + + if (of->is_dir) { + + if (file->is_dir || file->err) { + goto update; + } + + /* file became directory */ + + } else if (of->err == 0) { /* file */ + + if (file->is_dir || file->err) { + goto add_event; + } + + if (of->uniq == file->uniq) { + + file->count++; + + if (file->event) { + file->use_event = 1; } - if (of->is_dir) { - if (file->is_dir || file->err) { - goto update; - } - - /* file became directory */ - - } else if (of->err == 0) { /* file */ - - if (file->is_dir || file->err) { - goto update; - } + goto renew; + } - if (of->uniq == file->uniq - && of->mtime == file->mtime - && of->size == file->size) - { - if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - name->data); - } - - of->fd = file->fd; - file->count++; - - goto renew; - } + /* file was changed */ - /* file was changed */ - - } else { /* error to cache */ - - if (file->err || file->is_dir) { - goto update; - } - - /* file was removed, etc. */ - } + } else { /* error to cache */ - if (file->count == 0) { - if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - name->data); - } - - goto update; - } - - ngx_rbtree_delete(&cache->rbtree, &file->node); - - cache->current--; - - file->close = 1; - - goto create; + if (file->err || file->is_dir) { + goto update; } - node = (rc < 0) ? node->left : node->right; + /* file was removed, etc. */ + } + + if (file->count == 0) { + + ngx_open_file_del_event(file); - } while (node != sentinel && hash == node->key); + if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + name->data); + } - break; + goto add_event; + } + + ngx_rbtree_delete(&cache->rbtree, &file->node); + + cache->current--; + + file->close = 1; + + goto create; } /* not found */ - file = NULL; - rc = ngx_open_and_stat_file(name->data, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { @@ -349,51 +336,16 @@ create: cache->current++; + file->uses = 1; file->count = 0; + file->event = NULL; + +add_event: + + ngx_open_file_add_event(cache, file, of, pool->log); update: - if (of->events - && (ngx_event_flags & NGX_USE_VNODE_EVENT) - && of->fd != NGX_INVALID_FILE) - { - file->event = ngx_calloc(sizeof(ngx_event_t), pool->log); - if (file->event== NULL) { - goto failed; - } - - fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), pool->log); - if (fev == NULL) { - goto failed; - } - - fev->fd = of->fd; - fev->file = file; - fev->cache = cache; - - file->event->handler = ngx_open_file_cache_remove; - file->event->data = fev; - - /* - * although vnode event may be called while ngx_cycle->poll - * destruction; however, cleanup procedures are run before any - * memory freeing and events will be canceled. - */ - - file->event->log = ngx_cycle->log; - - if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) - != NGX_OK) - { - ngx_free(file->event->data); - ngx_free(file->event); - goto failed; - } - - } else { - file->event = NULL; - } - file->fd = of->fd; file->err = of->err; @@ -422,16 +374,11 @@ found: file->accessed = now; - /* add to the inactive list head */ + ngx_queue_insert_head(&cache->expire_queue, &file->queue); - file->next = cache->list_head.next; - file->next->prev = file; - file->prev = &cache->list_head; - cache->list_head.next = file; - - ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, - "cached open file: %s, fd:%d, c:%d, e:%d", - file->name, file->fd, file->count, file->err); + ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, + "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", + file->name, file->fd, file->count, file->err, file->uses); if (of->err == 0) { @@ -441,6 +388,7 @@ found: ofcln->cache = cache; ofcln->file = file; + ofcln->min_uses = of->min_uses; ofcln->log = pool->log; } @@ -451,18 +399,27 @@ found: failed: - if (file && file->count == 0) { + if (file) { ngx_rbtree_delete(&cache->rbtree, &file->node); cache->current--; - if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", file->name); + if (file->count == 0) { + + if (file->fd != NGX_INVALID_FILE) { + if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file->name); + } + } + + ngx_free(file->name); + ngx_free(file); + + } else { + file->close = 1; } - - ngx_free(file->name); - ngx_free(file); } if (of->fd != NGX_INVALID_FILE) { @@ -482,34 +439,38 @@ ngx_open_and_stat_file(u_char *name, ngx ngx_fd_t fd; ngx_file_info_t fi; - of->fd = NGX_INVALID_FILE; - - if (of->test_dir) { + if (of->fd != NGX_INVALID_FILE) { if (ngx_file_info(name, &fi) == -1) { - of->err = ngx_errno; - - return NGX_ERROR; + goto failed; } - of->uniq = ngx_file_uniq(&fi); - of->mtime = ngx_file_mtime(&fi); - of->size = ngx_file_size(&fi); - of->is_dir = ngx_is_dir(&fi); - of->is_file = ngx_is_file(&fi); - of->is_link = ngx_is_link(&fi); - of->is_exec = ngx_is_exec(&fi); + if (of->uniq == ngx_file_uniq(&fi)) { + goto done; + } + + } else if (of->test_dir) { + + if (ngx_file_info(name, &fi) == -1) { + goto failed; + } if (of->is_dir) { - return NGX_OK; + goto done; } } - fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (!of->log) { + fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + } else { + fd = ngx_open_file(name, NGX_FILE_RDWR, + NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, + NGX_FILE_DEFAULT_ACCESS); + } if (fd == NGX_INVALID_FILE) { - of->err = ngx_errno; - return NGX_ERROR; + goto failed; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { @@ -521,6 +482,8 @@ ngx_open_and_stat_file(u_char *name, ngx ngx_close_file_n " \"%s\" failed", name); } + of->fd = NGX_INVALID_FILE; + return NGX_ERROR; } @@ -530,10 +493,21 @@ ngx_open_and_stat_file(u_char *name, ngx ngx_close_file_n " \"%s\" failed", name); } - fd = NGX_INVALID_FILE; + of->fd = NGX_INVALID_FILE; + + } else { + of->fd = fd; + + if (of->directio <= ngx_file_size(&fi)) { + if (ngx_directio(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_directio_n " \"%s\" failed", name); + } + } } - of->fd = fd; +done: + of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); @@ -543,6 +517,82 @@ ngx_open_and_stat_file(u_char *name, ngx of->is_exec = ngx_is_exec(&fi); return NGX_OK; + +failed: + + of->fd = NGX_INVALID_FILE; + of->err = ngx_errno; + + return NGX_ERROR; +} + + +/* + * we ignore any possible event setting error and + * fallback to usual periodic file retests + */ + +static void +ngx_open_file_add_event(ngx_open_file_cache_t *cache, + ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) +{ + ngx_open_file_cache_event_t *fev; + + if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) + || !of->events + || file->event + || of->fd == NGX_INVALID_FILE + || file->uses < of->min_uses) + { + return; + } + + file->use_event = 0; + + file->event = ngx_calloc(sizeof(ngx_event_t), log); + if (file->event== NULL) { + return; + } + + fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); + if (fev == NULL) { + ngx_free(file->event); + file->event = NULL; + return; + } + + fev->fd = of->fd; + fev->file = file; + fev->cache = cache; + + file->event->handler = ngx_open_file_cache_remove; + file->event->data = fev; + + /* + * although vnode event may be called while ngx_cycle->poll + * destruction, however, cleanup procedures are run before any + * memory freeing and events will be canceled. + */ + + file->event->log = ngx_cycle->log; + + if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) + != NGX_OK) + { + ngx_free(file->event->data); + ngx_free(file->event); + file->event = NULL; + return; + } + + /* + * we do not set file->use_event here because there may be a race + * condition: a file may be deleted between opening the file and + * adding event, so we rely upon event notification only after + * one file revalidation on next file access + */ + + return; } @@ -553,7 +603,7 @@ ngx_open_file_cleanup(void *data) c->file->count--; - ngx_close_cached_file(c->cache, c->file, c->log); + ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log); /* drop one or two expired open files */ ngx_expire_old_cached_files(c->cache, 1, c->log); @@ -562,50 +612,43 @@ ngx_open_file_cleanup(void *data) static void ngx_close_cached_file(ngx_open_file_cache_t *cache, - ngx_cached_open_file_t *file, ngx_log_t *log) + ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log) { - ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0, - "close cached open file: %s, fd:%d, c:%d, %d", - file->name, file->fd, file->count, file->close); + ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0, + "close cached open file: %s, fd:%d, c:%d, u:%d, %d", + file->name, file->fd, file->count, file->uses, file->close); if (!file->close) { file->accessed = ngx_time(); - if (cache->list_head.next != file) { + ngx_queue_remove(&file->queue); - /* delete from inactive list */ - - file->next->prev = file->prev; - file->prev->next = file->next; + ngx_queue_insert_head(&cache->expire_queue, &file->queue); - /* add to the inactive list head */ - - file->next = cache->list_head.next; - file->next->prev = file; - file->prev = &cache->list_head; - cache->list_head.next = file; + if (file->uses >= min_uses || file->count) { + return; } - - return; } - if (file->event) { - (void) ngx_del_event(file->event, NGX_VNODE_EVENT, - file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); - - ngx_free(file->event->data); - ngx_free(file->event); - file->event = NULL; - } + ngx_open_file_del_event(file); if (file->count) { return; } - if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", file->name); + if (file->fd != NGX_INVALID_FILE) { + + if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file->name); + } + + file->fd = NGX_INVALID_FILE; + } + + if (!file->close) { + return; } ngx_free(file->name); @@ -614,10 +657,28 @@ ngx_close_cached_file(ngx_open_file_cach static void +ngx_open_file_del_event(ngx_cached_open_file_t *file) +{ + if (file->event == NULL) { + return; + } + + (void) ngx_del_event(file->event, NGX_VNODE_EVENT, + file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); + + ngx_free(file->event->data); + ngx_free(file->event); + file->event = NULL; + file->use_event = 0; +} + + +static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, ngx_log_t *log) { time_t now; + ngx_queue_t *q; ngx_cached_open_file_t *file; now = ngx_time(); @@ -630,18 +691,19 @@ ngx_expire_old_cached_files(ngx_open_fil while (n < 3) { - file = cache->list_tail.prev; - - if (file == &cache->list_head) { + if (ngx_queue_empty(&cache->expire_queue)) { return; } + q = ngx_queue_last(&cache->expire_queue); + + file = ngx_queue_data(q, ngx_cached_open_file_t, queue); + if (n++ != 0 && now - file->accessed <= cache->inactive) { return; } - file->next->prev = file->prev; - file->prev->next = file->next; + ngx_queue_remove(q); ngx_rbtree_delete(&cache->rbtree, &file->node); @@ -652,7 +714,7 @@ ngx_expire_old_cached_files(ngx_open_fil if (!file->err && !file->is_dir) { file->close = 1; - ngx_close_cached_file(cache, file, log); + ngx_close_cached_file(cache, file, 0, log); } else { ngx_free(file->name); @@ -703,6 +765,51 @@ ngx_open_file_cache_rbtree_insert_value( } +static ngx_cached_open_file_t * +ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_cached_open_file_t *file; + + node = cache->rbtree.root; + sentinel = cache->rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + do { + file = (ngx_cached_open_file_t *) node; + + rc = ngx_strcmp(name->data, file->name); + + if (rc == 0) { + return file; + } + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; + } + + return NULL; +} + + static void ngx_open_file_cache_remove(ngx_event_t *ev) { @@ -712,8 +819,7 @@ ngx_open_file_cache_remove(ngx_event_t * fev = ev->data; file = fev->file; - file->next->prev = file->prev; - file->prev->next = file->next; + ngx_queue_remove(&file->queue); ngx_rbtree_delete(&fev->cache->rbtree, &file->node); @@ -721,10 +827,11 @@ ngx_open_file_cache_remove(ngx_event_t * /* NGX_ONESHOT_EVENT was already deleted */ file->event = NULL; + file->use_event = 0; file->close = 1; - ngx_close_cached_file(fev->cache, file, ev->log); + ngx_close_cached_file(fev->cache, file, 0, ev->log); /* free memory only when fev->cache and fev->file are already not needed */ diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -17,11 +17,15 @@ typedef struct { ngx_file_uniq_t uniq; time_t mtime; off_t size; + off_t directio; ngx_err_t err; - time_t retest; + time_t valid; + + ngx_uint_t min_uses; unsigned test_dir:1; + unsigned log:1; unsigned errors:1; unsigned events:1; @@ -36,8 +40,7 @@ typedef struct ngx_cached_open_file_s n struct ngx_cached_open_file_s { ngx_rbtree_node_t node; - ngx_cached_open_file_t *prev; - ngx_cached_open_file_t *next; + ngx_queue_t queue; u_char *name; time_t created; @@ -49,8 +52,11 @@ struct ngx_cached_open_file_s { off_t size; ngx_err_t err; + uint32_t uses; + unsigned count:24; unsigned close:1; + unsigned use_event:1; unsigned is_dir:1; unsigned is_file:1; @@ -63,8 +69,8 @@ struct ngx_cached_open_file_s { typedef struct { ngx_rbtree_t rbtree; - ngx_cached_open_file_t list_head; - ngx_cached_open_file_t list_tail; + ngx_rbtree_node_t sentinel; + ngx_queue_t expire_queue; ngx_uint_t current; ngx_uint_t max; @@ -75,6 +81,7 @@ typedef struct { typedef struct { ngx_open_file_cache_t *cache; ngx_cached_open_file_t *file; + ngx_uint_t min_uses; ngx_log_t *log; } ngx_open_file_cache_cleanup_t; diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -32,6 +32,7 @@ ngx_output_chain(ngx_output_chain_ctx_t size_t size; ngx_int_t rc, last; ngx_uint_t recycled; + ngx_buf_t *b; ngx_chain_t *cl, *out, **last_out; if (ctx->in == NULL && ctx->busy == NULL) { @@ -161,13 +162,29 @@ ngx_output_chain(ngx_output_chain_ctx_t } } - ctx->buf = ngx_create_temp_buf(ctx->pool, size); - if (ctx->buf == NULL) { + b = ngx_calloc_buf(ctx->pool); + if (b == NULL) { return NGX_ERROR; } - ctx->buf->tag = ctx->tag; - ctx->buf->recycled = recycled; + /* + * allocate block aligned to a disk sector size + * to enable O_DIRECT + */ + + b->start = ngx_pmemalign(ctx->pool, size, 512); + if (b->start == NULL) { + return NGX_ERROR; + } + + b->pos = b->start; + b->last = b->start; + b->end = b->last + size; + b->temporary = 1; + b->tag = ctx->tag; + b->recycled = recycled; + + ctx->buf = b; ctx->allocated++; } } @@ -433,8 +450,11 @@ ngx_chain_writer(void *data, ngx_chain_t { ngx_chain_writer_ctx_t *ctx = data; - off_t size; - ngx_chain_t *cl; + off_t size; + ngx_chain_t *cl; + ngx_connection_t *c; + + c = ctx->connection; for (size = 0; in; in = in->next) { @@ -446,7 +466,7 @@ ngx_chain_writer(void *data, ngx_chain_t size += ngx_buf_size(in->buf); - ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, "chain writer buf fl:%d s:%uO", in->buf->flush, ngx_buf_size(in->buf)); @@ -461,7 +481,7 @@ ngx_chain_writer(void *data, ngx_chain_t ctx->last = &cl->next; } - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, "chain writer in: %p", ctx->out); for (cl = ctx->out; cl; cl = cl->next) { @@ -476,14 +496,13 @@ ngx_chain_writer(void *data, ngx_chain_t size += ngx_buf_size(cl->buf); } - if (size == 0 && !ctx->connection->buffered) { + if (size == 0 && !c->buffered) { return NGX_OK; } - ctx->out = ctx->connection->send_chain(ctx->connection, ctx->out, - ctx->limit); + ctx->out = c->send_chain(c, ctx->out, ctx->limit); - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, "chain writer out: %p", ctx->out); if (ctx->out == NGX_CHAIN_ERROR) { @@ -493,7 +512,7 @@ ngx_chain_writer(void *data, ngx_chain_t if (ctx->out == NULL) { ctx->last = &ctx->out; - if (!ctx->connection->buffered) { + if (!c->buffered) { return NGX_OK; } } diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -8,6 +8,10 @@ #include +static void *ngx_palloc_block(ngx_pool_t *pool, size_t size); +static void *ngx_palloc_large(ngx_pool_t *pool, size_t size); + + ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log) { @@ -18,11 +22,15 @@ ngx_create_pool(size_t size, ngx_log_t * return NULL; } - p->last = (u_char *) p + sizeof(ngx_pool_t); - p->end = (u_char *) p + size; + p->d.last = (u_char *) p + sizeof(ngx_pool_t); + p->d.end = (u_char *) p + size; + p->d.next = NULL; + + size = size - sizeof(ngx_pool_t); + p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL; + p->current = p; p->chain = NULL; - p->next = NULL; p->large = NULL; p->cleanup = NULL; p->log = log; @@ -40,6 +48,8 @@ ngx_destroy_pool(ngx_pool_t *pool) for (c = pool->cleanup; c; c = c->next) { if (c->handler) { + ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, + "run cleanup: %p", c); c->handler(c->data); } } @@ -60,9 +70,9 @@ ngx_destroy_pool(ngx_pool_t *pool) * so we can not use this log while the free()ing the pool */ - for (p = pool, n = pool->next; /* void */; p = n, n = n->next) { + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0, - "free: %p, unused: %uz", p, p->end - p->last); + "free: %p, unused: %uz", p, p->d.end - p->d.last); if (n == NULL) { break; @@ -71,7 +81,7 @@ ngx_destroy_pool(ngx_pool_t *pool) #endif - for (p = pool, n = pool->next; /* void */; p = n, n = n->next) { + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_free(p); if (n == NULL) { @@ -84,82 +94,136 @@ ngx_destroy_pool(ngx_pool_t *pool) void * ngx_palloc(ngx_pool_t *pool, size_t size) { - u_char *m; - ngx_pool_t *p, *n, *current; - ngx_pool_large_t *large; + u_char *m; + ngx_pool_t *p; - if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL - && size <= (size_t) (pool->end - (u_char *) pool) - - (size_t) ngx_align_ptr(sizeof(ngx_pool_t), NGX_ALIGNMENT)) - { + if (size <= pool->max) { + p = pool->current; - current = p; - - for ( ;; ) { - -#if (NGX_HAVE_NONALIGNED) - /* - * allow non-aligned memory blocks for small allocations (1, 2, - * or 3 bytes) and for odd length strings (struct's have aligned - * size) - */ + do { + m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); - if (size < sizeof(int) || (size & 1)) { - m = p->last; + if ((size_t) (p->d.end - m) >= size) { + p->d.last = m + size; - } else -#endif - - { - m = ngx_align_ptr(p->last, NGX_ALIGNMENT); + return m; } - if ((size_t) (p->end - m) >= size) { - p->last = m + size; + p = p->d.next; + + } while (p); + + return ngx_palloc_block(pool, size); + } + + return ngx_palloc_large(pool, size); +} + + +void * +ngx_pnalloc(ngx_pool_t *pool, size_t size) +{ + u_char *m; + ngx_pool_t *p; + + if (size <= pool->max) { + + p = pool->current; + + do { + m = p->d.last; + + if ((size_t) (p->d.end - m) >= size) { + p->d.last = m + size; return m; } - if ((size_t) (p->end - m) < NGX_ALIGNMENT) { - current = p->next; - } + p = p->d.next; + + } while (p); - if (p->next == NULL) { - break; - } + return ngx_palloc_block(pool, size); + } - p = p->next; - pool->current = current; - } + return ngx_palloc_large(pool, size); +} + - /* allocate a new pool block */ - - n = ngx_create_pool((size_t) (p->end - (u_char *) p), p->log); - if (n == NULL) { - return NULL; - } +static void * +ngx_palloc_block(ngx_pool_t *pool, size_t size) +{ + u_char *m; + size_t psize; + ngx_pool_t *p, *new, *current; - pool->current = current ? current : n; + psize = (size_t) (pool->d.end - (u_char *) pool); - p->next = n; - m = ngx_align_ptr(n->last, NGX_ALIGNMENT); - n->last = m + size; - - return m; + m = ngx_alloc(psize, pool->log); + if (m == NULL) { + return NULL; } -#if 0 - p = ngx_memalign(ngx_pagesize, size, pool->log); - if (p == NULL) { - return NULL; + new = (ngx_pool_t *) m; + + new->d.end = m + psize; + new->d.next = NULL; + + m += sizeof(ngx_pool_data_t); + new->d.last = m + size; + + current = pool->current; + + for (p = current; p->d.next; p = p->d.next) { + if ((size_t) (p->d.end - p->d.last) < NGX_ALIGNMENT) { + current = p->d.next; + } } -#else + + p->d.next = new; + + pool->current = current ? current : new; + + return m; +} + + +static void * +ngx_palloc_large(ngx_pool_t *pool, size_t size) +{ + void *p; + ngx_pool_large_t *large; + p = ngx_alloc(size, pool->log); if (p == NULL) { return NULL; } -#endif + + large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + if (large == NULL) { + ngx_free(p); + return NULL; + } + + large->alloc = p; + large->next = pool->large; + pool->large = large; + + return p; +} + + +void * +ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment) +{ + void *p; + ngx_pool_large_t *large; + + p = ngx_memalign(alignment, size, pool->log); + if (p == NULL) { + return NULL; + } large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); if (large == NULL) { @@ -245,8 +309,8 @@ ngx_pool_cleanup_file(void *data) { ngx_pool_cleanup_file_t *c = data; - ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "run cleanup: %p, fd:%d", - c, c->fd); + ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d", + c->fd); if (ngx_close_file(c->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, @@ -262,8 +326,8 @@ ngx_pool_delete_file(void *data) ngx_err_t err; - ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, c->log, 0, "run cleanup: %p, fd:%d %s", - c, c->fd, c->name); + ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s", + c->fd, c->name); if (ngx_delete_file(c->name) == NGX_FILE_ERROR) { err = ngx_errno; diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -43,12 +43,18 @@ struct ngx_pool_large_s { }; -struct ngx_pool_s { +typedef struct { u_char *last; u_char *end; + ngx_pool_t *next; +} ngx_pool_data_t; + + +struct ngx_pool_s { + ngx_pool_data_t d; + size_t max; ngx_pool_t *current; ngx_chain_t *chain; - ngx_pool_t *next; ngx_pool_large_t *large; ngx_pool_cleanup_t *cleanup; ngx_log_t *log; @@ -69,7 +75,9 @@ ngx_pool_t *ngx_create_pool(size_t size, void ngx_destroy_pool(ngx_pool_t *pool); void *ngx_palloc(ngx_pool_t *pool, size_t size); +void *ngx_pnalloc(ngx_pool_t *pool, size_t size); void *ngx_pcalloc(ngx_pool_t *pool, size_t size); +void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment); ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p); diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c --- a/src/core/ngx_parse.c +++ b/src/core/ngx_parse.c @@ -11,15 +11,15 @@ ssize_t ngx_parse_size(ngx_str_t *line) { - u_char last; + u_char unit; size_t len; ssize_t size; ngx_int_t scale; len = line->len; - last = line->data[len - 1]; + unit = line->data[len - 1]; - switch (last) { + switch (unit) { case 'K': case 'k': len--; @@ -50,15 +50,15 @@ ngx_parse_size(ngx_str_t *line) off_t ngx_parse_offset(ngx_str_t *line) { - u_char last; + u_char unit; off_t offset; size_t len; ngx_int_t scale; len = line->len; - last = line->data[len - 1]; + unit = line->data[len - 1]; - switch (last) { + switch (unit) { case 'K': case 'k': len--; @@ -93,12 +93,11 @@ ngx_parse_offset(ngx_str_t *line) ngx_int_t -ngx_parse_time(ngx_str_t *line, ngx_int_t sec) +ngx_parse_time(ngx_str_t *line, ngx_uint_t sec) { - size_t len; - u_char *start, last; + u_char *p, *last; ngx_int_t value, total, scale; - ngx_uint_t max, i; + ngx_uint_t max, valid; enum { st_start = 0, st_year, @@ -112,39 +111,30 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ st_last } step; - - start = line->data; - len = 0; + valid = 0; + value = 0; total = 0; step = sec ? st_start : st_month; + scale = sec ? 1 : 1000; - for (i = 0; /* void */ ; i++) { + p = line->data; + last = p + line->len; - if (i < line->len) { - if (line->data[i] != ' ') { - len++; - continue; - } + while (p < last) { - if (line->data[i] == ' ' && len == 0) { - start = &line->data[i + 1]; - continue; - } + if (*p >= '0' && *p <= '9') { + value = value * 10 + (*p++ - '0'); + valid = 1; + continue; } - if (len == 0) { - break; - } + switch (*p++) { - last = line->data[i - 1]; - - switch (last) { case 'y': if (step > st_start) { return NGX_ERROR; } step = st_year; - len--; max = 68; scale = 60 * 60 * 24 * 365; break; @@ -154,7 +144,6 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_month; - len--; max = 828; scale = 60 * 60 * 24 * 30; break; @@ -164,7 +153,6 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_week; - len--; max = 3550; scale = 60 * 60 * 24 * 7; break; @@ -174,7 +162,6 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_day; - len--; max = 24855; scale = 60 * 60 * 24; break; @@ -184,52 +171,49 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_hour; - len--; max = 596523; scale = 60 * 60; break; case 'm': + if (*p == 's') { + if (sec || step > st_sec) { + return NGX_ERROR; + } + p++; + step = st_msec; + max = 2147483647; + scale = 1; + break; + } + if (step > st_hour) { return NGX_ERROR; } step = st_min; - len--; max = 35791394; scale = 60; break; case 's': - len--; - - if (line->data[i - 2] == 'm') { - if (sec || step > st_sec) { - return NGX_ERROR; - } - step = st_msec; - len--; - max = 2147483647; - scale = 1; - break; - } - if (step > st_min) { return NGX_ERROR; } - step = st_sec; max = 2147483647; scale = 1; break; - default: + case ' ': + if (step > st_min) { + return NGX_ERROR; + } step = st_last; max = 2147483647; scale = 1; - } + break; - value = ngx_atoi(start, len); - if (value == NGX_ERROR) { + default: return NGX_ERROR; } @@ -238,23 +222,27 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ max /= 1000; } - if ((u_int) value > max) { - return NGX_PARSE_LARGE_TIME; + if ((ngx_uint_t) value > max) { + return NGX_ERROR; } total += value * scale; - if ((u_int) total > 2147483647) { - return NGX_PARSE_LARGE_TIME; + if ((ngx_uint_t) total > 2147483647) { + return NGX_ERROR; } - if (i >= line->len) { - break; + value = 0; + scale = sec ? 1 : 1000; + + while (p < last && *p == ' ') { + p++; } - - len = 0; - start = &line->data[i + 1]; } - return total; + if (valid) { + return total + value * scale; + } + + return NGX_ERROR; } diff --git a/src/core/ngx_parse.h b/src/core/ngx_parse.h --- a/src/core/ngx_parse.h +++ b/src/core/ngx_parse.h @@ -17,7 +17,7 @@ ssize_t ngx_parse_size(ngx_str_t *line); off_t ngx_parse_offset(ngx_str_t *line); -ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_int_t sec); +ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t sec); #endif /* _NGX_PARSE_H_INCLUDED_ */ diff --git a/src/core/ngx_queue.c b/src/core/ngx_queue.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_queue.c @@ -0,0 +1,79 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + + +/* + * find the middle queue element if the queue has odd number of elements + * or the first element of the queue's second part otherwise + */ + +ngx_queue_t * +ngx_queue_middle(ngx_queue_t *queue) +{ + ngx_queue_t *middle, *next; + + middle = ngx_queue_head(queue); + + if (middle == ngx_queue_last(queue)) { + return middle; + } + + next = ngx_queue_head(queue); + + for ( ;; ) { + middle = ngx_queue_next(middle); + + next = ngx_queue_next(next); + + if (next == ngx_queue_last(queue)) { + return middle; + } + + next = ngx_queue_next(next); + + if (next == ngx_queue_last(queue)) { + return middle; + } + } +} + + +/* the stable insertion sort */ + +void +ngx_queue_sort(ngx_queue_t *queue, + ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)) +{ + ngx_queue_t *q, *prev, *next; + + q = ngx_queue_head(queue); + + if (q == ngx_queue_last(queue)) { + return; + } + + for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) { + + prev = ngx_queue_prev(q); + next = ngx_queue_next(q); + + ngx_queue_remove(q); + + do { + if (cmp(prev, q) <= 0) { + break; + } + + prev = ngx_queue_prev(prev); + + } while (prev != ngx_queue_sentinel(queue)); + + ngx_queue_insert_after(prev, q); + } +} diff --git a/src/core/ngx_queue.h b/src/core/ngx_queue.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_queue.h @@ -0,0 +1,111 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + + +#ifndef _NGX_QUEUE_H_INCLUDED_ +#define _NGX_QUEUE_H_INCLUDED_ + + +typedef struct ngx_queue_s ngx_queue_t; + +struct ngx_queue_s { + ngx_queue_t *prev; + ngx_queue_t *next; +}; + + +#define ngx_queue_init(q) \ + (q)->prev = q; \ + (q)->next = q + + +#define ngx_queue_empty(h) \ + (h == (h)->prev) + + +#define ngx_queue_insert_head(h, x) \ + (x)->next = (h)->next; \ + (x)->next->prev = x; \ + (x)->prev = h; \ + (h)->next = x + + +#define ngx_queue_insert_after ngx_queue_insert_head + + +#define ngx_queue_insert_tail(h, x) \ + (x)->prev = (h)->prev; \ + (x)->prev->next = x; \ + (x)->next = h; \ + (h)->prev = x + + +#define ngx_queue_head(h) \ + (h)->next + + +#define ngx_queue_last(h) \ + (h)->prev + + +#define ngx_queue_sentinel(h) \ + (h) + + +#define ngx_queue_next(q) \ + (q)->next + + +#define ngx_queue_prev(q) \ + (q)->prev + + +#if (NGX_DEBUG) + +#define ngx_queue_remove(x) \ + (x)->next->prev = (x)->prev; \ + (x)->prev->next = (x)->next; \ + (x)->prev = NULL; \ + (x)->next = NULL + +#else + +#define ngx_queue_remove(x) \ + (x)->next->prev = (x)->prev; \ + (x)->prev->next = (x)->next + +#endif + + +#define ngx_queue_split(h, q, n) \ + (n)->prev = (h)->prev; \ + (n)->prev->next = n; \ + (n)->next = q; \ + (h)->prev = (q)->prev; \ + (h)->prev->next = h; \ + (q)->prev = n; + + +#define ngx_queue_add(h, n) \ + (h)->prev->next = (n)->next; \ + (n)->next->prev = (h)->prev; \ + (h)->prev = (n)->prev; \ + (h)->prev->next = h; + + +#define ngx_queue_data(q, type, link) \ + (type *) ((u_char *) q - offsetof(type, link)) + + +ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue); +void ngx_queue_sort(ngx_queue_t *queue, + ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)); + + +#endif /* _NGX_QUEUE_H_INCLUDED_ */ diff --git a/src/core/ngx_rbtree.c b/src/core/ngx_rbtree.c --- a/src/core/ngx_rbtree.c +++ b/src/core/ngx_rbtree.c @@ -97,28 +97,20 @@ void ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { + ngx_rbtree_node_t **p; + for ( ;; ) { - if (node->key < temp->key) { - - if (temp->left == sentinel) { - temp->left = node; - break; - } - - temp = temp->left; + p = (node->key < temp->key) ? &temp->left : &temp->right; - } else { + if (*p == sentinel) { + break; + } - if (temp->right == sentinel) { - temp->right = node; - break; - } - - temp = temp->right; - } + temp = *p; } + *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; @@ -130,6 +122,8 @@ void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { + ngx_rbtree_node_t **p; + for ( ;; ) { /* @@ -139,29 +133,20 @@ ngx_rbtree_insert_timer_value(ngx_rbtree * The comparison takes into account that overflow. */ - if ((ngx_rbtree_key_int_t) node->key - (ngx_rbtree_key_int_t) temp->key - < 0) - { - /* node->key < temp->key */ + /* node->key < temp->key */ - if (temp->left == sentinel) { - temp->left = node; - break; - } + p = ((ngx_rbtree_key_int_t) node->key - (ngx_rbtree_key_int_t) temp->key + < 0) + ? &temp->left : &temp->right; - temp = temp->left; - - } else { + if (*p == sentinel) { + break; + } - if (temp->right == sentinel) { - temp->right = node; - break; - } - - temp = temp->right; - } + temp = *p; } + *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; @@ -257,13 +242,13 @@ ngx_rbtree_delete(ngx_thread_volatile ng if (subst->right != sentinel) { subst->right->parent = subst; } + } - /* DEBUG stuff */ - node->left = NULL; - node->right = NULL; - node->parent = NULL; - node->key = 0; - } + /* DEBUG stuff */ + node->left = NULL; + node->right = NULL; + node->parent = NULL; + node->key = 0; if (red) { return; diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -40,6 +40,13 @@ struct ngx_rbtree_s { }; +#define ngx_rbtree_init(tree, s, i) \ + ngx_rbtree_sentinel_init(s); \ + (tree)->root = s; \ + (tree)->sentinel = s; \ + (tree)->insert = i + + void ngx_rbtree_insert(ngx_thread_volatile ngx_rbtree_t *tree, ngx_rbtree_node_t *node); void ngx_rbtree_delete(ngx_thread_volatile ngx_rbtree_t *tree, diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -114,6 +114,39 @@ ngx_regex_exec(ngx_regex_t *re, ngx_str_ } +ngx_int_t +ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) +{ + ngx_int_t n; + ngx_uint_t i; + ngx_regex_elt_t *re; + + re = a->elts; + + for (i = 0; i < a->nelts; i++) { + + n = ngx_regex_exec(re[i].regex, s, NULL, 0); + + if (n == NGX_REGEX_NO_MATCHED) { + continue; + } + + if (n < 0) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + ngx_regex_exec_n " failed: %d on \"%V\" using \"%s\"", + n, s, re[i].name); + return NGX_ERROR; + } + + /* match */ + + return NGX_OK; + } + + return NGX_DECLINED; +} + + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -20,12 +20,20 @@ typedef pcre ngx_regex_t; +typedef struct { + ngx_regex_t *regex; + u_char *name; +} ngx_regex_elt_t; + + void ngx_regex_init(void); ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, ngx_pool_t *pool, ngx_str_t *err); ngx_int_t ngx_regex_capture_count(ngx_regex_t *re); ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_int_t size); +ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); + #define ngx_regex_exec_n "pcre_exec()" #define ngx_regex_capture_count_n "pcre_fullinfo()" diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_resolver.c @@ -0,0 +1,2133 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +#define NGX_RESOLVER_UDP_SIZE 4096 + + +typedef struct { + u_char ident_hi; + u_char ident_lo; + u_char flags_hi; + u_char flags_lo; + u_char nqs_hi; + u_char nqs_lo; + u_char nan_hi; + u_char nan_lo; + u_char nns_hi; + u_char nns_lo; + u_char nar_hi; + u_char nar_lo; +} ngx_resolver_query_t; + + +typedef struct { + u_char type_hi; + u_char type_lo; + u_char class_hi; + u_char class_lo; +} ngx_resolver_qs_t; + + +typedef struct { + u_char type_hi; + u_char type_lo; + u_char class_hi; + u_char class_lo; + u_char ttl[4]; + u_char len_hi; + u_char len_lo; +} ngx_resolver_an_t; + + +ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc); + + +static void ngx_resolver_cleanup(void *data); +static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); +static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, + ngx_resolver_ctx_t *ctx); +static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); +static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn); +static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn, + ngx_resolver_ctx_t *ctx); +static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, + ngx_resolver_ctx_t *ctx); +static void ngx_resolver_resend_handler(ngx_event_t *ev); +static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); +static void ngx_resolver_read_response(ngx_event_t *rev); +static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, + size_t n); +static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans); +static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); +static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, + ngx_str_t *name, uint32_t hash); +static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r, + in_addr_t addr); +static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, + u_char *buf, u_char *src, u_char *last); +static void ngx_resolver_timeout_handler(ngx_event_t *ev); +static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn); +static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size); +static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size); +static void ngx_resolver_free(ngx_resolver_t *r, void *p); +static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); +static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); + + +/* STUB: ngx_peer_addr_t * */ + +ngx_resolver_t * +ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr) +{ + ngx_resolver_t *r; + ngx_pool_cleanup_t *cln; + ngx_udp_connection_t *uc; + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_resolver_cleanup; + + r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); + if (r == NULL) { + return NULL; + } + + cln->data = r; + + r->event = ngx_calloc(sizeof(ngx_event_t), cf->log); + if (r->event == NULL) { + return NULL; + } + + ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, + ngx_resolver_rbtree_insert_value); + + ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel, + ngx_rbtree_insert_value); + + ngx_queue_init(&r->name_resend_queue); + ngx_queue_init(&r->addr_resend_queue); + + ngx_queue_init(&r->name_expire_queue); + ngx_queue_init(&r->addr_expire_queue); + + r->event->handler = ngx_resolver_resend_handler; + r->event->data = r; + r->event->log = cf->cycle->new_log; + r->ident = -1; + + r->resend_timeout = 5; + r->expire = 30; + r->valid = 300; + + r->log = cf->cycle->new_log; + r->log_level = NGX_LOG_ALERT; + + if (addr) { + uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log); + if (uc == NULL) { + return NULL; + } + + r->udp_connection = uc; + + uc->sockaddr = addr->sockaddr; + uc->socklen = addr->socklen; + uc->server = addr->name; + uc->log = cf->cycle->new_log; + } + + return r; +} + + +static void +ngx_resolver_cleanup(void *data) +{ + ngx_resolver_t *r = data; + + if (r) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "cleanup resolver"); + + ngx_resolver_cleanup_tree(r, &r->name_rbtree); + + ngx_resolver_cleanup_tree(r, &r->addr_rbtree); + + if (r->event) { + ngx_free(r->event); + } + + if (r->udp_connection) { + if (r->udp_connection->connection) { + ngx_close_connection(r->udp_connection->connection); + } + + ngx_free(r->udp_connection); + } + + ngx_free(r); + } +} + + +static void +ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree) +{ + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; + + while (tree->root != tree->sentinel) { + + rn = (ngx_resolver_node_t *) ngx_rbtree_min(tree->root, tree->sentinel); + + ngx_queue_remove(&rn->queue); + + for (ctx = rn->waiting; ctx; ctx = next) { + next = ctx->next; + + if (ctx->event) { + ngx_resolver_free(r, ctx->event); + } + + ngx_resolver_free(r, ctx); + } + + ngx_rbtree_delete(tree, &rn->node); + + ngx_resolver_free_node(r, rn); + } +} + + +ngx_resolver_ctx_t * +ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) +{ + in_addr_t addr; + ngx_resolver_ctx_t *ctx; + + if (temp) { + addr = ngx_inet_addr(temp->name.data, temp->name.len); + + if (addr != INADDR_NONE) { + temp->resolver = r; + temp->state = NGX_OK; + temp->naddrs = 1; + temp->addrs = &temp->addr; + temp->addr = addr; + temp->quick = 1; + + return temp; + } + } + + if (r->udp_connection == NULL) { + return NGX_NO_RESOLVER; + } + + ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t)); + + if (ctx) { + ctx->resolver = r; + } + + return ctx; +} + + +ngx_int_t +ngx_resolve_name(ngx_resolver_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_resolver_t *r; + + r = ctx->resolver; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve: \"%V\"", &ctx->name); + + if (ctx->quick) { + ctx->handler(ctx); + return NGX_OK; + } + + /* lock name mutex */ + + rc = ngx_resolve_name_locked(r, ctx); + + if (rc == NGX_OK) { + return NGX_OK; + } + + /* unlock name mutex */ + + if (rc == NGX_AGAIN) { + return NGX_OK; + } + + /* NGX_ERROR */ + + if (ctx->event) { + ngx_resolver_free(r, ctx->event); + } + + ngx_resolver_free(r, ctx); + + return NGX_ERROR; +} + + +void +ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) +{ + uint32_t hash; + ngx_resolver_t *r; + ngx_resolver_ctx_t *w, **p; + ngx_resolver_node_t *rn; + + r = ctx->resolver; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve name done: %i", ctx->state); + + if (ctx->quick) { + return; + } + + if (ctx->event && ctx->event->timer_set) { + ngx_del_timer(ctx->event); + } + + /* lock name mutex */ + + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + + hash = ngx_crc32_short(ctx->name.data, ctx->name.len); + + rn = ngx_resolver_lookup_name(r, &ctx->name, hash); + + if (rn) { + p = &rn->waiting; + w = rn->waiting; + + while (w) { + if (w == ctx) { + *p = w->next; + + goto done; + } + + p = &w->next; + w = w->next; + } + } + + ngx_log_error(NGX_LOG_ALERT, r->log, 0, + "could not cancel %V resolving", &ctx->name); + } + +done: + + ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue); + + /* unlock name mutex */ + + /* lock alloc mutex */ + + if (ctx->event) { + ngx_resolver_free_locked(r, ctx->event); + } + + ngx_resolver_free_locked(r, ctx); + + /* unlock alloc mutex */ +} + + +/* NGX_RESOLVE_A only */ + +static ngx_int_t +ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +{ + uint32_t hash; + in_addr_t addr, *addrs; + ngx_int_t rc; + ngx_uint_t naddrs; + ngx_resolver_ctx_t *next; + ngx_resolver_node_t *rn; + + hash = ngx_crc32_short(ctx->name.data, ctx->name.len); + + rn = ngx_resolver_lookup_name(r, &ctx->name, hash); + + if (rn) { + + if (rn->valid >= ngx_time()) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached"); + + ngx_queue_remove(&rn->queue); + + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + + naddrs = rn->naddrs; + + if (naddrs) { + + /* NGX_RESOLVE_A answer */ + + if (naddrs != 1) { + addr = 0; + addrs = ngx_resolver_dup(r, rn->u.addrs, + naddrs * sizeof(in_addr_t)); + if (addrs == NULL) { + return NGX_ERROR; + } + + } else { + addr = rn->u.addr; + addrs = NULL; + } + + ctx->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ + + do { + ctx->state = NGX_OK; + ctx->naddrs = naddrs; + ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; + ctx->addr = addr; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); + + if (addrs) { + ngx_resolver_free(r, addrs); + } + + return NGX_OK; + } + + /* NGX_RESOLVE_CNAME */ + + if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { + + ctx->name.len = rn->cnlen; + ctx->name.data = rn->u.cname; + + return ngx_resolve_name_locked(r, ctx); + } + + ctx->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ + + do { + ctx->state = NGX_RESOLVE_NXDOMAIN; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); + + return NGX_OK; + } + + if (rn->waiting) { + + ctx->next = rn->waiting; + rn->waiting = ctx; + + return NGX_AGAIN; + } + + ngx_queue_remove(&rn->queue); + + /* lock alloc mutex */ + + ngx_resolver_free_locked(r, rn->query); + rn->query = NULL; + + if (rn->cnlen) { + ngx_resolver_free_locked(r, rn->u.cname); + } + + if (rn->naddrs > 1) { + ngx_resolver_free_locked(r, rn->u.addrs); + } + + /* unlock alloc mutex */ + + } else { + + rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); + if (rn == NULL) { + return NGX_ERROR; + } + + rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len); + if (rn->name == NULL) { + ngx_resolver_free(r, rn); + return NGX_ERROR; + } + + rn->node.key = hash; + rn->nlen = (u_short) ctx->name.len; + rn->query = NULL; + + ngx_rbtree_insert(&r->name_rbtree, &rn->node); + } + + rc = ngx_resolver_create_name_query(rn, ctx); + + if (rc == NGX_ERROR) { + goto failed; + } + + if (rc == NGX_DECLINED) { + ngx_rbtree_delete(&r->name_rbtree, &rn->node); + + ngx_resolver_free(r, rn->query); + ngx_resolver_free(r, rn->name); + ngx_resolver_free(r, rn); + + ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->handler(ctx); + + return NGX_OK; + } + + if (ngx_resolver_send_query(r, rn) != NGX_OK) { + goto failed; + } + + if (ctx->event == NULL) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + goto failed; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + } + + if (ngx_queue_empty(&r->name_resend_queue)) { + ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); + } + + rn->expire = ngx_time() + r->resend_timeout; + + ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); + + rn->cnlen = 0; + rn->naddrs = 0; + rn->valid = 0; + rn->waiting = ctx; + + ctx->state = NGX_AGAIN; + + return NGX_AGAIN; + +failed: + + ngx_rbtree_delete(&r->name_rbtree, &rn->node); + + if (rn->query) { + ngx_resolver_free(r, rn->query); + } + + ngx_resolver_free(r, rn->name); + + ngx_resolver_free(r, rn); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_resolve_addr(ngx_resolver_ctx_t *ctx) +{ + ngx_resolver_t *r; + ngx_resolver_node_t *rn; + + r = ctx->resolver; + + ctx->addr = ntohl(ctx->addr); + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, ctx->addr); + + if (rn) { + + if (rn->valid >= ngx_time()) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached"); + + ngx_queue_remove(&rn->queue); + + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue); + + ctx->name.len = rn->nlen; + ctx->name.data = ngx_resolver_dup(r, rn->name, rn->nlen); + if (ctx->name.data == NULL) { + goto failed; + } + + /* unlock addr mutex */ + + ctx->state = NGX_OK; + + ctx->handler(ctx); + + ngx_resolver_free(r, ctx->name.data); + + return NGX_OK; + } + + if (rn->waiting) { + + ctx->next = rn->waiting; + rn->waiting = ctx; + + return NGX_AGAIN; + } + + ngx_queue_remove(&rn->queue); + + ngx_resolver_free(r, rn->query); + rn->query = NULL; + + } else { + rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); + if (rn == NULL) { + goto failed; + } + + rn->node.key = ctx->addr; + rn->query = NULL; + + ngx_rbtree_insert(&r->addr_rbtree, &rn->node); + } + + if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) { + goto failed; + } + + if (ngx_resolver_send_query(r, rn) != NGX_OK) { + goto failed; + } + + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + goto failed; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + + if (ngx_queue_empty(&r->addr_resend_queue)) { + ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); + } + + rn->expire = ngx_time() + r->resend_timeout; + + ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue); + + rn->cnlen = 0; + rn->naddrs = 0; + rn->name = NULL; + rn->nlen = 0; + rn->valid = 0; + rn->waiting = ctx; + + /* unlock addr mutex */ + + ctx->state = NGX_AGAIN; + + return NGX_OK; + +failed: + + if (rn) { + ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + + if (rn->query) { + ngx_resolver_free(r, rn->query); + } + + ngx_resolver_free(r, rn); + } + + /* unlock addr mutex */ + + if (ctx->event) { + ngx_resolver_free(r, ctx->event); + } + + ngx_resolver_free(r, ctx); + + return NGX_ERROR; +} + + +void +ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) +{ + in_addr_t addr; + ngx_resolver_t *r; + ngx_resolver_ctx_t *w, **p; + ngx_resolver_node_t *rn; + + r = ctx->resolver; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve addr done: %i", ctx->state); + + if (ctx->event && ctx->event->timer_set) { + ngx_del_timer(ctx->event); + } + + /* lock addr mutex */ + + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + + rn = ngx_resolver_lookup_addr(r, ctx->addr); + + if (rn) { + p = &rn->waiting; + w = rn->waiting; + + while (w) { + if (w == ctx) { + *p = w->next; + + goto done; + } + + p = &w->next; + w = w->next; + } + } + + addr = ntohl(ctx->addr); + + ngx_log_error(NGX_LOG_ALERT, r->log, 0, + "could not cancel %ud.%ud.%ud.%ud resolving", + (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); + } + +done: + + ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue); + + /* unlock addr mutex */ + + /* lock alloc mutex */ + + if (ctx->event) { + ngx_resolver_free_locked(r, ctx->event); + } + + ngx_resolver_free_locked(r, ctx); + + /* unlock alloc mutex */ +} + + +static void +ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue) +{ + time_t now; + ngx_uint_t i; + ngx_queue_t *q; + ngx_resolver_node_t *rn; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire"); + + now = ngx_time(); + + for (i = 0; i < 2; i++) { + if (ngx_queue_empty(queue)) { + return; + } + + q = ngx_queue_last(queue); + + rn = ngx_queue_data(q, ngx_resolver_node_t, queue); + + if (now <= rn->expire) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name); + + ngx_queue_remove(q); + + ngx_rbtree_delete(tree, &rn->node); + + ngx_resolver_free_node(r, rn); + } +} + + +static ngx_int_t +ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) +{ + ssize_t n; + ngx_udp_connection_t *uc; + + uc = r->udp_connection; + + if (uc->connection == NULL) { + if (ngx_udp_connect(uc) != NGX_OK) { + return NGX_ERROR; + } + + uc->connection->data = r; + uc->connection->read->handler = ngx_resolver_read_response; + uc->connection->read->resolver = 1; + } + + n = ngx_send(uc->connection, rn->query, rn->qlen); + + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) rn->qlen) { + ngx_log_error(NGX_LOG_CRIT, uc->log, 0, "send() incomplete"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_resolver_resend_handler(ngx_event_t *ev) +{ + time_t timer, atimer, ntimer; + ngx_resolver_t *r; + + r = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver resend handler"); + + /* lock name mutex */ + + ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue); + + /* unlock name mutex */ + + /* lock addr mutex */ + + atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue); + + /* unlock addr mutex */ + + if (ntimer == 0) { + timer = atimer; + + } else if (atimer == 0) { + timer = ntimer; + + } else { + timer = (atimer < ntimer) ? atimer : ntimer; + } + + if (timer) { + ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000)); + } +} + + +static time_t +ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue) +{ + time_t now; + ngx_queue_t *q; + ngx_resolver_node_t *rn; + + now = ngx_time(); + + for ( ;; ) { + if (ngx_queue_empty(queue)) { + return 0; + } + + q = ngx_queue_last(queue); + + rn = ngx_queue_data(q, ngx_resolver_node_t, queue); + + if (now < rn->expire) { + return rn->expire - now; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver resend \"%*s\" %p", + (size_t) rn->nlen, rn->name, rn->waiting); + + ngx_queue_remove(q); + + if (rn->waiting) { + + if (ngx_resolver_send_query(r, rn) == NGX_OK) { + + rn->expire = now + r->resend_timeout; + + ngx_queue_insert_head(queue, &rn->queue); + } + + continue; + } + + ngx_rbtree_delete(tree, &rn->node); + + ngx_resolver_free_node(r, rn); + } +} + + +static void +ngx_resolver_read_response(ngx_event_t *rev) +{ + ssize_t n; + ngx_connection_t *c; + u_char buf[NGX_RESOLVER_UDP_SIZE]; + + c = rev->data; + + do { + n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); + + if (n < 0) { + return; + } + + ngx_resolver_process_response(c->data, buf, n); + + } while (rev->ready); +} + + +static void +ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) +{ + char *err; + size_t len; + ngx_uint_t i, ident, flags, code, nqs, nan, qtype, qclass; + ngx_resolver_qs_t *qs; + ngx_resolver_query_t *query; + + if ((size_t) n < sizeof(ngx_resolver_query_t) + 1) { + goto short_response; + } + + query = (ngx_resolver_query_t *) buf; + + ident = (query->ident_hi << 8) + query->ident_lo; + flags = (query->flags_hi << 8) + query->flags_lo; + nqs = (query->nqs_hi << 8) + query->nqs_lo; + nan = (query->nan_hi << 8) + query->nan_lo; + + ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver DNS response %ui fl:%04Xui %ui/%ui/%ui/%ui", + ident, flags, nqs, nan, + (query->nns_hi << 8) + query->nns_lo, + (query->nar_hi << 8) + query->nar_lo); + + if (!(flags & 0x8000)) { + ngx_log_error(r->log_level, r->log, 0, + "invalid DNS response %ui fl:%04Xui", ident, flags); + return; + } + + code = flags & 0x7f; + + if (code == NGX_RESOLVE_FORMERR || code > NGX_RESOLVE_REFUSED) { + ngx_log_error(r->log_level, r->log, 0, + "DNS error (%ui: %s), query id:%ui", + code, ngx_resolver_strerror(code), ident); + return; + } + + if (nqs != 1) { + err = "invalid number of questions in DNS response"; + goto done; + } + + i = sizeof(ngx_resolver_query_t); + + while (i < (ngx_uint_t) n) { + if (buf[i] == '\0') { + goto found; + } + + len = buf[i]; + i += 1 + len; + } + + goto short_response; + +found: + + if (i++ == 0) { + err = "zero-length domain name in DNS response"; + goto done; + } + + if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t)) + > (ngx_uint_t) n) + { + goto short_response; + } + + qs = (ngx_resolver_qs_t *) &buf[i]; + + qtype = (qs->type_hi << 8) + qs->type_lo; + qclass = (qs->class_hi << 8) + qs->class_lo; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver DNS response qt:%ui cl:%ui", qtype, qclass); + + if (qclass != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unknown query class %ui in DNS response", qclass); + return; + } + + switch (qtype) { + + case NGX_RESOLVE_A: + + ngx_resolver_process_a(r, buf, n, ident, code, nan, + i + sizeof(ngx_resolver_qs_t)); + + break; + + case NGX_RESOLVE_PTR: + + ngx_resolver_process_ptr(r, buf, n, ident, code, nan); + + break; + + default: + ngx_log_error(r->log_level, r->log, 0, + "unknown query type %ui in DNS response", qtype); + return; + } + + return; + +short_response: + + err = "short dns response"; + +done: + + ngx_log_error(r->log_level, r->log, 0, err); + + return; +} + + +static void +ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans) +{ + char *err; + u_char *cname; + size_t len; + uint32_t hash; + in_addr_t addr, *addrs; + ngx_str_t name; + ngx_uint_t qtype, qident, naddrs, a, i, n, start; + ngx_resolver_an_t *an; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; + + if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name); + + hash = ngx_crc32_short(name.data, name.len); + + /* lock name mutex */ + + rn = ngx_resolver_lookup_name(r, &name, hash); + + if (rn == NULL || rn->query == NULL) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + goto failed; + } + + qident = (rn->query[0] << 8) + rn->query[1]; + + if (ident != qident) { + ngx_log_error(r->log_level, r->log, 0, + "wrong ident %ui response for %V, expect %ui", + ident, &name, qident); + goto failed; + } + + if (code == 0 && nan == 0) { + code = 3; /* NXDOMAIN */ + } + + if (code) { + next = rn->waiting; + rn->waiting = NULL; + + ngx_queue_remove(&rn->queue); + + ngx_rbtree_delete(&r->name_rbtree, &rn->node); + + ngx_resolver_free_node(r, rn); + + /* unlock name mutex */ + + while (next) { + ctx = next; + ctx->state = code; + next = ctx->next; + + ctx->handler(ctx); + } + + return; + } + + i = ans; + naddrs = 0; + addr = 0; + addrs = NULL; + cname = NULL; + qtype = 0; + + for (a = 0; a < nan; a++) { + + start = i; + + while (i < last) { + + if (buf[i] & 0xc0) { + i += 2; + goto found; + } + + if (buf[i] == 0) { + i++; + goto test_length; + } + + i += 1 + buf[i]; + } + + goto short_response; + + test_length: + + if (i - start < 2) { + err = "invalid name in dns response"; + goto invalid; + } + + found: + + if (i + sizeof(ngx_resolver_an_t) >= last) { + goto short_response; + } + + an = (ngx_resolver_an_t *) &buf[i]; + + qtype = (an->type_hi << 8) + an->type_lo; + len = (an->len_hi << 8) + an->len_lo; + + if (qtype == NGX_RESOLVE_A) { + + i += sizeof(ngx_resolver_an_t); + + if (i + len > last) { + goto short_response; + } + + addr = htonl((buf[i] << 24) + (buf[i + 1] << 16) + + (buf[i + 2] << 8) + (buf[i + 3])); + + naddrs++; + + i += len; + + } else if (qtype == NGX_RESOLVE_CNAME) { + cname = &buf[i] + sizeof(ngx_resolver_an_t); + i += sizeof(ngx_resolver_an_t) + len; + + } else if (qtype == NGX_RESOLVE_DNAME) { + i += sizeof(ngx_resolver_an_t) + len; + + } else { + ngx_log_error(r->log_level, r->log, 0, + "unexpected qtype %ui", qtype); + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver naddrs:%ui cname:%p", naddrs, cname); + + if (naddrs) { + + if (naddrs == 1) { + rn->u.addr = addr; + + } else { + + addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t)); + if (addrs == NULL) { + return; + } + + n = 0; + i = ans; + + for (a = 0; a < nan; a++) { + + for ( ;; ) { + + if (buf[i] & 0xc0) { + i += 2; + goto ok; + } + + if (buf[i] == 0) { + i++; + goto ok; + } + + i += 1 + buf[i]; + } + + ok: + + an = (ngx_resolver_an_t *) &buf[i]; + + qtype = (an->type_hi << 8) + an->type_lo; + len = (an->len_hi << 8) + an->len_lo; + + i += sizeof(ngx_resolver_an_t); + + if (qtype == NGX_RESOLVE_A) { + + addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16) + + (buf[i + 2] << 8) + (buf[i + 3])); + + if (n == naddrs) { + break; + } + } + + i += len; + } + + rn->u.addrs = addrs; + + addrs = ngx_resolver_dup(r, rn->u.addrs, + naddrs * sizeof(in_addr_t)); + if (addrs == NULL) { + return; + } + } + + rn->naddrs = (u_short) naddrs; + + ngx_queue_remove(&rn->queue); + + rn->valid = ngx_time() + r->valid; + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + + next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ + + while (next) { + ctx = next; + ctx->state = NGX_OK; + ctx->naddrs = naddrs; + ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; + ctx->addr = addr; + next = ctx->next; + + ctx->handler(ctx); + } + + if (naddrs) { + ngx_resolver_free(r, addrs); + } + + return; + + } else if (cname) { + + /* CNAME only */ + + if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver cname:\"%V\"", &name); + + ngx_queue_remove(&rn->queue); + + rn->cnlen = (u_short) name.len; + rn->u.cname = name.data; + rn->valid = ngx_time() + r->valid; + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + + ctx = rn->waiting; + rn->waiting = NULL; + + if (ctx) { + ctx->name = name; + + (void) ngx_resolve_name_locked(r, ctx); + } + + return; + } + + ngx_log_error(r->log_level, r->log, 0, + "no A or CNAME types in DNS responses, unknown query type: %ui", + qtype); + return; + +short_response: + + err = "short dns response"; + +invalid: + + /* unlock name mutex */ + + ngx_log_error(r->log_level, r->log, 0, err); + + return; + +failed: + + /* unlock name mutex */ + + return; +} + + +static void +ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan) +{ + char *err; + size_t len; + in_addr_t addr; + ngx_int_t digit; + ngx_str_t name; + ngx_uint_t i, mask, qtype, qclass, qident; + ngx_resolver_an_t *an; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; + + if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) { + goto invalid_in_addr_arpa; + } + + addr = 0; + i = 12; + + for (mask = 0; mask < 32; mask += 8) { + len = buf[i++]; + + digit = ngx_atoi(&buf[i], len); + if (digit == NGX_ERROR || digit > 255) { + goto invalid_in_addr_arpa; + } + + addr += digit << mask; + i += len; + } + + if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) { + goto invalid_in_addr_arpa; + } + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, addr); + + if (rn == NULL || rn->query == NULL) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %ud.%ud.%ud.%ud", + (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); + goto failed; + } + + qident = (rn->query[0] << 8) + rn->query[1]; + + if (ident != qident) { + ngx_log_error(r->log_level, r->log, 0, + "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui", + ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff, qident); + goto failed; + } + + if (code == 0 && nan == 0) { + code = 3; /* NXDOMAIN */ + } + + if (code) { + next = rn->waiting; + rn->waiting = NULL; + + ngx_queue_remove(&rn->queue); + + ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + + ngx_resolver_free_node(r, rn); + + /* unlock addr mutex */ + + while (next) { + ctx = next; + ctx->state = code; + next = ctx->next; + + ctx->handler(ctx); + } + + return; + } + + i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t); + + if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) { + goto short_response; + } + + /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */ + + if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) { + err = "invalid in-addr.arpa name in DNS response"; + goto invalid; + } + + an = (ngx_resolver_an_t *) &buf[i + 2]; + + qtype = (an->type_hi << 8) + an->type_lo; + qclass = (an->class_hi << 8) + an->class_lo; + len = (an->len_hi << 8) + an->len_lo; + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver qt:%ui cl:%ui len:%uz", qtype, qclass, len); + + i += 2 + sizeof(ngx_resolver_an_t); + + if (i + len > (ngx_uint_t) n) { + goto short_response; + } + + len -= 2; + + if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name); + + if (len != (size_t) rn->nlen || ngx_strncmp(name.data, rn->name, len) != 0) + { + ngx_resolver_free(r, rn->name); + rn->name = name.data; + + name.data = ngx_resolver_dup(r, rn->name, len); + if (name.data == NULL) { + goto failed; + } + } + + ngx_queue_remove(&rn->queue); + + rn->valid = ngx_time() + r->valid; + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue); + + next = rn->waiting; + rn->waiting = NULL; + + /* unlock addr mutex */ + + while (next) { + ctx = next; + ctx->state = NGX_OK; + ctx->name = name; + next = ctx->next; + + ctx->handler(ctx); + } + + ngx_resolver_free(r, name.data); + + return; + +invalid_in_addr_arpa: + + ngx_log_error(r->log_level, r->log, 0, + "invalid in-addr.arpa name in DNS response"); + return; + +short_response: + + err = "short DNS response"; + +invalid: + + /* unlock addr mutex */ + + ngx_log_error(r->log_level, r->log, 0, err); + + return; + +failed: + + /* unlock addr mutex */ + + return; +} + + +static ngx_resolver_node_t * +ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash) +{ + ngx_int_t rc; + size_t len; + ngx_rbtree_node_t *node, *sentinel; + ngx_resolver_node_t *rn; + + node = r->name_rbtree.root; + sentinel = r->name_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + do { + rn = (ngx_resolver_node_t *) node; + + len = (name->len > (size_t) rn->nlen) ? rn->nlen : name->len; + + rc = ngx_strncmp(name->data, rn->name, len); + + if (rc == 0) { + return rn; + } + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; + } + + /* not found */ + + return NULL; +} + + +static ngx_resolver_node_t * +ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr) +{ + ngx_rbtree_node_t *node, *sentinel; + + node = r->addr_rbtree.root; + sentinel = r->addr_rbtree.sentinel; + + while (node != sentinel) { + + if (addr < node->key) { + node = node->left; + continue; + } + + if (addr > node->key) { + node = node->right; + continue; + } + + /* addr == node->key */ + + return (ngx_resolver_node_t *) node; + } + + /* not found */ + + return NULL; +} + + +static void +ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + size_t len; + ngx_rbtree_node_t **p; + ngx_resolver_node_t *rn, *rn_temp; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + rn = (ngx_resolver_node_t *) node; + rn_temp = (ngx_resolver_node_t *) temp; + + len = (rn->nlen > rn_temp->nlen) ? rn_temp->nlen : rn->nlen; + + p = (ngx_strncmp(rn->name, rn_temp->name, len) < 0) + ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +static ngx_int_t +ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) +{ + u_char *p, *s; + size_t len; + ngx_uint_t ident; + ngx_resolver_qs_t *qs; + ngx_resolver_query_t *query; + + len = sizeof(ngx_resolver_query_t) + + 1 + ctx->name.len + 1 + sizeof(ngx_resolver_qs_t); + + p = ngx_resolver_calloc(ctx->resolver, len); + if (p == NULL) { + return NGX_ERROR; + } + + rn->qlen = (u_short) len; + rn->query = p; + + query = (ngx_resolver_query_t *) p; + + ident = ngx_random(); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, + "resolve: \"%V\" %i", &ctx->name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + + /* recursion query */ + query->flags_hi = 1; query->flags_lo = 0; + + /* one question */ + query->nqs_hi = 0; query->nqs_lo = 1; + query->nan_hi = 0; query->nan_lo = 0; + query->nns_hi = 0; query->nns_lo = 0; + query->nar_hi = 0; query->nar_lo = 0; + + p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1; + + qs = (ngx_resolver_qs_t *) p; + + /* query type */ + qs->type_hi = 0; qs->type_lo = (u_char) ctx->type; + + /* IP query class */ + qs->class_hi = 0; qs->class_lo = 1; + + /* convert "www.example.com" to "\3www\7example\3com\0" */ + + len = 0; + p--; + *p-- = '\0'; + + for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) { + if (*s != '.') { + *p = *s; + len++; + + } else { + if (len == 0) { + return NGX_DECLINED; + } + + *p = (u_char) len; + len = 0; + } + + p--; + } + + *p = (u_char) len; + + return NGX_OK; +} + + +/* AF_INET only */ + +static ngx_int_t +ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) +{ + u_char *p, *d; + size_t len; + ngx_int_t n; + ngx_uint_t ident; + ngx_resolver_query_t *query; + + len = sizeof(ngx_resolver_query_t) + + sizeof(".255.255.255.255.in-addr.arpa.") - 1 + + sizeof(ngx_resolver_qs_t); + + p = ngx_resolver_calloc(ctx->resolver, len); + if (p == NULL) { + return NGX_ERROR; + } + + rn->query = p; + query = (ngx_resolver_query_t *) p; + + ident = ngx_random(); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + + /* recursion query */ + query->flags_hi = 1; query->flags_lo = 0; + + /* one question */ + query->nqs_hi = 0; query->nqs_lo = 1; + query->nan_hi = 0; query->nan_lo = 0; + query->nns_hi = 0; query->nns_lo = 0; + query->nar_hi = 0; query->nar_lo = 0; + + p += sizeof(ngx_resolver_query_t); + + 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; + } + + /* query type "PTR", IP query class */ + ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18); + + rn->qlen = (u_short) + (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t) + - rn->query); + + return NGX_OK; +} + + +static ngx_int_t +ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, + u_char *last) +{ + char *err; + u_char *p, *dst; + ssize_t len; + ngx_uint_t i, n; + + p = src; + len = -1; + + /* + * compression pointers allow to create endless loop, so we set limit; + * 128 pointers should be enough to store 255-byte name + */ + + for (i = 0; i < 128; i++) { + n = *p++; + + if (n == 0) { + goto done; + } + + if (n & 0xc0) { + n = (n & 0x3f << 8) + *p; + p = &buf[n]; + + } else { + len += 1 + n; + p = &p[n]; + } + + if (p >= last) { + err = "name is out of response"; + goto invalid; + } + } + + err = "compression pointers loop"; + +invalid: + + ngx_log_error(r->log_level, r->log, 0, err); + + return NGX_ERROR; + +done: + + if (name == NULL) { + return NGX_OK; + } + + dst = ngx_resolver_alloc(r, len); + if (dst == NULL) { + return NGX_ERROR; + } + + name->data = dst; + + n = *src++; + + for ( ;; ) { + if (n != 0xc0) { + ngx_memcpy(dst, src, n); + dst += n; + src += n; + + n = *src++; + + if (n != 0) { + *dst++ = '.'; + } + + } else { + n = (n & 0x3f << 8) + *src; + src = &buf[n]; + + n = *src++; + } + + if (n == 0) { + name->len = dst - name->data; + return NGX_OK; + } + } +} + + +static void +ngx_resolver_timeout_handler(ngx_event_t *ev) +{ + ngx_resolver_ctx_t *ctx; + + ctx = ev->data; + + ctx->state = NGX_RESOLVE_TIMEDOUT; + + ctx->handler(ctx); +} + + +static void +ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) +{ + /* lock alloc mutex */ + + if (rn->query) { + ngx_resolver_free_locked(r, rn->query); + } + + if (rn->name) { + ngx_resolver_free_locked(r, rn->name); + } + + if (rn->cnlen) { + ngx_resolver_free_locked(r, rn->u.cname); + } + + if (rn->naddrs > 1) { + ngx_resolver_free_locked(r, rn->u.addrs); + } + + ngx_resolver_free_locked(r, rn); + + /* unlock alloc mutex */ +} + + +static void * +ngx_resolver_alloc(ngx_resolver_t *r, size_t size) +{ + u_char *p; + + /* lock alloc mutex */ + + p = ngx_alloc(size, r->log); + + /* unlock alloc mutex */ + + return p; +} + + +static void * +ngx_resolver_calloc(ngx_resolver_t *r, size_t size) +{ + u_char *p; + + p = ngx_resolver_alloc(r, size); + + if (p) { + ngx_memzero(p, size); + } + + return p; +} + + +static void +ngx_resolver_free(ngx_resolver_t *r, void *p) +{ + /* lock alloc mutex */ + + ngx_free(p); + + /* unlock alloc mutex */ +} + + +static void +ngx_resolver_free_locked(ngx_resolver_t *r, void *p) +{ + ngx_free(p); +} + + +static void * +ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size) +{ + void *dst; + + dst = ngx_resolver_alloc(r, size); + + if (dst == NULL) { + return dst; + } + + ngx_memcpy(dst, src, size); + + return dst; +} + + +char * +ngx_resolver_strerror(ngx_int_t err) +{ + static char *errors[] = { + "Format error", /* FORMERR */ + "Server failure", /* SERVFAIL */ + "Host not found", /* NXDOMAIN */ + "Unimplemented", /* NOTIMP */ + "Operation refused" /* REFUSED */ + }; + + if (err > 0 && err < 6) { + return errors[err - 1]; + } + + if (err == NGX_RESOLVE_TIMEDOUT) { + return "Operation timed out"; + } + + return "Unknown error"; +} + + +ngx_int_t +ngx_udp_connect(ngx_udp_connection_t *uc) +{ + int rc; + ngx_int_t event; + ngx_event_t *rev, *wev; + ngx_socket_t s; + ngx_connection_t *c; + + s = ngx_socket(AF_INET, SOCK_DGRAM, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, uc->log, 0, "UDP socket %d", s); + + if (s == -1) { + ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + c = ngx_get_connection(s, uc->log); + + if (c == NULL) { + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_close_socket_n "failed"); + } + + return NGX_ERROR; + } + + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_nonblocking_n " failed"); + + ngx_free_connection(c); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; + } + + rev = c->read; + wev = c->write; + + rev->log = uc->log; + wev->log = uc->log; + + uc->connection = c; + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + +#if (NGX_THREADS) + + /* TODO: lock event when call completion handler */ + + rev->lock = &c->lock; + wev->lock = &c->lock; + rev->own_lock = &c->lock; + wev->own_lock = &c->lock; + +#endif + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, uc->log, 0, + "connect to %V, fd:%d #%d", &uc->server, s, c->number); + + rc = connect(s, uc->sockaddr, uc->socklen); + + /* TODO: aio, iocp */ + + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, uc->log, ngx_socket_errno, + "connect() to %V failed", &uc->server); + + return NGX_ERROR; + } + + /* UDP sockets are always ready to write */ + wev->ready = 1; + + if (ngx_add_event) { + + event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? + /* kqueue, epoll */ NGX_CLEAR_EVENT: + /* select, poll, /dev/poll */ NGX_LEVEL_EVENT; + /* eventport event type has no meaning: oneshot only */ + + if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { + return NGX_ERROR; + } + + } else { + /* rtsig */ + + if (ngx_add_conn(c) == NGX_ERROR) { + return NGX_ERROR; + } + } + + return NGX_OK; +} diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_resolver.h @@ -0,0 +1,148 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + + +#ifndef _NGX_RESOLVER_H_INCLUDED_ +#define _NGX_RESOLVER_H_INCLUDED_ + + +#define NGX_RESOLVE_A 1 +#define NGX_RESOLVE_CNAME 5 +#define NGX_RESOLVE_PTR 12 +#define NGX_RESOLVE_MX 15 +#define NGX_RESOLVE_TXT 16 +#define NGX_RESOLVE_DNAME 39 + +#define NGX_RESOLVE_FORMERR 1 +#define NGX_RESOLVE_SERVFAIL 2 +#define NGX_RESOLVE_NXDOMAIN 3 +#define NGX_RESOLVE_NOTIMP 4 +#define NGX_RESOLVE_REFUSED 5 +#define NGX_RESOLVE_TIMEDOUT NGX_ETIMEDOUT + + +#define NGX_NO_RESOLVER (void *) -1 + +#define NGX_RESOLVER_MAX_RECURSION 50 + + +typedef struct { + ngx_connection_t *connection; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t server; + ngx_log_t *log; +} ngx_udp_connection_t; + + +typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t; + +typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx); + + +typedef struct { + ngx_rbtree_node_t node; + ngx_queue_t queue; + + /* PTR: resolved name, A: name to resolve */ + u_char *name; + + u_short nlen; + u_short qlen; + + u_char *query; + + union { + in_addr_t addr; + in_addr_t *addrs; + u_char *cname; + } u; + + u_short naddrs; + u_short cnlen; + + time_t expire; + time_t valid; + + ngx_resolver_ctx_t *waiting; +} ngx_resolver_node_t; + + +typedef struct { + /* has to be pointer because of "incomplete type" */ + ngx_event_t *event; + + /* TODO: DNS peers balancer */ + /* STUB */ + ngx_udp_connection_t *udp_connection; + + ngx_log_t *log; + + /* ident must be after 3 pointers */ + ngx_int_t ident; + + ngx_rbtree_t name_rbtree; + ngx_rbtree_node_t name_sentinel; + + ngx_rbtree_t addr_rbtree; + ngx_rbtree_node_t addr_sentinel; + + ngx_queue_t name_resend_queue; + ngx_queue_t addr_resend_queue; + + ngx_queue_t name_expire_queue; + ngx_queue_t addr_expire_queue; + + time_t resend_timeout; + time_t expire; + time_t valid; + + ngx_uint_t log_level; +} ngx_resolver_t; + + +struct ngx_resolver_ctx_s { + ngx_resolver_ctx_t *next; + ngx_resolver_t *resolver; + ngx_udp_connection_t *udp_connection; + + /* ident must be after 3 pointers */ + ngx_int_t ident; + + ngx_int_t state; + ngx_int_t type; + ngx_str_t name; + + ngx_uint_t naddrs; + in_addr_t *addrs; + in_addr_t addr; + + /* TODO: DNS peers balancer ctx */ + + ngx_resolver_handler_pt handler; + void *data; + ngx_msec_t timeout; + + ngx_uint_t quick; /* unsigned quick:1; */ + ngx_uint_t recursion; + ngx_event_t *event; +}; + + +ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr); +ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, + ngx_resolver_ctx_t *temp); +ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx); +void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx); +ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx); +void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx); +char *ngx_resolver_strerror(ngx_int_t err); + + +#endif /* _NGX_RESOLVER_H_INCLUDED_ */ diff --git a/src/core/ngx_sha1.h b/src/core/ngx_sha1.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_sha1.h @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_SHA1_H_INCLUDED_ +#define _NGX_SHA1_H_INCLUDED_ + + +#include +#include + + +#if (NGX_HAVE_OPENSSL_SHA1_H) +#include +#else +#include +#endif + + +typedef SHA_CTX ngx_sha1_t; + + +#define ngx_sha1_init SHA1_Init +#define ngx_sha1_update SHA1_Update +#define ngx_sha1_final SHA1_Final + + +#endif /* _NGX_SHA1_H_INCLUDED_ */ diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -58,9 +58,22 @@ #if (NGX_DEBUG_MALLOC) -#define ngx_slab_junk(p, size) ngx_memset(p, 0xD0, size) + +#define ngx_slab_junk(p, size) ngx_memset(p, 0xD0, size) + #else + +#if (NGX_FREEBSD) + +#define ngx_slab_junk(p, size) \ + if (ngx_freebsd_debug_malloc) ngx_memset(p, 0xD0, size) + +#else + #define ngx_slab_junk(p, size) + +#endif + #endif static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool, @@ -111,10 +124,7 @@ ngx_slab_init(ngx_slab_pool_t *pool) p += n * sizeof(ngx_slab_page_t); - /* STUB: possible overflow on 64-bit platform */ - pages = (ngx_uint_t) ((uint64_t) size * ngx_pagesize - / (ngx_pagesize + sizeof(ngx_slab_page_t)) - / ngx_pagesize); + pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t))); ngx_memzero(p, pages * sizeof(ngx_slab_page_t)); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -8,6 +8,17 @@ #include +void +ngx_strlow(u_char *dst, u_char *src, size_t n) +{ + while (n--) { + *dst = ngx_tolower(*src); + dst++; + src++; + } +} + + u_char * ngx_cpystrn(u_char *dst, u_char *src, size_t n) { @@ -34,7 +45,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t { u_char *dst; - dst = ngx_palloc(pool, src->len); + dst = ngx_pnalloc(pool, src->len); if (dst == NULL) { return NULL; } @@ -63,6 +74,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t * %V ngx_str_t * * %v ngx_variable_value_t * * %s null-terminated string + * %*s length and string * %Z '\0' * %N '\n' * %c char @@ -112,7 +124,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c * but icc issues the warning */ int d; - size_t len; + size_t len, slen; uint32_t ui32; int64_t i64; uint64_t ui64; @@ -146,6 +158,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c sign = 1; hexadecimal = 0; max_width = 0; + slen = (size_t) -1; p = temp + NGX_INT64_LEN; @@ -179,6 +192,11 @@ ngx_vsnprintf(u_char *buf, size_t max, c fmt++; continue; + case '*': + slen = va_arg(args, size_t); + fmt++; + continue; + default: break; } @@ -214,9 +232,17 @@ ngx_vsnprintf(u_char *buf, size_t max, c case 's': p = va_arg(args, u_char *); - while (*p && buf < last) { - *buf++ = *p++; + if (slen == (size_t) -1) { + while (*p && buf < last) { + *buf++ = *p++; + } + + } else { + len = (buf + slen < last) ? slen : (size_t) (last - buf); + + buf = ngx_cpymem(buf, p, len); } + fmt++; continue; @@ -442,7 +468,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c /* - * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII string only, + * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only, * and implement our own ngx_strcasecmp()/ngx_strncasecmp() * to avoid libc locale overhead. Besides, we use the ngx_uint_t's * instead of the u_char's, because they are slightly faster. @@ -503,6 +529,95 @@ ngx_strncasecmp(u_char *s1, u_char *s2, } +u_char * +ngx_strnstr(u_char *s1, char *s2, size_t len) +{ + u_char c1, c2; + size_t n; + + c2 = *(u_char *) s2++; + + n = ngx_strlen(s2); + + do { + do { + if (len-- == 0) { + return NULL; + } + + c1 = *s1++; + + if (c1 == 0) { + return NULL; + } + + } while (c1 != c2); + + if (n > len) { + return NULL; + } + + } while (ngx_strncmp(s1, (u_char *) s2, n) != 0); + + return --s1; +} + + +/* + * ngx_strstrn() and ngx_strcasestrn() are intended to search for static + * substring with known length in null-terminated string. The argument n + * must be length of the second substring - 1. + */ + +u_char * +ngx_strstrn(u_char *s1, char *s2, size_t n) +{ + u_char c1, c2; + + c2 = *(u_char *) s2++; + + do { + do { + c1 = *s1++; + + if (c1 == 0) { + return NULL; + } + + } while (c1 != c2); + + } while (ngx_strncmp(s1, (u_char *) s2, n) != 0); + + return --s1; +} + + +u_char * +ngx_strcasestrn(u_char *s1, char *s2, size_t n) +{ + ngx_uint_t c1, c2; + + c2 = (ngx_uint_t) *s2++; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + + do { + do { + c1 = (ngx_uint_t) *s1++; + + if (c1 == 0) { + return NULL; + } + + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + + } while (c1 != c2); + + } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0); + + return --s1; +} + + ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n) { @@ -727,18 +842,17 @@ ngx_hextoi(u_char *line, size_t n) } -void -ngx_md5_text(u_char *text, u_char *md5) +u_char * +ngx_hex_dump(u_char *dst, u_char *src, size_t len) { - int i; static u_char hex[] = "0123456789abcdef"; - for (i = 0; i < 16; i++) { - *text++ = hex[md5[i] >> 4]; - *text++ = hex[md5[i] & 0xf]; + while (len--) { + *dst++ = hex[*src >> 4]; + *dst++ = hex[*src++ & 0xf]; } - *text = '\0'; + return dst; } @@ -849,16 +963,16 @@ ngx_decode_base64(ngx_str_t *dst, ngx_st /* - * ngx_utf_decode() decodes two and more bytes UTF sequences only + * ngx_utf8_decode() decodes two and more bytes UTF sequences only * the return values: * 0x80 - 0x10ffff valid character - * 0x10ffff - 0xfffffffd invalid sequence + * 0x110000 - 0xfffffffd invalid sequence * 0xfffffffe incomplete sequence * 0xffffffff error */ uint32_t -ngx_utf_decode(u_char **p, size_t n) +ngx_utf8_decode(u_char **p, size_t n) { size_t len; uint32_t u, i, valid; @@ -915,31 +1029,26 @@ ngx_utf_decode(u_char **p, size_t n) size_t -ngx_utf_length(u_char *p, size_t n) +ngx_utf8_length(u_char *p, size_t n) { - u_char c; - size_t len; - ngx_uint_t i; + u_char c, *last; + size_t len; - for (len = 0, i = 0; i < n; len++, i++) { + last = p + n; - c = p[i]; + for (len = 0; p < last; len++) { + + c = *p; if (c < 0x80) { + p++; continue; } - if (c >= 0xc0) { - for (c <<= 1; c & 0x80; c <<= 1) { - i++; - } - - continue; + if (ngx_utf8_decode(&p, n) > 0x10ffff) { + /* invalid UTF-8 */ + return n; } - - /* invalid utf */ - - return n; } return len; @@ -947,36 +1056,45 @@ ngx_utf_length(u_char *p, size_t n) u_char * -ngx_utf_cpystrn(u_char *dst, u_char *src, size_t n) +ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len) { - u_char c; + u_char c, *next; if (n == 0) { return dst; } - for ( /* void */ ; --n; dst++, src++) { + while (--n) { c = *src; *dst = c; if (c < 0x80) { - if (*dst != '\0') { + + if (c != '\0') { + dst++; + src++; + len--; + continue; } return dst; } - if (c >= 0xc0) { - for (c <<= 1; c & 0x80; c <<= 1) { - *++dst = *++src; - } + next = src; - continue; + if (ngx_utf8_decode(&next, len) > 0x10ffff) { + /* invalid UTF-8 */ + break; } - /* invalid utf */ + len--; + + while (src < next) { + *++dst = *++src; + len--; + } } *dst = '\0'; @@ -1058,7 +1176,7 @@ ngx_escape_uri(u_char *dst, u_char *src, 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x000000a5, /* 0000 0000 0000 0000 0000 0000 1010 0101 */ + 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ @@ -1154,7 +1272,9 @@ ngx_unescape_uri(u_char **dst, u_char ** switch (state) { case sw_usual: - if (ch == '?' && type == NGX_UNESCAPE_URI) { + if (ch == '?' + && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT))) + { *d++ = ch; goto done; } @@ -1197,7 +1317,7 @@ ngx_unescape_uri(u_char **dst, u_char ** if (ch >= '0' && ch <= '9') { ch = (u_char) ((decoded << 4) + ch - '0'); - if (type == NGX_UNESCAPE_URI) { + if (type & NGX_UNESCAPE_REDIRECT) { if (ch > '%' && ch < 0x7f) { *d++ = ch; break; @@ -1217,7 +1337,17 @@ ngx_unescape_uri(u_char **dst, u_char ** if (c >= 'a' && c <= 'f') { ch = (u_char) ((decoded << 4) + c - 'a' + 10); - if (type == NGX_UNESCAPE_URI) { + if (type & NGX_UNESCAPE_URI) { + if (ch == '?') { + *d++ = ch; + goto done; + } + + *d++ = ch; + break; + } + + if (type & NGX_UNESCAPE_REDIRECT) { if (ch == '?') { *d++ = ch; goto done; @@ -1250,30 +1380,97 @@ done: } +uintptr_t +ngx_escape_html(u_char *dst, u_char *src, size_t size) +{ + u_char ch; + ngx_uint_t i, len; + + if (dst == NULL) { + + len = 0; + + for (i = 0; i < size; i++) { + switch (*src++) { + + case '<': + len += sizeof("<") - 2; + break; + + case '>': + len += sizeof(">") - 2; + break; + + case '&': + len += sizeof("&") - 2; + break; + + default: + break; + } + } + + return (uintptr_t) len; + } + + for (i = 0; i < size; i++) { + ch = *src++; + + switch (ch) { + + case '<': + *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';'; + break; + + case '>': + *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';'; + break; + + case '&': + *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p'; + *dst++ = ';'; + break; + + default: + *dst++ = ch; + break; + } + } + + return (uintptr_t) dst; +} + + /* ngx_sort() is implemented as insertion sort because we need stable sort */ void ngx_sort(void *base, size_t n, size_t size, - int (*cmp)(const void *, const void *)) + ngx_int_t (*cmp)(const void *, const void *)) { - u_char *p1, *p2; - u_char buf[256]; + u_char *p1, *p2, *p; + + p = ngx_alloc(size, ngx_cycle->log); + if (p == NULL) { + return; + } for (p1 = (u_char *) base + size; p1 < (u_char *) base + n * size; p1 += size) { - ngx_memcpy(buf, p1, size); + ngx_memcpy(p, p1, size); for (p2 = p1; - p2 > (u_char *) base && cmp(p2 - size, buf) > 0; + p2 > (u_char *) base && cmp(p2 - size, p) > 0; p2 -= size) { ngx_memcpy(p2, p2 - size, size); } - ngx_memcpy(p2, buf, size); + ngx_memcpy(p2, p, size); } + + ngx_free(p); } diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -25,11 +25,12 @@ typedef struct { typedef struct { - unsigned len:29; + unsigned len:28; unsigned valid:1; - unsigned no_cachable:1; + unsigned no_cacheable:1; unsigned not_found:1; + unsigned escape:1; u_char *data; } ngx_variable_value_t; @@ -42,6 +43,8 @@ typedef struct { #define ngx_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c) #define ngx_toupper(c) (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c) +void ngx_strlow(u_char *dst, u_char *src, size_t n); + #define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n) @@ -114,7 +117,7 @@ ngx_copy(u_char *dst, u_char *src, size_ /* msvc and icc7 compile memcmp() to the inline loop */ -#define ngx_memcmp memcmp +#define ngx_memcmp(s1, s2, n) memcmp((const char *) s1, (const char *) s2, n) u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n); @@ -126,6 +129,11 @@ u_char *ngx_vsnprintf(u_char *buf, size_ ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2); ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n); +u_char *ngx_strnstr(u_char *s1, char *s2, size_t n); + +u_char *ngx_strstrn(u_char *s1, char *s2, size_t n); +u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n); + ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2); @@ -136,7 +144,7 @@ off_t ngx_atoof(u_char *line, size_t n); time_t ngx_atotm(u_char *line, size_t n); ngx_int_t ngx_hextoi(u_char *line, size_t n); -void ngx_md5_text(u_char *text, u_char *md5); +u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len); #define ngx_base64_encoded_length(len) (((len + 2) / 3) * 4) @@ -145,27 +153,30 @@ void ngx_md5_text(u_char *text, 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); -uint32_t ngx_utf_decode(u_char **p, size_t n); -size_t ngx_utf_length(u_char *p, size_t n); -u_char *ngx_utf_cpystrn(u_char *dst, u_char *src, size_t n); +uint32_t ngx_utf8_decode(u_char **p, size_t n); +size_t ngx_utf8_length(u_char *p, size_t n); +u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len); -#define NGX_ESCAPE_URI 0 -#define NGX_ESCAPE_ARGS 1 -#define NGX_ESCAPE_HTML 2 -#define NGX_ESCAPE_REFRESH 3 -#define NGX_ESCAPE_MEMCACHED 4 -#define NGX_ESCAPE_MAIL_AUTH 5 +#define NGX_ESCAPE_URI 0 +#define NGX_ESCAPE_ARGS 1 +#define NGX_ESCAPE_HTML 2 +#define NGX_ESCAPE_REFRESH 3 +#define NGX_ESCAPE_MEMCACHED 4 +#define NGX_ESCAPE_MAIL_AUTH 5 -#define NGX_UNESCAPE_URI 1 +#define NGX_UNESCAPE_URI 1 +#define NGX_UNESCAPE_REDIRECT 2 uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type); void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type); +uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size); + void ngx_sort(void *base, size_t n, size_t size, - int (*cmp)(const void *, const void *)); + ngx_int_t (*cmp)(const void *, const void *)); #define ngx_qsort qsort diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -203,70 +203,84 @@ ngx_http_cookie_time(u_char *buf, time_t void ngx_gmtime(time_t t, ngx_tm_t *tp) { - ngx_int_t sec, min, hour, mday, mon, year, wday, yday, days; + ngx_int_t yday; + ngx_uint_t n, sec, min, hour, mday, mon, year, wday, days, leap; - days = t / 86400; + /* the calculation is valid for positive time_t only */ + + n = (ngx_uint_t) t; + + days = n / 86400; /* Jaunary 1, 1970 was Thursday */ + wday = (4 + days) % 7; - t %= 86400; - hour = t / 3600; - t %= 3600; - min = t / 60; - sec = t % 60; + n %= 86400; + hour = n / 3600; + n %= 3600; + min = n / 60; + sec = n % 60; - /* the algorithm based on Gauss's formula */ + /* + * the algorithm based on Gauss' formula, + * see src/http/ngx_http_parse_time.c + */ + /* days since March 1, 1 BC */ days = days - (31 + 28) + 719527; - year = days * 400 / (365 * 400 + 100 - 4 + 1); + /* + * The "days" should be adjusted to 1 only, however, some March 1st's go + * to previous year, so we adjust them to 2. This causes also shift of the + * last Feburary days to next year, but we catch the case when "yday" + * becomes negative. + */ + + year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1); + yday = days - (365 * year + year / 4 - year / 100 + year / 400); - mon = (yday + 31) * 12 / 367; - mday = yday - (mon * 367 / 12 - 31); + if (yday < 0) { + leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0)); + yday = 365 + leap + yday; + year--; + } - mon += 2; + /* + * The empirical formula that maps "yday" to month. + * There are at least 10 variants, some of them are: + * mon = (yday + 31) * 15 / 459 + * mon = (yday + 31) * 17 / 520 + * mon = (yday + 31) * 20 / 612 + */ + + mon = (yday + 31) * 10 / 306; + + /* the Gauss' formula that evaluates days before the month */ + + mday = yday - (367 * mon / 12 - 30) + 1; if (yday >= 306) { + year++; + mon -= 10; + /* * there is no "yday" in Win32 SYSTEMTIME * * yday -= 306; */ - year++; - mon -= 12; - - if (mday == 0) { - /* Jaunary 31 */ - mon = 1; - mday = 31; + } else { - } else if (mon == 2) { - - if ((year % 4 == 0) && (year % 100 || (year % 400 == 0))) { - if (mday > 29) { - mon = 3; - mday -= 29; - } + mon += 2; - } else if (mday > 28) { - mon = 3; - mday -= 28; - } - } -/* - * there is no "yday" in Win32 SYSTEMTIME - * - * } else { - * yday += 31 + 28; - * - * if ((year % 4 == 0) && (year % 100 || (year % 400 == 0))) { - * yday++; - * } - */ + /* + * there is no "yday" in Win32 SYSTEMTIME + * + * yday += 31 + 28 + leap; + */ } tp->ngx_tm_sec = (ngx_tm_sec_t) sec; diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c --- a/src/event/modules/ngx_aio_module.c +++ b/src/event/modules/ngx_aio_module.c @@ -28,6 +28,7 @@ static ngx_int_t ngx_aio_process_events( ngx_os_io_t ngx_os_aio = { ngx_aio_read, ngx_aio_read_chain, + NULL, ngx_aio_write, ngx_aio_write_chain, 0 diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -143,15 +143,12 @@ ngx_module_t ngx_epoll_module = { static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) { - ngx_event_conf_t *ecf; ngx_epoll_conf_t *epcf; - ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); - epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module); if (ep == -1) { - ep = epoll_create(ecf->connections / 2); + ep = epoll_create(cycle->connection_n / 2); if (ep == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -40,11 +40,15 @@ typedef struct port_notify { void *portnfy_user; /* user defined */ } port_notify_t; +#if (__FreeBSD_version < 700005) + typedef struct itimerspec { /* definition per POSIX.4 */ struct timespec it_interval;/* timer period */ struct timespec it_value; /* timer expiration */ } itimerspec_t; +#endif + int port_create(void) { return -1; @@ -106,7 +110,7 @@ static char *ngx_eventport_init_conf(ngx static int ep = -1; static port_event_t *event_list; static ngx_uint_t nevents; -static timer_t event_timer = -1; +static timer_t event_timer = (timer_t) -1; static ngx_str_t eventport_name = ngx_string("eventport"); @@ -237,13 +241,13 @@ ngx_eventport_init(ngx_cycle_t *cycle, n static void ngx_eventport_done(ngx_cycle_t *cycle) { - if (event_timer != -1) { + if (event_timer != (timer_t) -1) { if (timer_delete(event_timer) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "timer_delete() failed"); } - event_timer = -1; + event_timer = (timer_t) -1; } if (close(ep) == -1) { diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -446,7 +446,7 @@ ngx_kqueue_set_event(ngx_event_t *ev, ng || __FreeBSD_version >= 500018 |NOTE_REVOKE #endif - ; + ; kev->data = 0; } else { diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -11,9 +11,14 @@ #if (NGX_TEST_BUILD_RTSIG) -#define F_SETSIG 10 +#ifdef SIGRTMIN +#define si_fd _reason.__spare__.__spare2__[0] +#else #define SIGRTMIN 33 #define si_fd __spare__[0] +#endif + +#define F_SETSIG 10 #define KERN_RTSIGNR 30 #define KERN_RTSIGMAX 31 diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -254,9 +254,6 @@ ngx_select_process_events(ngx_cycle_t *c ngx_event_t *ev, **queue; ngx_connection_t *c; struct timeval tv, *tp; -#if !(NGX_WIN32) - ngx_uint_t level; -#endif #if !(NGX_WIN32) @@ -348,6 +345,8 @@ ngx_select_process_events(ngx_cycle_t *c #else if (err) { + ngx_uint_t level; + if (err == NGX_EINTR) { if (ngx_event_timer_alarm) { @@ -437,10 +436,10 @@ ngx_select_init_conf(ngx_cycle_t *cycle, #if !(NGX_WIN32) - if ((unsigned) ecf->connections > FD_SETSIZE) { + if (cycle->connection_n > FD_SETSIZE) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "the maximum number of files " - "supported by select() is " ngx_value(FD_SETSIZE)); + "supported by select() is %ud", FD_SETSIZE); return NGX_CONF_ERROR; } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -428,13 +428,9 @@ ngx_event_module_init(ngx_cycle_t *cycle void ***cf; u_char *shared; size_t size, cl; - ngx_event_conf_t *ecf; + ngx_shm_t shm; ngx_core_conf_t *ccf; - ngx_shm_t shm; -#if !(NGX_WIN32) - ngx_int_t limit; - struct rlimit rlmt; -#endif + ngx_event_conf_t *ecf; cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); @@ -456,6 +452,9 @@ ngx_event_module_init(ngx_cycle_t *cycle ngx_timer_resolution = ccf->timer_resolution; #if !(NGX_WIN32) + { + ngx_int_t limit; + struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, @@ -475,7 +474,7 @@ ngx_event_module_init(ngx_cycle_t *cycle ecf->connections, limit); } } - + } #endif /* !(NGX_WIN32) */ @@ -573,13 +572,6 @@ ngx_event_process_init(ngx_cycle_t *cycl ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; -#if (NGX_WIN32) - ngx_iocp_conf_t *iocpcf; -#else - struct rlimit rlmt; - struct sigaction sa; - struct itimerval itv; -#endif ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); @@ -604,27 +596,30 @@ ngx_event_process_init(ngx_cycle_t *cycl return NGX_ERROR; } - cycle->connection_n = ecf->connections; - for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } - if (ngx_modules[m]->ctx_index == ecf->use) { - module = ngx_modules[m]->ctx; - if (module->actions.init(cycle, ngx_timer_resolution) == NGX_ERROR) - { - /* fatal */ - exit(2); - } - break; + if (ngx_modules[m]->ctx_index != ecf->use) { + continue; } + + module = ngx_modules[m]->ctx; + + if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { + /* fatal */ + exit(2); + } + + break; } #if !(NGX_WIN32) if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { + struct sigaction sa; + struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = ngx_timer_signal_handler; @@ -648,6 +643,7 @@ ngx_event_process_init(ngx_cycle_t *cycl } if (ngx_event_flags & NGX_USE_FD_EVENT) { + struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, @@ -666,15 +662,15 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif - cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections, - cycle->log); + cycle->connections = + ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; - cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, + cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; @@ -690,7 +686,7 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif } - cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, + cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; @@ -724,7 +720,7 @@ ngx_event_process_init(ngx_cycle_t *cycl } while (i); cycle->free_connections = next; - cycle->free_connection_n = ecf->connections; + cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ @@ -774,6 +770,8 @@ ngx_event_process_init(ngx_cycle_t *cycl #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + ngx_iocp_conf_t *iocpcf; + rev->handler = ngx_event_acceptex; if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { @@ -945,7 +943,7 @@ ngx_event_connections(ngx_conf_t *cf, ng ngx_str_t *value; if (ecf->connections != NGX_CONF_UNSET_UINT) { - return "is duplicate" ; + return "is duplicate"; } if (ngx_strcmp(cmd->name.data, "connections") == 0) { @@ -980,7 +978,7 @@ ngx_event_use(ngx_conf_t *cf, ngx_comman ngx_event_module_t *module; if (ecf->use != NGX_CONF_UNSET_UINT) { - return "is duplicate" ; + return "is duplicate"; } value = cf->args->elts; @@ -1140,11 +1138,10 @@ ngx_event_init_conf(ngx_cycle_t *cycle, ngx_uint_t rtsig; ngx_core_conf_t *ccf; #endif - ngx_int_t i, connections; + ngx_int_t i; ngx_module_t *module; ngx_event_module_t *event_module; - connections = NGX_CONF_UNSET_UINT; module = NULL; #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) @@ -1153,11 +1150,9 @@ ngx_event_init_conf(ngx_cycle_t *cycle, if (fd != -1) { close(fd); - connections = DEFAULT_CONNECTIONS; module = &ngx_epoll_module; } else if (ngx_errno != NGX_ENOSYS) { - connections = DEFAULT_CONNECTIONS; module = &ngx_epoll_module; } @@ -1166,7 +1161,6 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #if (NGX_HAVE_RTSIG) if (module == NULL) { - connections = DEFAULT_CONNECTIONS; module = &ngx_rtsig_module; rtsig = 1; @@ -1178,14 +1172,12 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #if (NGX_HAVE_DEVPOLL) - connections = DEFAULT_CONNECTIONS; module = &ngx_devpoll_module; #endif #if (NGX_HAVE_KQUEUE) - connections = DEFAULT_CONNECTIONS; module = &ngx_kqueue_module; #endif @@ -1193,12 +1185,6 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #if (NGX_HAVE_SELECT) if (module == NULL) { - -#if (NGX_WIN32 || FD_SETSIZE >= DEFAULT_CONNECTIONS) - connections = DEFAULT_CONNECTIONS; -#else - connections = FD_SETSIZE; -#endif module = &ngx_select_module; } @@ -1206,18 +1192,20 @@ ngx_event_init_conf(ngx_cycle_t *cycle, if (module == NULL) { for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type == NGX_EVENT_MODULE) { - event_module = ngx_modules[i]->ctx; + + if (ngx_modules[i]->type != NGX_EVENT_MODULE) { + continue; + } + + event_module = ngx_modules[i]->ctx; - if (ngx_strcmp(event_module->name->data, event_core_name.data) - == 0) - { - continue; - } + if (ngx_strcmp(event_module->name->data, event_core_name.data) == 0) + { + continue; + } - module = ngx_modules[i]; - break; - } + module = ngx_modules[i]; + break; } } @@ -1226,7 +1214,7 @@ ngx_event_init_conf(ngx_cycle_t *cycle, return NGX_CONF_ERROR; } - ngx_conf_init_uint_value(ecf->connections, connections); + ngx_conf_init_uint_value(ecf->connections, DEFAULT_CONNECTIONS); cycle->connection_n = ecf->connections; ngx_conf_init_uint_value(ecf->use, module->ctx_index); diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -136,6 +136,7 @@ struct ngx_event_s { /* to test on worker exit */ unsigned channel:1; + unsigned resolver:1; #if (NGX_THREADS) @@ -429,6 +430,7 @@ extern ngx_os_io_t ngx_io; #define ngx_recv ngx_io.recv #define ngx_recv_chain ngx_io.recv_chain +#define ngx_udp_recv ngx_io.udp_recv #define ngx_send ngx_io.send #define ngx_send_chain ngx_io.send_chain diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -201,7 +201,7 @@ ngx_event_accept(ngx_event_t *ev) #endif if (ls->addr_ntop) { - c->addr_text.data = ngx_palloc(c->pool, ls->addr_text_max_len); + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; diff --git a/src/event/ngx_event_busy_lock.c b/src/event/ngx_event_busy_lock.c --- a/src/event/ngx_event_busy_lock.c +++ b/src/event/ngx_event_busy_lock.c @@ -9,7 +9,7 @@ #include -static ngx_int_t ngx_event_busy_lock_look_cachable(ngx_event_busy_lock_t *bl, +static ngx_int_t ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx); static void ngx_event_busy_lock_handler(ngx_event_t *ev); static void ngx_event_busy_lock_posted_handler(ngx_event_t *ev); @@ -65,14 +65,14 @@ ngx_event_busy_lock(ngx_event_busy_lock_ ngx_int_t -ngx_event_busy_lock_cachable(ngx_event_busy_lock_t *bl, +ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx) { ngx_int_t rc; ngx_mutex_lock(bl->mutex); - rc = ngx_event_busy_lock_look_cachable(bl, ctx); + rc = ngx_event_busy_lock_look_cacheable(bl, ctx); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0, "event busy lock: %d w:%d mw:%d", @@ -201,14 +201,14 @@ ngx_event_busy_lock_cancel(ngx_event_bus static ngx_int_t -ngx_event_busy_lock_look_cachable(ngx_event_busy_lock_t *bl, +ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx) { ngx_int_t free; - ngx_uint_t i, bit, cachable, mask; + ngx_uint_t i, bit, cacheable, mask; bit = 0; - cachable = 0; + cacheable = 0; free = -1; #if (NGX_SUPPRESS_WARN) @@ -227,14 +227,14 @@ ngx_event_busy_lock_look_cachable(ngx_ev ctx->slot = i; return NGX_AGAIN; } - cachable++; + cacheable++; } else if (free == -1) { free = i; } - if (cachable == bl->cachable) { - if (free == -1 && cachable < bl->max_busy) { + if (cacheable == bl->cacheable) { + if (free == -1 && cacheable < bl->max_busy) { free = i + 1; } @@ -259,7 +259,7 @@ ngx_event_busy_lock_look_cachable(ngx_ev bl->md5_mask[free / 8] |= 1 << (free & 7); ctx->slot = free; - bl->cachable++; + bl->cacheable++; bl->busy++; return NGX_OK; diff --git a/src/event/ngx_event_busy_lock.h b/src/event/ngx_event_busy_lock.h --- a/src/event/ngx_event_busy_lock.h +++ b/src/event/ngx_event_busy_lock.h @@ -34,7 +34,7 @@ struct ngx_event_busy_lock_ctx_s { typedef struct { u_char *md5_mask; char *md5; - ngx_uint_t cachable; + ngx_uint_t cacheable; ngx_uint_t busy; ngx_uint_t max_busy; @@ -53,7 +53,7 @@ typedef struct { ngx_int_t ngx_event_busy_lock(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx); -ngx_int_t ngx_event_busy_lock_cachable(ngx_event_busy_lock_t *bl, +ngx_int_t ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx); void ngx_event_busy_unlock(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx); diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -139,12 +139,29 @@ ngx_event_connect_peer(ngx_peer_connecti if (rc == -1) { err = ngx_socket_errno; - /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ - if (err != NGX_EINPROGRESS && err != NGX_EAGAIN) { + if (err != NGX_EINPROGRESS +#if (NGX_WIN32) + /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ + && err != NGX_EAGAIN +#endif + ) + { + if (err == NGX_ECONNREFUSED +#if (NGX_LINUX) + /* + * Linux returns EAGAIN instead of ECONNREFUSED + * for unix sockets if listen queue is full + */ + || err == NGX_EAGAIN +#endif + || err == NGX_ENETDOWN + || err == NGX_ENETUNREACH + || err == NGX_EHOSTDOWN + || err == NGX_EHOSTUNREACH) + { + level = NGX_LOG_ERR; - if (err == NGX_ECONNREFUSED || err == NGX_EHOSTUNREACH) { - level = NGX_LOG_ERR; } else { level = NGX_LOG_CRIT; } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -22,6 +22,7 @@ static void ngx_ssl_read_handler(ngx_eve static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, char *text); +static void ngx_ssl_clear_error(ngx_log_t *log); static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); @@ -181,11 +182,17 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); #endif + SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); if (ngx_ssl_protocols[protocols >> 1] != 0) { SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]); } + /* + * we need this option because in ngx_ssl_send_chain() + * we may switch to a buffered write and may copy leftover part of + * previously unbuffered data to our internal buffer + */ SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_read_ahead(ssl->ctx, 1); @@ -279,10 +286,11 @@ ngx_ssl_client_certificate(ngx_conf_t *c static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) { +#if (NGX_DEBUG) char *subject, *issuer; int err, depth; X509 *cert; - X509_NAME *name; + X509_NAME *sname, *iname; ngx_connection_t *c; ngx_ssl_conn_t *ssl_conn; @@ -295,17 +303,26 @@ ngx_http_ssl_verify_callback(int ok, X50 err = X509_STORE_CTX_get_error(x509_store); depth = X509_STORE_CTX_get_error_depth(x509_store); - name = X509_get_subject_name(cert); - subject = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; - - name = X509_get_issuer_name(cert); - issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; + sname = X509_get_subject_name(cert); + subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)"; + + iname = X509_get_issuer_name(cert); + issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)"; ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "verify:%d, error:%d, depth:%d, " "subject:\"%s\",issuer: \"%s\"", ok, err, depth, subject, issuer); + if (sname) { + OPENSSL_free(subject); + } + + if (iname) { + OPENSSL_free(issuer); + } +#endif + return 1; } @@ -336,6 +353,89 @@ ngx_ssl_generate_rsa512_key(ngx_ssl_t *s ngx_int_t +ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) +{ + DH *dh; + BIO *bio; + + /* + * -----BEGIN DH PARAMETERS----- + * MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc + * y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl + * 7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC + * -----END DH PARAMETERS----- + */ + + static unsigned char dh1024_p[] = { + 0xBB, 0xBC, 0x2D, 0xCA, 0xD8, 0x46, 0x74, 0x90, 0x7C, 0x43, 0xFC, 0xF5, + 0x80, 0xE9, 0xCF, 0xDB, 0xD9, 0x58, 0xA3, 0xF5, 0x68, 0xB4, 0x2D, 0x4B, + 0x08, 0xEE, 0xD4, 0xEB, 0x0F, 0xB3, 0x50, 0x4C, 0x6C, 0x03, 0x02, 0x76, + 0xE7, 0x10, 0x80, 0x0C, 0x5C, 0xCB, 0xBA, 0xA8, 0x92, 0x26, 0x14, 0xC5, + 0xBE, 0xEC, 0xA5, 0x65, 0xA5, 0xFD, 0xF1, 0xD2, 0x87, 0xA2, 0xBC, 0x04, + 0x9B, 0xE6, 0x77, 0x80, 0x60, 0xE9, 0x1A, 0x92, 0xA7, 0x57, 0xE3, 0x04, + 0x8F, 0x68, 0xB0, 0x76, 0xF7, 0xD3, 0x6C, 0xC8, 0xF2, 0x9B, 0xA5, 0xDF, + 0x81, 0xDC, 0x2C, 0xA7, 0x25, 0xEC, 0xE6, 0x62, 0x70, 0xCC, 0x9A, 0x50, + 0x35, 0xD8, 0xCE, 0xCE, 0xEF, 0x9E, 0xA0, 0x27, 0x4A, 0x63, 0xAB, 0x1E, + 0x58, 0xFA, 0xFD, 0x49, 0x88, 0xD0, 0xF6, 0x5D, 0x14, 0x67, 0x57, 0xDA, + 0x07, 0x1D, 0xF0, 0x45, 0xCF, 0xE1, 0x6B, 0x9B + }; + + static unsigned char dh1024_g[] = { 0x02 }; + + + if (file->len == 0) { + + dh = DH_new(); + if (dh == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "DH_new() failed"); + return NGX_ERROR; + } + + dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); + dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); + + if (dh->p == NULL || dh->g == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BN_bin2bn() failed"); + DH_free(dh); + return NGX_ERROR; + } + + SSL_CTX_set_tmp_dh(ssl->ctx, dh); + + DH_free(dh); + + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, file, 1) == NGX_ERROR) { + return NGX_ERROR; + } + + bio = BIO_new_file((char *) file->data, "r"); + if (bio == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "BIO_new_file(\"%s\") failed", file->data); + return NGX_ERROR; + } + + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + if (dh == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "PEM_read_bio_DHparams(\"%s\") failed", file->data); + BIO_free(bio); + return NGX_ERROR; + } + + SSL_CTX_set_tmp_dh(ssl->ctx, dh); + + DH_free(dh); + BIO_free(bio); + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) { ngx_ssl_connection_t *sc; @@ -345,14 +445,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl return NGX_ERROR; } - if (flags & NGX_SSL_BUFFER) { - sc->buffer = 1; - - sc->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); - if (sc->buf == NULL) { - return NGX_ERROR; - } - } + sc->buffer = ((flags & NGX_SSL_BUFFER) != 0); sc->connection = SSL_new(ssl->ctx); @@ -404,12 +497,17 @@ ngx_ssl_handshake(ngx_connection_t *c) int n, sslerr; ngx_err_t err; + ngx_ssl_clear_error(c->log); + n = SSL_do_handshake(c->ssl->connection); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); if (n == 1) { + c->read->ready = 0; + c->write->ready = 1; + if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { return NGX_ERROR; } @@ -579,6 +677,11 @@ ngx_ssl_recv_chain(ngx_connection_t *c, } if (bytes) { + + if (n == 0 || n == NGX_ERROR) { + c->read->ready = 1; + } + return bytes; } @@ -605,6 +708,8 @@ ngx_ssl_recv(ngx_connection_t *c, u_char bytes = 0; + ngx_ssl_clear_error(c->log); + /* * SSL_read() may return data in parts, so try to read * until SSL_read() would return no data @@ -801,8 +906,28 @@ ngx_ssl_send_chain(ngx_connection_t *c, limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; } - buf = c->ssl->buf; + + if (buf == NULL) { + buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); + if (buf == NULL) { + return NGX_CHAIN_ERROR; + } + + c->ssl->buf = buf; + } + + if (buf->start == NULL) { + buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE); + if (buf->start == NULL) { + return NGX_CHAIN_ERROR; + } + + buf->pos = buf->start; + buf->last = buf->start; + buf->end = buf->start + NGX_SSL_BUFSIZE; + } + send = 0; flush = (in == NULL) ? 1 : 0; @@ -895,6 +1020,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha int n, sslerr; ngx_err_t err; + ngx_ssl_clear_error(c->log); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); n = SSL_write(c->ssl->connection, data, size); @@ -975,12 +1102,22 @@ ngx_ssl_read_handler(ngx_event_t *rev) } +void +ngx_ssl_free_buffer(ngx_connection_t *c) +{ + if (c->ssl->buf && c->ssl->buf->start) { + if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) { + c->ssl->buf->start = NULL; + } + } +} + + ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { - int n, sslerr, mode; - ngx_err_t err; - ngx_uint_t again; + int n, sslerr, mode; + ngx_err_t err; if (c->timedout) { mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; @@ -999,40 +1136,31 @@ ngx_ssl_shutdown(ngx_connection_t *c) SSL_set_shutdown(c->ssl->connection, mode); - again = 0; + ngx_ssl_clear_error(c->log); + + n = SSL_shutdown(c->ssl->connection); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); + sslerr = 0; - for ( ;; ) { - n = SSL_shutdown(c->ssl->connection); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); - - if (n == 1 || (n == 0 && c->timedout)) { - SSL_free(c->ssl->connection); - c->ssl = NULL; - - return NGX_OK; - } - - if (n == 0) { - again = 1; - break; - } - - break; - } - - if (!again) { + /* SSL_shutdown() never returns -1, on error it returns 0 */ + + if (n != 1 && ERR_peek_error()) { sslerr = SSL_get_error(c->ssl->connection, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); } - if (again - || sslerr == SSL_ERROR_WANT_READ - || sslerr == SSL_ERROR_WANT_WRITE) - { + if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) { + SSL_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_OK; + } + + if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { c->read->handler = ngx_ssl_shutdown_handler; c->write->handler = ngx_ssl_shutdown_handler; @@ -1044,7 +1172,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) return NGX_ERROR; } - if (again || sslerr == SSL_ERROR_WANT_READ) { + if (sslerr == SSL_ERROR_WANT_READ) { ngx_add_timer(c->read, 30000); } @@ -1089,6 +1217,7 @@ static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, char *text) { + int n; ngx_uint_t level; level = NGX_LOG_CRIT; @@ -1102,6 +1231,9 @@ ngx_ssl_connection_error(ngx_connection_ || err == NGX_ETIMEDOUT #endif || err == NGX_ECONNREFUSED + || err == NGX_ENETDOWN + || err == NGX_ENETUNREACH + || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { switch (c->log_error) { @@ -1119,18 +1251,69 @@ ngx_ssl_connection_error(ngx_connection_ break; } } + + } else if (sslerr == SSL_ERROR_SSL) { + + n = ERR_GET_REASON(ERR_peek_error()); + + /* handshake failures */ + if (n == SSL_R_DIGEST_CHECK_FAILED + || n == SSL_R_NO_SHARED_CIPHER + || n == SSL_R_UNEXPECTED_MESSAGE + || n == SSL_R_WRONG_VERSION_NUMBER + || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC + || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ + || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE + || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC + || n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE + || n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE + || n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE + || n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE + || n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED + || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED + || n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN + || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER + || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA) + { + switch (c->log_error) { + + case NGX_ERROR_IGNORE_ECONNRESET: + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + + default: + break; + } + } } ngx_ssl_error(level, c->log, err, text); } +static void +ngx_ssl_clear_error(ngx_log_t *log) +{ + while (ERR_peek_error()) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error"); + } + + ERR_clear_error(); +} + + void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) { - u_long n; - va_list args; - u_char errstr[NGX_MAX_CONF_ERRSTR], *p, *last; + u_long n; + va_list args; + u_char *p, *last; + u_char errstr[NGX_MAX_CONF_ERRSTR]; last = errstr + NGX_MAX_CONF_ERRSTR; @@ -1140,7 +1323,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); - while (p < last) { + for ( ;; ) { n = ERR_get_error(); @@ -1148,6 +1331,10 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ break; } + if (p >= last) { + continue; + } + *p++ = ' '; ERR_error_string_n(n, (char *) p, last - p); @@ -1167,6 +1354,34 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng { long cache_mode; + if (builtin_session_cache == NGX_SSL_NO_SCACHE) { + SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF); + return NGX_OK; + } + + if (builtin_session_cache == NGX_SSL_NONE_SCACHE) { + + /* + * If the server explicitly says that it does not support + * session reuse (see SSL_SESS_CACHE_OFF above), then + * Outlook Express fails to upload a sent email to + * the Sent Items folder on the IMAP server via a separate IMAP + * connection in the background. Therefore we have a special + * mode (SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE) + * where the server pretends that it supports session reuse, + * but it does not actually store any session. + */ + + SSL_CTX_set_session_cache_mode(ssl->ctx, + SSL_SESS_CACHE_SERVER + |SSL_SESS_CACHE_NO_AUTO_CLEAR + |SSL_SESS_CACHE_NO_INTERNAL_STORE); + + SSL_CTX_sess_set_cache_size(ssl->ctx, 1); + + return NGX_OK; + } + cache_mode = SSL_SESS_CACHE_SERVER; if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) { @@ -1210,7 +1425,6 @@ static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) { ngx_slab_pool_t *shpool; - ngx_rbtree_node_t *sentinel; ngx_ssl_session_cache_t *cache; if (data) { @@ -1225,27 +1439,10 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ return NGX_ERROR; } - cache->session_cache_head.prev = NULL; - cache->session_cache_head.next = &cache->session_cache_tail; - - cache->session_cache_tail.prev = &cache->session_cache_head; - cache->session_cache_tail.next = NULL; - - cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); - if (cache->session_rbtree == NULL) { - return NGX_ERROR; - } - - sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { - return NGX_ERROR; - } - - ngx_rbtree_sentinel_init(sentinel); - - cache->session_rbtree->root = sentinel; - cache->session_rbtree->sentinel = sentinel; - cache->session_rbtree->insert = ngx_ssl_session_rbtree_insert_value; + ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, + ngx_ssl_session_rbtree_insert_value); + + ngx_queue_init(&cache->expire_queue); shm_zone->data = cache; @@ -1277,7 +1474,6 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ u_char *p, *id, *cached_sess; uint32_t hash; SSL_CTX *ssl_ctx; - ngx_time_t *tp; ngx_shm_zone_t *shm_zone; ngx_connection_t *c; ngx_slab_pool_t *shpool; @@ -1353,22 +1549,17 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ "http ssl new session: %08XD:%d:%d", hash, sess->session_id_length, len); - tp = ngx_timeofday(); - sess_id->node.key = hash; sess_id->node.data = (u_char) sess->session_id_length; sess_id->id = id; sess_id->len = len; sess_id->session = cached_sess; - sess_id->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx); - - sess_id->next = cache->session_cache_head.next; - sess_id->next->prev = sess_id; - sess_id->prev = &cache->session_cache_head; - cache->session_cache_head.next = sess_id; - - ngx_rbtree_insert(cache->session_rbtree, &sess_id->node); + sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); + + ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); + + ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node); ngx_shmtx_unlock(&shpool->mutex); @@ -1403,7 +1594,6 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ u_char *p; uint32_t hash; ngx_int_t rc; - ngx_time_t *tp; ngx_shm_zone_t *shm_zone; ngx_slab_pool_t *shpool; ngx_connection_t *c; @@ -1426,18 +1616,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ cache = shm_zone->data; - if (cache->session_rbtree == NULL) { - return NULL; - } - sess = NULL; shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); - node = cache->session_rbtree->root; - sentinel = cache->session_rbtree->sentinel; + node = cache->session_rbtree.root; + sentinel = cache->session_rbtree.sentinel; while (node != sentinel) { @@ -1460,9 +1646,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ (size_t) len, (size_t) node->data); if (rc == 0) { - tp = ngx_timeofday(); - - if (sess_id->expire > tp->sec) { + if (sess_id->expire > ngx_time()) { ngx_memcpy(buf, sess_id->session, sess_id->len); ngx_shmtx_unlock(&shpool->mutex); @@ -1473,10 +1657,9 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ return sess; } - sess_id->next->prev = sess_id->prev; - sess_id->prev->next = sess_id->next; - - ngx_rbtree_delete(cache->session_rbtree, node); + ngx_queue_remove(&sess_id->queue); + + ngx_rbtree_delete(&cache->session_rbtree, node); ngx_slab_free_locked(shpool, sess_id->session); #if (NGX_PTR_SIZE == 4) @@ -1504,6 +1687,15 @@ done: } +void +ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) +{ + SSL_CTX_remove_session(ssl, sess); + + ngx_ssl_remove_session(ssl, sess); +} + + static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) { @@ -1519,6 +1711,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index); + if (shm_zone == NULL) { + return; + } + cache = shm_zone->data; id = sess->session_id; @@ -1533,8 +1729,8 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx ngx_shmtx_lock(&shpool->mutex); - node = cache->session_rbtree->root; - sentinel = cache->session_rbtree->sentinel; + node = cache->session_rbtree.root; + sentinel = cache->session_rbtree.sentinel; while (node != sentinel) { @@ -1556,10 +1752,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data); if (rc == 0) { - sess_id->next->prev = sess_id->prev; - sess_id->prev->next = sess_id->next; - - ngx_rbtree_delete(cache->session_rbtree, node); + + ngx_queue_remove(&sess_id->queue); + + ngx_rbtree_delete(&cache->session_rbtree, node); ngx_slab_free_locked(shpool, sess_id->session); #if (NGX_PTR_SIZE == 4) @@ -1587,31 +1783,33 @@ static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, ngx_slab_pool_t *shpool, ngx_uint_t n) { - ngx_time_t *tp; + time_t now; + ngx_queue_t *q; ngx_ssl_sess_id_t *sess_id; - tp = ngx_timeofday(); + now = ngx_time(); while (n < 3) { - sess_id = cache->session_cache_tail.prev; - - if (sess_id == &cache->session_cache_head) { + if (ngx_queue_empty(&cache->expire_queue)) { return; } - if (n++ != 0 && sess_id->expire > tp->sec) { + q = ngx_queue_last(&cache->expire_queue); + + sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue); + + if (n++ != 0 && sess_id->expire > now) { return; } - sess_id->next->prev = sess_id->prev; - sess_id->prev->next = sess_id->next; - - ngx_rbtree_delete(cache->session_rbtree, &sess_id->node); + ngx_queue_remove(q); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "expire session: %08Xi", sess_id->node.key); + ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); + ngx_slab_free_locked(shpool, sess_id->session); #if (NGX_PTR_SIZE == 4) ngx_slab_free_locked(shpool, sess_id->id); @@ -1625,56 +1823,37 @@ static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { - ngx_ssl_sess_id_t *sess_id, *sess_id_temp; + ngx_rbtree_node_t **p; + ngx_ssl_sess_id_t *sess_id, *sess_id_temp; for ( ;; ) { if (node->key < temp->key) { - if (temp->left == sentinel) { - temp->left = node; - break; - } - - temp = temp->left; + p = &temp->left; } else if (node->key > temp->key) { - if (temp->right == sentinel) { - temp->right = node; - break; - } - - temp = temp->right; + p = &temp->right; } else { /* node->key == temp->key */ sess_id = (ngx_ssl_sess_id_t *) node; sess_id_temp = (ngx_ssl_sess_id_t *) temp; - if (ngx_memn2cmp(sess_id->id, sess_id_temp->id, - (size_t) node->data, (size_t) temp->data) - < 0) - { - if (temp->left == sentinel) { - temp->left = node; - break; - } - - temp = temp->left; - - } else { - - if (temp->right == sentinel) { - temp->right = node; - break; - } - - temp = temp->right; - } + p = (ngx_memn2cmp(sess_id->id, sess_id_temp->id, + (size_t) node->data, (size_t) temp->data) + < 0) ? &temp->left : &temp->right; } + + if (*p == sentinel) { + break; + } + + temp = *p; } + *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; @@ -1708,6 +1887,100 @@ ngx_ssl_get_cipher_name(ngx_connection_t ngx_int_t +ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + size_t len; + BIO *bio; + X509 *cert; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); + X509_free(cert); + return NGX_ERROR; + } + + if (PEM_write_bio_X509(bio, cert) == 0) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "PEM_write_bio_X509() failed"); + goto failed; + } + + len = BIO_pending(bio); + s->len = len; + + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + goto failed; + } + + BIO_read(bio, s->data, len); + + BIO_free(bio); + X509_free(cert); + + return NGX_OK; + +failed: + + BIO_free(bio); + X509_free(cert); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_str_t cert; + + if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) { + return NGX_ERROR; + } + + if (cert.len == 0) { + s->len = 0; + return NGX_OK; + } + + len = cert.len - 1; + + for (i = 0; i < cert.len - 1; i++) { + if (cert.data[i] == LF) { + len++; + } + } + + s->len = len; + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + p = s->data; + + for (i = 0; i < len; i++) { + *p++ = cert.data[i]; + if (cert.data[i] == LF) { + *p++ = '\t'; + } + } + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { char *p; @@ -1724,6 +1997,7 @@ ngx_ssl_get_subject_dn(ngx_connection_t name = X509_get_subject_name(cert); if (name == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -1732,15 +2006,17 @@ ngx_ssl_get_subject_dn(ngx_connection_t for (len = 0; p[len]; len++) { /* void */ } s->len = len; - s->data = ngx_palloc(pool, len); + s->data = ngx_pnalloc(pool, len); if (s->data == NULL) { OPENSSL_free(p); + X509_free(cert); return NGX_ERROR; } ngx_memcpy(s->data, p, len); OPENSSL_free(p); + X509_free(cert); return NGX_OK; } @@ -1763,6 +2039,7 @@ ngx_ssl_get_issuer_dn(ngx_connection_t * name = X509_get_issuer_name(cert); if (name == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -1771,15 +2048,17 @@ ngx_ssl_get_issuer_dn(ngx_connection_t * for (len = 0; p[len]; len++) { /* void */ } s->len = len; - s->data = ngx_palloc(pool, len); + s->data = ngx_pnalloc(pool, len); if (s->data == NULL) { OPENSSL_free(p); + X509_free(cert); return NGX_ERROR; } ngx_memcpy(s->data, p, len); OPENSSL_free(p); + X509_free(cert); return NGX_OK; } @@ -1801,6 +2080,7 @@ ngx_ssl_get_serial_number(ngx_connection bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -1808,14 +2088,16 @@ ngx_ssl_get_serial_number(ngx_connection len = BIO_pending(bio); s->len = len; - s->data = ngx_palloc(pool, len); + s->data = ngx_pnalloc(pool, len); if (s->data == NULL) { BIO_free(bio); + X509_free(cert); return NGX_ERROR; } BIO_read(bio, s->data, len); BIO_free(bio); + X509_free(cert); return NGX_OK; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -51,11 +51,13 @@ typedef struct { } ngx_ssl_connection_t; -#define NGX_SSL_DFLT_BUILTIN_SCACHE -2 -#define NGX_SSL_NO_BUILTIN_SCACHE -3 +#define NGX_SSL_NO_SCACHE -2 +#define NGX_SSL_NONE_SCACHE -3 +#define NGX_SSL_NO_BUILTIN_SCACHE -4 +#define NGX_SSL_DFLT_BUILTIN_SCACHE -5 -#define NGX_SSL_MAX_SESSION_SIZE (4096) +#define NGX_SSL_MAX_SESSION_SIZE 4096 typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t; @@ -64,8 +66,7 @@ struct ngx_ssl_sess_id_s { u_char *id; size_t len; u_char *session; - ngx_ssl_sess_id_t *prev; - ngx_ssl_sess_id_t *next; + ngx_queue_t queue; time_t expire; #if (NGX_PTR_SIZE == 8) void *stub; @@ -75,9 +76,9 @@ struct ngx_ssl_sess_id_s { typedef struct { - ngx_rbtree_t *session_rbtree; - ngx_ssl_sess_id_t session_cache_head; - ngx_ssl_sess_id_t session_cache_tail; + ngx_rbtree_t session_rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t expire_queue; } ngx_ssl_session_cache_t; @@ -100,11 +101,13 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl); +ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout); ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags); +void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); #define ngx_ssl_get_session(c) SSL_get1_session(c->ssl->connection) #define ngx_ssl_free_session SSL_SESSION_free @@ -118,6 +121,10 @@ ngx_int_t ngx_ssl_get_protocol(ngx_conne ngx_str_t *s); ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, @@ -132,6 +139,7 @@ ssize_t ngx_ssl_write(ngx_connection_t * ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl); ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); +void ngx_ssl_free_buffer(ngx_connection_t *c); ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c); void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...); diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -21,7 +21,7 @@ static ngx_int_t ngx_event_pipe_drain_ch ngx_int_t -ngx_event_pipe(ngx_event_pipe_t *p, int do_write) +ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) { u_int flags; ngx_event_t *rev, *wev; @@ -192,7 +192,7 @@ ngx_event_pipe_read_upstream(ngx_event_p chain->buf = b; chain->next = NULL; - } else if (!p->cachable + } else if (!p->cacheable && p->downstream->data == p->output_ctx && p->downstream->write->ready && !p->downstream->write->delayed) @@ -209,7 +209,7 @@ ngx_event_pipe_read_upstream(ngx_event_p break; - } else if (p->cachable + } else if (p->cacheable || p->temp_file->offset < p->max_temp_file_size) { @@ -406,7 +406,7 @@ ngx_event_pipe_read_upstream(ngx_event_p } } - if (p->cachable && p->in) { + if (p->cacheable && p->in) { if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { return NGX_ABORT; } @@ -421,6 +421,7 @@ ngx_event_pipe_write_to_downstream(ngx_e { u_char *prev; size_t bsize; + ngx_int_t rc; ngx_uint_t flush, prev_last_shadow; ngx_chain_t *out, **ll, *cl; ngx_connection_t *downstream; @@ -451,7 +452,13 @@ ngx_event_pipe_write_to_downstream(ngx_e cl->buf->recycled = 0; } - if (p->output_filter(p->output_ctx, p->out) == NGX_ERROR) { + rc = p->output_filter(p->output_ctx, p->out); + + if (downstream->destroyed) { + return NGX_ABORT; + } + + if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } @@ -467,12 +474,13 @@ ngx_event_pipe_write_to_downstream(ngx_e cl->buf->recycled = 0; } - if (p->output_filter(p->output_ctx, p->in) == NGX_ERROR) { + rc = p->output_filter(p->output_ctx, p->in); - if (downstream->destroyed) { - return NGX_ABORT; - } + if (downstream->destroyed) { + return NGX_ABORT; + } + if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } @@ -542,7 +550,7 @@ ngx_event_pipe_write_to_downstream(ngx_e ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf); - } else if (!p->cachable && p->in) { + } else if (!p->cacheable && p->in) { cl = p->in; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, @@ -602,7 +610,13 @@ ngx_event_pipe_write_to_downstream(ngx_e break; } - if (p->output_filter(p->output_ctx, out) == NGX_ERROR) { + rc = p->output_filter(p->output_ctx, out); + + if (downstream->destroyed) { + return NGX_ABORT; + } + + if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } @@ -612,7 +626,7 @@ ngx_event_pipe_write_to_downstream(ngx_e for (cl = p->free; cl; cl = cl->next) { if (cl->buf->temp_file) { - if (p->cachable || !p->cyclic_temp_file) { + if (p->cacheable || !p->cyclic_temp_file) { continue; } @@ -659,7 +673,7 @@ ngx_event_pipe_write_chain_to_temp_file( out = p->in; } - if (!p->cachable) { + if (!p->cacheable) { size = 0; cl = out; @@ -866,7 +880,7 @@ ngx_event_pipe_free_shadow_raw_buf(ngx_c ll = free; - for (cl = *free ; cl; cl = cl->next) { + for (cl = *free; cl; cl = cl->next) { if (cl->buf == s) { *ll = cl->next; break; diff --git a/src/event/ngx_event_pipe.h b/src/event/ngx_event_pipe.h --- a/src/event/ngx_event_pipe.h +++ b/src/event/ngx_event_pipe.h @@ -47,7 +47,7 @@ struct ngx_event_pipe_s { void *output_ctx; unsigned read:1; - unsigned cachable:1; + unsigned cacheable:1; unsigned single_buf:1; unsigned free_bufs:1; unsigned upstream_done:1; @@ -86,7 +86,7 @@ struct ngx_event_pipe_s { }; -ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, int do_write); +ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write); ngx_int_t ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf); ngx_int_t ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b); diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -26,9 +26,8 @@ static ngx_rbtree_node_t ngx_ev ngx_int_t ngx_event_timer_init(ngx_log_t *log) { - ngx_event_timer_rbtree.root = &ngx_event_timer_sentinel; - ngx_event_timer_rbtree.sentinel = &ngx_event_timer_sentinel; - ngx_event_timer_rbtree.insert = ngx_rbtree_insert_timer_value; + ngx_rbtree_init(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel, + ngx_rbtree_insert_timer_value); #if (NGX_THREADS) diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h --- a/src/event/ngx_event_timer.h +++ b/src/event/ngx_event_timer.h @@ -65,9 +65,9 @@ ngx_event_add_timer(ngx_event_t *ev, ngx if (ev->timer_set) { /* - * Use the previous timer value if a difference between them is less - * then NGX_TIMER_LAZY_DELAY milliseconds. It allows to minimize - * the rbtree operations for the fast connections. + * Use a previous timer value if difference between it and a new + * value is less than NGX_TIMER_LAZY_DELAY milliseconds: this allows + * to minimize the rbtree operations for fast connections. */ diff = (ngx_msec_int_t) (key - ev->timer.key); diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -98,7 +98,7 @@ ngx_http_access_handler(ngx_http_request alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); if (alcf->rules == NULL) { - return NGX_OK; + return NGX_DECLINED; } /* AF_INET only */ @@ -116,7 +116,7 @@ ngx_http_access_handler(ngx_http_request if (rule[i].deny) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (!clcf->satisfy_any) { + if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "access forbidden by rule"); } @@ -128,7 +128,7 @@ ngx_http_access_handler(ngx_http_request } } - return NGX_OK; + return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -113,7 +113,7 @@ ngx_http_auth_basic_handler(ngx_http_req alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); if (alcf->realm.len == 0 || alcf->user_file.len == 0) { - return NGX_OK; + return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module); @@ -232,7 +232,7 @@ ngx_http_auth_basic_handler(ngx_http_req if (state == sw_passwd) { pwd.len = i - passwd; - pwd.data = ngx_palloc(r->pool, pwd.len + 1); + pwd.data = ngx_pnalloc(r->pool, pwd.len + 1); if (pwd.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -400,7 +400,7 @@ ngx_http_auth_basic(ngx_conf_t *cf, void len = sizeof("Basic realm=\"") - 1 + realm->len + 1; - basic = ngx_palloc(cf->pool, len); + basic = ngx_pnalloc(cf->pool, len); if (basic == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -135,7 +135,7 @@ ngx_http_autoindex_handler(ngx_http_requ { u_char *last, *filename, scale; off_t length; - size_t len, copy, allocated, root; + size_t len, utf_len, allocated, root; ngx_tm_t tm; ngx_err_t err; ngx_buf_t *b; @@ -181,7 +181,10 @@ ngx_http_autoindex_handler(ngx_http_requ } allocated = path.len; - path.len = last - path.data - 1; + path.len = last - path.data; + if (path.len > 1) { + path.len--; + } path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -236,6 +239,11 @@ ngx_http_autoindex_handler(ngx_http_requ rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%V\" failed", &path); + } + return rc; } @@ -274,7 +282,7 @@ ngx_http_autoindex_handler(ngx_http_requ allocated = path.len + 1 + len + 1 + NGX_HTTP_AUTOINDEX_PREALLOCATE; - filename = ngx_palloc(pool, allocated); + filename = ngx_pnalloc(pool, allocated); if (filename == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } @@ -310,7 +318,7 @@ ngx_http_autoindex_handler(ngx_http_requ entry->name.len = len; - entry->name.data = ngx_palloc(pool, len + 1); + entry->name.data = ngx_pnalloc(pool, len + 1); if (entry->name.data == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } @@ -321,7 +329,7 @@ ngx_http_autoindex_handler(ngx_http_requ NGX_ESCAPE_HTML); if (r->utf8) { - entry->utf_len = ngx_utf_length(entry->name.data, entry->name.len); + entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); } else { entry->utf_len = len; } @@ -404,15 +412,16 @@ ngx_http_autoindex_handler(ngx_http_requ len = entry[i].utf_len; - if (entry[i].name.len - len) { + if (entry[i].name.len != len) { if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { - copy = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; + utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; } else { - copy = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; + utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; } - b->last = ngx_utf_cpystrn(b->last, entry[i].name.data, copy); + b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, + utf_len, entry[i].name.len + 1); last = b->last; } else { diff --git a/src/http/modules/ngx_http_browser_module.c b/src/http/modules/ngx_http_browser_module.c --- a/src/http/modules/ngx_http_browser_module.c +++ b/src/http/modules/ngx_http_browser_module.c @@ -397,7 +397,7 @@ ngx_http_browser_add_variable(ngx_conf_t for (var = ngx_http_browsers; var->name.len; var++) { - v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGABLE); + v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGEABLE); if (v == NULL) { return NGX_ERROR; } @@ -673,7 +673,7 @@ ngx_http_modern_browser_value(ngx_conf_t bcf->modern_browser_value->len = value[1].len; bcf->modern_browser_value->valid = 1; - bcf->modern_browser_value->no_cachable = 0; + bcf->modern_browser_value->no_cacheable = 0; bcf->modern_browser_value->not_found = 0; bcf->modern_browser_value->data = value[1].data; @@ -698,7 +698,7 @@ ngx_http_ancient_browser_value(ngx_conf_ bcf->ancient_browser_value->len = value[1].len; bcf->ancient_browser_value->valid = 1; - bcf->ancient_browser_value->no_cachable = 0; + bcf->ancient_browser_value->no_cacheable = 0; bcf->ancient_browser_value->not_found = 0; bcf->ancient_browser_value->data = value[1].data; diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -204,6 +204,12 @@ ngx_http_charset_header_filter(ngx_http_ if (r == r->main) { + if (r->headers_out.content_encoding + && r->headers_out.content_encoding->value.len) + { + return ngx_http_next_header_filter(r); + } + if (r->headers_out.content_type.len == 0) { return ngx_http_next_header_filter(r); } @@ -366,8 +372,8 @@ ngx_http_charset_header_filter(ngx_http_ no_charset_map: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "no \"charset_map\" between the charsets " - "\"%V\" and \"%V\"", from, to); + "no \"charset_map\" between the charsets \"%V\" and \"%V\"", + from, to); return ngx_http_next_header_filter(r); } @@ -561,25 +567,33 @@ ngx_http_charset_body_filter(ngx_http_re static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table) { - u_char *p; - - for (p = b->pos; p < b->last; p++) { + u_char *p, *last; - if (*p == table[*p]) { - continue; - } + last = b->last; - while (p < b->last) { - *p = table[*p]; - p++; + for (p = b->pos; p < last; p++) { + + if (*p != table[*p]) { + goto recode; } - - b->in_file = 0; - - return 1; } return 0; + +recode: + + do { + if (*p != table[*p]) { + *p = table[*p]; + } + + p++; + + } while (p < last); + + b->in_file = 0; + + return 1; } @@ -628,7 +642,7 @@ ngx_http_charset_recode_from_utf8(ngx_po size = buf->last - src; saved = src; - n = ngx_utf_decode(&saved, size); + n = ngx_utf8_decode(&saved, size); if (n == 0xfffffffe) { /* incomplete UTF-8 symbol */ @@ -696,7 +710,7 @@ ngx_http_charset_recode_from_utf8(ngx_po } saved = ctx->saved; - n = ngx_utf_decode(&saved, i); + n = ngx_utf8_decode(&saved, i); c = '\0'; @@ -804,7 +818,7 @@ recode: len = buf->last - src; - n = ngx_utf_decode(&src, len); + n = ngx_utf8_decode(&src, len); if (n < 0x10000) { @@ -1256,7 +1270,7 @@ ngx_http_charset_map(ngx_conf_t *cf, ngx p = &table->src2dst[src * NGX_UTF_LEN] + 1; - n = ngx_utf_decode(&p, i); + n = ngx_utf8_decode(&p, i); if (n > 0xffff) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -1462,6 +1476,12 @@ ngx_http_charset_merge_loc_conf(ngx_conf return NGX_CONF_OK; } + if (conf->source_charset >= NGX_HTTP_CHARSET_VAR + || conf->charset >= NGX_HTTP_CHARSET_VAR) + { + return NGX_CONF_OK; + } + mcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_charset_filter_module); recode = mcf->recodes.elts; @@ -1519,9 +1539,8 @@ ngx_http_charset_postconfiguration(ngx_c } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - " no \"charset_map\" between the charsets " - "\"%V\" and \"%V\"", - &charset[c].name, &charset[recode[i].dst].name); + "no \"charset_map\" between the charsets \"%V\" and \"%V\"", + &charset[c].name, &charset[recode[i].dst].name); return NGX_ERROR; next: diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -21,8 +21,9 @@ typedef struct { ngx_uint_t methods; + ngx_uint_t access; + ngx_uint_t min_delete_depth; ngx_flag_t create_full_put_path; - ngx_uint_t access; } ngx_http_dav_loc_conf_t; @@ -37,10 +38,11 @@ static ngx_int_t ngx_http_dav_handler(ng static void ngx_http_dav_put_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r); -static ngx_int_t ngx_http_dav_no_init(void *ctx, void *prev); -static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r, + ngx_str_t *path, ngx_uint_t dir); static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path); static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf); @@ -49,10 +51,11 @@ static ngx_int_t ngx_http_dav_copy_move_ static ngx_int_t ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path); static ngx_int_t ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path); -static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, + ngx_str_t *path); +static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, + u_char *to); -static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r, - ngx_str_t *path, ngx_uint_t dir); static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt); static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found, char *failed, u_char *path); @@ -90,6 +93,13 @@ static ngx_command_t ngx_http_dav_comma offsetof(ngx_http_dav_loc_conf_t, create_full_put_path), NULL }, + { ngx_string("min_delete_depth"), + 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_dav_loc_conf_t, min_delete_depth), + NULL }, + { ngx_string("dav_access"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, ngx_conf_set_access_slot, @@ -154,7 +164,9 @@ ngx_http_dav_handler(ngx_http_request_t case NGX_HTTP_PUT: if (r->uri.data[r->uri.len - 1] == '/') { - return NGX_HTTP_BAD_REQUEST; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "can not PUT to a collection"); + return NGX_HTTP_CONFLICT; } r->request_body_in_file_only = 1; @@ -195,14 +207,12 @@ ngx_http_dav_handler(ngx_http_request_t static void ngx_http_dav_put_handler(ngx_http_request_t *r) { - char *failed; - u_char *name; size_t root; time_t date; - ngx_err_t err; ngx_str_t *temp, path; - ngx_uint_t status, not_found; + ngx_uint_t status; ngx_file_info_t fi; + ngx_ext_rename_file_t ext; ngx_http_dav_loc_conf_t *dlcf; ngx_http_map_uri_to_path(r, &path, &root, 0); @@ -235,94 +245,27 @@ ngx_http_dav_put_handler(ngx_http_reques dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); -#if !(NGX_WIN32) - - if (ngx_change_file_access(temp->data, dlcf->access) == NGX_FILE_ERROR) { - err = ngx_errno; - not_found = NGX_HTTP_INTERNAL_SERVER_ERROR; - failed = ngx_change_file_access_n; - name = temp->data; - - goto failed; - } - -#endif + ext.access = dlcf->access; + ext.time = -1; + ext.create_path = dlcf->create_full_put_path; + ext.delete_file = 1; + ext.log = r->connection->log; if (r->headers_in.date) { date = ngx_http_parse_time(r->headers_in.date->value.data, r->headers_in.date->value.len); if (date != NGX_ERROR) { - if (ngx_set_file_time(temp->data, - r->request_body->temp_file->file.fd, date) - != NGX_OK) - { - err = ngx_errno; - not_found = NGX_HTTP_INTERNAL_SERVER_ERROR; - failed = ngx_set_file_time_n; - name = temp->data; - - goto failed; - } + ext.time = date; + ext.fd = r->request_body->temp_file->file.fd; } } - not_found = NGX_HTTP_CONFLICT; - failed = ngx_rename_file_n; - name = path.data; - - if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { - goto ok; - } - - err = ngx_errno; - - if (err == NGX_ENOENT) { - - if (dlcf->create_full_put_path) { - err = ngx_create_full_path(path.data, ngx_dir_access(dlcf->access)); - - if (err == 0) { - if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { - goto ok; - } - - err = ngx_errno; - } - } + if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; } -#if (NGX_WIN32) - - if (err == NGX_EEXIST) { - if (ngx_win32_rename_file(temp, &path, r->pool) != NGX_ERROR) { - - if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { - goto ok; - } - } - - err = ngx_errno; - } - -#endif - -failed: - - if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", - temp->data); - } - - ngx_http_finalize_request(r, - ngx_http_dav_error(r->connection->log, err, - not_found, failed, name)); - - return; - -ok: - if (status == NGX_HTTP_CREATED) { if (ngx_http_dav_location(r, path.data) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -343,43 +286,67 @@ ok: static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r) { - size_t root; - ngx_int_t rc, depth; - ngx_uint_t dir; - ngx_str_t path; - ngx_file_info_t fi; + size_t root; + ngx_err_t err; + ngx_int_t rc, depth; + ngx_uint_t i, d, dir; + ngx_str_t path; + ngx_file_info_t fi; + ngx_http_dav_loc_conf_t *dlcf; if (r->headers_in.content_length_n > 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "DELETE with body is unsupported"); return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } - rc = ngx_http_discard_request_body(r); + dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); + + if (dlcf->min_delete_depth) { + d = 0; - if (rc != NGX_OK) { - return rc; + for (i = 0; i < r->uri.len; /* void */) { + if (r->uri.data[i++] == '/') { + if (++d >= dlcf->min_delete_depth && i < r->uri.len) { + goto ok; + } + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "insufficient URI depth:%i to DELETE", d); + return NGX_HTTP_CONFLICT; } +ok: + ngx_http_map_uri_to_path(r, &path, &root, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete filename: \"%s\"", path.data); if (ngx_file_info(path.data, &fi) == -1) { - return ngx_http_dav_error(r->connection->log, ngx_errno, - NGX_HTTP_NOT_FOUND, ngx_file_info_n, - path.data); + 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); } if (ngx_is_dir(&fi)) { if (r->uri.data[r->uri.len - 1] != '/') { - /* TODO: 301 */ - return NGX_HTTP_BAD_REQUEST; + ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR, + "DELETE \"%s\" failed", path.data); + return NGX_HTTP_CONFLICT; } depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "\"Depth\" header must be infinity"); return NGX_HTTP_BAD_REQUEST; } @@ -389,9 +356,16 @@ ngx_http_dav_delete_handler(ngx_http_req } else { + /* + * we do not need to test (r->uri.data[r->uri.len - 1] == '/') + * because ngx_file_info("/file/") returned NGX_ENOTDIR above + */ + depth = ngx_http_dav_depth(r, 0); if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "\"Depth\" header must be 0 or infinity"); return NGX_HTTP_BAD_REQUEST; } @@ -409,16 +383,45 @@ ngx_http_dav_delete_handler(ngx_http_req static ngx_int_t -ngx_http_dav_no_init(void *ctx, void *prev) +ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir) { - return NGX_OK; -} + char *failed; + ngx_tree_ctx_t tree; + + if (dir) { + + tree.init_handler = NULL; + tree.file_handler = ngx_http_dav_delete_file; + tree.pre_tree_handler = ngx_http_dav_noop; + tree.post_tree_handler = ngx_http_dav_delete_dir; + tree.spec_handler = ngx_http_dav_delete_file; + tree.data = NULL; + tree.alloc = 0; + tree.log = r->connection->log; + + /* TODO: 207 */ + if (ngx_walk_tree(&tree, path) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } -static ngx_int_t -ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) -{ - return NGX_OK; + if (ngx_delete_dir(path->data) != NGX_FILE_ERROR) { + return NGX_OK; + } + + failed = ngx_delete_dir_n; + + } else { + + if (ngx_delete_file(path->data) != NGX_FILE_ERROR) { + return NGX_OK; + } + + failed = ngx_delete_file_n; + } + + return ngx_http_dav_error(r->connection->log, ngx_errno, + NGX_HTTP_NOT_FOUND, failed, path->data); } @@ -459,23 +462,34 @@ ngx_http_dav_delete_file(ngx_tree_ctx_t static ngx_int_t +ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + return NGX_OK; +} + + +static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf) { + u_char *p; size_t root; - ngx_int_t rc; ngx_str_t path; if (r->headers_in.content_length_n > 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "MKCOL with body is unsupported"); return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; + if (r->uri.data[r->uri.len - 1] != '/') { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "MKCOL can create a collection only"); + return NGX_HTTP_CONFLICT; } - ngx_http_map_uri_to_path(r, &path, &root, 0); + p = ngx_http_map_uri_to_path(r, &path, &root, 0); + + *(p - 1) = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http mkcol path: \"%s\"", path.data); @@ -491,8 +505,7 @@ ngx_http_dav_mkcol_handler(ngx_http_requ } return ngx_http_dav_error(r->connection->log, ngx_errno, - NGX_HTTP_BAD_REQUEST, ngx_create_dir_n, - path.data); + NGX_HTTP_CONFLICT, ngx_create_dir_n, path.data); } @@ -500,15 +513,16 @@ static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r) { u_char *p, *host, *last, ch; - size_t root; + size_t len, root; ngx_err_t err; ngx_int_t rc, depth; - ngx_uint_t overwrite, slash; + ngx_uint_t overwrite, slash, dir; ngx_str_t path, uri; ngx_tree_ctx_t tree; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_http_dav_copy_ctx_t copy; + ngx_http_dav_loc_conf_t *dlcf; if (r->headers_in.content_length_n > 0) { return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; @@ -522,8 +536,12 @@ ngx_http_dav_copy_move_handler(ngx_http_ return NGX_HTTP_BAD_REQUEST; } - if (dest->value.len < sizeof("http://") - 1 + r->server_name.len + 1) { - goto invalid_destination; + len = r->headers_in.server.len; + + if (len == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent no \"Host\" header"); + return NGX_HTTP_BAD_REQUEST; } #if (NGX_HTTP_SSL) @@ -549,18 +567,17 @@ ngx_http_dav_copy_move_handler(ngx_http_ host = dest->value.data + sizeof("http://") - 1; } - if (ngx_strncmp(host, r->server_name.data, r->server_name.len) != 0) { + if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "Destination URI \"%V\" is handled by " + "\"Destination\" URI \"%V\" is handled by " "different repository than the source URI", &dest->value); - return NGX_HTTP_BAD_REQUEST; } last = dest->value.data + dest->value.len; - for (p = host + r->server_name.len; p < last; p++) { + for (p = host + len; p < last; p++) { if (*p == '/') { goto destination_done; } @@ -571,15 +588,36 @@ invalid_destination: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Destination\" header: \"%V\"", &dest->value); - return NGX_HTTP_BAD_REQUEST; destination_done: - depth = ngx_http_dav_depth(r, 0); + if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') + || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "both URI \"%V\" and \"Destination\" URI \"%V\" " + "should be either collections or non-collections", + &r->uri, &dest->value); + return NGX_HTTP_CONFLICT; + } + + depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); - if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) { - return NGX_HTTP_BAD_REQUEST; + if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { + + if (r->method == NGX_HTTP_COPY) { + if (depth != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "\"Depth\" header must be 0 or infinity"); + return NGX_HTTP_BAD_REQUEST; + } + + } else { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "\"Depth\" header must be infinity"); + return NGX_HTTP_BAD_REQUEST; + } } over = r->headers_in.overwrite; @@ -603,7 +641,6 @@ destination_done: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Overwrite\" header: \"%V\"", &over->value); - return NGX_HTTP_BAD_REQUEST; } @@ -611,12 +648,6 @@ destination_done: overwrite_done: - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - ngx_http_map_uri_to_path(r, &path, &root, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -656,26 +687,27 @@ overwrite_done: /* destination does not exist */ + overwrite = 0; + dir = 0; + } else { /* destination exists */ if (ngx_is_dir(&fi) && !slash) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "\"%V\" could not be %Ved to collection \"%V\"", + &r->uri, &r->method_name, &dest->value); return NGX_HTTP_CONFLICT; } if (!overwrite) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST, + "\"%s\" could not be created", copy.path.data); return NGX_HTTP_PRECONDITION_FAILED; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http delete: \"%s\"", copy.path.data); - - rc = ngx_http_dav_delete_path(r, ©.path, ngx_is_dir(&fi)); - - if (rc != NGX_OK) { - return rc; - } + dir = ngx_is_dir(&fi); } if (ngx_file_info(path.data, &fi) == -1) { @@ -684,14 +716,28 @@ overwrite_done: path.data); } - if (ngx_is_dir(&fi)) { if (r->uri.data[r->uri.len - 1] != '/') { - /* TODO: 301 */ + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "\"%V\" is collection", &r->uri); return NGX_HTTP_BAD_REQUEST; } + if (overwrite) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http delete: \"%s\"", copy.path.data); + + rc = ngx_http_dav_delete_path(r, ©.path, dir); + + if (rc != NGX_OK) { + return rc; + } + } + } + + if (ngx_is_dir(&fi)) { + path.len -= 2; /* omit "/\0" */ if (r->method == NGX_HTTP_MOVE) { @@ -710,8 +756,8 @@ overwrite_done: copy.len = path.len; - tree.init_handler = ngx_http_dav_no_init; - tree.file_handler = ngx_http_dav_copy_file; + tree.init_handler = NULL; + tree.file_handler = ngx_http_dav_copy_tree_file; tree.pre_tree_handler = ngx_http_dav_copy_dir; tree.post_tree_handler = ngx_http_dav_copy_dir_time; tree.spec_handler = ngx_http_dav_noop; @@ -734,21 +780,21 @@ overwrite_done: } else { - if (dest->value.data[dest->value.len - 1] == '/') { - return NGX_HTTP_BAD_REQUEST; - } - if (r->method == NGX_HTTP_MOVE) { if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) { return NGX_HTTP_NO_CONTENT; } } - tree.data = © + dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); + + tree.size = ngx_file_size(&fi); + tree.mtime = ngx_file_mtime(&fi); + tree.access = dlcf->access; tree.log = r->connection->log; - if (ngx_http_dav_copy_file(&tree, &path) != NGX_FILE_ERROR) { - + if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK) + { if (r->method == NGX_HTTP_MOVE) { rc = ngx_http_dav_delete_path(r, &path, 0); @@ -807,9 +853,6 @@ ngx_http_dav_copy_dir_time(ngx_tree_ctx_ u_char *p, *dir; size_t len; ngx_http_dav_copy_ctx_t *copy; -#if (WIN32) - ngx_fd_t fd; -#endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy dir time: \"%s\"", path->data); @@ -829,7 +872,9 @@ ngx_http_dav_copy_dir_time(ngx_tree_ctx_ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy dir time to: \"%s\"", dir); -#if (WIN32) +#if (NGX_WIN32) + { + ngx_fd_t fd; fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0); @@ -847,6 +892,7 @@ ngx_http_dav_copy_dir_time(ngx_tree_ctx_ ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, ngx_close_file_n " \"%s\" failed", dir); } + } failed: @@ -866,15 +912,11 @@ failed: static ngx_int_t -ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) +ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { u_char *p, *file; size_t len; - off_t size; - ssize_t n; - ngx_fd_t fd, copy_fd; ngx_http_dav_copy_ctx_t *copy; - u_char buf[NGX_HTTP_DAV_COPY_BLOCK]; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy file: \"%s\"", path->data); @@ -894,21 +936,39 @@ ngx_http_dav_copy_file(ngx_tree_ctx_t *c ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy file to: \"%s\"", file); - fd = ngx_open_file(path->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + (void) ngx_http_dav_copy_file(ctx, path->data, file); + + ngx_free(file); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to) +{ + off_t size; + ssize_t n; + ngx_fd_t fd, cfd; + ngx_int_t rc; + u_char buf[NGX_HTTP_DAV_COPY_BLOCK]; + + fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, - path->data); - goto failed; + from); + return NGX_ERROR; } - copy_fd = ngx_open_file(file, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - ctx->access); + cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, + ctx->access); - if (copy_fd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, - file); - goto copy_failed; + rc = NGX_ERROR; + + if (cfd == NGX_INVALID_FILE) { + (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to); + goto failed; } for (size = ctx->size; size > 0; size -= n) { @@ -917,81 +977,39 @@ ngx_http_dav_copy_file(ngx_tree_ctx_t *c if (n == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_read_fd_n " \"%s\" failed", path->data); - break; + ngx_read_fd_n " \"%s\" failed", from); + goto failed; } - if (ngx_write_fd(copy_fd, buf, n) == NGX_FILE_ERROR) { + if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_write_fd_n " \"%s\" failed", file); + ngx_write_fd_n " \"%s\" failed", to); + goto failed; } } - if (ngx_set_file_time(file, copy_fd, ctx->mtime) != NGX_OK) { + if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", file); + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; } - if (ngx_close_file(copy_fd) == NGX_FILE_ERROR) { + if (ngx_close_file(cfd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", file); + ngx_close_file_n " \"%s\" failed", to); + goto failed; } -copy_failed: - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", path->data); - } + rc = NGX_OK; failed: - ngx_free(file); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir) -{ - char *failed; - ngx_tree_ctx_t tree; - - if (dir) { - - tree.init_handler = ngx_http_dav_no_init; - tree.file_handler = ngx_http_dav_delete_file; - tree.pre_tree_handler = ngx_http_dav_noop; - tree.post_tree_handler = ngx_http_dav_delete_dir; - tree.spec_handler = ngx_http_dav_delete_file; - tree.data = NULL; - tree.alloc = 0; - tree.log = r->connection->log; - - /* todo: 207 */ - - if (ngx_walk_tree(&tree, path) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (ngx_delete_dir(path->data) != NGX_FILE_ERROR) { - return NGX_OK; - } - - failed = ngx_delete_dir_n; - - } else { - - if (ngx_delete_file(path->data) != NGX_FILE_ERROR) { - return NGX_OK; - } - - failed = ngx_delete_file_n; + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", from); } - return ngx_http_dav_error(r->connection->log, ngx_errno, - NGX_HTTP_NOT_FOUND, failed, path->data); + return rc; } @@ -1084,7 +1102,7 @@ ngx_http_dav_location(ngx_http_request_t location = path + clcf->root.len; } else { - location = ngx_palloc(r->pool, r->uri.len); + location = ngx_pnalloc(r->pool, r->uri.len); if (location == NULL) { return NGX_ERROR; } @@ -1120,8 +1138,9 @@ ngx_http_dav_create_loc_conf(ngx_conf_t * conf->methods = 0; */ + conf->min_delete_depth = NGX_CONF_UNSET_UINT; + conf->access = NGX_CONF_UNSET_UINT; conf->create_full_put_path = NGX_CONF_UNSET; - conf->access = NGX_CONF_UNSET_UINT; return conf; } @@ -1136,11 +1155,14 @@ ngx_http_dav_merge_loc_conf(ngx_conf_t * ngx_conf_merge_bitmask_value(conf->methods, prev->methods, (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF)); - ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path, - 0); + ngx_conf_merge_uint_value(conf->min_delete_depth, + prev->min_delete_depth, 0); ngx_conf_merge_uint_value(conf->access, prev->access, 0600); + ngx_conf_merge_value(conf->create_full_put_path, + prev->create_full_put_path, 0); + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -127,6 +127,8 @@ ngx_http_empty_gif_handler(ngx_http_requ 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); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -135,44 +135,9 @@ static char *ngx_http_fastcgi_upstream_f ngx_command_t *cmd, void *conf); -static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = { - { 1, /* version */ - NGX_HTTP_FASTCGI_BEGIN_REQUEST, /* type */ - 0, /* request_id_hi */ - 1, /* request_id_lo */ - 0, /* content_length_hi */ - sizeof(ngx_http_fastcgi_begin_request_t), /* content_length_lo */ - 0, /* padding_length */ - 0 }, /* reserved */ - - { 0, /* role_hi */ - NGX_HTTP_FASTCGI_RESPONDER, /* role_lo */ - 0, /* NGX_HTTP_FASTCGI_KEEP_CONN */ /* flags */ - { 0, 0, 0, 0, 0 } }, /* reserved[5] */ - - { 1, /* version */ - NGX_HTTP_FASTCGI_PARAMS, /* type */ - 0, /* request_id_hi */ - 1 }, /* request_id_lo */ - -}; - - -static ngx_str_t ngx_http_fastcgi_script_name = - ngx_string("fastcgi_script_name"); - - static ngx_conf_post_t ngx_http_fastcgi_lowat_post = { ngx_http_fastcgi_lowat_check }; -static ngx_conf_deprecated_t ngx_conf_deprecated_fastcgi_header_buffer_size = { - ngx_conf_deprecated, "fastcgi_header_buffer_size", "fastcgi_buffer_size" -}; - -static ngx_conf_deprecated_t ngx_conf_deprecated_fastcgi_redirect_errors = { - ngx_conf_deprecated, "fastcgi_redirect_errors", "fastcgi_intercept_errors" -}; - static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -251,13 +216,6 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size), NULL }, - { ngx_string("fastcgi_header_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_fastcgi_loc_conf_t, upstream.buffer_size), - &ngx_conf_deprecated_fastcgi_header_buffer_size }, - { ngx_string("fastcgi_pass_request_headers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -279,13 +237,6 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors), NULL }, - { ngx_string("fastcgi_redirect_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_fastcgi_loc_conf_t, upstream.intercept_errors), - &ngx_conf_deprecated_fastcgi_redirect_errors }, - { ngx_string("fastcgi_read_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -412,12 +363,40 @@ ngx_module_t ngx_http_fastcgi_module = }; +static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = { + { 1, /* version */ + NGX_HTTP_FASTCGI_BEGIN_REQUEST, /* type */ + 0, /* request_id_hi */ + 1, /* request_id_lo */ + 0, /* content_length_hi */ + sizeof(ngx_http_fastcgi_begin_request_t), /* content_length_lo */ + 0, /* padding_length */ + 0 }, /* reserved */ + + { 0, /* role_hi */ + NGX_HTTP_FASTCGI_RESPONDER, /* role_lo */ + 0, /* NGX_HTTP_FASTCGI_KEEP_CONN */ /* flags */ + { 0, 0, 0, 0, 0 } }, /* reserved[5] */ + + { 1, /* version */ + NGX_HTTP_FASTCGI_PARAMS, /* type */ + 0, /* request_id_hi */ + 1 }, /* request_id_lo */ + +}; + + +static ngx_str_t ngx_http_fastcgi_script_name = + ngx_string("fastcgi_script_name"); + + static ngx_str_t ngx_http_fastcgi_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-Buffer"), + ngx_string("X-Accel-Buffering"), + ngx_string("X-Accel-Charset"), ngx_null_string }; @@ -432,7 +411,7 @@ ngx_http_fastcgi_handler(ngx_http_reques if (r->subrequest_in_memory) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_http_fastcgi_module does not support " - "subrequest in memeory"); + "subrequest in memory"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -443,6 +422,8 @@ ngx_http_fastcgi_handler(ngx_http_reques return NGX_HTTP_INTERNAL_SERVER_ERROR; } + u->schema = flcf->upstream.schema; + u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #if (NGX_THREADS) @@ -505,7 +486,7 @@ ngx_http_fastcgi_create_request(ngx_http if (flcf->params_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); - ngx_http_script_flush_no_cachable_variables(r, flcf->flushes); + ngx_http_script_flush_no_cacheable_variables(r, flcf->flushes); le.flushed = 1; le.ip = flcf->params_len->elts; @@ -551,7 +532,7 @@ ngx_http_fastcgi_create_request(ngx_http if (len > 65535) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "fastcgi: the request record is too big"); + "fastcgi request record is too big: %uz", len); return NGX_ERROR; } @@ -636,6 +617,11 @@ ngx_http_fastcgi_create_request(ngx_http code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "fastcgi param: \"%*s: %*s\"", + key_len, e.pos - (key_len + val_len), + val_len, e.pos - val_len); } b->last = e.pos; @@ -885,7 +871,7 @@ ngx_http_fastcgi_process_header(ngx_http if (f == NULL) { f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); if (f == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); @@ -993,7 +979,7 @@ ngx_http_fastcgi_process_header(ngx_http for (i = 0; i < flcf->catch_stderr->nelts; i++) { if (ngx_strstr(line.data, pattern[i].data)) { - return NGX_HTTP_BAD_GATEWAY; + return NGX_HTTP_UPSTREAM_INVALID_HEADER; } } } @@ -1061,7 +1047,7 @@ ngx_http_fastcgi_process_header(ngx_http h = ngx_list_push(&u->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } if (f->split_parts && f->split_parts->nelts) { @@ -1073,9 +1059,9 @@ ngx_http_fastcgi_process_header(ngx_http size += part[i].end - part[i].start; } - p = ngx_palloc(r->pool, size); + p = ngx_pnalloc(r->pool, size); if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } buf.pos = p; @@ -1101,9 +1087,9 @@ ngx_http_fastcgi_process_header(ngx_http h->value.data = r->header_start; h->value.data[h->value.len] = '\0'; - h->lowcase_key = ngx_palloc(r->pool, h->key.len); + h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } } else { @@ -1111,11 +1097,11 @@ ngx_http_fastcgi_process_header(ngx_http h->key.len = r->header_name_end - r->header_name_start; h->value.len = r->header_end - r->header_start; - h->key.data = ngx_palloc(r->pool, - h->key.len + 1 + h->value.len + 1 - + h->key.len); + 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_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->value.data = h->key.data + h->key.len + 1; @@ -1134,16 +1120,14 @@ ngx_http_fastcgi_process_header(ngx_http ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { - for (i = 0; i < h->key.len; i++) { - h->lowcase_key[i] = ngx_tolower(h->key.data[i]); - } + 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_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1172,12 +1156,22 @@ ngx_http_fastcgi_process_header(ngx_http status = ngx_atoi(status_line->data, 3); if (status == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent invalid status \"%V\"", + status_line); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = status; u->headers_in.status_line = *status_line; + } 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"; + } else { u->headers_in.status_n = 200; u->headers_in.status_line.len = sizeof("200 OK") - 1; @@ -1186,8 +1180,8 @@ ngx_http_fastcgi_process_header(ngx_http u->state->status = u->headers_in.status_n; #if 0 - if (u->cachable) { - u->cachable = ngx_http_upstream_is_cachable(r); + if (u->cacheable) { + u->cacheable = ngx_http_upstream_is_cacheable(r); } #endif @@ -1221,7 +1215,7 @@ ngx_http_fastcgi_process_header(ngx_http } if (rc == NGX_OK) { - return NGX_AGAIN; + continue; } /* rc == NGX_AGAIN */ @@ -1233,7 +1227,7 @@ ngx_http_fastcgi_process_header(ngx_http f->split_parts = ngx_array_create(r->pool, 1, sizeof(ngx_http_fastcgi_split_part_t)); if (f->split_parts == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } } @@ -1610,7 +1604,7 @@ ngx_http_fastcgi_add_variables(ngx_conf_ ngx_http_variable_t *var; var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, - NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHABLE); + NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE); if (var == NULL) { return NGX_ERROR; } @@ -1638,8 +1632,6 @@ ngx_http_fastcgi_create_loc_conf(ngx_con * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.hide_headers = NULL; - * conf->upstream.pass_headers = NULL; * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; @@ -1669,6 +1661,9 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; + conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; + conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; + conf->upstream.intercept_errors = NGX_CONF_UNSET; /* "fastcgi_cyclic_temp_file" is disabled */ @@ -1689,11 +1684,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf u_char *p; size_t size; uintptr_t *code; - ngx_str_t *header; - ngx_uint_t i, j; - ngx_array_t hide_headers; + ngx_uint_t i; ngx_keyval_t *src; - ngx_hash_key_t *hk; ngx_hash_init_t hash; ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; @@ -1855,108 +1847,19 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_conf_merge_str_value(conf->index, prev->index, ""); - if (conf->upstream.hide_headers == NULL - && conf->upstream.pass_headers == NULL) - { - conf->upstream.hide_headers = prev->upstream.hide_headers; - conf->upstream.pass_headers = prev->upstream.pass_headers; - conf->upstream.hide_headers_hash = prev->upstream.hide_headers_hash; - - if (conf->upstream.hide_headers_hash.buckets) { - goto peers; - } - - } else { - if (conf->upstream.hide_headers == NULL) { - conf->upstream.hide_headers = prev->upstream.hide_headers; - } - - if (conf->upstream.pass_headers == NULL) { - conf->upstream.pass_headers = prev->upstream.pass_headers; - } - } - - if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) + hash.max_size = 512; + hash.bucket_size = ngx_align(64, ngx_cacheline_size); + hash.name = "fastcgi_hide_headers_hash"; + + if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, + &prev->upstream, + ngx_http_fastcgi_hide_headers, + &hash) != NGX_OK) { return NGX_CONF_ERROR; } - for (header = ngx_http_fastcgi_hide_headers; header->len; header++) { - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = *header; - hk->key_hash = ngx_hash_key_lc(header->data, header->len); - hk->value = (void *) 1; - } - - if (conf->upstream.hide_headers) { - - header = conf->upstream.hide_headers->elts; - - for (i = 0; i < conf->upstream.hide_headers->nelts; i++) { - - hk = hide_headers.elts; - - for (j = 0; j < hide_headers.nelts; j++) { - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - goto exist; - } - } - - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = header[i]; - hk->key_hash = ngx_hash_key_lc(header[i].data, header[i].len); - hk->value = (void *) 1; - - exist: - - continue; - } - } - - if (conf->upstream.pass_headers) { - - hk = hide_headers.elts; - header = conf->upstream.pass_headers->elts; - - for (i = 0; i < conf->upstream.pass_headers->nelts; i++) { - - for (j = 0; j < hide_headers.nelts; j++) { - - if (hk[j].key.data == NULL) { - continue; - } - - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - hk[j].key.data = NULL; - break; - } - } - } - } - - hash.hash = &conf->upstream.hide_headers_hash; - hash.key = ngx_hash_key_lc; - hash.max_size = 512; - hash.bucket_size = ngx_align(64, ngx_cacheline_size); - hash.name = "fastcgi_hide_headers_hash"; - hash.pool = cf->pool; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) { - return NGX_CONF_ERROR; - } - -peers: - if (conf->upstream.upstream == NULL) { conf->upstream.upstream = prev->upstream.upstream; conf->upstream.schema = prev->upstream.schema; @@ -2104,7 +2007,7 @@ ngx_http_fastcgi_script_name_variable(ng if (r->uri.len) { v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); @@ -2117,7 +2020,7 @@ ngx_http_fastcgi_script_name_variable(ng v->len = r->uri.len + flcf->index.len; - v->data = ngx_palloc(r->pool, v->len); + v->data = ngx_pnalloc(r->pool, v->len); if (v->data == NULL) { return NGX_ERROR; } @@ -2128,7 +2031,7 @@ ngx_http_fastcgi_script_name_variable(ng } else { v->len = 0; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = NULL; @@ -2171,8 +2074,6 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng clcf->handler = ngx_http_fastcgi_handler; - lcf->upstream.location = clcf->name; - if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } @@ -2215,7 +2116,7 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, n sc.source = &value[1]; sc.lengths = &flcf->upstream.store_lengths; sc.values = &flcf->upstream.store_values; - sc.variables = ngx_http_script_variables_count(&value[1]);; + sc.variables = ngx_http_script_variables_count(&value[1]); sc.complete_lengths = 1; sc.complete_values = 1; diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -60,10 +60,9 @@ ngx_module_t ngx_http_flv_module = { static ngx_int_t ngx_http_flv_handler(ngx_http_request_t *r) { - u_char *p, *last; + u_char *p, *n, *last; off_t start, len; size_t root; - ngx_fd_t fd; ngx_int_t rc; ngx_uint_t level, i; ngx_str_t path; @@ -106,15 +105,17 @@ ngx_http_flv_handler(ngx_http_request_t clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; - - rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); - if (rc == NGX_ERROR) { - + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { switch (of.err) { case 0: @@ -149,11 +150,9 @@ ngx_http_flv_handler(ngx_http_request_t return rc; } - fd = of.fd; - if (!of.is_file) { - if (ngx_close_file(fd) == NGX_FILE_ERROR) { + if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } @@ -161,17 +160,25 @@ ngx_http_flv_handler(ngx_http_request_t return NGX_DECLINED; } + r->root_tested = 1; + start = 0; len = of.size; i = 1; if (r->args.len) { - p = (u_char *) ngx_strstr(r->args.data, "start="); + p = (u_char *) ngx_strnstr(r->args.data, "start=", r->args.len); if (p) { p += 6; - start = ngx_atoof(p, r->args.len - (p - r->args.data)); + for (n = p; n < r->args.data + r->args.len; n++) { + if (*n == '&') { + break; + } + } + + start = ngx_atoof(p, n - p); if (start == NGX_ERROR || start >= len) { start = 0; @@ -206,9 +213,6 @@ ngx_http_flv_handler(ngx_http_request_t out[0].buf = b; out[0].next = &out[1]; - - } else { - r->allow_ranges = 1; } @@ -222,6 +226,8 @@ ngx_http_flv_handler(ngx_http_request_t return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->allow_ranges = 1; + rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { @@ -235,7 +241,7 @@ ngx_http_flv_handler(ngx_http_request_t b->last_buf = 1; b->last_in_chain = 1; - b->file->fd = fd; + b->file->fd = of.fd; b->file->name = path; b->file->log = log; diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -116,7 +116,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c name.data++; } - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGABLE); + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); if (var == NULL) { return NGX_CONF_ERROR; } @@ -257,7 +257,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command } var->valid = 1; - var->no_cachable = 0; + var->no_cacheable = 0; var->not_found = 0; v = ngx_array_push(&ctx->values); diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -19,9 +19,6 @@ typedef struct { ngx_bufs_t bufs; - ngx_uint_t http_version; - ngx_uint_t proxied; - ngx_int_t level; size_t wbits; size_t memlevel; @@ -29,17 +26,6 @@ typedef struct { } ngx_http_gzip_conf_t; -#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 -#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 -#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 -#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010 -#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020 -#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040 -#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080 -#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100 -#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 - - typedef struct { ngx_chain_t *in; ngx_chain_t *free; @@ -69,8 +55,6 @@ typedef struct { } ngx_http_gzip_ctx_t; -static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r, - ngx_http_gzip_conf_t *conf); static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size); static void ngx_http_gzip_filter_free(void *opaque, void *address); @@ -98,27 +82,6 @@ static ngx_conf_post_handler_pt ngx_htt static ngx_conf_post_handler_pt ngx_http_gzip_hash_p = ngx_http_gzip_hash; -static ngx_conf_enum_t ngx_http_gzip_http_version[] = { - { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, - { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { - { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, - { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, - { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, - { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, - { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, - { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, - { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, - { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, - { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_http_gzip_filter_commands[] = { { ngx_string("gzip"), @@ -171,20 +134,6 @@ static ngx_command_t ngx_http_gzip_filt offsetof(ngx_http_gzip_conf_t, no_buffer), NULL }, - { ngx_string("gzip_http_version"), - 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_gzip_conf_t, http_version), - &ngx_http_gzip_http_version }, - - { ngx_string("gzip_proxied"), - 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_gzip_conf_t, proxied), - &ngx_http_gzip_proxied_mask }, - { ngx_string("gzip_min_length"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -247,10 +196,6 @@ struct gztrailer { static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); -static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache"); -static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store"); -static ngx_str_t ngx_http_gzip_private = ngx_string("private"); - static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; @@ -261,6 +206,7 @@ ngx_http_gzip_header_filter(ngx_http_req { ngx_str_t *type; ngx_uint_t i; + ngx_table_elt_t *h; ngx_http_gzip_ctx_t *ctx; ngx_http_gzip_conf_t *conf; @@ -271,21 +217,16 @@ ngx_http_gzip_header_filter(ngx_http_req && r->headers_out.status != NGX_HTTP_FORBIDDEN && r->headers_out.status != NGX_HTTP_NOT_FOUND) || r->header_only - || r != r->main - || r->http_version < conf->http_version || r->headers_out.content_type.len == 0 || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) - || r->headers_in.accept_encoding == NULL || (r->headers_out.content_length_n != -1 && r->headers_out.content_length_n < conf->min_length) - || ngx_strstr(r->headers_in.accept_encoding->value.data, "gzip") == NULL - ) + || ngx_http_gzip_ok(r) != NGX_OK) { return ngx_http_next_header_filter(r); } - type = conf->types->elts; for (i = 0; i < conf->types->nelts; i++) { if (r->headers_out.content_type.len >= type[i].len @@ -298,32 +239,8 @@ ngx_http_gzip_header_filter(ngx_http_req return ngx_http_next_header_filter(r); - found: - if (r->headers_in.via) { - if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) { - return ngx_http_next_header_filter(r); - } - - if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_ANY) - && ngx_http_gzip_proxied(r, conf) == NGX_DECLINED) - { - return ngx_http_next_header_filter(r); - } - } - - - /* - * if the URL (without the "http://" prefix) is longer than 253 bytes - * then MSIE 4.x can not handle the compressed stream - it waits too long, - * hangs up or crashes - */ - - if (r->headers_in.msie4 && r->unparsed_uri.len > 200) { - return ngx_http_next_header_filter(r); - } - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -331,19 +248,20 @@ found: ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); - ctx->request = r; - r->headers_out.content_encoding = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_encoding == NULL) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { return NGX_ERROR; } - r->headers_out.content_encoding->hash = 1; - r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1; - r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding"; - r->headers_out.content_encoding->value.len = sizeof("gzip") - 1; - r->headers_out.content_encoding->value.data = (u_char *) "gzip"; + 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"; + + r->headers_out.content_encoding = h; ctx->length = r->headers_out.content_length_n; @@ -357,89 +275,6 @@ found: static ngx_int_t -ngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf) -{ - time_t date, expires; - - if (r->headers_in.authorization - && (conf->proxied & NGX_HTTP_GZIP_PROXIED_AUTH)) - { - return NGX_OK; - } - - if (r->headers_out.expires) { - - if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { - return NGX_DECLINED; - } - - expires = ngx_http_parse_time(r->headers_out.expires->value.data, - r->headers_out.expires->value.len); - if (expires == NGX_ERROR) { - return NGX_DECLINED; - } - - if (r->headers_out.date) { - date = ngx_http_parse_time(r->headers_out.date->value.data, - r->headers_out.date->value.len); - if (date == NGX_ERROR) { - return NGX_DECLINED; - } - - } else { - date = ngx_time(); - } - - if (expires < date) { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if (r->headers_out.cache_control.elts) { - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE) - && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, - &ngx_http_gzip_no_cache, NULL) >= 0) - { - return NGX_OK; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE) - && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, - &ngx_http_gzip_no_store, NULL) >= 0) - { - return NGX_OK; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE) - && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, - &ngx_http_gzip_private, NULL) >= 0) - { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_LM) - && r->headers_out.last_modified) - { - return NGX_DECLINED; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_ETAG) - && r->headers_out.etag) - { - return NGX_DECLINED; - } - - return NGX_OK; -} - - -static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc, wbits, memlevel; @@ -811,12 +646,15 @@ ngx_http_gzip_body_filter(ngx_http_reque } } - if (last == NGX_AGAIN && !ctx->done) { - return NGX_AGAIN; - } + if (ctx->out == NULL) { - if (ctx->out == NULL && ctx->busy == NULL) { - return NGX_OK; + if (last == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (ctx->busy == NULL) { + return NGX_OK; + } } last = ngx_http_next_body_filter(r, ctx->out); @@ -938,7 +776,7 @@ ngx_http_gzip_ratio_variable(ngx_http_re ngx_http_gzip_ctx_t *ctx; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); @@ -948,7 +786,7 @@ ngx_http_gzip_ratio_variable(ngx_http_re return NGX_OK; } - v->data = ngx_palloc(r->pool, NGX_INT32_LEN + 3); + v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3); if (v->data == NULL) { return NGX_ERROR; } @@ -988,15 +826,12 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf * set by ngx_pcalloc(): * * conf->bufs.num = 0; - * conf->proxied = 0; * conf->types = NULL; */ conf->enable = NGX_CONF_UNSET; conf->no_buffer = NGX_CONF_UNSET; - conf->http_version = NGX_CONF_UNSET_UINT; - conf->level = NGX_CONF_UNSET; conf->wbits = (size_t) NGX_CONF_UNSET; conf->memlevel = (size_t) NGX_CONF_UNSET; @@ -1018,11 +853,6 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize); - ngx_conf_merge_uint_value(conf->http_version, prev->http_version, - NGX_HTTP_VERSION_11); - ngx_conf_merge_bitmask_value(conf->proxied, prev->proxied, - (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF)); - ngx_conf_merge_value(conf->level, prev->level, 1); ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS); ngx_conf_merge_size_value(conf->memlevel, prev->memlevel, @@ -1105,7 +935,7 @@ ngx_http_gzip_types(ngx_conf_t *cf, ngx_ type->len = value[i].len; - type->data = ngx_palloc(cf->pool, type->len + 1); + type->data = ngx_pnalloc(cf->pool, type->len + 1); if (type->data == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -0,0 +1,290 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_flag_t enable; +} ngx_http_gzip_static_conf_t; + + +static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r); +static void *ngx_http_gzip_static_create_conf(ngx_conf_t *cf); +static char *ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_http_gzip_static_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_gzip_static_commands[] = { + + { ngx_string("gzip_static"), + 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_gzip_static_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_gzip_static_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_gzip_static_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_gzip_static_create_conf, /* create location configuration */ + ngx_http_gzip_static_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_gzip_static_module = { + NGX_MODULE_V1, + &ngx_http_gzip_static_module_ctx, /* module context */ + ngx_http_gzip_static_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_gzip_static_handler(ngx_http_request_t *r) +{ + u_char *p; + size_t root; + ngx_str_t path; + ngx_int_t rc; + ngx_uint_t level; + ngx_log_t *log; + ngx_buf_t *b; + ngx_chain_t out; + ngx_table_elt_t *h; + ngx_open_file_info_t of; + ngx_http_core_loc_conf_t *clcf; + ngx_http_gzip_static_conf_t *gzcf; + + if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { + return NGX_DECLINED; + } + + if (r->uri.data[r->uri.len - 1] == '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); + + if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) { + return NGX_DECLINED; + } + + log = r->connection->log; + + p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + *p++ = '.'; + *p++ = 'g'; + *p++ = 'z'; + *p = '\0'; + + path.len = p - path.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http filename: \"%s\"", path.data); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { + switch (of.err) { + + case 0: + return NGX_HTTP_INTERNAL_SERVER_ERROR; + + case NGX_ENOENT: + case NGX_ENOTDIR: + case NGX_ENAMETOOLONG: + + return NGX_DECLINED; + + case NGX_EACCES: + + level = NGX_LOG_ERR; + break; + + default: + + level = NGX_LOG_CRIT; + break; + } + + ngx_log_error(level, log, of.err, + ngx_open_file_n " \"%s\" failed", path.data); + + return NGX_DECLINED; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); + + if (of.is_dir) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); + return NGX_DECLINED; + } + +#if !(NGX_WIN32) /* the not regular files are probably Unix specific */ + + if (!of.is_file) { + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + "\"%s\" is not a regular file", path.data); + + return NGX_HTTP_NOT_FOUND; + } + +#endif + + r->root_tested = 1; + + rc = ngx_http_discard_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + log->action = "sending response to client"; + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = of.size; + r->headers_out.last_modified_time = of.mtime; + + if (ngx_http_set_content_type(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + 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"; + + r->headers_out.content_encoding = h; + + /* we need to allocate all before the header would be sent */ + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); + if (b->file == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + b->file_pos = 0; + b->file_last = of.size; + + b->in_file = b->file_last ? 1 : 0; + b->last_buf = 1; + b->last_in_chain = 1; + + b->file->fd = of.fd; + b->file->name = path; + b->file->log = log; + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +static void * +ngx_http_gzip_static_create_conf(ngx_conf_t *cf) +{ + ngx_http_gzip_static_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_gzip_static_conf_t *prev = parent; + ngx_http_gzip_static_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_gzip_static_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_gzip_static_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -31,18 +31,20 @@ struct ngx_http_header_val_s { }; +#define NGX_HTTP_EXPIRES_OFF 0 +#define NGX_HTTP_EXPIRES_EPOCH 1 +#define NGX_HTTP_EXPIRES_MAX 2 +#define NGX_HTTP_EXPIRES_ACCESS 3 +#define NGX_HTTP_EXPIRES_MODIFIED 4 + + typedef struct { - time_t expires; + ngx_uint_t expires; + time_t expires_time; ngx_array_t *headers; } ngx_http_headers_conf_t; -#define NGX_HTTP_EXPIRES_UNSET -2147483647 -#define NGX_HTTP_EXPIRES_OFF -2147483646 -#define NGX_HTTP_EXPIRES_EPOCH -2147483645 -#define NGX_HTTP_EXPIRES_MAX -2147483644 - - static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf); static ngx_int_t ngx_http_add_cache_control(ngx_http_request_t *r, @@ -76,7 +78,7 @@ static ngx_command_t ngx_http_headers_f { ngx_string("expires"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE1, + |NGX_CONF_TAKE12, ngx_http_headers_expires, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -185,6 +187,7 @@ static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) { size_t len; + time_t since; ngx_uint_t i; ngx_table_elt_t *expires, *cc, **ccp; @@ -261,12 +264,12 @@ ngx_http_set_expires(ngx_http_request_t return NGX_OK; } - expires->value.data = ngx_palloc(r->pool, len); + expires->value.data = ngx_pnalloc(r->pool, len); if (expires->value.data == NULL) { return NGX_ERROR; } - if (conf->expires == 0) { + if (conf->expires_time == 0) { ngx_memcpy(expires->value.data, ngx_cached_http_time.data, ngx_cached_http_time.len + 1); @@ -276,22 +279,32 @@ ngx_http_set_expires(ngx_http_request_t return NGX_OK; } - ngx_http_time(expires->value.data, ngx_time() + conf->expires); + if (conf->expires == NGX_HTTP_EXPIRES_ACCESS + || r->headers_out.last_modified_time == -1) + { + since = ngx_time(); - if (conf->expires < 0) { + } else { + since = r->headers_out.last_modified_time; + } + + ngx_http_time(expires->value.data, since + conf->expires_time); + + if (conf->expires_time < 0) { cc->value.len = sizeof("no-cache") - 1; cc->value.data = (u_char *) "no-cache"; return NGX_OK; } - cc->value.data = ngx_palloc(r->pool, - sizeof("max-age=") + NGX_TIME_T_LEN + 1); + cc->value.data = ngx_pnalloc(r->pool, + sizeof("max-age=") + NGX_TIME_T_LEN + 1); if (cc->value.data == NULL) { return NGX_ERROR; } - cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", conf->expires) + cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", + since + conf->expires_time - ngx_time()) - cc->value.data; return NGX_OK; @@ -369,7 +382,14 @@ ngx_http_set_last_modified(ngx_http_requ old = NULL; } + r->headers_out.last_modified_time = -1; + if (old == NULL || *old == NULL) { + + if (value->len == 0) { + return NGX_OK; + } + h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { return NGX_ERROR; @@ -377,14 +397,17 @@ ngx_http_set_last_modified(ngx_http_requ } else { h = *old; + + if (value->len == 0) { + h->hash = 0; + return NGX_OK; + } } h->hash = hv->value.hash; h->key = hv->value.key; h->value = *value; - r->headers_out.last_modified_time = -1; - return NGX_OK; } @@ -403,9 +426,10 @@ ngx_http_headers_create_conf(ngx_conf_t * set by ngx_pcalloc(): * * conf->headers = NULL; + * conf->expires_time = 0; */ - conf->expires = NGX_HTTP_EXPIRES_UNSET; + conf->expires = NGX_CONF_UNSET_UINT; return conf; } @@ -417,9 +441,13 @@ ngx_http_headers_merge_conf(ngx_conf_t * ngx_http_headers_conf_t *prev = parent; ngx_http_headers_conf_t *conf = child; - if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { - conf->expires = (prev->expires == NGX_HTTP_EXPIRES_UNSET) ? - NGX_HTTP_EXPIRES_OFF : prev->expires; + if (conf->expires == NGX_CONF_UNSET_UINT) { + conf->expires = prev->expires; + conf->expires_time = prev->expires_time; + + if (conf->expires == NGX_CONF_UNSET_UINT) { + conf->expires = NGX_HTTP_EXPIRES_OFF; + } } if (conf->headers == NULL) { @@ -445,56 +473,73 @@ ngx_http_headers_expires(ngx_conf_t *cf, { ngx_http_headers_conf_t *hcf = conf; - ngx_uint_t minus; + ngx_uint_t minus, n; ngx_str_t *value; - if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) { + if (hcf->expires != NGX_CONF_UNSET_UINT) { return "is duplicate"; } value = cf->args->elts; - if (ngx_strcmp(value[1].data, "epoch") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_EPOCH; - return NGX_CONF_OK; - } + if (cf->args->nelts == 2) { + + if (ngx_strcmp(value[1].data, "epoch") == 0) { + hcf->expires = NGX_HTTP_EXPIRES_EPOCH; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "max") == 0) { + hcf->expires = NGX_HTTP_EXPIRES_MAX; + return NGX_CONF_OK; + } - if (ngx_strcmp(value[1].data, "max") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_MAX; - return NGX_CONF_OK; + if (ngx_strcmp(value[1].data, "off") == 0) { + hcf->expires = NGX_HTTP_EXPIRES_OFF; + return NGX_CONF_OK; + } + + hcf->expires = NGX_HTTP_EXPIRES_ACCESS; + + n = 1; + + } else { /* cf->args->nelts == 3 */ + + if (ngx_strcmp(value[1].data, "modified") != 0) { + return "invalid value"; + } + + hcf->expires = NGX_HTTP_EXPIRES_MODIFIED; + + n = 2; } - if (ngx_strcmp(value[1].data, "off") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_OFF; - return NGX_CONF_OK; - } - - if (value[1].data[0] == '+') { - value[1].data++; - value[1].len--; + if (value[n].data[0] == '+') { + value[n].data++; + value[n].len--; minus = 0; - } else if (value[1].data[0] == '-') { - value[1].data++; - value[1].len--; + } else if (value[n].data[0] == '-') { + value[n].data++; + value[n].len--; minus = 1; } else { minus = 0; } - hcf->expires = ngx_parse_time(&value[1], 1); + hcf->expires_time = ngx_parse_time(&value[n], 1); - if (hcf->expires == NGX_ERROR) { + if (hcf->expires_time == NGX_ERROR) { return "invalid value"; } - if (hcf->expires == NGX_PARSE_LARGE_TIME) { + if (hcf->expires_time == NGX_PARSE_LARGE_TIME) { return "value must be less than 68 years"; } if (minus) { - hcf->expires = - hcf->expires; + hcf->expires_time = - hcf->expires_time; } return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -22,25 +22,13 @@ typedef struct { } ngx_http_index_loc_conf_t; -typedef struct { - ngx_uint_t current; - - ngx_str_t path; - ngx_str_t index; - - size_t root; - - ngx_uint_t tested; /* unsigned tested:1 */ -} ngx_http_index_ctx_t; - - #define NGX_HTTP_DEFAULT_INDEX "index.html" static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, - ngx_http_core_loc_conf_t *clcf, ngx_http_index_ctx_t *ctx); -static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx, ngx_err_t err); + ngx_http_core_loc_conf_t *clcf, u_char *path, u_char *last); +static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, u_char *file, + ngx_err_t err); static ngx_int_t ngx_http_index_init(ngx_conf_t *cf); static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); @@ -107,14 +95,13 @@ ngx_module_t ngx_http_index_module = { static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { - u_char *last; - size_t len; + u_char *p, *name; + size_t len, nlen, root, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_log_t *log; - ngx_uint_t i; + ngx_uint_t i, dir_tested; ngx_http_index_t *index; - ngx_http_index_ctx_t *ctx; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; @@ -140,24 +127,14 @@ ngx_http_index_handler(ngx_http_request_ ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - /* - * we use context because the handler supports an async file opening, - * and may be called several times - */ - - ctx = ngx_http_get_module_ctx(r, ngx_http_index_module); - if (ctx == NULL) { - - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_index_ctx_t)); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_index_module); - } + allocated = 0; + root = 0; + dir_tested = 0; + name = NULL; + path.data = NULL; index = ilcf->indices->elts; - for (i = ctx->current; i < ilcf->indices->nelts; i++) { + for (i = 0; i < ilcf->indices->nelts; i++) { if (index[i].lengths == NULL) { @@ -166,7 +143,7 @@ ngx_http_index_handler(ngx_http_request_ } len = ilcf->max_index_len; - ctx->index.len = index[i].name.len; + nlen = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); @@ -184,45 +161,44 @@ ngx_http_index_handler(ngx_http_request_ len += lcode(&e); } - ctx->index.len = len; + nlen = len; /* 16 bytes are preallocation */ len += 16; } - if (len > (size_t) (ctx->path.data + ctx->path.len - ctx->index.data)) { + if (len > (size_t) (path.data + allocated - name)) { - last = ngx_http_map_uri_to_path(r, &ctx->path, &ctx->root, len); - if (last == NULL) { + name = ngx_http_map_uri_to_path(r, &path, &root, len); + if (name == NULL) { return NGX_ERROR; } - ctx->index.data = last; + allocated = path.len; } - path.data = ctx->path.data; - if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ - ngx_memcpy(ctx->index.data, index[i].name.data, index[i].name.len); + ngx_memcpy(name, index[i].name.data, index[i].name.len); - path.len = (ctx->index.data + index[i].name.len - 1) - path.data; + path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; - e.pos = ctx->index.data; + e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } - if (*ctx->index.data == '/') { - ctx->index.len--; - return ngx_http_internal_redirect(r, &ctx->index, &r->args); + if (*name == '/') { + uri.len = nlen - 1; + uri.data = name; + return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; @@ -230,47 +206,38 @@ ngx_http_index_handler(ngx_http_request_ *e.pos++ = '\0'; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "open index \"%V\"", &path); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%V\"", &path); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; - rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); - -#if 0 - if (rc == NGX_AGAIN) { - ctx->current = i; - return NGX_AGAIN; - } -#endif - - if (rc == NGX_ERROR) { - + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, of.err, - ngx_open_file_n " \"%s\" failed", ctx->path.data); + ngx_open_file_n " \"%s\" failed", path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (of.err == NGX_ENOTDIR) { - return ngx_http_index_error(r, ctx, of.err); - - } else if (of.err == NGX_EACCES) { - return ngx_http_index_error(r, ctx, of.err); + if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) { + return ngx_http_index_error(r, path.data, of.err); } - if (!ctx->tested) { - rc = ngx_http_index_test_dir(r, clcf, ctx); + if (!dir_tested) { + rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } - ctx->tested = 1; + dir_tested = 1; } if (of.err == NGX_ENOENT) { @@ -278,24 +245,24 @@ ngx_http_index_handler(ngx_http_request_ } ngx_log_error(NGX_LOG_ERR, log, of.err, - ngx_open_file_n " \"%s\" failed", ctx->path.data); + ngx_open_file_n " \"%s\" failed", path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } - uri.len = r->uri.len + ctx->index.len - 1; + uri.len = r->uri.len + nlen - 1; if (!clcf->alias) { - uri.data = ctx->path.data + ctx->root; + uri.data = path.data + root; } else { - uri.data = ngx_palloc(r->pool, uri.len); + uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_copy(uri.data, r->uri.data, r->uri.len); - ngx_memcpy(last, ctx->index.data, ctx->index.len - 1); + p = ngx_copy(uri.data, r->uri.data, r->uri.len); + ngx_memcpy(p, name, nlen - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); @@ -307,70 +274,73 @@ ngx_http_index_handler(ngx_http_request_ static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, - ngx_http_index_ctx_t *ctx) + u_char *path, u_char *last) { u_char c; - ngx_str_t path; - ngx_uint_t i; + ngx_str_t dir; ngx_open_file_info_t of; - c = *(ctx->index.data - 1); - i = (c == '/') ? 1 : 0; - *(ctx->index.data - i) = '\0'; + c = *last; + if (c != '/' || path == last) { + /* "alias" without trailing slash */ + c = *(++last); + } + *last = '\0'; - path.len = (ctx->index.data - i) - ctx->path.data; - path.data = ctx->path.data; + dir.len = last - path; + dir.data = path; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http index check dir: \"%V\"", &path); + "http index check dir: \"%V\"", &dir); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.test_dir = 1; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; of.errors = clcf->open_file_cache_errors; - if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) != NGX_OK) { if (of.err) { if (of.err == NGX_ENOENT) { - *(ctx->index.data - i) = c; - return ngx_http_index_error(r, ctx, of.err); + *last = c; + return ngx_http_index_error(r, dir.data, NGX_ENOENT); } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + ngx_open_file_n " \"%s\" failed", dir.data); } return NGX_HTTP_INTERNAL_SERVER_ERROR; } - *(ctx->index.data - i) = c; + *last = c; if (of.is_dir) { return NGX_OK; } ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "\"%s\" is not a directory", path.data); + "\"%s\" is not a directory", dir.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } static ngx_int_t -ngx_http_index_error(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx, - ngx_err_t err) +ngx_http_index_error(ngx_http_request_t *r, u_char *file, ngx_err_t err) { if (err == NGX_EACCES) { ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is forbidden", ctx->path.data); + "\"%s\" is forbidden", file); return NGX_HTTP_FORBIDDEN; } ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is not found", ctx->path.data); + "\"%s\" is not found", file); return NGX_HTTP_NOT_FOUND; } @@ -472,11 +442,11 @@ ngx_http_index_set_index(ngx_conf_t *cf, value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { + if (value[i].data[0] == '/' && i != cf->args->nelts - 1) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "only the last index in \"index\" directive " - "may be absolute"); - return NGX_CONF_ERROR; + "should be absolute"); } if (value[i].len == 0) { @@ -503,6 +473,10 @@ ngx_http_index_set_index(ngx_conf_t *cf, ilcf->max_index_len = index->name.len; } + if (index->name.data[0] == '/') { + continue; + } + /* include the terminating '\0' to the length to use ngx_copy() */ index->name.len++; diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c --- a/src/http/modules/ngx_http_limit_zone_module.c +++ b/src/http/modules/ngx_http_limit_zone_module.c @@ -239,54 +239,36 @@ static void ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { - ngx_http_limit_zone_node_t *lzn, *lznt; + ngx_rbtree_node_t **p; + ngx_http_limit_zone_node_t *lzn, *lznt; for ( ;; ) { if (node->key < temp->key) { - if (temp->left == sentinel) { - temp->left = node; - break; - } - - temp = temp->left; + p = &temp->left; } else if (node->key > temp->key) { - if (temp->right == sentinel) { - temp->right = node; - break; - } - - temp = temp->right; + p = &temp->right; } else { /* node->key == temp->key */ lzn = (ngx_http_limit_zone_node_t *) &node->color; lznt = (ngx_http_limit_zone_node_t *) &temp->color; - if (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) { - - if (temp->left == sentinel) { - temp->left = node; - break; - } - - temp = temp->left; + p = (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) + ? &temp->left : &temp->right; + } - } else { + if (*p == sentinel) { + break; + } - if (temp->right == sentinel) { - temp->right = node; - break; - } - - temp = temp->right; - } - } + temp = *p; } + *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; @@ -362,11 +344,8 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo return NGX_ERROR; } - ngx_rbtree_sentinel_init(sentinel); - - ctx->rbtree->root = sentinel; - ctx->rbtree->sentinel = sentinel; - ctx->rbtree->insert = ngx_http_limit_zone_rbtree_insert_value; + ngx_rbtree_init(ctx->rbtree, sentinel, + ngx_http_limit_zone_rbtree_insert_value); return NGX_OK; } diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -40,7 +40,14 @@ typedef struct { typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; +} ngx_http_log_script_t; + + +typedef struct { ngx_open_file_t *file; + ngx_http_log_script_t *script; time_t disk_full_time; time_t error_log_time; ngx_array_t *ops; /* array of ngx_http_log_op_t */ @@ -49,6 +56,11 @@ typedef struct { typedef struct { ngx_array_t *logs; /* array of ngx_http_log_t */ + + ngx_open_file_cache_t *open_file_cache; + time_t open_file_cache_valid; + ngx_uint_t open_file_cache_min_uses; + ngx_uint_t off; /* unsigned off:1 */ } ngx_http_log_loc_conf_t; @@ -62,6 +74,8 @@ typedef struct { static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, size_t len); +static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, + ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len); static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); @@ -88,6 +102,7 @@ static size_t ngx_http_log_variable_getl uintptr_t data); static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); +static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size); static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); @@ -100,6 +115,8 @@ static char *ngx_http_log_set_format(ngx void *conf); static char *ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s); +static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_int_t ngx_http_log_init(ngx_conf_t *cf); @@ -114,12 +131,19 @@ static ngx_command_t ngx_http_log_comma { ngx_string("access_log"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE123, + |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123, ngx_http_log_set_log, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, + { ngx_string("open_log_file_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_http_log_open_file_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -234,7 +258,7 @@ ngx_http_log_handler(ngx_http_request_t file = log[l].file; - if (file->buffer) { + if (file && file->buffer) { if (len > (size_t) (file->last - file->pos)) { @@ -260,7 +284,7 @@ ngx_http_log_handler(ngx_http_request_t } } - line = ngx_palloc(r->pool, len); + line = ngx_pnalloc(r->pool, len); if (line == NULL) { return NGX_ERROR; } @@ -284,11 +308,19 @@ static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, size_t len) { - time_t now; - ssize_t n; - ngx_err_t err; + u_char *name; + time_t now; + ssize_t n; + ngx_err_t err; - n = ngx_write_fd(log->file->fd, buf, len); + if (log->script == NULL) { + name = log->file->name.data; + n = ngx_write_fd(log->file->fd, buf, len); + + } else { + name = NULL; + n = ngx_http_log_script_write(r, log->script, &name, buf, len); + } if (n == (ssize_t) len) { return; @@ -305,8 +337,7 @@ ngx_http_log_write(ngx_http_request_t *r if (now - log->error_log_time > 59) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, - ngx_write_fd_n " to \"%V\" failed", - &log->file->name); + ngx_write_fd_n " to \"%s\" failed", name); log->error_log_time = now; } @@ -316,14 +347,109 @@ ngx_http_log_write(ngx_http_request_t *r if (now - log->error_log_time > 59) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_write_fd_n " to \"%V\" was incomplete: %z of %uz", - &log->file->name, n, len); + ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", + name, n, len); log->error_log_time = now; } } +static ssize_t +ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script, + u_char **name, u_char *buf, size_t len) +{ + size_t root; + ssize_t n; + ngx_str_t log, path; + ngx_open_file_info_t of; + ngx_http_log_loc_conf_t *llcf; + ngx_http_core_loc_conf_t *clcf; + + if (!r->root_tested) { + + /* test root directory existance */ + + if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { + /* simulate successfull logging */ + return len; + } + + path.data[root] = '\0'; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { + if (of.err == 0) { + /* simulate successfull logging */ + return len; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, + "testing \"%s\" existence failed", path.data); + + /* simulate successfull logging */ + return len; + } + + if (!of.is_dir) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR, + "testing \"%s\" existence failed", path.data); + + /* simulate successfull logging */ + return len; + } + } + + if (ngx_http_script_run(r, &log, script->lengths->elts, 1, + script->values->elts) + == NULL) + { + /* simulate successfull logging */ + return len; + } + + log.data[log.len - 1] = '\0'; + *name = log.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http log \"%s\"", log.data); + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.log = 1; + of.valid = llcf->open_file_cache_valid; + of.min_uses = llcf->open_file_cache_min_uses; + + if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) + != NGX_OK) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", log.data); + /* simulate successfull logging */ + return len; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http log #%d", of.fd); + + n = ngx_write_fd(of.fd, buf, len); + + return n; +} + + static u_char * ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) @@ -400,7 +526,8 @@ ngx_http_log_request_time(ngx_http_reque tp = ngx_timeofday(); - ms = (tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec); + ms = (ngx_msec_int_t) + ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec)); ms = (ms >= 0) ? ms : 0; return ngx_sprintf(buf, "%T.%03M", ms / 1000, ms % 1000); @@ -477,6 +604,7 @@ ngx_http_log_variable_compile(ngx_conf_t static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data) { + uintptr_t len; ngx_http_variable_value_t *value; value = ngx_http_get_indexed_variable(r, data); @@ -485,7 +613,11 @@ ngx_http_log_variable_getlen(ngx_http_re return 1; } - return value->len; + len = ngx_http_log_escape(NULL, value->data, value->len); + + value->escape = len ? 1 : 0; + + return value->len + len * 3; } @@ -501,7 +633,70 @@ ngx_http_log_variable(ngx_http_request_t return buf + 1; } - return ngx_cpymem(buf, value->data, value->len); + if (value->escape == 0) { + return ngx_cpymem(buf, value->data, value->len); + + } else { + return (u_char *) ngx_http_log_escape(buf, value->data, value->len); + } +} + + +static uintptr_t +ngx_http_log_escape(u_char *dst, u_char *src, size_t size) +{ + ngx_uint_t i, n; + static u_char hex[] = "0123456789ABCDEF"; + + static uint32_t escape[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + }; + + + if (dst == NULL) { + + /* find the number of the characters to be escaped */ + + n = 0; + + for (i = 0; i < size; i++) { + if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + n++; + } + src++; + } + + return (uintptr_t) n; + } + + for (i = 0; i < size; i++) { + if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + *dst++ = '\\'; + *dst++ = 'x'; + *dst++ = hex[*src >> 4]; + *dst++ = hex[*src & 0xf]; + src++; + + } else { + *dst++ = *src++; + } + } + + return (uintptr_t) dst; } @@ -550,6 +745,8 @@ ngx_http_log_create_loc_conf(ngx_conf_t return NGX_CONF_ERROR; } + conf->open_file_cache = NGX_CONF_UNSET_PTR; + return conf; } @@ -564,11 +761,23 @@ ngx_http_log_merge_loc_conf(ngx_conf_t * ngx_http_log_fmt_t *fmt; ngx_http_log_main_conf_t *lmcf; + if (conf->open_file_cache == NGX_CONF_UNSET_PTR) { + + conf->open_file_cache = prev->open_file_cache; + conf->open_file_cache_valid = prev->open_file_cache_valid; + conf->open_file_cache_min_uses = prev->open_file_cache_min_uses; + + if (conf->open_file_cache == NGX_CONF_UNSET_PTR) { + conf->open_file_cache = NULL; + } + } + if (conf->logs || conf->off) { return NGX_CONF_OK; } - *conf = *prev; + conf->logs = prev->logs; + conf->off = prev->off; if (conf->logs || conf->off) { return NGX_CONF_OK; @@ -589,6 +798,7 @@ ngx_http_log_merge_loc_conf(ngx_conf_t * return NGX_CONF_ERROR; } + log->script = NULL; log->disk_full_time = 0; log->error_log_time = 0; @@ -608,12 +818,13 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx { ngx_http_log_loc_conf_t *llcf = conf; - ssize_t buf; - ngx_uint_t i; - ngx_str_t *value, name; - ngx_http_log_t *log; - ngx_http_log_fmt_t *fmt; - ngx_http_log_main_conf_t *lmcf; + ssize_t buf; + ngx_uint_t i, n; + ngx_str_t *value, name; + ngx_http_log_t *log; + ngx_http_log_fmt_t *fmt; + ngx_http_log_main_conf_t *lmcf; + ngx_http_script_compile_t sc; value = cf->args->elts; @@ -636,14 +847,41 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - log->file = ngx_conf_open_file(cf->cycle, &value[1]); - if (log->file == NULL) { - return NGX_CONF_ERROR; + ngx_memzero(log, sizeof(ngx_http_log_t)); + + n = ngx_http_script_variables_count(&value[1]); + + if (n == 0) { + log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t)); + if (log->script == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &value[1]; + sc.lengths = &log->script->lengths; + sc.values = &log->script->values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } } - log->disk_full_time = 0; - log->error_log_time = 0; - if (cf->args->nelts >= 3) { name = value[2]; @@ -680,6 +918,12 @@ buffer: return NGX_CONF_ERROR; } + if (log->script) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "buffered logs can not have variables in name"); + return NGX_CONF_ERROR; + } + name.len = value[3].len - 7; name.data = value[3].data + 7; @@ -727,7 +971,10 @@ ngx_http_log_set_format(ngx_conf_t *cf, if (fmt[i].name.len == value[1].len && ngx_strcmp(fmt[i].name.data, value[1].data) == 0) { - return "duplicate \"log_format\" name"; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"log_format\" name \"%V\"", + &value[1]); + return NGX_CONF_ERROR; } } @@ -897,7 +1144,7 @@ ngx_http_log_compile_format(ngx_conf_t * } else { op->run = ngx_http_log_copy_long; - p = ngx_palloc(cf->pool, len); + p = ngx_pnalloc(cf->pool, len); if (p == NULL) { return NGX_CONF_ERROR; } @@ -919,6 +1166,114 @@ invalid: } +static char * +ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_log_loc_conf_t *llcf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max, min_uses; + ngx_uint_t i; + + if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + min_uses = 1; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max == NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive < 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) { + + min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9); + if (min_uses == NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid < 0) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + llcf->open_file_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid \"open_log_file_cache\" parameter \"%V\"", + &value[i]); + return NGX_CONF_ERROR; + } + + if (llcf->open_file_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"open_log_file_cache\" must have \"max\" parameter"); + return NGX_CONF_ERROR; + } + + llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive); + + if (llcf->open_file_cache) { + + llcf->open_file_cache_valid = valid; + llcf->open_file_cache_min_uses = min_uses; + + return NGX_CONF_OK; + } + + return NGX_CONF_ERROR; +} + + static ngx_int_t ngx_http_log_init(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -106,7 +106,7 @@ ngx_http_map_variable(ngx_http_request_t size_t len; u_char *name; - ngx_uint_t key, i; + ngx_uint_t key; ngx_http_variable_value_t *vv, *value; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -130,16 +130,12 @@ ngx_http_map_variable(ngx_http_request_t return NGX_OK; } - name = ngx_palloc(r->pool, len); + name = ngx_pnalloc(r->pool, len); if (name == NULL) { return NGX_ERROR; } - key = 0; - for (i = 0; i < len; i++) { - name[i] = ngx_tolower(vv->data[i]); - key = ngx_hash(key, name[i]); - } + key = ngx_hash_strlow(name, vv->data, len); value = ngx_hash_find_combined(&map->hash, key, name, len); @@ -221,7 +217,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c name.len--; name.data++; - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGABLE); + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); if (var == NULL) { return NGX_CONF_ERROR; } @@ -430,7 +426,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command } var->valid = 1; - var->no_cachable = 0; + var->no_cacheable = 0; var->not_found = 0; vp = ngx_array_push(&ctx->values_hash[key]); diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -58,7 +58,7 @@ static ngx_conf_bitmask_t ngx_http_memc static ngx_command_t ngx_http_memcached_commands[] = { { ngx_string("memcached_pass"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, ngx_http_memcached_pass, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -184,6 +184,8 @@ ngx_http_memcached_handler(ngx_http_requ return NGX_HTTP_INTERNAL_SERVER_ERROR; } + u->schema = mlcf->upstream.schema; + u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #if (NGX_THREADS) @@ -371,6 +373,7 @@ found: } u->headers_in.status_n = 200; + u->state->status = 200; u->buffer.pos = p + 1; return NGX_OK; @@ -381,6 +384,7 @@ found: "key: \"%V\" was not found by memcached", &ctx->key); u->headers_in.status_n = 404; + u->state->status = 404; return NGX_OK; } @@ -425,16 +429,16 @@ ngx_http_memcached_filter(void *data, ss if (u->length == ctx->rest) { if (ngx_strncmp(b->last, - ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - - ctx->rest, - bytes) != 0) + ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest, + ctx->rest) + != 0) { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, "memcached sent invalid trailer"); } - u->length -= bytes; - ctx->rest -= bytes; + u->length = 0; + ctx->rest = 0; return NGX_OK; } @@ -453,28 +457,29 @@ ngx_http_memcached_filter(void *data, ss *ll = cl; - cl->buf->pos = b->last; + last = b->last; + cl->buf->pos = last; b->last += bytes; cl->buf->last = b->last; + cl->buf->tag = u->output.tag; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, "memcached filter bytes:%z size:%z length:%z rest:%z", bytes, b->last - b->pos, u->length, ctx->rest); - if (b->last - b->pos <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) { + if (bytes <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) { u->length -= bytes; return NGX_OK; } - - last = b->pos + u->length - NGX_HTTP_MEMCACHED_END; + last += u->length - NGX_HTTP_MEMCACHED_END; if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, "memcached sent invalid trailer"); } - ctx->rest = u->length - (b->last - b->pos); + ctx->rest -= b->last - last; b->last = last; cl->buf->last = last; u->length = ctx->rest; @@ -520,8 +525,6 @@ ngx_http_memcached_create_loc_conf(ngx_c * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; - * - * conf->index = 0; */ conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; @@ -544,6 +547,8 @@ ngx_http_memcached_create_loc_conf(ngx_c conf->upstream.pass_request_headers = 0; conf->upstream.pass_request_body = 0; + conf->index = NGX_CONF_UNSET; + return conf; } @@ -578,6 +583,15 @@ ngx_http_memcached_merge_loc_conf(ngx_co |NGX_HTTP_UPSTREAM_FT_OFF; } + if (conf->upstream.upstream == NULL) { + conf->upstream.upstream = prev->upstream.upstream; + conf->upstream.schema = prev->upstream.schema; + } + + if (conf->index == NGX_CONF_UNSET) { + conf->index = prev->index; + } + return NGX_CONF_OK; } @@ -614,8 +628,6 @@ ngx_http_memcached_pass(ngx_conf_t *cf, clcf->handler = ngx_http_memcached_handler; - lcf->upstream.location = clcf->name; - if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -70,7 +70,7 @@ ngx_int_t ngx_http_not_modified_header_f * I think that the equality of the dates is correcter */ - if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) { + if (ims == r->headers_out.last_modified_time) { r->headers_out.status = NGX_HTTP_NOT_MODIFIED; r->headers_out.content_type.len = 0; ngx_http_clear_content_length(r); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -33,6 +33,13 @@ struct ngx_http_proxy_redirect_s { typedef struct { + ngx_str_t host_header; + ngx_str_t port; + ngx_str_t uri; +} ngx_http_proxy_vars_t; + + +typedef struct { ngx_http_upstream_conf_t upstream; ngx_array_t *flushes; @@ -45,13 +52,18 @@ typedef struct { ngx_array_t *headers_source; ngx_array_t *headers_names; + ngx_array_t *proxy_lengths; + ngx_array_t *proxy_values; + ngx_array_t *redirects; ngx_str_t body_source; ngx_str_t method; - ngx_str_t host_header; - ngx_str_t port; + ngx_str_t location; + ngx_str_t url; + + ngx_http_proxy_vars_t vars; ngx_flag_t redirect; @@ -66,6 +78,8 @@ typedef struct { u_char *status_start; u_char *status_end; + ngx_http_proxy_vars_t vars; + size_t internal_body_length; } ngx_http_proxy_ctx_t; @@ -73,11 +87,13 @@ typedef struct { #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); 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 *p); + 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, @@ -115,18 +131,17 @@ static char *ngx_http_proxy_upstream_max 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); +#endif +static ngx_int_t ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u, + ngx_http_proxy_vars_t *v); + static ngx_conf_post_t ngx_http_proxy_lowat_post = { ngx_http_proxy_lowat_check }; -static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_header_buffer_size = { - ngx_conf_deprecated, "proxy_header_buffer_size", "proxy_buffer_size" -}; - -static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_redirect_errors = { - ngx_conf_deprecated, "proxy_redirect_errors", "proxy_intercept_errors" -}; - static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -212,13 +227,6 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors), NULL }, - { ngx_string("proxy_redirect_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_proxy_loc_conf_t, upstream.intercept_errors), - &ngx_conf_deprecated_proxy_redirect_errors }, - { ngx_string("proxy_set_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_keyval_slot, @@ -275,13 +283,6 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size), NULL }, - { ngx_string("proxy_header_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_proxy_loc_conf_t, upstream.buffer_size), - &ngx_conf_deprecated_proxy_header_buffer_size }, - { ngx_string("proxy_read_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -401,6 +402,7 @@ static ngx_keyval_t ngx_http_proxy_head { ngx_string("Host"), ngx_string("$proxy_host") }, { ngx_string("Connection"), ngx_string("close") }, { ngx_string("Keep-Alive"), ngx_string("") }, + { ngx_string("Expect"), ngx_string("") }, { ngx_null_string, ngx_null_string } }; @@ -412,7 +414,8 @@ static ngx_str_t ngx_http_proxy_hide_he ngx_string("X-Accel-Expires"), ngx_string("X-Accel-Redirect"), ngx_string("X-Accel-Limit-Rate"), - ngx_string("X-Accel-Buffer"), + ngx_string("X-Accel-Buffering"), + ngx_string("X-Accel-Charset"), ngx_null_string }; @@ -420,10 +423,10 @@ static ngx_str_t ngx_http_proxy_hide_he static ngx_http_variable_t ngx_http_proxy_vars[] = { { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0, - NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 }, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0, - NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 }, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("proxy_add_x_forwarded_for"), NULL, ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, @@ -444,15 +447,38 @@ ngx_http_proxy_handler(ngx_http_request_ { ngx_int_t rc; ngx_http_upstream_t *u; + ngx_http_proxy_ctx_t *ctx; ngx_http_proxy_loc_conf_t *plcf; - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); if (u == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->upstream = u; + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_proxy_module); + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + if (plcf->proxy_lengths == 0) { + ctx->vars = plcf->vars; + u->schema = plcf->upstream.schema; +#if (NGX_HTTP_SSL) + u->ssl = (plcf->upstream.ssl != NULL); +#endif + + } else { + if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #if (NGX_THREADS) @@ -484,8 +510,6 @@ ngx_http_proxy_handler(ngx_http_request_ u->accel = 1; - r->upstream = u; - rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -497,6 +521,82 @@ ngx_http_proxy_handler(ngx_http_request_ 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) +{ + size_t add; + u_short port; + ngx_str_t proxy; + ngx_url_t u; + + if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0, + plcf->proxy_values->elts) + == NULL) + { + return NGX_ERROR; + } + + if (ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0) { + + add = 7; + port = 80; + +#if (NGX_HTTP_SSL) + + } else if (ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0) { + + add = 8; + port = 443; + r->upstream->ssl = 1; + +#endif + + } else { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid URL prefix in \"%V\"", &proxy); + return NGX_ERROR; + } + + r->upstream->schema.len = add; + r->upstream->schema.data = proxy.data; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url.len = proxy.len - add; + u.url.data = proxy.data + add; + u.default_port = port; + u.uri_part = 1; + u.no_resolve = 1; + + if (ngx_parse_url(r->pool, &u) != NGX_OK) { + if (u.err) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "%s in upstream \"%V\"", u.err, &u.url); + } + + return NGX_ERROR; + } + + if (ngx_http_proxy_set_vars(r->pool, &u, &ctx->vars) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->resolved = ngx_pcalloc(r->pool, + sizeof(ngx_http_upstream_resolved_t)); + if (r->upstream->resolved == NULL) { + return NGX_ERROR; + } + + r->upstream->resolved->host = u.host; + r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port: + u.port); + r->upstream->resolved->default_port = u.default_port; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r) { size_t len, loc_len, body_len; @@ -508,7 +608,7 @@ ngx_http_proxy_create_request(ngx_http_r ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_upstream_t *u; - ngx_http_proxy_ctx_t *p; + ngx_http_proxy_ctx_t *ctx; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_proxy_loc_conf_t *plcf; @@ -518,15 +618,6 @@ ngx_http_proxy_create_request(ngx_http_r plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); - if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, p, ngx_http_proxy_module); - - len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; - if (u->method.len) { /* HEAD was changed to GET to cache response */ method = u->method; @@ -540,28 +631,36 @@ ngx_http_proxy_create_request(ngx_http_r method.len++; } - len += method.len + u->conf->uri.len; + len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; escape = 0; - - loc_len = (r->valid_location && u->conf->uri.len) ? u->conf->location.len: - 0; - - if (u->conf->uri.len == 0 && r->valid_unparsed_uri && r == r->main) { + loc_len = 0; + unparsed_uri = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (plcf->proxy_lengths) { + len += ctx->vars.uri.len; + + } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main) + { unparsed_uri = 1; len += r->unparsed_uri.len; } else { - unparsed_uri = 0; + loc_len = (r->valid_location && ctx->vars.uri.len) ? + plcf->location.len : 0; + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } - len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; + len += ctx->vars.uri.len + r->uri.len - loc_len + escape + + sizeof("?") - 1 + r->args.len; } - ngx_http_script_flush_no_cachable_variables(r, plcf->flushes); + ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes); if (plcf->body_set_len) { le.ip = plcf->body_set_len->elts; @@ -574,7 +673,7 @@ ngx_http_proxy_create_request(ngx_http_r body_len += lcode(&le); } - p->internal_body_length = body_len; + ctx->internal_body_length = body_len; len += body_len; } @@ -638,12 +737,15 @@ ngx_http_proxy_create_request(ngx_http_r u->uri.data = b->last; - if (unparsed_uri) { + if (plcf->proxy_lengths) { + b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len); + + } else if (unparsed_uri) { b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len); } else { if (r->valid_location) { - b->last = ngx_copy(b->last, u->conf->uri.data, u->conf->uri.len); + b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len); } if (escape) { @@ -759,16 +861,9 @@ ngx_http_proxy_create_request(ngx_http_r b->last = e.pos; } -#if (NGX_DEBUG) - { - ngx_str_t s; - - s.len = b->last - b->pos; - s.data = b->pos; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy header:\n\"%V\"", &s); - } -#endif + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header:\n\"%*s\"", + (size_t) (b->last - b->pos), b->pos); if (plcf->body_set == NULL && plcf->upstream.pass_request_body) { @@ -809,18 +904,18 @@ ngx_http_proxy_create_request(ngx_http_r static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r) { - ngx_http_proxy_ctx_t *p; - - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - - if (p == NULL) { + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL) { return NGX_OK; } - p->status = 0; - p->status_count = 0; - p->status_start = NULL; - p->status_end = NULL; + ctx->status = 0; + ctx->status_count = 0; + ctx->status_start = NULL; + ctx->status_end = NULL; r->upstream->process_header = ngx_http_proxy_process_status_line; @@ -833,15 +928,15 @@ ngx_http_proxy_process_status_line(ngx_h { ngx_int_t rc; ngx_http_upstream_t *u; - ngx_http_proxy_ctx_t *p; - - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - - if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL) { + return NGX_ERROR; } - rc = ngx_http_proxy_parse_status_line(r, p); + rc = ngx_http_proxy_parse_status_line(r, ctx); if (rc == NGX_AGAIN) { return rc; @@ -860,22 +955,23 @@ ngx_http_proxy_process_status_line(ngx_h #endif r->http_version = NGX_HTTP_VERSION_9; - p->status = NGX_HTTP_OK; + u->headers_in.status_n = NGX_HTTP_OK; + u->state->status = NGX_HTTP_OK; return NGX_OK; } - u->headers_in.status_n = p->status; - u->state->status = p->status; - - u->headers_in.status_line.len = p->status_end - p->status_start; - u->headers_in.status_line.data = ngx_palloc(r->pool, - u->headers_in.status_line.len); + u->headers_in.status_n = ctx->status; + u->state->status = 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); if (u->headers_in.status_line.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } - ngx_memcpy(u->headers_in.status_line.data, p->status_start, + ngx_memcpy(u->headers_in.status_line.data, ctx->status_start, u->headers_in.status_line.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -889,10 +985,11 @@ 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 *p) +ngx_http_proxy_parse_status_line(ngx_http_request_t *r, + ngx_http_proxy_ctx_t *ctx) { u_char ch; - u_char *pos; + u_char *p; ngx_http_upstream_t *u; enum { sw_start = 0, @@ -914,8 +1011,8 @@ ngx_http_proxy_parse_status_line(ngx_htt state = r->state; - for (pos = u->buffer.pos; pos < u->buffer.last; pos++) { - ch = *pos; + for (p = u->buffer.pos; p < u->buffer.last; p++) { + ch = *p; switch (state) { @@ -1024,11 +1121,11 @@ ngx_http_proxy_parse_status_line(ngx_htt return NGX_HTTP_PROXY_PARSE_NO_HEADER; } - p->status = p->status * 10 + ch - '0'; - - if (++p->status_count == 3) { + ctx->status = ctx->status * 10 + ch - '0'; + + if (++ctx->status_count == 3) { state = sw_space_after_status; - p->status_start = pos - 2; + ctx->status_start = p - 2; } break; @@ -1066,7 +1163,7 @@ ngx_http_proxy_parse_status_line(ngx_htt /* end of status line */ case sw_almost_done: - p->status_end = pos - 1; + ctx->status_end = p - 1; switch (ch) { case LF: goto done; @@ -1076,17 +1173,17 @@ ngx_http_proxy_parse_status_line(ngx_htt } } - u->buffer.pos = pos; + u->buffer.pos = p; r->state = state; return NGX_AGAIN; done: - u->buffer.pos = pos + 1; - - if (p->status_end == NULL) { - p->status_end = pos; + u->buffer.pos = p + 1; + + if (ctx->status_end == NULL) { + ctx->status_end = p; } r->state = sw_start; @@ -1099,14 +1196,13 @@ static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r) { ngx_int_t rc; - ngx_uint_t i; ngx_table_elt_t *h; 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 ( ;; ) { + for ( ;; ) { rc = ngx_http_parse_header_line(r, &r->upstream->buffer); @@ -1116,7 +1212,7 @@ ngx_http_proxy_process_header(ngx_http_r h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->hash = r->header_hash; @@ -1124,10 +1220,10 @@ ngx_http_proxy_process_header(ngx_http_r h->key.len = r->header_name_end - r->header_name_start; h->value.len = r->header_end - r->header_start; - h->key.data = ngx_palloc(r->pool, + 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_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->value.data = h->key.data + h->key.len + 1; @@ -1140,16 +1236,14 @@ ngx_http_proxy_process_header(ngx_http_r ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { - for (i = 0; i < h->key.len; i++) { - h->lowcase_key[i] = ngx_tolower(h->key.data[i]); - } + 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_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1174,7 +1268,7 @@ ngx_http_proxy_process_header(ngx_http_r if (r->upstream->headers_in.server == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( @@ -1190,7 +1284,7 @@ ngx_http_proxy_process_header(ngx_http_r if (r->upstream->headers_in.date == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); @@ -1243,15 +1337,20 @@ static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_proxy_loc_conf_t *plcf; - - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - - v->len = plcf->host_header.len; + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->len = ctx->vars.host_header.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; - v->data = plcf->host_header.data; + v->data = ctx->vars.host_header.data; return NGX_OK; } @@ -1261,15 +1360,20 @@ static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_proxy_loc_conf_t *plcf; - - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - - v->len = plcf->port.len; + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->len = ctx->vars.port.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; - v->data = plcf->port.data; + v->data = ctx->vars.port.data; return NGX_OK; } @@ -1282,7 +1386,7 @@ ngx_http_proxy_add_x_forwarded_for_varia u_char *p; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; if (r->headers_in.x_forwarded_for == NULL) { @@ -1294,7 +1398,7 @@ ngx_http_proxy_add_x_forwarded_for_varia v->len = r->headers_in.x_forwarded_for->value.len + sizeof(", ") - 1 + r->connection->addr_text.len; - p = ngx_palloc(r->pool, v->len); + p = ngx_pnalloc(r->pool, v->len); if (p == NULL) { return NGX_ERROR; } @@ -1316,26 +1420,26 @@ static ngx_int_t ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_proxy_ctx_t *p; - - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - - if (p == NULL) { + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL) { v->not_found = 1; return NGX_OK; } v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; - v->data = ngx_palloc(r->connection->pool, NGX_SIZE_T_LEN); + v->data = ngx_pnalloc(r->connection->pool, NGX_SIZE_T_LEN); if (v->data == NULL) { return NGX_ERROR; } - v->len = ngx_sprintf(v->data, "%uz", p->internal_body_length) - v->data; + v->len = ngx_sprintf(v->data, "%uz", ctx->internal_body_length) - v->data; return NGX_OK; } @@ -1386,7 +1490,7 @@ ngx_http_proxy_rewrite_redirect_text(ngx len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len; - data = ngx_palloc(r->pool, len); + data = ngx_pnalloc(r->pool, len); if (data == NULL) { return NGX_ERROR; } @@ -1438,7 +1542,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx len += lcode(&e); } - data = ngx_palloc(r->pool, len); + data = ngx_pnalloc(r->pool, len); if (data == NULL) { return NGX_ERROR; } @@ -1501,8 +1605,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.hide_headers = NULL; - * conf->upstream.pass_headers = NULL; * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; @@ -1539,6 +1641,9 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; + conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; + conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; + conf->upstream.intercept_errors = NGX_CONF_UNSET; /* "proxy_cyclic_temp_file" is disabled */ @@ -1563,9 +1668,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t u_char *p; size_t size; uintptr_t *code; - ngx_str_t *header; - ngx_uint_t i, j; - ngx_array_t hide_headers; + ngx_uint_t i; ngx_keyval_t *src, *s, *h; ngx_hash_key_t *hk; ngx_hash_init_t hash; @@ -1739,7 +1842,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t conf->redirects = prev->redirects; } - if (conf->redirects == NULL && conf->upstream.url.data) { + if (conf->redirects == NULL && conf->url.data) { conf->redirects = ngx_array_create(cf->pool, 1, sizeof(ngx_http_proxy_redirect_t)); @@ -1753,10 +1856,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } pr->handler = ngx_http_proxy_rewrite_redirect_text; - pr->redirect = conf->upstream.url; - - if (conf->upstream.uri.len) { - pr->replacement.text = conf->upstream.location; + pr->redirect = conf->url; + + if (conf->vars.uri.len) { + pr->replacement.text = conf->location; } else { pr->replacement.text.len = 0; @@ -1765,6 +1868,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } } + /* STUB */ + if (prev->proxy_lengths) { + conf->proxy_lengths = prev->proxy_lengths; + conf->proxy_values = prev->proxy_values; + } + ngx_conf_merge_uint_value(conf->headers_hash_max_size, prev->headers_hash_max_size, 512); @@ -1774,112 +1883,22 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size, ngx_cacheline_size); - if (conf->upstream.hide_headers == NULL - && conf->upstream.pass_headers == NULL) - { - conf->upstream.hide_headers = prev->upstream.hide_headers; - conf->upstream.pass_headers = prev->upstream.pass_headers; - conf->upstream.hide_headers_hash = prev->upstream.hide_headers_hash; - - if (conf->upstream.hide_headers_hash.buckets) { - goto peers; - } - - } else { - if (conf->upstream.hide_headers == NULL) { - conf->upstream.hide_headers = prev->upstream.hide_headers; - } - - if (conf->upstream.pass_headers == NULL) { - conf->upstream.pass_headers = prev->upstream.pass_headers; - } - } - - if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) + hash.max_size = conf->headers_hash_max_size; + hash.bucket_size = conf->headers_hash_bucket_size; + hash.name = "proxy_headers_hash"; + + if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, + &prev->upstream, + ngx_http_proxy_hide_headers, &hash) != NGX_OK) { return NGX_CONF_ERROR; } - for (header = ngx_http_proxy_hide_headers; header->len; header++) { - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = *header; - hk->key_hash = ngx_hash_key_lc(header->data, header->len); - hk->value = (void *) 1; - } - - if (conf->upstream.hide_headers) { - - header = conf->upstream.hide_headers->elts; - - for (i = 0; i < conf->upstream.hide_headers->nelts; i++) { - - hk = hide_headers.elts; - - for (j = 0; j < hide_headers.nelts; j++) { - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - goto exist; - } - } - - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = header[i]; - hk->key_hash = ngx_hash_key_lc(header[i].data, header[i].len); - hk->value = (void *) 1; - - exist: - - continue; - } - } - - if (conf->upstream.pass_headers) { - - hk = hide_headers.elts; - header = conf->upstream.pass_headers->elts; - - for (i = 0; i < conf->upstream.pass_headers->nelts; i++) { - for (j = 0; j < hide_headers.nelts; j++) { - - if (hk[j].key.data == NULL) { - continue; - } - - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - hk[j].key.data = NULL; - break; - } - } - } - } - - hash.hash = &conf->upstream.hide_headers_hash; - hash.key = ngx_hash_key_lc; - hash.max_size = conf->headers_hash_max_size; - hash.bucket_size = conf->headers_hash_bucket_size; - hash.name = "proxy_headers_hash"; - hash.pool = cf->pool; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) { - return NGX_CONF_ERROR; - } - -peers: - if (conf->upstream.upstream == NULL) { conf->upstream.upstream = prev->upstream.upstream; - conf->host_header = prev->host_header; - conf->port = prev->port; + conf->vars = prev->vars; conf->upstream.schema = prev->upstream.schema; } @@ -2155,24 +2174,53 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ { ngx_http_proxy_loc_conf_t *plcf = conf; - u_char *p; - size_t add; - u_short port; - ngx_str_t *value, *url; - ngx_url_t u; - ngx_http_core_loc_conf_t *clcf; -#if (NGX_HTTP_SSL) - ngx_pool_cleanup_t *cln; -#endif + size_t add; + u_short port; + ngx_str_t *value, *url; + ngx_url_t u; + ngx_uint_t n; + ngx_http_core_loc_conf_t *clcf; + ngx_http_script_compile_t sc; if (plcf->upstream.schema.len) { return "is duplicate"; } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + 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 = &plcf->proxy_lengths; + sc.values = &plcf->proxy_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + +#if (NGX_HTTP_SSL) + if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) { + return NGX_CONF_ERROR; + } +#endif + + clcf->handler = ngx_http_proxy_handler; + + return NGX_CONF_OK; + } + if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) { add = 7; port = 80; @@ -2180,32 +2228,12 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) { #if (NGX_HTTP_SSL) + if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) { + return NGX_CONF_ERROR; + } add = 8; port = 443; - - plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (plcf->upstream.ssl == NULL) { - return NGX_CONF_ERROR; - } - - plcf->upstream.ssl->log = cf->log; - - if (ngx_ssl_create(plcf->upstream.ssl, - NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1, NULL) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NGX_CONF_ERROR; - } - - cln->handler = ngx_ssl_cleanup_ctx; - cln->data = plcf->upstream.ssl; - #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "https protocol requires SSL support"); @@ -2230,59 +2258,23 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if (!u.unix_socket) { - if (u.no_port || u.port == port) { - plcf->host_header = u.host; - - if (port == 80) { - plcf->port.len = sizeof("80") - 1; - plcf->port.data = (u_char *) "80"; - - } else { - plcf->port.len = sizeof("443") - 1; - plcf->port.data = (u_char *) "443"; - } - - } else { - p = ngx_palloc(cf->pool, u.host.len + sizeof(":65536") - 1); - if (p == NULL) { - return NGX_CONF_ERROR; - } - - plcf->host_header.len = ngx_sprintf(p, "%V:%d", &u.host, u.port) - - p; - plcf->host_header.data = p; - - plcf->port.len = plcf->host_header.len - u.host.len - 1; - plcf->port.data = p + u.host.len + 1; - } - - - } else { - plcf->host_header.len = sizeof("localhost") - 1; - plcf->host_header.data = (u_char *) "localhost"; - plcf->port.len = 0; - plcf->port.data = (u_char *) ""; + if (ngx_http_proxy_set_vars(cf->pool, &u, &plcf->vars) != NGX_OK) { + return NGX_CONF_ERROR; } - plcf->upstream.uri = u.uri; - plcf->upstream.schema.len = add; plcf->upstream.schema.data = url->data; - - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + plcf->location = clcf->name; clcf->handler = ngx_http_proxy_handler; - plcf->upstream.location = clcf->name; - if (clcf->named #if (NGX_PCRE) || clcf->regex #endif || clcf->noname) { - if (plcf->upstream.uri.len) { + if (plcf->vars.uri.len) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_pass\" may not have URI part in " "location given by regular expression, " @@ -2292,10 +2284,10 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - plcf->upstream.location.len = 0; + plcf->location.len = 0; } - plcf->upstream.url = *url; + plcf->url = *url; if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; @@ -2341,7 +2333,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, } if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) { - if (plcf->upstream.url.data == NULL) { + if (plcf->url.data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_rewrite_location default\" must go " "after the \"proxy_pass\" directive"); @@ -2349,10 +2341,10 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, } pr->handler = ngx_http_proxy_rewrite_redirect_text; - pr->redirect = plcf->upstream.url; - - if (plcf->upstream.uri.len) { - pr->replacement.text = plcf->upstream.location; + pr->redirect = plcf->url; + + if (plcf->vars.uri.len) { + pr->replacement.text = plcf->location; } else { pr->replacement.text.len = 0; @@ -2429,7 +2421,7 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx sc.source = &value[1]; sc.lengths = &plcf->upstream.store_lengths; sc.values = &plcf->upstream.store_values; - sc.variables = ngx_http_script_variables_count(&value[1]);; + sc.variables = ngx_http_script_variables_count(&value[1]); sc.complete_lengths = 1; sc.complete_values = 1; @@ -2494,3 +2486,74 @@ ngx_http_proxy_upstream_fail_timeout_uns return NGX_CONF_ERROR; } + + +#if (NGX_HTTP_SSL) + +static ngx_int_t +ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) +{ + ngx_pool_cleanup_t *cln; + + plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (plcf->upstream.ssl == NULL) { + return NGX_ERROR; + } + + plcf->upstream.ssl->log = cf->log; + + if (ngx_ssl_create(plcf->upstream.ssl, + NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1, NULL) + != NGX_OK) + { + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = plcf->upstream.ssl; + + return NGX_OK; +} + +#endif + + +static ngx_int_t +ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u, + ngx_http_proxy_vars_t *v) +{ + if (!u->unix_socket) { + if (u->no_port || u->port == u->default_port) { + v->host_header = u->host; + + if (u->default_port == 80) { + v->port.len = sizeof("80") - 1; + v->port.data = (u_char *) "80"; + + } else { + v->port.len = sizeof("443") - 1; + v->port.data = (u_char *) "443"; + } + + } else { + v->host_header.len = u->host.len + 1 + u->port_text.len; + v->host_header.data = u->host.data; + v->port = u->port_text; + } + + } else { + v->host_header.len = sizeof("localhost") - 1; + v->host_header.data = (u_char *) "localhost"; + v->port.len = 0; + v->port.data = (u_char *) ""; + } + + v->uri = u->uri; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -58,6 +58,20 @@ typedef struct { } ngx_http_range_filter_ctx_t; +ngx_int_t ngx_http_range_parse(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx); +static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx); +static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx); +static ngx_int_t ngx_http_range_not_satisfiable(ngx_http_request_t *r); +static ngx_int_t ngx_http_range_test_overlapped(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_int_t ngx_http_range_singlepart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); + static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); @@ -131,14 +145,8 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r) { - u_char *p; - size_t len; - off_t start, end; + time_t if_range; ngx_int_t rc; - ngx_uint_t suffix, i; - ngx_atomic_uint_t boundary; - ngx_table_elt_t *content_range; - ngx_http_range_t *range; ngx_http_range_filter_ctx_t *ctx; if (r->http_version < NGX_HTTP_VERSION_10 @@ -156,18 +164,21 @@ ngx_http_range_header_filter(ngx_http_re (u_char *) "bytes=", 6) != 0) { - r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.accept_ranges == NULL) { - return NGX_ERROR; - } + goto next_filter; + } + + if (r->headers_in.if_range && r->headers_out.last_modified_time != -1) { + + if_range = ngx_http_parse_time(r->headers_in.if_range->value.data, + r->headers_in.if_range->value.len); - 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_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http ir:%d lm:%d", + if_range, r->headers_out.last_modified_time); - return ngx_http_next_header_filter(r); + if (if_range != r->headers_out.last_modified_time) { + goto next_filter; + } } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t)); @@ -181,8 +192,54 @@ ngx_http_range_header_filter(ngx_http_re return NGX_ERROR; } - rc = 0; - range = NULL; + rc = ngx_http_range_parse(r, ctx); + + if (rc == NGX_OK) { + + ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); + + r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; + + if (ctx->ranges.nelts == 1) { + return ngx_http_range_singlepart_header(r, ctx); + } + + return ngx_http_range_multipart_header(r, ctx); + } + + if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) { + return ngx_http_range_not_satisfiable(r); + } + + /* rc == NGX_ERROR */ + + return rc; + +next_filter: + + r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.accept_ranges == NULL) { + return NGX_ERROR; + } + + 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"; + + return ngx_http_next_header_filter(r); +} + + +ngx_int_t +ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) +{ + u_char *p; + off_t start, end; + ngx_uint_t suffix; + ngx_http_range_t *range; + p = r->headers_in.range->value.data + 6; for ( ;; ) { @@ -194,8 +251,7 @@ ngx_http_range_header_filter(ngx_http_re if (*p != '-') { if (*p < '0' || *p > '9') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } while (*p >= '0' && *p <= '9') { @@ -205,13 +261,11 @@ ngx_http_range_header_filter(ngx_http_re while (*p == ' ') { p++; } if (*p++ != '-') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } if (start >= r->headers_out.content_length_n) { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } while (*p == ' ') { p++; } @@ -226,7 +280,7 @@ ngx_http_range_header_filter(ngx_http_re range->end = r->headers_out.content_length_n; if (*p++ != ',') { - break; + return NGX_OK; } continue; @@ -238,8 +292,7 @@ ngx_http_range_header_filter(ngx_http_re } if (*p < '0' || *p > '9') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } while (*p >= '0' && *p <= '9') { @@ -249,8 +302,7 @@ ngx_http_range_header_filter(ngx_http_re while (*p == ' ') { p++; } if (*p != ',' && *p != '\0') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } if (suffix) { @@ -259,8 +311,7 @@ ngx_http_range_header_filter(ngx_http_re } if (start > end) { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } range = ngx_array_push(&ctx->ranges); @@ -282,86 +333,65 @@ ngx_http_range_header_filter(ngx_http_re } if (*p++ != ',') { - break; + return NGX_OK; } } +} + + +static ngx_int_t +ngx_http_range_singlepart_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx) +{ + ngx_table_elt_t *content_range; + ngx_http_range_t *range; + + content_range = ngx_list_push(&r->headers_out.headers); + if (content_range == NULL) { + return NGX_ERROR; + } - if (rc) { - - /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ - - r->headers_out.status = rc; - - content_range = ngx_list_push(&r->headers_out.headers); - if (content_range == NULL) { - return NGX_ERROR; - } - - r->headers_out.content_range = content_range; + 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"; + content_range->hash = 1; + content_range->key.len = sizeof("Content-Range") - 1; + content_range->key.data = (u_char *) "Content-Range"; - content_range->value.data = ngx_palloc(r->pool, - sizeof("bytes */") - 1 + NGX_OFF_T_LEN); - if (content_range->value.data == NULL) { - return NGX_ERROR; - } - - content_range->value.len = ngx_sprintf(content_range->value.data, - "bytes */%O", - r->headers_out.content_length_n) - - content_range->value.data; - - ngx_http_clear_content_length(r); - - return rc; + content_range->value.data = ngx_pnalloc(r->pool, + sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); + if (content_range->value.data == NULL) { + return NGX_ERROR; } - ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); - - r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; - - if (ctx->ranges.nelts == 1) { + /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ - content_range = ngx_list_push(&r->headers_out.headers); - if (content_range == NULL) { - return NGX_ERROR; - } - - 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"; + range = ctx->ranges.elts; - content_range->value.data = - ngx_palloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); - if (content_range->value.data == NULL) { - return NGX_ERROR; - } - - /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ + content_range->value.len = ngx_sprintf(content_range->value.data, + "bytes %O-%O/%O", + range->start, range->end - 1, + r->headers_out.content_length_n) + - content_range->value.data; - content_range->value.len = ngx_sprintf(content_range->value.data, - "bytes %O-%O/%O", - range->start, range->end - 1, - r->headers_out.content_length_n) - - content_range->value.data; + r->headers_out.content_length_n = range->end - range->start; - r->headers_out.content_length_n = range->end - range->start; - - if (r->headers_out.content_length) { - r->headers_out.content_length->hash = 0; - r->headers_out.content_length = NULL; - } - - return ngx_http_next_header_filter(r); + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; } + return ngx_http_next_header_filter(r); +} - /* TODO: what if no content_type ?? */ + +static ngx_int_t +ngx_http_range_multipart_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx) +{ + size_t len; + ngx_uint_t i; + ngx_http_range_t *range; + ngx_atomic_uint_t boundary; len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof(CRLF "Content-Type: ") - 1 @@ -372,7 +402,7 @@ ngx_http_range_header_filter(ngx_http_re len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } - ctx->boundary_header.data = ngx_palloc(r->pool, len); + ctx->boundary_header.data = ngx_pnalloc(r->pool, len); if (ctx->boundary_header.data == NULL) { return NGX_ERROR; } @@ -399,7 +429,7 @@ ngx_http_range_header_filter(ngx_http_re r->headers_out.charset.len = 0; - } else { + } else if (r->headers_out.content_type.len) { ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, CRLF "--%0muA" CRLF "Content-Type: %V" CRLF @@ -407,12 +437,19 @@ ngx_http_range_header_filter(ngx_http_re boundary, &r->headers_out.content_type) - ctx->boundary_header.data; + + } else { + ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, + CRLF "--%0muA" CRLF + "Content-Range: bytes ", + boundary) + - ctx->boundary_header.data; } r->headers_out.content_type.data = - ngx_palloc(r->pool, - sizeof("Content-Type: multipart/byteranges; boundary=") - 1 - + NGX_ATOMIC_T_LEN); + ngx_pnalloc(r->pool, + sizeof("Content-Type: multipart/byteranges; boundary=") - 1 + + NGX_ATOMIC_T_LEN); if (r->headers_out.content_type.data == NULL) { return NGX_ERROR; @@ -437,7 +474,7 @@ ngx_http_range_header_filter(ngx_http_re /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */ range[i].content_range.data = - ngx_palloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4); + ngx_pnalloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4); if (range[i].content_range.data == NULL) { return NGX_ERROR; @@ -465,13 +502,43 @@ ngx_http_range_header_filter(ngx_http_re static ngx_int_t +ngx_http_range_not_satisfiable(ngx_http_request_t *r) +{ + ngx_table_elt_t *content_range; + + r->headers_out.status = NGX_HTTP_RANGE_NOT_SATISFIABLE; + + content_range = ngx_list_push(&r->headers_out.headers); + if (content_range == NULL) { + return NGX_ERROR; + } + + 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"; + + content_range->value.data = ngx_pnalloc(r->pool, + sizeof("bytes */") - 1 + NGX_OFF_T_LEN); + if (content_range->value.data == NULL) { + return NGX_ERROR; + } + + content_range->value.len = ngx_sprintf(content_range->value.data, + "bytes */%O", + r->headers_out.content_length_n) + - content_range->value.data; + + ngx_http_clear_content_length(r); + + return NGX_HTTP_RANGE_NOT_SATISFIABLE; +} + + +static ngx_int_t ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { - off_t start, last; - ngx_buf_t *b, *buf; - ngx_uint_t i; - ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; - ngx_http_range_t *range; ngx_http_range_filter_ctx_t *ctx; if (in == NULL) { @@ -484,17 +551,40 @@ ngx_http_range_body_filter(ngx_http_requ return ngx_http_next_body_filter(r, in); } - buf = in->buf; + if (ctx->ranges.nelts == 1) { + return ngx_http_range_singlepart_body(r, ctx, in); + } + + /* + * multipart ranges are supported only if whole body is in a single buffer + */ if (ngx_buf_special(in->buf)) { return ngx_http_next_body_filter(r, in); } + if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) { + return NGX_ERROR; + } + + return ngx_http_range_multipart_body(r, ctx, in); +} + + +static ngx_int_t +ngx_http_range_test_overlapped(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) +{ + off_t start, last; + ngx_buf_t *buf; + ngx_uint_t i; + ngx_http_range_t *range; + if (ctx->offset) { goto overlapped; } - range = ctx->ranges.elts; + buf = in->buf; if (!buf->last_buf) { @@ -507,6 +597,7 @@ ngx_http_range_body_filter(ngx_http_requ last = buf->last - buf->start + ctx->offset; } + range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { if (start > range[i].start || last < range[i].end) { goto overlapped; @@ -514,29 +605,111 @@ ngx_http_range_body_filter(ngx_http_requ } } - /* - * the optimized version for the responses - * that are passed in the single buffer - */ - ctx->offset = ngx_buf_size(buf); - if (ctx->ranges.nelts == 1) { + return NGX_OK; + +overlapped: + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "range in overlapped buffers"); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_range_singlepart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) +{ + off_t start, last; + ngx_buf_t *buf; + ngx_chain_t *out, *cl, **ll; + ngx_http_range_t *range; + + out = NULL; + ll = &out; + range = ctx->ranges.elts; - if (buf->in_file) { - buf->file_pos = range->start; - buf->file_last = range->end; + for (cl = in; cl; cl = cl->next) { + + buf = cl->buf; + + start = ctx->offset; + last = ctx->offset + ngx_buf_size(buf); + + ctx->offset = last; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http range body buf: %O-%O", start, last); + + if (ngx_buf_special(buf)) { + *ll = cl; + ll = &cl->next; + continue; + } + + if (range->end <= start || range->start >= last) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http range body skip"); + + buf->pos = buf->last; + continue; } - if (ngx_buf_in_memory(buf)) { - buf->pos = buf->start + (size_t) range->start; - buf->last = buf->start + (size_t) range->end; + if (range->start > start) { + + if (buf->in_file) { + buf->file_pos += range->start - start; + } + + if (ngx_buf_in_memory(buf)) { + buf->pos += (size_t) (range->start - start); + } } - return ngx_http_next_body_filter(r, in); + if (range->end <= last) { + + if (buf->in_file) { + buf->file_last -= last - range->end; + } + + if (ngx_buf_in_memory(buf)) { + buf->last -= (size_t) (last - range->end); + } + + buf->last_buf = 1; + *ll = cl; + cl->next = NULL; + + break; + } + + *ll = cl; + ll = &cl->next; } + if (out == NULL) { + return NGX_OK; + } + + return ngx_http_next_body_filter(r, out); +} + + +static ngx_int_t +ngx_http_range_multipart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) +{ + ngx_buf_t *b, *buf; + ngx_uint_t i; + ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; + ngx_http_range_t *range; + ll = &out; + buf = in->buf; + range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { @@ -630,8 +803,8 @@ ngx_http_range_body_filter(ngx_http_requ b->temporary = 1; b->last_buf = 1; - b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN - + sizeof("--" CRLF) - 1); + b->pos = ngx_pnalloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + + sizeof("--" CRLF) - 1); if (b->pos == NULL) { return NGX_ERROR; } @@ -652,13 +825,6 @@ ngx_http_range_body_filter(ngx_http_requ *ll = hcl; return ngx_http_next_body_filter(r, out); - -overlapped: - - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "range in overlapped buffers"); - - return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -163,7 +163,7 @@ ngx_http_realip_handler(ngx_http_request return NGX_DECLINED; } - p = ngx_palloc(r->connection->pool, len); + p = ngx_pnalloc(r->connection->pool, len); if (p == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -11,14 +11,7 @@ #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) -#if (NGX_PCRE) - -typedef struct { - ngx_regex_t *regex; - ngx_str_t name; -} ngx_http_referer_regex_t; - -#else +#if !(NGX_PCRE) #define ngx_regex_t void @@ -106,11 +99,6 @@ ngx_http_referer_variable(ngx_http_reque ngx_uint_t i, key; ngx_http_referer_conf_t *rlcf; u_char buf[256]; -#if (NGX_PCRE) - ngx_int_t n; - ngx_str_t referer; - ngx_http_referer_regex_t *regex; -#endif rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); @@ -173,31 +161,23 @@ ngx_http_referer_variable(ngx_http_reque #if (NGX_PCRE) if (rlcf->regex) { + ngx_int_t rc; + ngx_str_t referer; referer.len = len - 7; referer.data = ref; - regex = rlcf->regex->elts; - - for (i = 0; i < rlcf->regex->nelts; i++) { - n = ngx_regex_exec(regex[i].regex, &referer, NULL, 0); - - if (n == NGX_REGEX_NO_MATCHED) { - continue; - } + rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log); - if (n < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n - " failed: %d on \"%V\" using \"%V\"", - n, &referer, ®ex[i].name); - return NGX_ERROR; - } - - /* match */ - + if (rc == NGX_OK) { goto valid; } + + if (rc == NGX_ERROR) { + return rc; + } + + /* NGX_DECLINED */ } #endif @@ -244,6 +224,10 @@ ngx_http_referer_create_conf(ngx_conf_t return NGX_CONF_ERROR; } +#if (NGX_PCRE) + conf->regex = NGX_CONF_UNSET_PTR; +#endif + conf->no_referer = NGX_CONF_UNSET; conf->blocked_referer = NGX_CONF_UNSET; @@ -262,6 +246,9 @@ ngx_http_referer_merge_conf(ngx_conf_t * if (conf->keys == NULL) { conf->hash = prev->hash; +#if (NGX_PCRE) + ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); +#endif ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); @@ -337,6 +324,10 @@ ngx_http_referer_merge_conf(ngx_conf_t * conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } +#if (NGX_PCRE) + ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); +#endif + if (conf->no_referer == NGX_CONF_UNSET) { conf->no_referer = 0; } @@ -367,7 +358,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, name.data = (u_char *) "invalid_referer"; var = ngx_http_add_variable(cf, &name, - NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH); + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_CONF_ERROR; } @@ -511,26 +502,25 @@ ngx_http_add_regex_referer(ngx_conf_t *c ngx_str_t *name, ngx_regex_t *regex) { #if (NGX_PCRE) - ngx_str_t err; - ngx_http_referer_regex_t *rr; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_str_t err; + ngx_regex_elt_t *re; + u_char errstr[NGX_MAX_CONF_ERRSTR]; - if (rlcf->regex == NULL) { - rlcf->regex = ngx_array_create(cf->pool, 2, - sizeof(ngx_http_referer_regex_t)); + if (rlcf->regex == NGX_CONF_UNSET_PTR) { + rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t)); if (rlcf->regex == NULL) { return NGX_CONF_ERROR; } } - rr = ngx_array_push(rlcf->regex); - if (rr == NULL) { + re = ngx_array_push(rlcf->regex); + if (re == NULL) { return NGX_CONF_ERROR; } if (regex) { - rr->regex = regex; - rr->name = *name; + re->regex = regex; + re->name = name->data; return NGX_CONF_OK; } @@ -541,14 +531,14 @@ ngx_http_add_regex_referer(ngx_conf_t *c name->len--; name->data++; - rr->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); + re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); - if (rr->regex == NULL) { + if (re->regex == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_CONF_ERROR; } - rr->name = *name; + re->name = name->data; return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -357,6 +357,12 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com last = 1; } + if (ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0) { + regex->status = NGX_HTTP_MOVED_TEMPORARILY; + regex->redirect = 1; + last = 1; + } + if (cf->args->nelts == 4) { if (ngx_strcmp(value[3].data, "last") == 0) { last = 1; @@ -524,7 +530,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ ngx_conf_t save; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; - ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; + ngx_http_core_loc_conf_t *clcf, *pclcf; ngx_http_script_if_code_t *if_code; ngx_http_rewrite_loc_conf_t *nlcf; @@ -567,21 +573,10 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ clcf->name = pclcf->name; clcf->noname = 1; - if (pclcf->locations == NULL) { - pclcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *)); - if (pclcf->locations == NULL) { - return NGX_CONF_ERROR; - } - } - - clcfp = ngx_array_push(pclcf->locations); - if (clcfp == NULL) { + if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { return NGX_CONF_ERROR; } - *clcfp = clcf; - - if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) { return NGX_CONF_ERROR; } @@ -924,7 +919,7 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx value[1].len--; value[1].data++; - v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGABLE); + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE); if (v == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -100,7 +100,7 @@ static ngx_int_t ngx_http_ssi_endblock(n ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); static ngx_int_t ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t gmt); + ngx_http_variable_value_t *v, uintptr_t gmt); static char *ngx_http_ssi_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -212,6 +212,7 @@ static ngx_str_t ngx_http_ssi_null_strin #define NGX_HTTP_SSI_ECHO_VAR 0 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 +#define NGX_HTTP_SSI_ECHO_ENCODING 2 #define NGX_HTTP_SSI_CONFIG_ERRMSG 0 #define NGX_HTTP_SSI_CONFIG_TIMEFMT 1 @@ -237,6 +238,7 @@ static ngx_http_ssi_param_t ngx_http_ss static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1, 0 }, { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0, 0 }, + { ngx_string("encoding"), NGX_HTTP_SSI_ECHO_ENCODING, 0, 0 }, { ngx_null_string, 0, 0, 0 } }; @@ -301,10 +303,10 @@ static ngx_http_ssi_command_t ngx_http_ static ngx_http_variable_t ngx_http_ssi_vars[] = { { ngx_string("date_local"), NULL, ngx_http_ssi_date_gmt_local_variable, 0, - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("date_gmt"), NULL, ngx_http_ssi_date_gmt_local_variable, 1, - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -355,6 +357,7 @@ found: ctx->value_len = slcf->value_len; ctx->last_out = &ctx->out; + ctx->encoding = NGX_HTTP_SSI_ENTITY_ENCODING; ctx->output = 1; ctx->params.elts = ctx->params_array; @@ -555,8 +558,9 @@ ngx_http_ssi_body_filter(ngx_http_reques if (b->in_file) { if (slcf->min_file_chunk < (size_t) (b->last - b->pos)) { - b->file_last = b->file_pos + (b->last - b->start); - b->file_pos += b->pos - b->start; + b->file_last = b->file_pos + + (b->last - ctx->buf->pos); + b->file_pos += b->pos - ctx->buf->pos; } else { b->in_file = 0; @@ -1148,8 +1152,8 @@ ngx_http_ssi_parse(ngx_http_request_t *r default: ctx->command.len = 1; - ctx->command.data = ngx_palloc(r->pool, - NGX_HTTP_SSI_COMMAND_LEN); + ctx->command.data = ngx_pnalloc(r->pool, + NGX_HTTP_SSI_COMMAND_LEN); if (ctx->command.data == NULL) { return NGX_ERROR; } @@ -1215,8 +1219,8 @@ ngx_http_ssi_parse(ngx_http_request_t *r } ctx->param->key.len = 1; - ctx->param->key.data = ngx_palloc(r->pool, - NGX_HTTP_SSI_PARAM_LEN); + ctx->param->key.data = ngx_pnalloc(r->pool, + NGX_HTTP_SSI_PARAM_LEN); if (ctx->param->key.data == NULL) { return NGX_ERROR; } @@ -1226,8 +1230,8 @@ ngx_http_ssi_parse(ngx_http_request_t *r ctx->param->value.len = 0; if (ctx->value_buf == NULL) { - ctx->param->value.data = ngx_palloc(r->pool, - ctx->value_len); + ctx->param->value.data = ngx_pnalloc(r->pool, + ctx->value_len); if (ctx->param->value.data == NULL) { return NGX_ERROR; } @@ -1405,7 +1409,7 @@ ngx_http_ssi_parse(ngx_http_request_t *r case ssi_postparam_state: if (ctx->param->value.len + 1 < ctx->value_len / 2) { - value = ngx_palloc(r->pool, ctx->param->value.len + 1); + value = ngx_pnalloc(r->pool, ctx->param->value.len + 1); if (value == NULL) { return NGX_ERROR; } @@ -1601,7 +1605,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re size_t *size, len, prefix, part_len; ngx_str_t var, *val; ngx_int_t key; - ngx_uint_t i, j, n, bracket, quoted; + ngx_uint_t i, n, bracket, quoted; ngx_array_t lengths, values; ngx_http_variable_value_t *vv; @@ -1623,7 +1627,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re if (prefix) { len = prefix + text->len; - data = ngx_palloc(r->pool, len); + data = ngx_pnalloc(r->pool, len); if (data == NULL) { return NGX_ERROR; } @@ -1634,7 +1638,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re quoted = 0; - for (i = 0 ; i < text->len; i++) { + for (i = 0; i < text->len; i++) { ch = text->data[i]; if (!quoted) { @@ -1727,12 +1731,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re goto invalid_variable; } - key = 0; - - for (j = 0; j < var.len; j++) { - var.data[j] = ngx_tolower(var.data[j]); - key = ngx_hash(key, var.data[j]); - } + key = ngx_hash_strlow(var.data, var.data, var.len); val = ngx_http_ssi_get_variable(r, &var, key); @@ -1826,7 +1825,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re } } - p = ngx_palloc(r->pool, len + ((flags & NGX_HTTP_SSI_ADD_ZERO) ? 1 : 0)); + p = ngx_pnalloc(r->pool, len + ((flags & NGX_HTTP_SSI_ADD_ZERO) ? 1 : 0)); if (p == NULL) { return NGX_ERROR; } @@ -1855,6 +1854,8 @@ static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { + u_char *dst, *src; + size_t len; ngx_int_t rc, key; ngx_str_t *uri, *file, *wait, *set, *stub, args; ngx_buf_t *b; @@ -1924,13 +1925,25 @@ ngx_http_ssi_include(ngx_http_request_t return rc; } + dst = uri->data; + src = uri->data; + + ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI); + + len = (uri->data + uri->len) - src; + if (len) { + dst = ngx_copy(dst, src, len); + } + + uri->len = dst - uri->data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "ssi include: \"%V\"", uri); + args.len = 0; args.data = NULL; flags = 0; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "ssi include: \"%V\"", uri); - if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { return NGX_HTTP_SSI_ERROR; } @@ -1966,6 +1979,7 @@ ngx_http_ssi_include(ngx_http_request_t if (bl[i].count++) { + out = NULL; ll = &out; for (tl = bl[i].bufs; tl; tl = tl->next) { @@ -2006,12 +2020,7 @@ ngx_http_ssi_include(ngx_http_request_t } if (set) { - key = 0; - - for (i = 0; i < set->len; i++) { - set->data[i] = ngx_tolower(set->data[i]); - key = ngx_hash(key, set->data[i]); - } + key = ngx_hash_strlow(set->data, set->data, set->len); psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { @@ -2119,10 +2128,11 @@ static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { + u_char *p; + uintptr_t len; ngx_int_t key; - ngx_uint_t i; ngx_buf_t *b; - ngx_str_t *var, *value, text; + ngx_str_t *var, *value, *enc, text; ngx_chain_t *cl; ngx_http_variable_value_t *vv; @@ -2131,12 +2141,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ssi echo \"%V\"", var); - key = 0; - - for (i = 0; i < var->len; i++) { - var->data[i] = ngx_tolower(var->data[i]); - key = ngx_hash(key, var->data[i]); - } + key = ngx_hash_strlow(var->data, var->data, var->len); value = ngx_http_ssi_get_variable(r, var, key); @@ -2170,6 +2175,69 @@ ngx_http_ssi_echo(ngx_http_request_t *r, } } + enc = params[NGX_HTTP_SSI_ECHO_ENCODING]; + + if (enc) { + if (enc->len == 4 && ngx_strncmp(enc->data, "none", 4) == 0) { + + ctx->encoding = NGX_HTTP_SSI_NO_ENCODING; + + } else if (enc->len == 3 && ngx_strncmp(enc->data, "url", 3) == 0) { + + ctx->encoding = NGX_HTTP_SSI_URL_ENCODING; + + } else if (enc->len == 6 && ngx_strncmp(enc->data, "entity", 6) == 0) { + + ctx->encoding = NGX_HTTP_SSI_ENTITY_ENCODING; + + } else { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown encoding \"%V\" in the \"echo\" command", + enc); + } + } + + 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); + + if (len) { + p = ngx_pnalloc(r->pool, value->len + len); + if (p == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + (void) ngx_escape_uri(p, value->data, value->len, NGX_ESCAPE_HTML); + + value->len += len; + value->data = p; + } + + break; + + case NGX_HTTP_SSI_ENTITY_ENCODING: + len = ngx_escape_html(NULL, value->data, value->len); + + if (len) { + p = ngx_pnalloc(r->pool, value->len + len); + if (p == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + (void) ngx_escape_html(p, value->data, value->len); + + value->len += len; + value->data = p; + } + + break; + } + b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_HTTP_SSI_ERROR; @@ -2203,7 +2271,7 @@ ngx_http_ssi_config(ngx_http_request_t * if (value) { ctx->timefmt.len = value->len; - ctx->timefmt.data = ngx_palloc(r->pool, value->len + 1); + ctx->timefmt.data = ngx_pnalloc(r->pool, value->len + 1); if (ctx->timefmt.data == NULL) { return NGX_HTTP_SSI_ERROR; } @@ -2226,7 +2294,6 @@ ngx_http_ssi_set(ngx_http_request_t *r, ngx_str_t **params) { ngx_int_t key, rc; - ngx_uint_t i; ngx_str_t *name, *value, *vv; ngx_http_ssi_var_t *var; ngx_http_ssi_ctx_t *mctx; @@ -2253,12 +2320,7 @@ ngx_http_ssi_set(ngx_http_request_t *r, return rc; } - key = 0; - - for (i = 0; i < name->len; i++) { - name->data[i] = ngx_tolower(name->data[i]); - key = ngx_hash(key, name->data[i]); - } + key = ngx_hash_strlow(name->data, name->data, name->len); vv = ngx_http_ssi_get_variable(r, name, key); @@ -2291,11 +2353,6 @@ ngx_http_ssi_if(ngx_http_request_t *r, n ngx_str_t *expr, left, right; ngx_int_t rc; ngx_uint_t negative, noregex, flags; -#if (NGX_PCRE) - ngx_str_t err; - ngx_regex_t *regex; - u_char errstr[NGX_MAX_CONF_ERRSTR]; -#endif if (ctx->command.len == 2) { if (ctx->conditional) { @@ -2429,6 +2486,10 @@ ngx_http_ssi_if(ngx_http_request_t *r, n } else { #if (NGX_PCRE) + ngx_str_t err; + ngx_regex_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + err.len = NGX_MAX_CONF_ERRSTR; err.data = errstr; @@ -2565,7 +2626,7 @@ ngx_http_ssi_endblock(ngx_http_request_t static ngx_int_t ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t gmt) + ngx_http_variable_value_t *v, uintptr_t gmt) { ngx_http_ssi_ctx_t *ctx; ngx_time_t *tp; @@ -2573,17 +2634,18 @@ ngx_http_ssi_date_gmt_local_variable(ngx char buf[NGX_HTTP_SSI_DATE_LEN]; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; tp = ngx_timeofday(); ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); - if (ctx->timefmt.len == sizeof("%s") - 1 - && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's') + if (ctx == NULL + || (ctx->timefmt.len == sizeof("%s") - 1 + && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's')) { - v->data = ngx_palloc(r->pool, NGX_TIME_T_LEN); + v->data = ngx_pnalloc(r->pool, NGX_TIME_T_LEN); if (v->data == NULL) { return NGX_ERROR; } @@ -2606,7 +2668,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx return NGX_ERROR; } - v->data = ngx_palloc(r->pool, v->len); + v->data = ngx_pnalloc(r->pool, v->len); if (v->data == NULL) { return NGX_ERROR; } @@ -2655,7 +2717,7 @@ ngx_http_ssi_types(ngx_conf_t *cf, ngx_c type->len = value[i].len; - type->data = ngx_palloc(cf->pool, type->len + 1); + type->data = ngx_pnalloc(cf->pool, type->len + 1); if (type->data == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.h b/src/http/modules/ngx_http_ssi_filter_module.h --- a/src/http/modules/ngx_http_ssi_filter_module.h +++ b/src/http/modules/ngx_http_ssi_filter_module.h @@ -13,15 +13,20 @@ #include -#define NGX_HTTP_SSI_MAX_PARAMS 16 +#define NGX_HTTP_SSI_MAX_PARAMS 16 -#define NGX_HTTP_SSI_COMMAND_LEN 32 -#define NGX_HTTP_SSI_PARAM_LEN 32 -#define NGX_HTTP_SSI_PARAMS_N 4 +#define NGX_HTTP_SSI_COMMAND_LEN 32 +#define NGX_HTTP_SSI_PARAM_LEN 32 +#define NGX_HTTP_SSI_PARAMS_N 4 -#define NGX_HTTP_SSI_COND_IF 1 -#define NGX_HTTP_SSI_COND_ELSE 2 +#define NGX_HTTP_SSI_COND_IF 1 +#define NGX_HTTP_SSI_COND_ELSE 2 + + +#define NGX_HTTP_SSI_NO_ENCODING 0 +#define NGX_HTTP_SSI_URL_ENCODING 1 +#define NGX_HTTP_SSI_ENTITY_ENCODING 2 typedef struct { @@ -60,6 +65,7 @@ typedef struct { ngx_array_t *blocks; unsigned conditional:2; + unsigned encoding:2; unsigned block:1; unsigned output:1; unsigned output_chosen:1; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -13,9 +13,9 @@ typedef ngx_int_t (*ngx_ssl_variable_han ngx_pool_t *pool, ngx_str_t *s); -#define NGX_DEFLAUT_CERTIFICATE "cert.pem" -#define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" -#define NGX_DEFLAUT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" +#define NGX_DEFAULT_CERTIFICATE "cert.pem" +#define NGX_DEFAULT_CERTIFICATE_KEY "cert.pem" +#define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, @@ -49,6 +49,14 @@ static ngx_conf_bitmask_t ngx_http_ssl_ }; +static ngx_conf_enum_t ngx_http_ssl_verify[] = { + { ngx_string("off"), 0 }, + { ngx_string("on"), 1 }, + { ngx_string("ask"), 2 }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_ssl_commands[] = { { ngx_string("ssl"), @@ -72,6 +80,13 @@ static ngx_command_t ngx_http_ssl_comma offsetof(ngx_http_ssl_srv_conf_t, certificate_key), NULL }, + { ngx_string("ssl_dhparam"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, dhparam), + NULL }, + { ngx_string("ssl_protocols"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -88,10 +103,10 @@ static ngx_command_t ngx_http_ssl_comma { ngx_string("ssl_verify_client"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_conf_set_enum_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, verify), - NULL }, + &ngx_http_ssl_verify }, { ngx_string("ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, @@ -170,19 +185,26 @@ ngx_module_t ngx_http_ssl_module = { static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_protocol"), NULL, ngx_http_ssl_static_variable, - (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGABLE, 0 }, + (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 }, { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable, - (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGABLE, 0 }, + (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_client_raw_cert"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_raw_certificate, + NGX_HTTP_VAR_CHANGEABLE, 0 }, { ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_variable, - (uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGABLE, 0 }, + (uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGEABLE, 0 }, { ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_variable, - (uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGABLE, 0 }, + (uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGEABLE, 0 }, { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable, - (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGABLE, 0 }, + (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 }, { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -210,7 +232,7 @@ ngx_http_ssl_static_variable(ngx_http_re v->len = len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; return NGX_OK; @@ -241,7 +263,7 @@ ngx_http_ssl_variable(ngx_http_request_t if (v->len) { v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; return NGX_OK; @@ -287,21 +309,19 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t * set by ngx_pcalloc(): * * sscf->protocols = 0; - * sscf->certificate.len = 0; - * sscf->certificate.data = NULL; - * sscf->certificate_key.len = 0; - * sscf->certificate_key.data = NULL; - * sscf->client_certificate.len = 0; - * sscf->client_certificate.data = NULL; + * sscf->certificate = { 0, NULL }; + * sscf->certificate_key = { 0, NULL }; + * sscf->dhparam = { 0, NULL }; + * sscf->client_certificate = { 0, NULL }; * sscf->ciphers.len = 0; * sscf->ciphers.data = NULL; * sscf->shm_zone = NULL; */ sscf->enable = NGX_CONF_UNSET; + sscf->prefer_server_ciphers = NGX_CONF_UNSET; sscf->verify = NGX_CONF_UNSET; sscf->verify_depth = NGX_CONF_UNSET; - sscf->prefer_server_ciphers = NGX_CONF_UNSET; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; @@ -333,19 +353,21 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * (NGX_CONF_BITMASK_SET |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); - ngx_conf_merge_value(conf->verify, prev->verify, 0); - ngx_conf_merge_value(conf->verify_depth, prev->verify_depth, 1); + ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); + ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFLAUT_CERTIFICATE); + NGX_DEFAULT_CERTIFICATE); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFLAUT_CERTIFICATE_KEY); + NGX_DEFAULT_CERTIFICATE_KEY); + + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, ""); - ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS); + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); conf->ssl.log = cf->log; @@ -392,6 +414,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * } if (conf->verify) { + + if (conf->client_certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl_client_certificate for ssl_client_verify"); + return NGX_CONF_ERROR; + } + if (ngx_ssl_client_certificate(cf, &conf->ssl, &conf->client_certificate, conf->verify_depth) @@ -414,9 +443,12 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * return NGX_CONF_ERROR; } + if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { + return NGX_CONF_ERROR; + } + ngx_conf_merge_value(conf->builtin_session_cache, - prev->builtin_session_cache, - NGX_SSL_DFLT_BUILTIN_SCACHE); + prev->builtin_session_cache, NGX_SSL_NONE_SCACHE); if (conf->shm_zone == NULL) { conf->shm_zone = prev->shm_zone; @@ -448,6 +480,16 @@ ngx_http_ssl_session_cache(ngx_conf_t *c for (i = 1; i < cf->args->nelts; i++) { + if (ngx_strcmp(value[i].data, "off") == 0) { + sscf->builtin_session_cache = NGX_SSL_NO_SCACHE; + continue; + } + + if (ngx_strcmp(value[i].data, "none") == 0) { + sscf->builtin_session_cache = NGX_SSL_NONE_SCACHE; + continue; + } + if (ngx_strcmp(value[i].data, "builtin") == 0) { sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -22,8 +22,8 @@ typedef struct { ngx_uint_t protocols; - ngx_int_t verify; - ngx_int_t verify_depth; + ngx_uint_t verify; + ngx_uint_t verify_depth; ssize_t builtin_session_cache; @@ -31,6 +31,7 @@ typedef struct { ngx_str_t certificate; ngx_str_t certificate_key; + ngx_str_t dhparam; ngx_str_t client_certificate; ngx_str_t ciphers; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -48,8 +48,7 @@ static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; - size_t root; - ngx_fd_t fd; + size_t root, len; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; @@ -97,15 +96,17 @@ ngx_http_static_handler(ngx_http_request clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; - rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); - - if (rc == NGX_ERROR) { - + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { switch (of.err) { case 0: @@ -140,9 +141,9 @@ ngx_http_static_handler(ngx_http_request return rc; } - fd = of.fd; + r->root_tested = 1; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { @@ -153,26 +154,39 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (!clcf->alias && clcf->root_lengths == NULL) { + len = r->uri.len + 1; + + if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = path.data + clcf->root.len; + *last = '/'; + } else { - location = ngx_palloc(r->pool, r->uri.len + 1); + if (r->args.len) { + len += r->args.len + 1; + } + + location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); - } + + *last = '/'; - *last = '/'; + if (r->args.len) { + *++last = '?'; + ngx_memcpy(++last, r->args.data, r->args.len); + } + } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ - r->headers_out.location->value.len = r->uri.len + 1; + r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; @@ -230,7 +244,7 @@ ngx_http_static_handler(ngx_http_request b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; - b->file->fd = fd; + b->file->fd = of.fd; b->file->name = path; b->file->log = log; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -129,7 +129,7 @@ static ngx_int_t ngx_http_status_handler return rc; } - return ngx_http_output_filter(r, &out);; + return ngx_http_output_filter(r, &out); } diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -322,8 +322,8 @@ ngx_http_sub_body_filter(ngx_http_reques b->recycled = 0; if (b->in_file) { - b->file_last = b->file_pos + (b->last - b->start); - b->file_pos += b->pos - b->start; + b->file_last = b->file_pos + (b->last - ctx->buf->pos); + b->file_pos += b->pos - ctx->buf->pos; } cl->next = NULL; @@ -369,9 +369,14 @@ ngx_http_sub_body_filter(ngx_http_reques } } - b->memory = 1; - b->pos = ctx->sub.data; - b->last = ctx->sub.data + ctx->sub.len; + if (ctx->sub.len) { + b->memory = 1; + b->pos = ctx->sub.data; + b->last = ctx->sub.data + ctx->sub.len; + + } else { + b->sync = 1; + } cl->buf = b; cl->next = NULL; @@ -557,6 +562,7 @@ ngx_http_sub_parse(ngx_http_request_t *r ch = ngx_tolower(ch); } + ctx->state = state; ctx->pos = p; ctx->looked = looked; ctx->copy_end = p; @@ -578,9 +584,13 @@ ngx_http_sub_parse(ngx_http_request_t *r looked++; if (looked == ctx->match.len) { + if ((size_t) (p - ctx->pos) < looked) { + ctx->saved = 0; + } + ctx->state = sub_start_state; ctx->pos = p + 1; - ctx->looked = looked; + ctx->looked = 0; ctx->copy_end = copy_end; if (ctx->copy_start == NULL && copy_end) { @@ -622,7 +632,6 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_ ngx_str_t *value; ngx_int_t n; - ngx_uint_t i; ngx_http_script_compile_t sc; if (slcf->match.len) { @@ -631,11 +640,9 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_ value = cf->args->elts; - slcf->match = value[1]; + ngx_strlow(value[1].data, value[1].data, value[1].len); - for (i = 0; i < value[1].len; i++) { - value[1].data[i] = ngx_tolower(value[1].data[i]); - } + slcf->match = value[1]; n = ngx_http_script_variables_count(&value[2]); @@ -700,7 +707,7 @@ ngx_http_sub_types(ngx_conf_t *cf, ngx_c type->len = value[i].len; - type->data = ngx_palloc(cf->pool, type->len + 1); + type->data = ngx_pnalloc(cf->pool, type->len + 1); if (type->data == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -41,15 +41,14 @@ typedef struct { } ngx_http_userid_ctx_t; -static void ngx_http_userid_get_uid(ngx_http_request_t *r, - ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); +static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r, + ngx_http_userid_conf_t *conf); +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); 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_add_variables(ngx_conf_t *cf); -static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf); static void *ngx_http_userid_create_conf(ngx_conf_t *cf); static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, @@ -61,9 +60,11 @@ static char *ngx_http_userid_expires(ngx static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle); +static uint32_t start_value; static uint32_t sequencer_v1 = 1; static uint32_t sequencer_v2 = 0x03030302; @@ -173,7 +174,7 @@ ngx_module_t ngx_http_userid_filter_mod NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ - NULL, /* init process */ + ngx_http_userid_init_worker, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ @@ -189,7 +190,6 @@ static ngx_str_t ngx_http_userid_set = static ngx_int_t ngx_http_userid_filter(ngx_http_request_t *r) { - ngx_int_t rc; ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; @@ -199,25 +199,18 @@ 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_OFF) { + if (conf->enable <= NGX_HTTP_USERID_LOG) { return ngx_http_next_header_filter(r); } + ctx = ngx_http_userid_get_uid(r, conf); - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_userid_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } - ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module); - - ngx_http_userid_get_uid(r, ctx, conf); + if (ctx->uid_got[3] != 0) { - if (conf->enable == NGX_HTTP_USERID_LOG) { - return ngx_http_next_header_filter(r); - } - - if (ctx->uid_got[3] != 0) { if (conf->mark == '\0') { return ngx_http_next_header_filter(r); @@ -231,28 +224,95 @@ ngx_http_userid_filter(ngx_http_request_ } } - rc = ngx_http_userid_set_uid(r, ctx, conf); + /* ctx->status == NGX_DECLINED */ - if (rc != NGX_OK) { - return rc; + if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) { + return ngx_http_next_header_filter(r); } - return ngx_http_next_header_filter(r); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_userid_got_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module); + + if (conf->enable == NGX_HTTP_USERID_OFF) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_http_userid_get_uid(r, 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); + } + + /* ctx->status == NGX_DECLINED */ + + v->not_found = 1; + + return NGX_OK; } -static void -ngx_http_userid_get_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_set_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_int_t n; - ngx_str_t src, dst; - ngx_table_elt_t **cookies; + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + + if (ctx == NULL || ctx->uid_set[3] == 0) { + v->not_found = 1; + return NGX_OK; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + + return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_set); +} + + +static ngx_http_userid_ctx_t * +ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) +{ + ngx_int_t n; + ngx_str_t src, dst; + ngx_table_elt_t **cookies; + ngx_http_userid_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + + if (ctx) { + return ctx; + } + + if (ctx == NULL) { + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_userid_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module); + } n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, &ctx->cookie); if (n == NGX_DECLINED) { - return; + return ctx; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -263,7 +323,7 @@ ngx_http_userid_get_uid(ngx_http_request ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent too short userid cookie \"%V\"", &cookies[n]->value); - return; + return ctx; } src = ctx->cookie; @@ -284,13 +344,15 @@ ngx_http_userid_get_uid(ngx_http_request ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid userid cookie \"%V\"", &cookies[n]->value); - return; + return ctx; } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uid: %08XD%08XD%08XD%08XD", ctx->uid_got[0], ctx->uid_got[1], ctx->uid_got[2], ctx->uid_got[3]); + + return ctx; } @@ -298,13 +360,10 @@ 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; - socklen_t slen; - struct sockaddr_in sin; - ngx_str_t src, dst; - ngx_table_elt_t *set_cookie, *p3p; - + u_char *cookie, *p; + size_t len; + ngx_str_t src, dst; + ngx_table_elt_t *set_cookie, *p3p; /* * TODO: in the threaded mode the sequencers should be in TLS and their * ranges should be divided between threads @@ -318,25 +377,15 @@ ngx_http_userid_set_uid(ngx_http_request } else { ctx->uid_set[0] = conf->service; } - ctx->uid_set[1] = ngx_time(); - ctx->uid_set[2] = ngx_pid; + 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) { - if (r->in_addr == 0) { - slen = sizeof(struct sockaddr_in); - if (getsockname(r->connection->fd, - (struct sockaddr *) &sin, &slen) - == -1) - { - ngx_connection_error(r->connection, ngx_socket_errno, - "getsockname() failed"); - return NGX_ERROR; - } - - r->in_addr = sin.sin_addr.s_addr; + if (ngx_http_server_addr(r, NULL) != NGX_OK) { + return NGX_ERROR; } ctx->uid_set[0] = htonl(r->in_addr); @@ -345,8 +394,8 @@ ngx_http_userid_set_uid(ngx_http_request ctx->uid_set[0] = htonl(conf->service); } - ctx->uid_set[1] = htonl(ngx_time()); - ctx->uid_set[2] = htonl(ngx_pid); + 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) { @@ -371,7 +420,7 @@ ngx_http_userid_set_uid(ngx_http_request len += conf->domain.len; } - cookie = ngx_palloc(r->pool, len); + cookie = ngx_pnalloc(r->pool, len); if (cookie == NULL) { return NGX_ERROR; } @@ -443,6 +492,27 @@ ngx_http_userid_set_uid(ngx_http_request 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) +{ + v->len = name->len + sizeof("=00001111222233334444555566667777") - 1; + v->data = ngx_pnalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD", + name, uid[0], uid[1], uid[2], uid[3]); + + return NGX_OK; +} + + +static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf) { ngx_http_variable_t *var; @@ -452,52 +522,14 @@ ngx_http_userid_add_variables(ngx_conf_t return NGX_ERROR; } - var->get_handler = ngx_http_userid_variable; - var->data = offsetof(ngx_http_userid_ctx_t, uid_got); + var->get_handler = ngx_http_userid_got_variable; var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_ERROR; } - var->get_handler = ngx_http_userid_variable; - var->data = offsetof(ngx_http_userid_ctx_t, uid_set); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, - uintptr_t data) -{ - uint32_t *uid; - ngx_http_userid_ctx_t *ctx; - ngx_http_userid_conf_t *conf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); - - uid = (uint32_t *) ((char *) ctx + data); - - if (ctx == NULL || uid[3] == 0) { - v->not_found = 1; - return NGX_OK; - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - - v->len = conf->name.len + sizeof("=00001111222233334444555566667777") - 1; - v->data = ngx_palloc(r->pool, v->len); - if (v->data == NULL) { - return NGX_ERROR; - } - - v->valid = 1; - v->no_cachable = 0; - v->not_found = 0; - - ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD", - &conf->name, uid[0], uid[1], uid[2], uid[3]); + var->get_handler = ngx_http_userid_set_variable; return NGX_OK; } @@ -588,7 +620,7 @@ ngx_http_userid_domain(ngx_conf_t *cf, v return NGX_CONF_OK; } - new = ngx_palloc(cf->pool, sizeof("; domain=") - 1 + domain->len); + new = ngx_pnalloc(cf->pool, sizeof("; domain=") - 1 + domain->len); if (new == NULL) { return NGX_CONF_ERROR; } @@ -610,7 +642,7 @@ ngx_http_userid_path(ngx_conf_t *cf, voi u_char *p, *new; - new = ngx_palloc(cf->pool, sizeof("; path=") - 1 + path->len); + new = ngx_pnalloc(cf->pool, sizeof("; path=") - 1 + path->len); if (new == NULL) { return NGX_CONF_ERROR; } @@ -706,3 +738,18 @@ ngx_http_userid_mark(ngx_conf_t *cf, ngx return NGX_CONF_OK; } + + +static ngx_int_t +ngx_http_userid_init_worker(ngx_cycle_t *cycle) +{ + struct timeval tp; + + ngx_gettimeofday(&tp); + + /* use the most significant usec part that fits to 16 bits */ + start_value = ((tp.tv_usec / 20) << 16) | ngx_pid; + + return NGX_OK; +} + diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -0,0 +1,1109 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#ifndef NGX_HTTP_XSLT_REUSE_DTD +#define NGX_HTTP_XSLT_REUSE_DTD 1 +#endif + + +typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; +} ngx_http_xslt_param_t; + + +typedef struct { + xsltStylesheetPtr stylesheet; + ngx_array_t params; /* ngx_http_xslt_param_t */ +} ngx_http_xslt_sheet_t; + + +typedef struct { + xmlDtdPtr dtd; + ngx_array_t sheets; /* ngx_http_xslt_sheet_t */ + ngx_hash_t types_hash; + ngx_array_t *keys; +} ngx_http_xslt_filter_conf_t; + + +typedef struct { + xmlDocPtr doc; + xmlParserCtxtPtr ctxt; + xmlSAXHandler *sax; + ngx_http_request_t *request; + ngx_array_t params; + unsigned done:1; + unsigned html:1; +} ngx_http_xslt_filter_ctx_t; + + +static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r, + ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); +static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r); +static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r, + ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); + + +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, ...); + + +static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r, + ngx_http_xslt_filter_ctx_t *ctx); +static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r, + ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params); +static void ngx_http_xslt_cleanup(void *data); + +static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void ngx_http_xslt_cleanup_stylesheet(void *data); +static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf); +static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf); + + +ngx_str_t ngx_http_xslt_default_types[] = { + ngx_string("text/xml"), + ngx_null_string +}; + + +static ngx_command_t ngx_http_xslt_filter_commands[] = { + + { ngx_string("xml_entities"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_http_xslt_entities, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("xslt_stylesheet"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_1MORE, + ngx_http_xslt_stylesheet, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("xslt_types"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_1MORE, + ngx_http_types_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_xslt_filter_conf_t, keys), + &ngx_http_xslt_default_types[0] }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_xslt_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_xslt_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_xslt_filter_create_conf, /* create location configuration */ + ngx_http_xslt_filter_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_xslt_filter_module = { + NGX_MODULE_V1, + &ngx_http_xslt_filter_module_ctx, /* module context */ + ngx_http_xslt_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_xslt_header_filter(ngx_http_request_t *r) +{ + ngx_http_xslt_filter_ctx_t *ctx; + ngx_http_xslt_filter_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter header"); + + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + return ngx_http_next_header_filter(r); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); + + if (conf->sheets.nelts == 0 + || ngx_http_test_content_type(r, &conf->types_hash) == NULL) + { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module); + + if (ctx) { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xslt_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module); + + r->main_filter_need_in_memory = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_chain_t *cl; + ngx_http_xslt_filter_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter body"); + + if (in == NULL) { + return ngx_http_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module); + + if (ctx == NULL || ctx->done) { + return ngx_http_next_body_filter(r, in); + } + + for (cl = in; cl; cl = cl->next) { + + if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) { + + if (ctx->ctxt->myDoc){ + +#if (NGX_HTTP_XSLT_REUSE_DTD) + ctx->ctxt->myDoc->extSubset = NULL; +#endif + xmlFreeDoc(ctx->ctxt->myDoc); + } + + xmlFreeParserCtxt(ctx->ctxt); + + return ngx_http_xslt_send(r, ctx, NULL); + } + + if (cl->buf->last_buf) { + + ctx->doc = ctx->ctxt->myDoc; + +#if (NGX_HTTP_XSLT_REUSE_DTD) + ctx->doc->extSubset = NULL; +#endif + + xmlFreeParserCtxt(ctx->ctxt); + + if (ctx->ctxt->wellFormed) { + return ngx_http_xslt_send(r, ctx, + ngx_http_xslt_apply_stylesheet(r, ctx)); + } + + xmlFreeDoc(ctx->doc); + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "not well formed XML document"); + + return ngx_http_xslt_send(r, ctx, NULL); + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, + ngx_buf_t *b) +{ + ngx_int_t rc; + ngx_chain_t out; + ngx_pool_cleanup_t *cln; + + ctx->done = 1; + + if (b == NULL) { + return ngx_http_xslt_filter_internal_error(r); + } + + cln = ngx_pool_cleanup_add(r->pool, 0); + + if (cln == NULL) { + ngx_free(b->pos); + return ngx_http_special_response_handler(r, + NGX_HTTP_INTERNAL_SERVER_ERROR); + } + + if (ctx->html) { + 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_length_n = b->last - b->pos; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } + + r->allow_ranges = 1; + + rc = ngx_http_next_header_filter(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + ngx_free(b->pos); + return rc; + } + + cln->handler = ngx_http_xslt_cleanup; + cln->data = b->pos; + + out.buf = b; + out.next = NULL; + + return ngx_http_next_body_filter(r, &out); +} + + +static ngx_int_t +ngx_http_xslt_filter_internal_error(ngx_http_request_t *r) +{ + ngx_int_t rc; + + /* clear the modules contexts */ + ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); + + rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + + /* NGX_ERROR resets any pending data */ + + return (rc == NGX_OK) ? NGX_ERROR : rc; +} + + +static ngx_int_t +ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, + ngx_buf_t *b) +{ + int err; + xmlSAXHandler *sax; + xmlParserCtxtPtr ctxt; + + if (ctx->ctxt == NULL) { + + ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); + if (ctxt == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "xmlCreatePushParserCtxt() failed"); + 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->replaceEntities = 1; + ctxt->loadsubset = 1; + + ctx->ctxt = ctxt; + ctx->request = r; + } + + err = xmlParseChunk(ctx->ctxt, (char *) b->pos, + (int) (b->last - b->pos), b->last_buf); + + if (err == 0) { + b->pos = b->last; + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "xmlParseChunk() failed, error:%d", err); + + return NGX_ERROR; +} + + +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; + + xmlDocPtr doc; + xmlDtdPtr dtd; + ngx_http_request_t *r; + ngx_http_xslt_filter_conf_t *conf; + + r = ctx->request; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter extSubset: \"%s\" \"%s\" \"%s\"", + name ? name : (xmlChar *) "", + externalId ? externalId : (xmlChar *) "", + systemId ? systemId : (xmlChar *) ""); + + doc = ctx->ctxt->myDoc; + +#if (NGX_HTTP_XSLT_REUSE_DTD) + + dtd = conf->dtd; + +#else + + dtd = xmlCopyDtd(conf->dtd); + if (dtd == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "xmlCopyDtd() failed"); + return; + } + + dtd->name = xmlStrdup(name); + + if (doc->children == NULL) { + xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); + + } else { + xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd); + } + +#endif + + doc->extSubset = dtd; +} + + +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; + + size_t n; + va_list args; + u_char buf[NGX_MAX_ERROR_STR]; + + buf[0] = '\0'; + + va_start(args, msg); + n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args); + va_end(args); + + while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ } + + ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, + "libxml2 error: \"%*s\"", n, buf); +} + + +static ngx_buf_t * +ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r, + ngx_http_xslt_filter_ctx_t *ctx) +{ + int len, rc; + ngx_buf_t *b; + ngx_uint_t i; + xmlChar *buf; + xmlDocPtr doc, res; + ngx_http_xslt_sheet_t *sheet; + ngx_http_xslt_filter_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); + sheet = conf->sheets.elts; + doc = ctx->doc; + + /* preallocate array for 4 params */ + + if (ngx_array_init(&ctx->params, r->pool, 4 * 2 + 1, sizeof(char *)) + != NGX_OK) + { + xmlFreeDoc(doc); + return NULL; + } + + for (i = 0; i < conf->sheets.nelts; i++) { + + if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) { + xmlFreeDoc(doc); + return NULL; + } + + res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts); + + xmlFreeDoc(doc); + + if (res == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "xsltApplyStylesheet() failed"); + return NULL; + } + + doc = res; + + /* reset array elements */ + ctx->params.nelts = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter doc type: %d", doc->type); + + ctx->html = (doc->type == XML_HTML_DOCUMENT_NODE) ? 1 : 0; + + rc = xsltSaveResultToString(&buf, &len, doc, sheet[i - 1].stylesheet); + + xmlFreeDoc(doc); + + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "xsltSaveResultToString() failed"); + return NULL; + } + + if (len == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "xsltSaveResultToString() returned zero-length result"); + return NULL; + } + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + ngx_free(buf); + return NULL; + } + + b->pos = buf; + b->last = buf + len; + b->memory = 1; + b->last_buf = 1; + + return b; +} + + +static ngx_int_t +ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, + ngx_array_t *params) +{ + u_char *p, *last, *value, *dst, *src, **s; + size_t len; + ngx_uint_t i; + ngx_str_t string; + ngx_http_xslt_param_t *param; + + param = params->elts; + + for (i = 0; i < params->nelts; i++) { + + if (ngx_http_script_run(r, &string, param[i].lengths->elts, 1, + param[i].values->elts) + == NULL) + { + return NGX_ERROR; + } + + last = string.data + string.len - 1; + *last = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter param: \"%s\"", string.data); + + p = string.data; + + while (p && *p) { + + value = p; + p = (u_char *) ngx_strchr(p, '='); + if (p == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid libxslt parameter \"%s\"", value); + return NGX_ERROR; + } + *p++ = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter param name: \"%s\"", value); + + s = ngx_array_push(&ctx->params); + if (s == NULL) { + return NGX_ERROR; + } + + *s = value; + + value = p; + p = (u_char *) ngx_strchr(p, ':'); + + if (p) { + len = p - value; + *p++ = '\0'; + + } else { + len = last - value; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter param value: \"%s\"", value); + + dst = value; + src = value; + + ngx_unescape_uri(&dst, &src, len, 0); + + *dst = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "xslt filter param unescaped: \"%s\"", value); + + s = ngx_array_push(&ctx->params); + if (s == NULL) { + return NGX_ERROR; + } + + *s = value; + } + } + + s = ngx_array_push(&ctx->params); + if (s == NULL) { + return NGX_ERROR; + } + + *s = NULL; + + return NGX_OK; +} + + +static void +ngx_http_xslt_cleanup(void *data) +{ + ngx_free(data); +} + + +static char * +ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_xslt_filter_conf_t *xlcf = conf; + + ngx_str_t *value; + + if (xlcf->dtd) { + return "is duplicate"; + } + + value = cf->args->elts; + + xlcf->dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data); + + if (xlcf->dtd == NULL) { + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "xmlParseDTD() failed"); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + + +static char * +ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_xslt_filter_conf_t *xlcf = conf; + + ngx_str_t *value; + ngx_uint_t i, n; + ngx_pool_cleanup_t *cln; + ngx_http_xslt_sheet_t *sheet; + ngx_http_xslt_param_t *param; + ngx_http_script_compile_t sc; + + value = cf->args->elts; + + if (xlcf->sheets.elts == NULL) { + if (ngx_array_init(&xlcf->sheets, cf->pool, 1, + sizeof(ngx_http_xslt_sheet_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + + sheet = ngx_array_push(&xlcf->sheets); + if (sheet == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(sheet, sizeof(ngx_http_xslt_sheet_t)); + + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + sheet->stylesheet = xsltParseStylesheetFile(value[1].data); + if (sheet->stylesheet == NULL) { + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, + "xsltParseStylesheetFile(\"%s\") failed", + value[1].data); + return NGX_CONF_ERROR; + } + + cln->handler = ngx_http_xslt_cleanup_stylesheet; + cln->data = sheet->stylesheet; + + n = cf->args->nelts; + + if (n == 2) { + return NGX_CONF_OK; + } + + if (ngx_array_init(&sheet->params, cf->pool, n - 2, + sizeof(ngx_http_xslt_param_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + for (i = 2; i < n; i++) { + + param = ngx_array_push(&sheet->params); + if (param == NULL) { + return NGX_CONF_ERROR; + } + + param->lengths = NULL; + param->values = NULL; + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &value[i]; + sc.lengths = ¶m->lengths; + sc.values = ¶m->values; + sc.variables = ngx_http_script_variables_count(&value[i]); + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + +static void +ngx_http_xslt_cleanup_stylesheet(void *data) +{ + xsltStylesheetPtr stylesheet = data; + + xsltFreeStylesheet(stylesheet); +} + + + +static void * +ngx_http_xslt_filter_create_conf(ngx_conf_t *cf) +{ + ngx_http_xslt_filter_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->dtd + * conf->sheets + */ + + return conf; +} + + +static char * +ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_xslt_filter_conf_t *prev = parent; + ngx_http_xslt_filter_conf_t *conf = child; + + if (conf->dtd == NULL) { + conf->dtd = prev->dtd; + } + + if (conf->sheets.nelts == 0) { + conf->sheets = prev->sheets; + } + + if (ngx_http_merge_types(cf, conf->keys, &conf->types_hash, prev->keys, + &prev->types_hash, ngx_http_xslt_default_types) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_xslt_filter_init(ngx_conf_t *cf) +{ + xmlInitParser(); + + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_xslt_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_xslt_body_filter; + + return NGX_OK; +} + + +static void +ngx_http_xslt_filter_exit(ngx_cycle_t *cycle) +{ + xsltCleanupGlobals(); + xmlCleanupParser(); +} diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.6.12'; +our $VERSION = '0.7.8'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -13,19 +13,16 @@ #include "XSUB.h" + #define ngx_http_perl_set_request(r) \ r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) -#define ngx_http_perl_set_targ(p, len, z) \ +#define ngx_http_perl_set_targ(p, len) \ \ - sv_upgrade(TARG, SVt_PV); \ + SvUPGRADE(TARG, SVt_PV); \ SvPOK_on(TARG); \ - SvPV_set(TARG, (char *) p); \ - SvLEN_set(TARG, len + z); \ - SvCUR_set(TARG, len); \ - SvFAKE_on(TARG); \ - SvREADONLY_on(TARG); \ + sv_setpvn(TARG, (char *) p, len) static ngx_int_t @@ -42,18 +39,25 @@ ngx_http_perl_sv2str(pTHX_ ngx_http_requ s->len = len; - if (SvREADONLY(sv)) { + if (SvREADONLY(sv) && SvPOK(sv)) { s->data = p; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "perl sv2str: %08XD \"%V\"", sv->sv_flags, s); + return NGX_OK; } - s->data = ngx_palloc(r->pool, len); + s->data = ngx_pnalloc(r->pool, len); if (s->data == NULL) { return NGX_ERROR; } ngx_memcpy(s->data, p, len); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "perl sv2str: %08XD \"%V\"", sv->sv_flags, s); + return NGX_OK; } @@ -165,7 +169,7 @@ uri(r) ngx_http_request_t *r; ngx_http_perl_set_request(r); - ngx_http_perl_set_targ(r->uri.data, r->uri.len, 0); + ngx_http_perl_set_targ(r->uri.data, r->uri.len); ST(0) = TARG; @@ -178,7 +182,7 @@ args(r) ngx_http_request_t *r; ngx_http_perl_set_request(r); - ngx_http_perl_set_targ(r->args.data, r->args.len, 0); + ngx_http_perl_set_targ(r->args.data, r->args.len); ST(0) = TARG; @@ -191,7 +195,7 @@ request_method(r) ngx_http_request_t *r; ngx_http_perl_set_request(r); - ngx_http_perl_set_targ(r->method_name.data, r->method_name.len, 0); + ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); ST(0) = TARG; @@ -205,7 +209,7 @@ remote_addr(r) ngx_http_perl_set_request(r); ngx_http_perl_set_targ(r->connection->addr_text.data, - r->connection->addr_text.len, 1); + r->connection->addr_text.len); ST(0) = TARG; @@ -238,16 +242,12 @@ header_in(r, key) /* look up hashed headers */ - lowcase_key = ngx_palloc(r->pool, len); + lowcase_key = ngx_pnalloc(r->pool, len); if (lowcase_key == NULL) { XSRETURN_UNDEF; } - hash = 0; - for (i = 0; i < len; i++) { - lowcase_key[i] = ngx_tolower(p[i]); - hash = ngx_hash(hash, lowcase_key[i]); - } + hash = ngx_hash_strlow(lowcase_key, p, len); cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); @@ -259,7 +259,7 @@ header_in(r, key) ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset); if (*ph) { - ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len, 0); + ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); goto done; } @@ -278,7 +278,7 @@ header_in(r, key) ph = r->headers_in.cookies.elts; if (n == 1) { - ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len, 0); + ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); goto done; } @@ -289,7 +289,7 @@ header_in(r, key) size += ph[i]->value.len + sizeof("; ") - 1; } - cookie = ngx_palloc(r->pool, size); + cookie = ngx_pnalloc(r->pool, size); if (cookie == NULL) { XSRETURN_UNDEF; } @@ -306,7 +306,7 @@ header_in(r, key) *p++ = ';'; *p++ = ' '; } - ngx_http_perl_set_targ(cookie, size, 0); + ngx_http_perl_set_targ(cookie, size); goto done; } @@ -334,7 +334,7 @@ header_in(r, key) continue; } - ngx_http_perl_set_targ(h[i].value.data, h[i].value.len, 0); + ngx_http_perl_set_targ(h[i].value.data, h[i].value.len); goto done; } @@ -402,7 +402,7 @@ request_body(r) XSRETURN_UNDEF; } - ngx_http_perl_set_targ(r->request_body->bufs->buf->pos, len, 0); + ngx_http_perl_set_targ(r->request_body->bufs->buf->pos, len); ST(0) = TARG; @@ -421,7 +421,7 @@ request_body_file(r) } ngx_http_perl_set_targ(r->request_body->temp_file->file.name.data, - r->request_body->temp_file->file.name.len, 1); + r->request_body->temp_file->file.name.len); ST(0) = TARG; @@ -500,7 +500,7 @@ filename(r) done: - ngx_http_perl_set_targ(ctx->filename.data, ctx->filename.len, 1); + ngx_http_perl_set_targ(ctx->filename.data, ctx->filename.len); ST(0) = TARG; @@ -532,7 +532,7 @@ print(r, ...) sv = SvRV(sv); } - if (SvREADONLY(sv)) { + if (SvREADONLY(sv) && SvPOK(sv)) { p = (u_char *) SvPV(sv, len); @@ -609,7 +609,6 @@ sendfile(r, filename, offset = -1, bytes char *filename; int offset; size_t bytes; - ngx_int_t rc; ngx_str_t path; ngx_buf_t *b; ngx_open_file_info_t of; @@ -636,26 +635,28 @@ sendfile(r, filename, offset = -1, bytes XSRETURN_EMPTY; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; - path.len = ngx_strlen(filename); - path.data = ngx_pcalloc(r->pool, path.len + 1); + path.data = ngx_pnalloc(r->pool, path.len + 1); if (path.data == NULL) { XSRETURN_EMPTY; } (void) ngx_cpystrn(path.data, filename, path.len + 1); - - rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - if (rc == NGX_ERROR) { + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { if (of.err == 0) { XSRETURN_EMPTY; } @@ -766,7 +767,7 @@ unescape(r, text, type = 0) src = (u_char *) SvPV(text, len); - p = ngx_palloc(r->pool, len + 1); + p = ngx_pnalloc(r->pool, len + 1); if (p == NULL) { XSRETURN_UNDEF; } @@ -778,7 +779,7 @@ unescape(r, text, type = 0) ngx_unescape_uri(&dst, &src, len, (ngx_uint_t) type); *dst = '\0'; - ngx_http_perl_set_targ(p, dst - p, 1); + ngx_http_perl_set_targ(p, dst - p); ST(0) = TARG; @@ -823,16 +824,12 @@ variable(r, name, value = NULL) p = (u_char *) SvPV(name, len); - lowcase = ngx_palloc(r->pool, len); + lowcase = ngx_pnalloc(r->pool, len); if (lowcase == NULL) { XSRETURN_UNDEF; } - hash = 0; - for (i = 0; i < len; i++) { - lowcase[i] = ngx_tolower(p[i]); - hash = ngx_hash(hash, lowcase[i]); - } + hash = ngx_hash_strlow(lowcase, p, len); var.len = len; var.data = lowcase; @@ -875,7 +872,7 @@ variable(r, name, value = NULL) XSRETURN_UNDEF; } - ngx_http_perl_set_targ(v[i].value.data, v[i].value.len, 0); + ngx_http_perl_set_targ(v[i].value.data, v[i].value.len); goto done; } @@ -912,14 +909,14 @@ variable(r, name, value = NULL) if (value) { vv->len = val.len; vv->valid = 1; - vv->no_cachable = 0; + vv->no_cacheable = 0; vv->not_found = 0; vv->data = val.data; XSRETURN_UNDEF; } - ngx_http_perl_set_targ(vv->data, vv->len, 0); + ngx_http_perl_set_targ(vv->data, vv->len); done: @@ -930,19 +927,24 @@ void sleep(r, sleep, next) CODE: - dXSTARG; ngx_http_request_t *r; + ngx_msec_t sleep; ngx_http_perl_ctx_t *ctx; ngx_http_perl_set_request(r); + sleep = (ngx_msec_t) SvIV(ST(1)); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "perl sleep: %M", sleep); + ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - ctx->sleep = SvIV(ST(1)); ctx->next = SvRV(ST(2)); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "perl sleep: %d", ctx->sleep); + ngx_add_timer(r->connection->write, sleep); + + r->write_event_handler = ngx_http_perl_sleep_handler; void diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -41,7 +41,6 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params); #endif -static void ngx_http_perl_sleep_handler(ngx_http_request_t *r); static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf); static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf, @@ -49,7 +48,7 @@ static PerlInterpreter *ngx_http_perl_cr static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log); static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, - HV *nginx, SV *sub, ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv); + HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); @@ -230,6 +229,10 @@ ngx_http_perl_handle_request(ngx_http_re } + if (rc == NGX_DONE) { + return; + } + if (rc > 600) { rc = NGX_OK; } @@ -248,12 +251,6 @@ ngx_http_perl_handle_request(ngx_http_re ctx->filename.data = NULL; ctx->redirect_uri.len = 0; - if (ctx->sleep) { - ngx_add_timer(r->connection->write, (ngx_msec_t) ctx->sleep); - r->write_event_handler = ngx_http_perl_sleep_handler; - ctx->sleep = 0; - } - if (ctx->done || ctx->next) { return; } @@ -272,7 +269,7 @@ ngx_http_perl_handle_request(ngx_http_re } -static void +void ngx_http_perl_sleep_handler(ngx_http_request_t *r) { ngx_event_t *wev; @@ -336,7 +333,7 @@ ngx_http_perl_variable(ngx_http_request_ if (value.data) { v->len = value.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = value.data; @@ -360,9 +357,10 @@ static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params) { - SV *sv; + SV *sv, **asv; ngx_int_t rc; - ngx_str_t *handler; + ngx_str_t *handler, **args; + ngx_uint_t i; ngx_http_perl_ctx_t *ctx; ngx_http_perl_main_conf_t *pmcf; @@ -412,9 +410,31 @@ ngx_http_perl_ssi(ngx_http_request_t *r, sv = newSVpvn((char *) handler->data, handler->len); - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, - ¶ms[NGX_HTTP_PERL_SSI_ARG], - handler, NULL); + args = ¶ms[NGX_HTTP_PERL_SSI_ARG]; + + if (args) { + + for (i = 0; args[i]; i++) { /* void */ } + + asv = ngx_pcalloc(r->pool, (i + 1) * sizeof(SV *)); + + if (asv == NULL) { + SvREFCNT_dec(sv); + return NGX_ERROR; + } + + asv[0] = (SV *) i; + + for (i = 0; args[i]; i++) { + asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len); + } + + } else { + asv = NULL; + } + + rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, + NULL); SvREFCNT_dec(sv); @@ -625,14 +645,15 @@ ngx_http_perl_run_requires(pTHX_ ngx_arr static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, - ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv) + SV **args, ngx_str_t *handler, ngx_str_t *rv) { - SV *sv; - int n, status; - char *line; - STRLEN len, n_a; - ngx_str_t err; - ngx_uint_t i; + SV *sv; + int n, status; + char *line; + STRLEN len, n_a; + ngx_str_t err; + ngx_uint_t i; + ngx_connection_t *c; dSP; @@ -647,33 +668,42 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt XPUSHs(sv); if (args) { - for (i = 0; args[i]; i++) { /* void */ } + EXTEND(sp, (intptr_t) args[0]); - EXTEND(sp, (int) i); - - for (i = 0; args[i]; i++) { - PUSHs(sv_2mortal(newSVpvn((char *) args[i]->data, args[i]->len))); + for (i = 1; i <= (ngx_uint_t) args[0]; i++) { + PUSHs(sv_2mortal(args[i])); } } PUTBACK; + c = r->connection; + n = call_sv(sub, G_EVAL); SPAGAIN; + if (c->destroyed) { + PUTBACK; + + FREETMPS; + LEAVE; + + return NGX_DONE; + } + if (n) { if (rv == NULL) { status = POPi; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "call_sv: %d", status); } else { line = SvPVx(POPs, n_a); rv->len = n_a; - rv->data = ngx_palloc(r->pool, n_a); + rv->data = ngx_pnalloc(r->pool, n_a); if (rv->data == NULL) { return NGX_ERROR; } @@ -697,9 +727,8 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt } err.len = len + 1; - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "call_sv(\"%V\") failed: \"%V\"", - handler, &err); + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "call_sv(\"%V\") failed: \"%V\"", handler, &err); if (rv) { return NGX_ERROR; @@ -709,7 +738,7 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt } if (n != 1) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "call_sv(\"%V\") returned %d results", handler, n); status = NGX_OK; } @@ -954,7 +983,7 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co value[1].len--; value[1].data++; - v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGABLE); + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE); if (v == NULL) { return NGX_CONF_ERROR; } @@ -1026,8 +1055,20 @@ ngx_http_perl_init_worker(ngx_cycle_t *c return NGX_OK; } + static void ngx_http_perl_exit(ngx_cycle_t *cycle) { + ngx_http_perl_main_conf_t *pmcf; + + pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module); + + { + + dTHXa(pmcf->perl); + PERL_SET_CONTEXT(pmcf->perl); + PERL_SYS_TERM(); + + } } diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -25,9 +25,8 @@ typedef struct { ngx_str_t redirect_args; SV *next; - int sleep; - ngx_uint_t done; /* unsigned done:1; */ + ngx_uint_t done; /* unsigned done:1; */ ngx_array_t *variables; /* array of ngx_http_perl_var_t */ @@ -61,6 +60,7 @@ extern void boot_DynaLoader(pTHX_ CV* cv void ngx_http_perl_handle_request(ngx_http_request_t *r); +void ngx_http_perl_sleep_handler(ngx_http_request_t *r); #endif /* _NGX_HTTP_PERL_MODULE_H_INCLUDED_ */ diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -11,22 +11,48 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf); +static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf); +static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf); + +static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf, + ngx_array_t *servers, ngx_array_t *in_ports); static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, - ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf, - ngx_http_core_srv_conf_t *cscf); + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_port_t *in_port, + ngx_http_listen_t *listen); static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, - ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf); + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr); + static char *ngx_http_merge_locations(ngx_conf_t *cf, - ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module, + ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index); -static int ngx_http_cmp_conf_in_addrs(const void *one, const void *two); +static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf, + ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one, + const ngx_queue_t *two); +static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, + ngx_queue_t *locations); +static void ngx_http_create_locations_list(ngx_queue_t *locations, + ngx_queue_t *q); +static ngx_http_location_tree_node_t * + ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, + size_t prefix); + +static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports); +static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two); static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one, const void *two); -ngx_uint_t ngx_http_max_module; +static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf, + ngx_http_conf_in_port_t *in_port); -ngx_uint_t ngx_http_total_requests; -uint64_t ngx_http_total_sent; +ngx_uint_t ngx_http_max_module; ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r); @@ -73,37 +99,14 @@ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_int_t rc, j; - ngx_uint_t mi, m, s, l, p, a, i, n; - ngx_uint_t find_config_index, use_rewrite, use_access; - ngx_uint_t last, bind_all, done; + ngx_uint_t mi, m, s; ngx_conf_t pcf; - ngx_array_t headers_in, in_ports; - ngx_hash_key_t *hk; - ngx_hash_init_t hash; - ngx_listening_t *ls; - ngx_http_listen_t *lscf; + ngx_array_t in_ports; ngx_http_module_t *module; - ngx_http_header_t *header; - ngx_http_in_port_t *hip; - ngx_http_handler_pt *h; ngx_http_conf_ctx_t *ctx; - ngx_http_conf_in_port_t *in_port; - ngx_http_conf_in_addr_t *in_addr; - ngx_hash_keys_arrays_t ha; - ngx_http_server_name_t *name; - ngx_http_phase_handler_t *ph; - ngx_http_virtual_names_t *vn; - ngx_http_core_srv_conf_t **cscfp, *cscf; ngx_http_core_loc_conf_t *clcf; - ngx_http_phase_handler_pt checker; + ngx_http_core_srv_conf_t **cscfp; ngx_http_core_main_conf_t *cmcf; -#if (NGX_PCRE) - ngx_uint_t regex; -#endif -#if (NGX_WIN32) - ngx_iocp_conf_t *iocpcf; -#endif /* the main http context */ @@ -202,7 +205,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; if (module->preconfiguration) { if (module->preconfiguration(cf) != NGX_OK) { @@ -218,8 +220,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma rv = ngx_conf_parse(cf, NULL); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } /* @@ -243,8 +244,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (module->init_main_conf) { rv = module->init_main_conf(cf, ctx->main_conf[mi]); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } } @@ -253,12 +253,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* merge the server{}s' srv_conf's */ if (module->merge_srv_conf) { - rv = module->merge_srv_conf(cf, - ctx->srv_conf[mi], + rv = module->merge_srv_conf(cf, ctx->srv_conf[mi], cscfp[s]->ctx->srv_conf[mi]); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } } @@ -266,112 +264,48 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* merge the server{}'s loc_conf */ - rv = module->merge_loc_conf(cf, - ctx->loc_conf[mi], + rv = module->merge_loc_conf(cf, ctx->loc_conf[mi], cscfp[s]->ctx->loc_conf[mi]); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } /* merge the locations{}' loc_conf's */ - rv = ngx_http_merge_locations(cf, &cscfp[s]->locations, + 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) { - *cf = pcf; - return rv; + goto failed; } } } } - /* init lists of the handlers */ - - if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } + /* create location trees */ + for (s = 0; s < cmcf->servers.nelts; s++) { - if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - + clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; - if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - + if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) { + return NGX_CONF_ERROR; + } - if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - - if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, - cf->pool, 2, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; + if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { + return NGX_CONF_ERROR; + } } - if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, - cf->pool, 4, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - - if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { + if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } - - if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - for (header = ngx_http_headers_in; header->name.len; header++) { - hk = ngx_array_push(&headers_in); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = header->name; - hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len); - hk->value = header; - } - - hash.hash = &cmcf->headers_in_hash; - hash.key = ngx_hash_key_lc; - hash.max_size = 512; - hash.bucket_size = ngx_align(64, ngx_cacheline_size); - hash.name = "headers_in_hash"; - hash.pool = cf->pool; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) { + if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -382,7 +316,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; if (module->postconfiguration) { if (module->postconfiguration(cf) != NGX_OK) { @@ -403,6 +336,148 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma *cf = pcf; + if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + + /* + * create the lists of ports, addresses and server names + * to find quickly the server core module configuration at run-time + */ + + /* AF_INET only */ + + if (ngx_http_init_server_lists(cf, &cmcf->servers, &in_ports) != NGX_OK) { + return NGX_CONF_ERROR; + } + + + /* optimize the lists of ports, addresses and server names */ + + /* AF_INET only */ + + if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + +failed: + + *cf = pcf; + + return rv; +} + + +static ngx_int_t +ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) +{ + if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, + cf->pool, 2, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, + cf->pool, 4, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) +{ + ngx_array_t headers_in; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_header_t *header; + + if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (header = ngx_http_headers_in; header->name.len; header++) { + hk = ngx_array_push(&headers_in); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = header->name; + hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len); + hk->value = header; + } + + hash.hash = &cmcf->headers_in_hash; + hash.key = ngx_hash_key_lc; + hash.max_size = 512; + hash.bucket_size = ngx_align(64, ngx_cacheline_size); + hash.name = "headers_in_hash"; + hash.pool = cf->pool; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) +{ + ngx_int_t j; + ngx_uint_t i, n; + ngx_uint_t find_config_index, use_rewrite, use_access; + ngx_http_handler_pt *h; + ngx_http_phase_handler_t *ph; + ngx_http_phase_handler_pt checker; + cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1; cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1; find_config_index = 0; @@ -418,7 +493,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ph = ngx_pcalloc(cf->pool, n * sizeof(ngx_http_phase_handler_t) + sizeof(void *)); if (ph == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } cmcf->phase_engine.handlers = ph; @@ -496,35 +571,551 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } + return NGX_OK; +} - /* - * create the lists of ports, addresses and server names - * to quickly find the server core module configuration at run-time - */ + +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_core_loc_conf_t *clcf; + ngx_http_location_queue_t *lq; + + if (locations == NULL) { + return NGX_CONF_OK; + } + + for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + clcf = lq->exact ? lq->exact : lq->inclusive; + + rv = module->merge_loc_conf(cf, loc_conf[ctx_index], + clcf->loc_conf[ctx_index]); + if (rv != NGX_CONF_OK) { + return rv; + } + + rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf, + module, ctx_index); + if (rv != NGX_CONF_OK) { + return rv; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_core_loc_conf_t *pclcf) +{ + ngx_uint_t n; + ngx_queue_t *q, *locations, *named, tail; + ngx_http_core_loc_conf_t *clcf; + ngx_http_location_queue_t *lq; + ngx_http_core_loc_conf_t **clcfp; +#if (NGX_PCRE) + ngx_uint_t r; + ngx_queue_t *regex; +#endif + + locations = pclcf->locations; + + if (locations == NULL) { + return NGX_OK; + } + + ngx_queue_sort(locations, ngx_http_cmp_locations); + + named = NULL; + n = 0; +#if (NGX_PCRE) + regex = NULL; + r = 0; +#endif + + for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + clcf = lq->exact ? lq->exact : lq->inclusive; + + if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) { + return NGX_ERROR; + } + +#if (NGX_PCRE) + + if (clcf->regex) { + r++; + + if (regex == NULL) { + regex = q; + } + + continue; + } + +#endif + + if (clcf->named) { + n++; + + if (named == NULL) { + named = q; + } + + continue; + } + + if (clcf->noname) { + break; + } + } + + if (q != ngx_queue_sentinel(locations)) { + ngx_queue_split(locations, q, &tail); + } + + if (named) { + clcfp = ngx_palloc(cf->pool, + (n + 1) * sizeof(ngx_http_core_loc_conf_t **)); + if (clcfp == NULL) { + return NGX_ERROR; + } + + cscf->named_locations = clcfp; + + for (q = named; + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + *(clcfp++) = lq->exact; + } + + *clcfp = NULL; + + ngx_queue_split(locations, named, &tail); + } + +#if (NGX_PCRE) + + if (regex) { + + clcfp = ngx_palloc(cf->pool, + (r + 1) * sizeof(ngx_http_core_loc_conf_t **)); + if (clcfp == NULL) { + return NGX_ERROR; + } + + pclcf->regex_locations = clcfp; + + for (q = regex; + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + *(clcfp++) = lq->exact; + } + + *clcfp = NULL; + + ngx_queue_split(locations, regex, &tail); + } + +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_init_static_location_trees(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *pclcf) +{ + ngx_queue_t *q, *locations; + ngx_http_core_loc_conf_t *clcf; + ngx_http_location_queue_t *lq; + + locations = pclcf->locations; + + if (locations == NULL) { + return NGX_OK; + } + + if (ngx_queue_empty(locations)) { + return NGX_OK; + } + + for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + clcf = lq->exact ? lq->exact : lq->inclusive; + + if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) { + return NGX_ERROR; + } + + ngx_http_create_locations_list(locations, ngx_queue_head(locations)); + + pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0); + if (pclcf->static_locations == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, + ngx_http_core_loc_conf_t *clcf) +{ + ngx_http_location_queue_t *lq; + + if (*locations == NULL) { + *locations = ngx_palloc(cf->temp_pool, + sizeof(ngx_http_location_queue_t)); + if (*locations == NULL) { + return NGX_ERROR; + } + + ngx_queue_init(*locations); + } + + lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t)); + if (lq == NULL) { + return NGX_ERROR; + } + + if (clcf->exact_match +#if (NGX_PCRE) + || clcf->regex +#endif + || clcf->named || clcf->noname) + { + lq->exact = clcf; + lq->inclusive = NULL; + + } else { + lq->exact = NULL; + lq->inclusive = clcf; + } + + lq->name = &clcf->name; + lq->file_name = cf->conf_file->file.name.data; + lq->line = cf->conf_file->line; + + ngx_queue_init(&lq->list); + + ngx_queue_insert_tail(*locations, &lq->queue); + + return NGX_OK; +} - if (ngx_array_init(&in_ports, cf->temp_pool, 2, + +static ngx_int_t +ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two) +{ + ngx_int_t rc; + ngx_http_core_loc_conf_t *first, *second; + ngx_http_location_queue_t *lq1, *lq2; + + lq1 = (ngx_http_location_queue_t *) one; + lq2 = (ngx_http_location_queue_t *) two; + + first = lq1->exact ? lq1->exact : lq1->inclusive; + second = lq2->exact ? lq2->exact : lq2->inclusive; + + if (first->noname && !second->noname) { + /* shift no named locations to the end */ + return 1; + } + + if (!first->noname && second->noname) { + /* shift no named locations to the end */ + return -1; + } + + if (first->noname || second->noname) { + /* do not sort no named locations */ + return 0; + } + + if (first->named && !second->named) { + /* shift named locations to the end */ + return 1; + } + + if (!first->named && second->named) { + /* shift named locations to the end */ + return -1; + } + + if (first->named && second->named) { + return ngx_strcmp(first->name.data, second->name.data); + } + +#if (NGX_PCRE) + + if (first->regex && !second->regex) { + /* shift the regex matches to the end */ + return 1; + } + + if (!first->regex && second->regex) { + /* shift the regex matches to the end */ + return -1; + } + + if (first->regex || second->regex) { + /* do not sort the regex matches */ + return 0; + } + +#endif + + rc = ngx_strcmp(first->name.data, second->name.data); + + if (rc == 0 && !first->exact_match && second->exact_match) { + /* an exact match must be before the same inclusive one */ + return 1; + } + + return rc; +} + + +static ngx_int_t +ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations) +{ + ngx_queue_t *q, *x; + ngx_http_location_queue_t *lq, *lx; + + q = ngx_queue_head(locations); + + while (q != ngx_queue_last(locations)) { + + x = ngx_queue_next(q); + + lq = (ngx_http_location_queue_t *) q; + lx = (ngx_http_location_queue_t *) x; + + if (ngx_strcmp(lq->name->data, lx->name->data) == 0) { + + if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "duplicate location \"%V\" in %s:%ui", + lx->name, lx->file_name, lx->line); + + return NGX_ERROR; + } + + lq->inclusive = lx->inclusive; + + ngx_queue_remove(x); + + continue; + } + + q = ngx_queue_next(q); + } + + return NGX_OK; +} + + +static void +ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q) +{ + u_char *name; + size_t len; + ngx_queue_t *x, tail; + ngx_http_location_queue_t *lq, *lx; + + if (q == ngx_queue_last(locations)) { + return; + } + + lq = (ngx_http_location_queue_t *) q; + + if (lq->inclusive == NULL) { + ngx_http_create_locations_list(locations, ngx_queue_next(q)); + return; + } + + len = lq->name->len; + name = lq->name->data; + + for (x = ngx_queue_next(q); + x != ngx_queue_sentinel(locations); + x = ngx_queue_next(x)) + { + lx = (ngx_http_location_queue_t *) x; + + if (len > lx->name->len + || (ngx_strncmp(name, lx->name->data, len) != 0)) + { + break; + } + } + + q = ngx_queue_next(q); + + if (q == x) { + ngx_http_create_locations_list(locations, x); + return; + } + + ngx_queue_split(locations, q, &tail); + ngx_queue_add(&lq->list, &tail); + + if (x == ngx_queue_sentinel(locations)) { + ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); + return; + } + + ngx_queue_split(&lq->list, x, &tail); + ngx_queue_add(locations, &tail); + + ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); + + ngx_http_create_locations_list(locations, x); +} + + +/* + * to keep cache locality for left leaf nodes, allocate nodes in following + * order: node, left subtree, right subtree, inclusive subtree + */ + +static ngx_http_location_tree_node_t * +ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, + size_t prefix) +{ + size_t len; + ngx_queue_t *q, tail; + ngx_http_location_queue_t *lq; + ngx_http_location_tree_node_t *node; + + q = ngx_queue_middle(locations); + + lq = (ngx_http_location_queue_t *) q; + len = lq->name->len - prefix; + + node = ngx_palloc(cf->pool, + offsetof(ngx_http_location_tree_node_t, name) + len); + if (node == NULL) { + return NULL; + } + + node->left = NULL; + node->right = NULL; + node->tree = NULL; + node->exact = lq->exact; + node->inclusive = lq->inclusive; + + node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect) + || (lq->inclusive && lq->inclusive->auto_redirect)); + + node->len = (u_char) len; + ngx_memcpy(node->name, &lq->name->data[prefix], len); + + ngx_queue_split(locations, q, &tail); + + if (ngx_queue_empty(locations)) { + /* + * ngx_queue_split() insures that if left part is empty, + * then right one is empty too + */ + goto inclusive; + } + + node->left = ngx_http_create_locations_tree(cf, locations, prefix); + if (node->left == NULL) { + return NULL; + } + + ngx_queue_remove(q); + + if (ngx_queue_empty(&tail)) { + goto inclusive; + } + + node->right = ngx_http_create_locations_tree(cf, &tail, prefix); + if (node->right == NULL) { + return NULL; + } + +inclusive: + + if (ngx_queue_empty(&lq->list)) { + return node; + } + + node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len); + if (node->tree == NULL) { + return NULL; + } + + return node; +} + + +static ngx_int_t +ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers, + ngx_array_t *in_ports) +{ + ngx_uint_t s, l, p, a; + ngx_http_listen_t *listen; + ngx_http_conf_in_port_t *in_port; + ngx_http_conf_in_addr_t *in_addr; + ngx_http_core_srv_conf_t **cscfp; + + if (ngx_array_init(in_ports, cf->temp_pool, 2, sizeof(ngx_http_conf_in_port_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } /* "server" directives */ - cscfp = cmcf->servers.elts; - for (s = 0; s < cmcf->servers.nelts; s++) { + cscfp = servers->elts; + for (s = 0; s < servers->nelts; s++) { /* "listen" directives */ - lscf = cscfp[s]->listen.elts; + listen = cscfp[s]->listen.elts; for (l = 0; l < cscfp[s]->listen.nelts; l++) { /* AF_INET only */ - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { + in_port = in_ports->elts; + for (p = 0; p < in_ports->nelts; p++) { - if (lscf[l].port != in_port[p].port) { + if (listen[l].port != in_port[p].port) { continue; } @@ -533,15 +1124,15 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_addr = in_port[p].addrs.elts; for (a = 0; a < in_port[p].addrs.nelts; a++) { - if (lscf[l].addr != in_addr[a].addr) { + if (listen[l].addr != in_addr[a].addr) { continue; } /* the address is already in the address list */ - if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK) + if (ngx_http_add_names(cf, cscfp[s], &in_addr[a]) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } /* @@ -549,14 +1140,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * for this address:port */ - if (lscf[l].conf.default_server) { + if (listen[l].conf.default_server) { if (in_addr[a].default_server) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "the duplicate default server in %s:%ui", - &lscf[l].file_name, lscf[l].line); + listen[l].file_name, listen[l].line); - return NGX_CONF_ERROR; + return NGX_ERROR; } in_addr[a].core_srv_conf = cscfp[s]; @@ -571,10 +1162,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * bound to this port */ - if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s]) + if (ngx_http_add_address(cf, cscfp[s], &in_port[p], &listen[l]) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } goto found; @@ -582,17 +1173,18 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* add the port to the in_port list */ - in_port = ngx_array_push(&in_ports); + in_port = ngx_array_push(in_ports); if (in_port == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } - in_port->port = lscf[l].port; + in_port->port = listen[l].port; in_port->addrs.elts = NULL; - if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) != NGX_OK) + if (ngx_http_add_address(cf, cscfp[s], in_port, &listen[l]) + != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } found: @@ -601,21 +1193,130 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } + return NGX_OK; +} - /* optimize the lists of ports, addresses and server names */ + +/* + * add the server address, the server names and the server core module + * configurations to the port (in_port) + */ + +static ngx_int_t +ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *listen) +{ + ngx_http_conf_in_addr_t *in_addr; + + if (in_port->addrs.elts == NULL) { + if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4, + sizeof(ngx_http_conf_in_addr_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + in_addr = ngx_array_push(&in_port->addrs); + if (in_addr == NULL) { + return NGX_ERROR; + } + + in_addr->addr = listen->addr; + in_addr->hash.buckets = NULL; + in_addr->hash.size = 0; + in_addr->wc_head = NULL; + in_addr->wc_tail = NULL; + in_addr->names.elts = NULL; +#if (NGX_PCRE) + in_addr->nregex = 0; + in_addr->regex = NULL; +#endif + in_addr->core_srv_conf = cscf; + in_addr->default_server = listen->conf.default_server; + in_addr->bind = listen->conf.bind; + in_addr->listen_conf = &listen->conf; + +#if (NGX_DEBUG) + { + u_char text[20]; + ngx_inet_ntop(AF_INET, &in_addr->addr, text, 20); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "address: %s:%d", + text, in_port->port); + } +#endif + + return ngx_http_add_names(cf, cscf, in_addr); +} + - /* AF_INET only */ +/* + * add the server names and the server core module + * configurations to the address:port (in_addr) + */ + +static ngx_int_t +ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_conf_in_addr_t *in_addr) +{ + ngx_uint_t i; + ngx_http_server_name_t *server_names, *name; + + if (in_addr->names.elts == NULL) { + if (ngx_array_init(&in_addr->names, cf->temp_pool, 4, + sizeof(ngx_http_server_name_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + server_names = cscf->server_names.elts; + + for (i = 0; i < cscf->server_names.nelts; i++) { + + ngx_strlow(server_names[i].name.data, server_names[i].name.data, + server_names[i].name.len); - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "name: %V", &server_names[i].name); + + name = ngx_array_push(&in_addr->names); + if (name == NULL) { + return NGX_ERROR; + } + + *name = server_names[i]; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, + ngx_array_t *in_ports) +{ + ngx_int_t rc; + ngx_uint_t s, p, a; + ngx_hash_init_t hash; + ngx_http_server_name_t *name; + ngx_hash_keys_arrays_t ha; + ngx_http_conf_in_port_t *in_port; + ngx_http_conf_in_addr_t *in_addr; +#if (NGX_PCRE) + ngx_uint_t regex, i; +#endif + + in_port = in_ports->elts; + for (p = 0; p < in_ports->nelts; p++) { ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs); /* - * check whether all name-based servers have the same configuraiton - * as the default server, - * or some servers disable optimizing the server names + * check whether all name-based servers have + * the same configuraiton as the default server */ in_addr = in_port[p].addrs.elts; @@ -624,18 +1325,15 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma name = in_addr[a].names.elts; for (s = 0; s < in_addr[a].names.nelts; s++) { - if (in_addr[a].core_srv_conf != name[s].core_srv_conf - || name[s].core_srv_conf->optimize_server_names == 0) - { + if (in_addr[a].core_srv_conf != name[s].core_srv_conf) { goto virtual_names; } } /* * if all name-based servers have the same configuration - * as the default server, - * and no servers disable optimizing the server names - * then we do not need to check them at run-time at all + * as the default server, then we do not need to check + * them at run-time at all */ in_addr[a].names.nelts = 0; @@ -648,14 +1346,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ha.temp_pool = ngx_create_pool(16384, cf->log); if (ha.temp_pool == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } ha.pool = cf->pool; if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; + goto failed; } #if (NGX_PCRE) @@ -677,14 +1374,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma NGX_HASH_WILDCARD_KEY); if (rc == NGX_ERROR) { - return NGX_CONF_ERROR; + return NGX_ERROR; } if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid server name or wildcard \"%V\" on %s", &name[s].name, in_addr[a].listen_conf->addr); - return NGX_CONF_ERROR; + return NGX_ERROR; } if (rc == NGX_BUSY) { @@ -706,8 +1403,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; + goto failed; } } @@ -725,8 +1421,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ha.dns_wc_head.nelts) != NGX_OK) { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; + goto failed; } in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash; @@ -746,8 +1441,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ha.dns_wc_tail.nelts) != NGX_OK) { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; + goto failed; } in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash; @@ -766,7 +1460,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma regex * sizeof(ngx_http_server_name_t)); if (in_addr[a].regex == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) { @@ -777,318 +1471,22 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma #endif } - in_addr = in_port[p].addrs.elts; - last = in_port[p].addrs.nelts; - - /* - * if there is the binding to the "*:port" then we need to bind() - * to the "*:port" only and ignore the other bindings - */ - - if (in_addr[last - 1].addr == INADDR_ANY) { - in_addr[last - 1].bind = 1; - bind_all = 0; - - } else { - bind_all = 1; - } - - for (a = 0; a < last; /* void */ ) { - - if (!bind_all && !in_addr[a].bind) { - a++; - continue; - } - - ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, - in_port[p].port); - if (ls == NULL) { - return NGX_CONF_ERROR; - } - - ls->addr_ntop = 1; - - ls->handler = ngx_http_init_connection; - - cscf = in_addr[a].core_srv_conf; - ls->pool_size = cscf->connection_pool_size; - ls->post_accept_timeout = cscf->client_header_timeout; - - clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; - - ls->log = *clcf->err_log; - ls->log.data = &ls->addr_text; - ls->log.handler = ngx_accept_log_error; - -#if (NGX_WIN32) - iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); - if (iocpcf->acceptex_read) { - ls->post_accept_buffer_size = cscf->client_header_buffer_size; - } -#endif - - ls->backlog = in_addr[a].listen_conf->backlog; - ls->rcvbuf = in_addr[a].listen_conf->rcvbuf; - ls->sndbuf = in_addr[a].listen_conf->sndbuf; - -#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) - ls->accept_filter = in_addr[a].listen_conf->accept_filter; -#endif - -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; -#endif - - hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); - if (hip == NULL) { - return NGX_CONF_ERROR; - } - - hip->port = in_port[p].port; - - hip->port_text.data = ngx_palloc(cf->pool, 7); - if (hip->port_text.data == NULL) { - return NGX_CONF_ERROR; - } - - ls->servers = hip; - - hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", - hip->port) - - hip->port_text.data; - - in_addr = in_port[p].addrs.elts; - - if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { - hip->naddrs = 1; - done = 0; - - } else if (in_port[p].addrs.nelts > 1 - && in_addr[last - 1].addr == INADDR_ANY) - { - hip->naddrs = last; - done = 1; - - } else { - hip->naddrs = 1; - done = 0; - } - -#if 0 - ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - "%ui: %V %d %ui %ui", - a, &ls->addr_text, in_addr[a].bind, - hip->naddrs, last); -#endif - - hip->addrs = ngx_pcalloc(cf->pool, - hip->naddrs * sizeof(ngx_http_in_addr_t)); - if (hip->addrs == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 0; i < hip->naddrs; i++) { - hip->addrs[i].addr = in_addr[i].addr; - hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; - - if (in_addr[i].hash.buckets == NULL - && (in_addr[i].wc_head == NULL - || in_addr[i].wc_head->hash.buckets == NULL) - && (in_addr[i].wc_head == NULL - || in_addr[i].wc_head->hash.buckets == NULL)) - { - continue; - } - - vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); - if (vn == NULL) { - return NGX_CONF_ERROR; - } - hip->addrs[i].virtual_names = vn; - - vn->names.hash = in_addr[i].hash; - vn->names.wc_head = in_addr[i].wc_head; - vn->names.wc_tail = in_addr[i].wc_tail; -#if (NGX_PCRE) - vn->nregex = in_addr[i].nregex; - vn->regex = in_addr[i].regex; -#endif - } - - if (done) { - break; - } - - in_addr++; - in_port[p].addrs.elts = in_addr; - last--; - - a = 0; - } - } - -#if 0 - { - u_char address[20]; - ngx_uint_t p, a; - - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "port: %d %p", in_port[p].port, &in_port[p]); - in_addr = in_port[p].addrs.elts; - for (a = 0; a < in_port[p].addrs.nelts; a++) { - ngx_inet_ntop(AF_INET, &in_addr[a].addr, address, 20); - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "%s:%d %p", - address, in_port[p].port, in_addr[a].core_srv_conf); - name = in_addr[a].names.elts; - for (n = 0; n < in_addr[a].names.nelts; n++) { - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "%s:%d %V %p", - address, in_port[p].port, &name[n].name, - name[n].core_srv_conf); - } - } - } - } -#endif - - return NGX_CONF_OK; -} - - -/* - * add the server address, the server names and the server core module - * configurations to the port (in_port) - */ - -static ngx_int_t -ngx_http_add_address(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port, - ngx_http_listen_t *lscf, ngx_http_core_srv_conf_t *cscf) -{ - ngx_http_conf_in_addr_t *in_addr; - - if (in_port->addrs.elts == NULL) { - if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4, - sizeof(ngx_http_conf_in_addr_t)) - != NGX_OK) - { + if (ngx_http_init_listening(cf, &in_port[p]) != NGX_OK) { return NGX_ERROR; } } - in_addr = ngx_array_push(&in_port->addrs); - if (in_addr == NULL) { - return NGX_ERROR; - } + return NGX_OK; + +failed: - in_addr->addr = lscf->addr; - in_addr->hash.buckets = NULL; - in_addr->hash.size = 0; - in_addr->wc_head = NULL; - in_addr->wc_tail = NULL; - in_addr->names.elts = NULL; -#if (NGX_PCRE) - in_addr->nregex = 0; - in_addr->regex = NULL; -#endif - in_addr->core_srv_conf = cscf; - in_addr->default_server = lscf->conf.default_server; - in_addr->bind = lscf->conf.bind; - in_addr->listen_conf = &lscf->conf; + ngx_destroy_pool(ha.temp_pool); -#if (NGX_DEBUG) - { - u_char text[20]; - ngx_inet_ntop(AF_INET, &in_addr->addr, text, 20); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "address: %s:%d", - text, in_port->port); - } -#endif - - return ngx_http_add_names(cf, in_addr, cscf); + return NGX_ERROR; } -/* - * add the server names and the server core module - * configurations to the address:port (in_addr) - */ - static ngx_int_t -ngx_http_add_names(ngx_conf_t *cf, ngx_http_conf_in_addr_t *in_addr, - ngx_http_core_srv_conf_t *cscf) -{ - ngx_uint_t i, n; - ngx_http_server_name_t *server_names, *name; - - if (in_addr->names.elts == NULL) { - if (ngx_array_init(&in_addr->names, cf->temp_pool, 4, - sizeof(ngx_http_server_name_t)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - server_names = cscf->server_names.elts; - - for (i = 0; i < cscf->server_names.nelts; i++) { - - for (n = 0; n < server_names[i].name.len; n++) { - server_names[i].name.data[n] = - ngx_tolower(server_names[i].name.data[n]); - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "name: %V", &server_names[i].name); - - name = ngx_array_push(&in_addr->names); - if (name == NULL) { - return NGX_ERROR; - } - - *name = server_names[i]; - } - - return NGX_OK; -} - - -static char * -ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations, - void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index) -{ - char *rv; - ngx_uint_t i; - ngx_http_core_loc_conf_t **clcfp; - - clcfp = locations->elts; - - for (i = 0; i < locations->nelts; i++) { - rv = module->merge_loc_conf(cf, loc_conf[ctx_index], - clcfp[i]->loc_conf[ctx_index]); - if (rv != NGX_CONF_OK) { - return rv; - } - - if (clcfp[i]->locations == NULL) { - continue; - } - - rv = ngx_http_merge_locations(cf, clcfp[i]->locations, - clcfp[i]->loc_conf, module, ctx_index); - if (rv != NGX_CONF_OK) { - return rv; - } - } - - return NGX_CONF_OK; -} - - -static int ngx_http_cmp_conf_in_addrs(const void *one, const void *two) { ngx_http_conf_in_addr_t *first, *second; @@ -1127,3 +1525,297 @@ ngx_http_cmp_dns_wildcards(const void *o return ngx_strcmp(first->key.data, second->key.data); } + + +static ngx_int_t +ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port) +{ + ngx_uint_t i, a, last, bind_all, done; + ngx_listening_t *ls; + ngx_http_in_port_t *hip; + ngx_http_conf_in_addr_t *in_addr; + ngx_http_virtual_names_t *vn; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + + in_addr = in_port->addrs.elts; + last = in_port->addrs.nelts; + + /* + * if there is a binding to a "*:port" then we need to bind() + * to the "*:port" only and ignore other bindings + */ + + if (in_addr[last - 1].addr == INADDR_ANY) { + in_addr[last - 1].bind = 1; + bind_all = 0; + + } else { + bind_all = 1; + } + + a = 0; + + while (a < last) { + + if (!bind_all && !in_addr[a].bind) { + a++; + continue; + } + + ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, + in_port->port); + if (ls == NULL) { + return NGX_ERROR; + } + + ls->addr_ntop = 1; + + ls->handler = ngx_http_init_connection; + + cscf = in_addr[a].core_srv_conf; + ls->pool_size = cscf->connection_pool_size; + ls->post_accept_timeout = cscf->client_header_timeout; + + clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; + + ls->log = *clcf->err_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; + +#if (NGX_WIN32) + { + ngx_iocp_conf_t *iocpcf; + + iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); + if (iocpcf->acceptex_read) { + ls->post_accept_buffer_size = cscf->client_header_buffer_size; + } + } +#endif + + ls->backlog = in_addr[a].listen_conf->backlog; + ls->rcvbuf = in_addr[a].listen_conf->rcvbuf; + ls->sndbuf = in_addr[a].listen_conf->sndbuf; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + ls->accept_filter = in_addr[a].listen_conf->accept_filter; +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; +#endif + + hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); + if (hip == NULL) { + return NGX_ERROR; + } + + hip->port = in_port->port; + + hip->port_text.data = ngx_pnalloc(cf->pool, 7); + if (hip->port_text.data == NULL) { + return NGX_ERROR; + } + + ls->servers = hip; + + hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", hip->port) + - hip->port_text.data; + + in_addr = in_port->addrs.elts; + + if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { + hip->naddrs = 1; + done = 0; + + } else if (in_port->addrs.nelts > 1 + && in_addr[last - 1].addr == INADDR_ANY) + { + hip->naddrs = last; + done = 1; + + } else { + hip->naddrs = 1; + done = 0; + } + + hip->addrs = ngx_pcalloc(cf->pool, + hip->naddrs * sizeof(ngx_http_in_addr_t)); + if (hip->addrs == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < hip->naddrs; i++) { + hip->addrs[i].addr = in_addr[i].addr; + hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; + + if (in_addr[i].hash.buckets == NULL + && (in_addr[i].wc_head == NULL + || in_addr[i].wc_head->hash.buckets == NULL) + && (in_addr[i].wc_head == NULL + || in_addr[i].wc_head->hash.buckets == NULL)) + { + continue; + } + + vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); + if (vn == NULL) { + return NGX_ERROR; + } + hip->addrs[i].virtual_names = vn; + + vn->names.hash = in_addr[i].hash; + vn->names.wc_head = in_addr[i].wc_head; + vn->names.wc_tail = in_addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = in_addr[i].nregex; + vn->regex = in_addr[i].regex; +#endif + } + + if (done) { + return NGX_OK; + } + + in_addr++; + in_port->addrs.elts = in_addr; + last--; + + a = 0; + } + + return NGX_OK; +} + + +char * +ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_array_t **types; + ngx_str_t *value, *default_type; + ngx_uint_t i, n, hash; + ngx_hash_key_t *type; + + types = (ngx_array_t **) (p + cmd->offset); + + default_type = cmd->post; + + if (*types == NULL) { + *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t)); + if (*types == NULL) { + return NGX_CONF_ERROR; + } + + if (default_type) { + type = ngx_array_push(*types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->key = *default_type; + type->key_hash = ngx_hash_key(default_type->data, + default_type->len); + type->value = (void *) 4; + } + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len); + value[i].data[value[i].len] = '\0'; + + type = (*types)->elts; + for (n = 0; n < (*types)->nelts; n++) { + + if (ngx_strcmp(value[i].data, type[n].key.data) == 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate MIME type \"%V\"", &value[i]); + continue; + } + } + + type = ngx_array_push(*types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->key = value[i]; + type->key_hash = hash; + type->value = (void *) 4; + } + + return NGX_CONF_OK; +} + + +char * +ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, ngx_hash_t *types_hash, + ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash, + ngx_str_t *default_types) +{ + ngx_hash_init_t hash; + + if (keys == NULL) { + + if (prev_keys) { + *types_hash = *prev_types_hash; + return NGX_CONF_OK; + } + + if (ngx_http_set_default_types(cf, &keys, default_types) + != NGX_CONF_OK) + { + return NGX_CONF_ERROR; + } + } + + hash.hash = types_hash; + hash.key = NULL; + hash.max_size = 2048; + hash.bucket_size = 64; + hash.name = "test_types_hash"; + hash.pool = cf->pool; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, keys->elts, keys->nelts) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + +} + + +char * +ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, + ngx_str_t *default_type) +{ + ngx_hash_key_t *type; + + *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t)); + if (*types == NULL) { + return NGX_CONF_ERROR; + } + + while (default_type->len) { + + type = ngx_array_push(*types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->key = *default_type; + type->key_hash = ngx_hash_key(default_type->data, + default_type->len); + type->value = (void *) 4; + + default_type++; + } + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -47,7 +47,7 @@ typedef u_char *(*ngx_http_log_handler_p struct ngx_http_log_ctx_s { - ngx_str_t *client; + ngx_connection_t *connection; ngx_http_request_t *request; ngx_http_request_t *current_request; }; @@ -57,6 +57,10 @@ struct ngx_http_log_ctx_s { #define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c; +ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, + ngx_http_core_loc_conf_t *clcf); + + void ngx_http_init_connection(ngx_connection_t *c); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME @@ -64,7 +68,8 @@ int ngx_http_ssl_servername(ngx_ssl_conn #endif 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_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r, + ngx_uint_t merge_slashes); 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); @@ -102,20 +107,19 @@ ngx_int_t ngx_http_discard_request_body( void ngx_http_block_reading(ngx_http_request_t *r); -extern ngx_module_t ngx_http_module; +char *ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, + ngx_hash_t *types_hash, ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash, + ngx_str_t *default_types); +char *ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, + ngx_str_t *default_type); -extern ngx_uint_t ngx_http_total_requests; -extern uint64_t ngx_http_total_sent; +extern ngx_module_t ngx_http_module; extern ngx_http_output_header_filter_pt ngx_http_top_header_filter; extern ngx_http_output_body_filter_pt ngx_http_top_body_filter; -/* STUB */ -ngx_int_t ngx_http_log_handler(ngx_http_request_t *r); -/**/ - - #endif /* _NGX_HTTP_H_INCLUDED_ */ diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c --- a/src/http/ngx_http_busy_lock.c +++ b/src/http/ngx_http_busy_lock.c @@ -10,9 +10,9 @@ -static int ngx_http_busy_lock_look_cachable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, - int lock); +static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl, + ngx_http_busy_lock_ctx_t *bc, + int lock); int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc) @@ -60,12 +60,12 @@ int ngx_http_busy_lock(ngx_http_busy_loc } -int ngx_http_busy_lock_cachable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, int lock) +int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl, + ngx_http_busy_lock_ctx_t *bc, int lock) { int rc; - rc = ngx_http_busy_lock_look_cachable(bl, bc, lock); + rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0, "http busylock: %d w:%d mw::%d", @@ -121,22 +121,22 @@ void ngx_http_busy_unlock(ngx_http_busy_ if (bl->md5) { bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7)); - bl->cachable--; + bl->cacheable--; } bl->busy--; } -static int ngx_http_busy_lock_look_cachable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, - int lock) +static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl, + ngx_http_busy_lock_ctx_t *bc, + int lock) { - int i, b, cachable, free; + int i, b, cacheable, free; u_int mask; b = 0; - cachable = 0; + cacheable = 0; free = -1; #if (NGX_SUPPRESS_WARN) @@ -153,15 +153,15 @@ static int ngx_http_busy_lock_look_cacha if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) { return NGX_AGAIN; } - cachable++; + cacheable++; } else if (free == -1) { free = i; } #if 1 - if (cachable == bl->cachable) { - if (free == -1 && cachable < bl->max_busy) { + if (cacheable == bl->cacheable) { + if (free == -1 && cacheable < bl->max_busy) { free = i + 1; } @@ -186,7 +186,7 @@ static int ngx_http_busy_lock_look_cacha bl->md5_mask[free / 8] |= 1 << (free & 7); bc->slot = free; - bl->cachable++; + bl->cacheable++; bl->busy++; } diff --git a/src/http/ngx_http_busy_lock.h b/src/http/ngx_http_busy_lock.h --- a/src/http/ngx_http_busy_lock.h +++ b/src/http/ngx_http_busy_lock.h @@ -17,7 +17,7 @@ typedef struct { u_char *md5_mask; char *md5; - int cachable; + int cacheable; int busy; int max_busy; @@ -41,8 +41,8 @@ typedef struct { int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc); -int ngx_http_busy_lock_cachable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, int lock); +int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl, + ngx_http_busy_lock_ctx_t *bc, int lock); void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc); diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -121,11 +121,8 @@ ngx_http_copy_filter(ngx_http_request_t r->out = ctx->in; } -#if (NGX_DEBUG) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); -#endif - } return rc; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -17,19 +17,15 @@ typedef struct { } ngx_http_method_name_t; -#define NGX_HTTP_LOCATION_EXACT 1 -#define NGX_HTTP_LOCATION_AUTO_REDIRECT 2 -#define NGX_HTTP_LOCATION_NOREGEX 3 -#define NGX_HTTP_LOCATION_REGEX 4 - - #define NGX_HTTP_REQUEST_BODY_FILE_OFF 0 #define NGX_HTTP_REQUEST_BODY_FILE_ON 1 #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2 -static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r, - ngx_array_t *locations, ngx_uint_t regex_start, size_t len); +static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r); +static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, + ngx_http_location_tree_node_t *node); +static ngx_int_t ngx_http_core_send_continue(ngx_http_request_t *r); static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf); static void *ngx_http_core_create_main_conf(ngx_conf_t *cf); @@ -45,7 +41,6 @@ static char *ngx_http_core_server(ngx_co void *dummy); static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); -static int ngx_http_core_cmp_locations(const void *first, const void *second); static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -59,6 +54,8 @@ static char *ngx_http_core_server_name(n static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, @@ -69,6 +66,12 @@ static char *ngx_http_core_keepalive(ngx void *conf); static char *ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +#if (NGX_HTTP_GZIP) +static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +#endif static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data); @@ -79,8 +82,16 @@ static ngx_conf_post_t ngx_http_core_lo static ngx_conf_post_handler_pt ngx_http_core_pool_size_p = ngx_http_core_pool_size; -static ngx_conf_deprecated_t ngx_conf_deprecated_optimize_host_names = { - ngx_conf_deprecated, "optimize_host_names", "optimize_server_names" +static ngx_conf_deprecated_t ngx_conf_deprecated_optimize_server_names = { + ngx_conf_deprecated, "optimize_server_names", "server_name_in_redirect" +}; + +static ngx_conf_deprecated_t ngx_conf_deprecated_open_file_cache_retest = { + ngx_conf_deprecated, "open_file_cache_retest", "open_file_cache_valid" +}; + +static ngx_conf_deprecated_t ngx_conf_deprecated_satisfy_any = { + ngx_conf_deprecated, "satisfy_any", "satisfy" }; @@ -92,6 +103,43 @@ static ngx_conf_enum_t ngx_http_core_re }; +static ngx_conf_enum_t ngx_http_core_satisfy[] = { + { ngx_string("all"), NGX_HTTP_SATISFY_ALL }, + { ngx_string("any"), NGX_HTTP_SATISFY_ANY }, + { ngx_null_string, 0 } +}; + + +#if (NGX_HTTP_GZIP) + +static ngx_conf_enum_t ngx_http_gzip_http_version[] = { + { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, + { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { + { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, + { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, + { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, + { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, + { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, + { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, + { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, + { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, + { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, + { ngx_null_string, 0 } +}; + + +static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache"); +static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store"); +static ngx_str_t ngx_http_gzip_private = ngx_string("private"); + +#endif + + static ngx_command_t ngx_http_core_commands[] = { { ngx_string("variables_hash_max_size"), @@ -167,16 +215,9 @@ static ngx_command_t ngx_http_core_comm { ngx_string("optimize_server_names"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_core_srv_conf_t, optimize_server_names), - NULL }, - - { ngx_string("optimize_host_names"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_core_srv_conf_t, optimize_server_names), - &ngx_conf_deprecated_optimize_host_names }, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, server_name_in_redirect), + &ngx_conf_deprecated_optimize_server_names }, { ngx_string("ignore_invalid_headers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, @@ -185,6 +226,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_srv_conf_t, ignore_invalid_headers), NULL }, + { ngx_string("merge_slashes"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_core_srv_conf_t, merge_slashes), + NULL }, + { ngx_string("location"), NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12, ngx_http_core_location, @@ -307,6 +355,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk), NULL }, + { ngx_string("directio"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_core_directio, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("tcp_nopush"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -357,12 +412,19 @@ static ngx_command_t ngx_http_core_comm 0, NULL }, + { ngx_string("satisfy"), + 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, satisfy), + &ngx_http_core_satisfy }, + { ngx_string("satisfy_any"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, satisfy_any), - NULL }, + offsetof(ngx_http_core_loc_conf_t, satisfy), + &ngx_conf_deprecated_satisfy_any }, { ngx_string("internal"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, @@ -392,6 +454,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, reset_timedout_connection), NULL }, + { ngx_string("server_name_in_redirect"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, server_name_in_redirect), + NULL }, + { ngx_string("port_in_redirect"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -427,6 +496,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, recursive_error_pages), NULL }, + { ngx_string("server_tokens"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, server_tokens), + NULL }, + { ngx_string("error_page"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_2MORE, @@ -457,11 +533,25 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, open_file_cache), NULL }, + { ngx_string("open_file_cache_valid"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_sec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid), + NULL }, + { ngx_string("open_file_cache_retest"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_sec_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, open_file_cache_retest), + offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid), + &ngx_conf_deprecated_open_file_cache_retest }, + + { ngx_string("open_file_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_core_loc_conf_t, open_file_cache_min_uses), NULL }, { ngx_string("open_file_cache_errors"), @@ -478,6 +568,52 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, open_file_cache_events), NULL }, + { ngx_string("resolver"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_core_resolver, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("resolver_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_core_loc_conf_t, resolver_timeout), + NULL }, + +#if (NGX_HTTP_GZIP) + + { ngx_string("gzip_vary"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, gzip_vary), + NULL }, + + { ngx_string("gzip_http_version"), + 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, gzip_http_version), + &ngx_http_gzip_http_version }, + + { ngx_string("gzip_proxied"), + 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_core_loc_conf_t, gzip_proxied), + &ngx_http_gzip_proxied_mask }, + + { ngx_string("gzip_disable"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_gzip_disable, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + +#endif + ngx_null_command }; @@ -513,6 +649,9 @@ ngx_module_t ngx_http_core_module = { }; +static ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " }; + + void ngx_http_handler(ngx_http_request_t *r) { @@ -570,6 +709,7 @@ ngx_http_handler(ngx_http_request_t *r) } r->valid_location = 1; + r->gzip = 0; r->write_event_handler = ngx_http_core_run_phases; ngx_http_core_run_phases(r); @@ -641,16 +781,13 @@ ngx_http_core_find_config_phase(ngx_http { u_char *p; size_t len; - ngx_int_t rc; + ngx_int_t rc, expect; ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t *cscf; r->content_handler = NULL; r->uri_changed = 0; - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - rc = ngx_http_core_find_location(r, &cscf->locations, cscf->regex_start, 0); + rc = ngx_http_core_find_location(r); if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -681,15 +818,23 @@ ngx_http_core_find_config_phase(ngx_http && clcf->client_max_body_size < r->headers_in.content_length_n) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "client intented to send too large body: %O bytes", + "client intended to send too large body: %O bytes", r->headers_in.content_length_n); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; } - - if (rc == NGX_HTTP_LOCATION_AUTO_REDIRECT) { + if (r->headers_in.expect) { + expect = ngx_http_core_send_continue(r); + + if (expect != NGX_OK) { + ngx_http_finalize_request(r, expect); + return NGX_OK; + } + } + + if (rc == NGX_DONE) { r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -706,7 +851,7 @@ ngx_http_core_find_config_phase(ngx_http } else { len = clcf->name.len + 1 + r->args.len; - p = ngx_palloc(r->pool, len); + p = ngx_pnalloc(r->pool, len); if (p == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -734,6 +879,8 @@ ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { + ngx_http_core_srv_conf_t *cscf; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "post rewrite phase: %ui", r->phase_handler); @@ -765,6 +912,9 @@ ngx_http_core_post_rewrite_phase(ngx_htt r->phase_handler = ph->next; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + r->loc_conf = cscf->ctx->loc_conf; + return NGX_AGAIN; } @@ -796,7 +946,7 @@ ngx_http_core_access_phase(ngx_http_requ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (clcf->satisfy_any == 0) { + if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { if (rc == NGX_OK) { r->phase_handler++; @@ -896,7 +1046,7 @@ ngx_http_core_content_phase(ngx_http_req if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "directory index of \"%V\" is forbidden", &path); + "directory index of \"%s\" is forbidden", path.data); } ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN); @@ -968,150 +1118,232 @@ ngx_http_update_location_config(ngx_http static ngx_int_t -ngx_http_core_find_location(ngx_http_request_t *r, - ngx_array_t *locations, ngx_uint_t regex_start, size_t len) +ngx_http_core_find_location(ngx_http_request_t *r) { - ngx_int_t n, rc; - ngx_uint_t i, found; + ngx_int_t rc; + ngx_http_core_loc_conf_t *pclcf; + + pclcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + rc = ngx_http_core_find_static_location(r, pclcf->static_locations); + + if (rc == NGX_AGAIN) { + /* look up nested locations */ + rc = ngx_http_core_find_location(r); + } + + if (rc == NGX_OK || rc == NGX_DONE) { + return rc; + } + + /* rc == NGX_DECLINED or rc == NGX_AGAIN in nested location */ + +#if (NGX_PCRE) + { + ngx_int_t n; ngx_http_core_loc_conf_t *clcf, **clcfp; -#if (NGX_PCRE) - ngx_uint_t noregex; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->noregex == 0 && pclcf->regex_locations) { + + for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "test location: ~ \"%V\"", &(*clcfp)->name); + + n = ngx_regex_exec((*clcfp)->regex, &r->uri, NULL, 0); + + if (n == NGX_REGEX_NO_MATCHED) { + continue; + } + + if (n < 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n + " failed: %d on \"%V\" using \"%V\"", + n, &r->uri, &(*clcfp)->name); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* match */ + + r->loc_conf = (*clcfp)->loc_conf; + + /* look up nested locations */ + + return ngx_http_core_find_location(r); + } + } + } #endif - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "find location for \"%V\"", &r->uri); - - found = 0; -#if (NGX_PCRE) - noregex = 0; -#endif - - clcfp = locations->elts; - for (i = 0; i < locations->nelts; i++) { - - if (clcfp[i]->noname -#if (NGX_PCRE) - || clcfp[i]->regex -#endif - || clcfp[i]->named) - { - break; + return rc; +} + + +/* + * NGX_OK - exact match + * NGX_DONE - auto redirect + * NGX_AGAIN - inclusive match + * NGX_DECLINED - no match + */ + +static ngx_int_t +ngx_http_core_find_static_location(ngx_http_request_t *r, + ngx_http_location_tree_node_t *node) +{ + u_char *uri; + size_t len, n; + ngx_int_t rc, rv; + + len = r->uri.len; + uri = r->uri.data; + + rv = NGX_DECLINED; + + for ( ;; ) { + + if (node == NULL) { + return rv; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "find location: %s\"%V\"", - clcfp[i]->exact_match ? "= " : "", &clcfp[i]->name); - - if (clcfp[i]->auto_redirect - && r->uri.len == clcfp[i]->name.len - 1 - && ngx_strncmp(r->uri.data, clcfp[i]->name.data, - clcfp[i]->name.len - 1) - == 0) - { - /* the locations are lexicographically sorted */ - - r->loc_conf = clcfp[i]->loc_conf; - - return NGX_HTTP_LOCATION_AUTO_REDIRECT; - } - - if (r->uri.len < clcfp[i]->name.len) { + "test location: \"%*s\"", node->len, node->name); + + n = (len <= (size_t) node->len) ? len : node->len; + + rc = ngx_filename_cmp(uri, node->name, n); + + if (rc != 0) { + node = (rc < 0) ? node->left : node->right; + continue; } - n = ngx_strncmp(r->uri.data, clcfp[i]->name.data, clcfp[i]->name.len); - - if (n < 0) { - /* the locations are lexicographically sorted */ - break; - } - - if (n == 0) { - if (clcfp[i]->exact_match) { - - if (r->uri.len == clcfp[i]->name.len) { - r->loc_conf = clcfp[i]->loc_conf; - return NGX_HTTP_LOCATION_EXACT; - } + if (len > (size_t) node->len) { + + if (node->inclusive) { + + r->loc_conf = node->inclusive->loc_conf; + rv = NGX_AGAIN; + + node = node->tree; + uri += n; + len -= n; continue; } - if (len > clcfp[i]->name.len) { - /* the previous match is longer */ - break; - } - - found = 1; - - r->loc_conf = clcfp[i]->loc_conf; -#if (NGX_PCRE) - noregex = clcfp[i]->noregex; -#endif - } - } - - if (found) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->locations) { - rc = ngx_http_core_find_location(r, clcf->locations, - clcf->regex_start, len); - - if (rc != NGX_OK) { - return rc; - } - } - } - -#if (NGX_PCRE) - - if (noregex) { - return NGX_HTTP_LOCATION_NOREGEX; - } - - /* regex matches */ - - for (i = regex_start; i < locations->nelts; i++) { - - if (!clcfp[i]->regex) { - break; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "find location: ~ \"%V\"", &clcfp[i]->name); - - n = ngx_regex_exec(clcfp[i]->regex, &r->uri, NULL, 0); - - if (n == NGX_REGEX_NO_MATCHED) { + /* exact only */ + + node = node->right; + continue; } - if (n < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n - " failed: %d on \"%V\" using \"%V\"", - n, &r->uri, &clcfp[i]->name); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (len == (size_t) node->len) { + + r->loc_conf = (node->exact) ? node->exact->loc_conf: + node->inclusive->loc_conf; + return NGX_OK; + } + + /* len < node->len */ + + if (len + 1 == (size_t) node->len && node->auto_redirect) { + + r->loc_conf = (node->exact) ? node->exact->loc_conf: + node->inclusive->loc_conf; + rv = NGX_DONE; } - /* match */ - - r->loc_conf = clcfp[i]->loc_conf; - - return NGX_HTTP_LOCATION_REGEX; + node = node->left; + } +} + + +static ngx_int_t +ngx_http_core_send_continue(ngx_http_request_t *r) +{ + ngx_int_t n; + ngx_str_t *expect; + + if (r->expect_tested) { + return NGX_OK; + } + + r->expect_tested = 1; + + expect = &r->headers_in.expect->value; + + if (expect->len != sizeof("100-continue") - 1 + || ngx_strncasecmp(expect->data, (u_char *) "100-continue", + sizeof("100-continue") - 1) + != 0) + { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "send 100 Continue"); + + n = r->connection->send(r->connection, + (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF, + sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1); + + if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) { + return NGX_OK; } -#endif /* NGX_PCRE */ - - return NGX_OK; + /* we assume that such small packet should be send successfully */ + + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +void * +ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash) +{ + u_char c, *p; + ngx_uint_t i, hash; + + if (r->headers_out.content_type.len == 0) { + return NULL; + } + + if (r->headers_out.content_type_lowcase == NULL) { + + p = ngx_pnalloc(r->pool, r->headers_out.content_type_len); + + if (p == NULL) { + return NULL; + } + + r->headers_out.content_type_lowcase = p; + + hash = 0; + + for (i = 0; i < r->headers_out.content_type_len; i++) { + c = ngx_tolower(r->headers_out.content_type.data[i]); + hash = ngx_hash(hash, c); + *p++ = c; + } + + r->headers_out.content_type_hash = hash; + } + + return ngx_hash_find(types_hash, + r->headers_out.content_type_hash, + r->headers_out.content_type_lowcase, + r->headers_out.content_type_len); } ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r) { - u_char c, *p, *exten; + u_char c, *exten; ngx_str_t *type; ngx_uint_t i, hash; ngx_http_core_loc_conf_t *clcf; @@ -1131,19 +1363,12 @@ ngx_http_set_content_type(ngx_http_reque if (c >= 'A' && c <= 'Z') { - p = ngx_palloc(r->pool, r->exten.len); - if (p == NULL) { + exten = ngx_pnalloc(r->pool, r->exten.len); + if (exten == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - hash = 0; - exten = p; - - for (i = 0; i < r->exten.len; i++) { - c = ngx_tolower(r->exten.data[i]); - hash = ngx_hash(hash, c); - *p++ = c; - } + hash = ngx_hash_strlow(exten, r->exten.data, r->exten.len); r->exten.data = exten; @@ -1254,7 +1479,7 @@ ngx_http_map_uri_to_path(ngx_http_reques path->len = clcf->root.len + reserved; - path->data = ngx_palloc(r->pool, path->len); + path->data = ngx_pnalloc(r->pool, path->len); if (path->data == NULL) { return NULL; } @@ -1324,7 +1549,7 @@ ngx_http_auth_basic_user(ngx_http_reques } auth.len = ngx_base64_decoded_length(encoded.len); - auth.data = ngx_palloc(r->pool, auth.len + 1); + auth.data = ngx_pnalloc(r->pool, auth.len + 1); if (auth.data == NULL) { return NGX_ERROR; } @@ -1357,6 +1582,196 @@ ngx_http_auth_basic_user(ngx_http_reques ngx_int_t +ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s) +{ + socklen_t len; + ngx_connection_t *c; + struct sockaddr_in sin; + + /* AF_INET only */ + + c = r->connection; + + if (r->in_addr == 0) { + len = sizeof(struct sockaddr_in); + if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { + ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); + return NGX_ERROR; + } + + r->in_addr = sin.sin_addr.s_addr; + } + + if (s == NULL) { + return NGX_OK; + } + + s->len = ngx_inet_ntop(c->listening->family, &r->in_addr, + s->data, INET_ADDRSTRLEN); + + return NGX_OK; +} + + +#if (NGX_HTTP_GZIP) + +ngx_int_t +ngx_http_gzip_ok(ngx_http_request_t *r) +{ + time_t date, expires; + ngx_uint_t p; + ngx_array_t *cc; + ngx_table_elt_t *e, *d; + ngx_http_core_loc_conf_t *clcf; + + if (r->gzip == 1) { + return NGX_OK; + } + + if (r->gzip == 2) { + return NGX_DECLINED; + } + + r->gzip = 2; + + if (r != r->main + || r->headers_in.accept_encoding == NULL + || ngx_strcasestrn(r->headers_in.accept_encoding->value.data, + "gzip", 4 - 1) + == NULL + + /* + * if the URL (without the "http://" prefix) is longer than 253 bytes, + * then MSIE 4.x can not handle the compressed stream - it waits + * too long, hangs up or crashes + */ + + || (r->headers_in.msie4 && r->unparsed_uri.len > 200)) + { + return NGX_DECLINED; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->http_version < clcf->gzip_http_version) { + return NGX_DECLINED; + } + + if (r->headers_in.via == NULL) { + goto ok; + } + + p = clcf->gzip_proxied; + + if (p & NGX_HTTP_GZIP_PROXIED_OFF) { + return NGX_DECLINED; + } + + if (p & NGX_HTTP_GZIP_PROXIED_ANY) { + goto ok; + } + + if (r->headers_in.authorization && (p & NGX_HTTP_GZIP_PROXIED_AUTH)) { + goto ok; + } + + e = r->headers_out.expires; + + if (e) { + + if (!(p & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { + return NGX_DECLINED; + } + + expires = ngx_http_parse_time(e->value.data, e->value.len); + if (expires == NGX_ERROR) { + return NGX_DECLINED; + } + + d = r->headers_out.date; + + if (d) { + date = ngx_http_parse_time(d->value.data, d->value.len); + if (date == NGX_ERROR) { + return NGX_DECLINED; + } + + } else { + date = ngx_time(); + } + + if (expires < date) { + goto ok; + } + + return NGX_DECLINED; + } + + cc = &r->headers_out.cache_control; + + if (cc->elts) { + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE) + && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache, + NULL) + >= 0) + { + goto ok; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE) + && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store, + NULL) + >= 0) + { + goto ok; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE) + && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private, + NULL) + >= 0) + { + goto ok; + } + + return NGX_DECLINED; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_LM) && r->headers_out.last_modified) { + return NGX_DECLINED; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_ETAG) && r->headers_out.etag) { + return NGX_DECLINED; + } + +ok: + +#if (NGX_PCRE) + + if (clcf->gzip_disable && r->headers_in.user_agent) { + + if (ngx_regex_exec_array(clcf->gzip_disable, + &r->headers_in.user_agent->value, + r->connection->log) + != NGX_DECLINED) + { + return NGX_DECLINED; + } + } + +#endif + + r->gzip = 1; + + return NGX_OK; +} + +#endif + + +ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, ngx_http_post_subrequest_t *ps, ngx_uint_t flags) @@ -1430,7 +1845,7 @@ ngx_http_subrequest(ngx_http_request_t * sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0; sr->unparsed_uri = r->unparsed_uri; - sr->method_name = r->method_name; + sr->method_name = ngx_http_core_get_method; sr->http_protocol = r->http_protocol; if (ngx_http_set_exten(sr) != NGX_OK) { @@ -1450,7 +1865,6 @@ ngx_http_subrequest(ngx_http_request_t * sr->in_addr = r->in_addr; sr->port = r->port; sr->port_text = r->port_text; - sr->server_name = r->server_name; sr->variables = r->variables; @@ -1563,44 +1977,46 @@ ngx_http_internal_redirect(ngx_http_requ ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name) { - ngx_uint_t i; ngx_http_core_srv_conf_t *cscf; ngx_http_core_loc_conf_t **clcfp; ngx_http_core_main_conf_t *cmcf; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - clcfp = cscf->locations.elts; - - for (i = cscf->named_start; i < cscf->locations.nelts; i++) { - - if (name->len != clcfp[i]->name.len - || ngx_strncmp(name->data, clcfp[i]->name.data, name->len) != 0) + for (clcfp = cscf->named_locations; *clcfp; clcfp++) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "test location: \"%V\"", &(*clcfp)->name); + + if (name->len != (*clcfp)->name.len + || ngx_strncmp(name->data, (*clcfp)->name.data, name->len) != 0) { continue; } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "named location: %V \"%V?%V\"", name, &r->uri, &r->args); + "using location: %V \"%V?%V\"", name, &r->uri, &r->args); r->internal = 1; - - r->loc_conf = clcfp[i]->loc_conf; + r->content_handler = NULL; + r->loc_conf = (*clcfp)->loc_conf; ngx_http_update_location_config(r); cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); r->phase_handler = cmcf->phase_engine.location_rewrite_index; + ngx_http_core_run_phases(r); return NGX_DONE; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "could not find name location \"%V\"", name); + "could not find named location \"%V\"", name); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; } @@ -1649,7 +2065,6 @@ ngx_http_core_server(ngx_conf_t *cf, ngx ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *http_ctx; ngx_http_core_srv_conf_t *cscf, **cscfp; - ngx_http_core_loc_conf_t **clcfp; ngx_http_core_main_conf_t *cmcf; ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); @@ -1727,37 +2142,6 @@ ngx_http_core_server(ngx_conf_t *cf, ngx *cf = pcf; - if (rv != NGX_CONF_OK) { - return rv; - } - - ngx_sort(cscf->locations.elts, (size_t) cscf->locations.nelts, - sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations); - - clcfp = cscf->locations.elts; - -#if (NGX_PCRE) - - cscf->regex_start = cscf->locations.nelts; - - for (i = 0; i < cscf->locations.nelts; i++) { - if (clcfp[i]->regex) { - cscf->regex_start = i; - break; - } - } - -#endif - - cscf->named_start = cscf->locations.nelts; - - for (i = 0; i < cscf->locations.nelts; i++) { - if (clcfp[i]->named) { - cscf->named_start = i; - break; - } - } - return rv; } @@ -1771,12 +2155,7 @@ ngx_http_core_location(ngx_conf_t *cf, n ngx_conf_t save; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; - ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; -#if (NGX_PCRE) - ngx_str_t err; - u_char errstr[NGX_MAX_CONF_ERRSTR]; -#endif + ngx_http_core_loc_conf_t *clcf, *pclcf; ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { @@ -1831,6 +2210,9 @@ ngx_http_core_location(ngx_conf_t *cf, n && value[1].data[1] == '*')) { #if (NGX_PCRE) + ngx_str_t err; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + err.len = NGX_MAX_CONF_ERRSTR; err.data = errstr; @@ -1868,15 +2250,10 @@ ngx_http_core_location(ngx_conf_t *cf, n pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; - if (pclcf->name.len == 0) { - cscf = ctx->srv_conf[ngx_http_core_module.ctx_index]; - - clcfp = ngx_array_push(&cscf->locations); - if (clcfp == NULL) { - return NGX_CONF_ERROR; - } - - } else { + if (pclcf->name.len) { + + /* nested location */ + #if 0 clcf->prev_location = pclcf; #endif @@ -1897,6 +2274,14 @@ ngx_http_core_location(ngx_conf_t *cf, n return NGX_CONF_ERROR; } + if (clcf->named) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "named location \"%V\" must be " + "on server level only", + &clcf->name); + return NGX_CONF_ERROR; + } + #if (NGX_PCRE) if (clcf->regex == NULL && ngx_strncmp(clcf->name.data, pclcf->name.data, pclcf->name.len) @@ -1911,22 +2296,11 @@ ngx_http_core_location(ngx_conf_t *cf, n &clcf->name, &pclcf->name); return NGX_CONF_ERROR; } - - if (pclcf->locations == NULL) { - pclcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *)); - - if (pclcf->locations == NULL) { - return NGX_CONF_ERROR; - } - } - - clcfp = ngx_array_push(pclcf->locations); - if (clcfp == NULL) { - return NGX_CONF_ERROR; - } } - *clcfp = clcf; + if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { + return NGX_CONF_ERROR; + } save = *cf; cf->ctx = ctx; @@ -1936,103 +2310,10 @@ ngx_http_core_location(ngx_conf_t *cf, n *cf = save; - if (rv != NGX_CONF_OK) { - return rv; - } - - if (clcf->locations == NULL) { - return rv; - } - - ngx_sort(clcf->locations->elts, (size_t) clcf->locations->nelts, - sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations); - -#if (NGX_PCRE) - - clcf->regex_start = clcf->locations->nelts; - clcfp = clcf->locations->elts; - - for (i = 0; i < clcf->locations->nelts; i++) { - if (clcfp[i]->regex) { - clcf->regex_start = i; - break; - } - } - -#endif - return rv; } -static int -ngx_http_core_cmp_locations(const void *one, const void *two) -{ - ngx_int_t rc; - ngx_http_core_loc_conf_t *first, *second; - - first = *(ngx_http_core_loc_conf_t **) one; - second = *(ngx_http_core_loc_conf_t **) two; - - if (first->named && !second->named) { - /* shift named locations to the end */ - return 1; - } - - if (!first->named && second->named) { - /* shift named locations to the end */ - return -1; - } - - if (first->named && second->named) { - return ngx_strcmp(first->name.data, second->name.data); - } - - if (first->noname && !second->noname) { - /* shift no named locations to the end */ - return 1; - } - - if (!first->noname && second->noname) { - /* shift no named locations to the end */ - return -1; - } - - if (first->noname || second->noname) { - /* do not sort no named locations */ - return 0; - } - -#if (NGX_PCRE) - - if (first->regex && !second->regex) { - /* shift the regex matches to the end */ - return 1; - } - - if (!first->regex && second->regex) { - /* shift the regex matches to the end */ - return -1; - } - - if (first->regex || second->regex) { - /* do not sort the regex matches */ - return 0; - } - -#endif - - rc = ngx_strcmp(first->name.data, second->name.data); - - if (rc == 0 && second->exact_match) { - /* an exact match must be before the same inclusive one */ - return 1; - } - - return (int) rc; -} - - static char * ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -2066,7 +2347,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c ngx_http_core_loc_conf_t *lcf = conf; ngx_str_t *value, *content_type, *old, file; - ngx_uint_t i, n; + ngx_uint_t i, n, hash; ngx_hash_key_t *type; value = cf->args->elts; @@ -2092,9 +2373,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c for (i = 1; i < cf->args->nelts; i++) { - for (n = 0; n < value[i].len; n++) { - value[i].data[n] = ngx_tolower(value[i].data[n]); - } + hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len); type = lcf->types->elts; for (n = 0; n < lcf->types->nelts; n++) { @@ -2118,7 +2397,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c } type->key = value[i]; - type->key_hash = ngx_hash_key(value[i].data, value[i].len); + type->key_hash = hash; type->value = content_type; } @@ -2208,12 +2487,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t * conf->client_large_buffers.num = 0; */ - if (ngx_array_init(&cscf->locations, cf->pool, 4, sizeof(void *)) - == NGX_ERROR) - { - return NGX_CONF_ERROR; - } - if (ngx_array_init(&cscf->listen, cf->pool, 4, sizeof(ngx_http_listen_t)) == NGX_ERROR) { @@ -2231,8 +2504,8 @@ ngx_http_core_create_srv_conf(ngx_conf_t cscf->request_pool_size = NGX_CONF_UNSET_SIZE; cscf->client_header_timeout = NGX_CONF_UNSET_MSEC; cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE; - cscf->optimize_server_names = NGX_CONF_UNSET; cscf->ignore_invalid_headers = NGX_CONF_UNSET; + cscf->merge_slashes = NGX_CONF_UNSET; return cscf; } @@ -2272,29 +2545,19 @@ ngx_http_core_merge_srv_conf(ngx_conf_t } if (conf->server_name.data == NULL) { - conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN); - if (conf->server_name.data == NULL) { - return NGX_CONF_ERROR; - } - - if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN) - == -1) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, - "gethostname() failed"); - return NGX_CONF_ERROR; - } - - conf->server_name.len = ngx_strlen(conf->server_name.data); + conf->server_name = cf->cycle->hostname; sn = ngx_array_push(&conf->server_names); if (sn == NULL) { return NGX_CONF_ERROR; } +#if (NGX_PCRE) + sn->regex = NULL; +#endif + sn->core_srv_conf = conf; sn->name.len = conf->server_name.len; sn->name.data = conf->server_name.data; - sn->core_srv_conf = conf; } ngx_conf_merge_size_value(conf->connection_pool_size, @@ -2316,12 +2579,11 @@ ngx_http_core_merge_srv_conf(ngx_conf_t return NGX_CONF_ERROR; } - ngx_conf_merge_value(conf->optimize_server_names, - prev->optimize_server_names, 1); - ngx_conf_merge_value(conf->ignore_invalid_headers, prev->ignore_invalid_headers, 1); + ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1); + return NGX_CONF_OK; } @@ -2351,16 +2613,18 @@ ngx_http_core_create_loc_conf(ngx_conf_t * lcf->exact_match = 0; * lcf->auto_redirect = 0; * lcf->alias = 0; + * lcf->gzip_proxied = 0; */ lcf->client_max_body_size = NGX_CONF_UNSET; lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; lcf->client_body_timeout = NGX_CONF_UNSET_MSEC; - lcf->satisfy_any = NGX_CONF_UNSET; + lcf->satisfy = NGX_CONF_UNSET_UINT; lcf->internal = NGX_CONF_UNSET; lcf->client_body_in_file_only = NGX_CONF_UNSET; lcf->sendfile = NGX_CONF_UNSET; lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; + lcf->directio = NGX_CONF_UNSET; lcf->tcp_nopush = NGX_CONF_UNSET; lcf->tcp_nodelay = NGX_CONF_UNSET; lcf->send_timeout = NGX_CONF_UNSET_MSEC; @@ -2371,19 +2635,32 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->keepalive_header = NGX_CONF_UNSET; lcf->lingering_time = NGX_CONF_UNSET_MSEC; lcf->lingering_timeout = NGX_CONF_UNSET_MSEC; + lcf->resolver_timeout = NGX_CONF_UNSET_MSEC; lcf->reset_timedout_connection = NGX_CONF_UNSET; + lcf->server_name_in_redirect = NGX_CONF_UNSET; lcf->port_in_redirect = NGX_CONF_UNSET; lcf->msie_padding = NGX_CONF_UNSET; lcf->msie_refresh = NGX_CONF_UNSET; lcf->log_not_found = NGX_CONF_UNSET; lcf->recursive_error_pages = NGX_CONF_UNSET; + lcf->server_tokens = NGX_CONF_UNSET; lcf->types_hash_max_size = NGX_CONF_UNSET_UINT; lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT; + lcf->open_file_cache = NGX_CONF_UNSET_PTR; - lcf->open_file_cache_retest = NGX_CONF_UNSET; + lcf->open_file_cache_valid = NGX_CONF_UNSET; + lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT; lcf->open_file_cache_errors = NGX_CONF_UNSET; lcf->open_file_cache_events = NGX_CONF_UNSET; +#if (NGX_HTTP_GZIP) + lcf->gzip_vary = NGX_CONF_UNSET; + lcf->gzip_http_version = NGX_CONF_UNSET_UINT; +#if (NGX_PCRE) + lcf->gzip_disable = NGX_CONF_UNSET_PTR; +#endif +#endif + return lcf; } @@ -2528,13 +2805,16 @@ 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_value(conf->satisfy_any, prev->satisfy_any, 0); + ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy, + NGX_HTTP_SATISFY_ALL); ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->client_body_in_file_only, prev->client_body_in_file_only, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, prev->sendfile_max_chunk, 0); + ngx_conf_merge_off_value(conf->directio, prev->directio, + NGX_MAX_OFF_T_VALUE); ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1); @@ -2551,6 +2831,26 @@ ngx_http_core_merge_loc_conf(ngx_conf_t prev->lingering_time, 30000); ngx_conf_merge_msec_value(conf->lingering_timeout, prev->lingering_timeout, 5000); + ngx_conf_merge_msec_value(conf->resolver_timeout, + prev->resolver_timeout, 30000); + + if (conf->resolver == NULL) { + + if (prev->resolver == NULL) { + + /* + * create dummy resolver in http {} context + * to inherit it in all servers + */ + + prev->resolver = ngx_resolver_create(cf, NULL); + if (prev->resolver == NULL) { + return NGX_CONF_ERROR; + } + } + + conf->resolver = prev->resolver; + } ngx_conf_merge_path_value(conf->client_body_temp_path, prev->client_body_temp_path, @@ -2559,24 +2859,43 @@ 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); 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); ngx_conf_merge_value(conf->log_not_found, prev->log_not_found, 1); 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_ptr_value(conf->open_file_cache, - prev->open_file_cache, NULL); - - ngx_conf_merge_sec_value(conf->open_file_cache_retest, - prev->open_file_cache_retest, 60); + prev->open_file_cache, NULL); + + ngx_conf_merge_sec_value(conf->open_file_cache_valid, + prev->open_file_cache_valid, 60); + + ngx_conf_merge_uint_value(conf->open_file_cache_min_uses, + prev->open_file_cache_min_uses, 1); ngx_conf_merge_sec_value(conf->open_file_cache_errors, - prev->open_file_cache_errors, 0); + prev->open_file_cache_errors, 0); ngx_conf_merge_sec_value(conf->open_file_cache_events, - prev->open_file_cache_events, 0); + prev->open_file_cache_events, 0); +#if (NGX_HTTP_GZIP) + + ngx_conf_merge_value(conf->gzip_vary, prev->gzip_vary, 0); + ngx_conf_merge_uint_value(conf->gzip_http_version, prev->gzip_http_version, + NGX_HTTP_VERSION_11); + ngx_conf_merge_bitmask_value(conf->gzip_proxied, prev->gzip_proxied, + (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF)); + +#if (NGX_PCRE) + ngx_conf_merge_ptr_value(conf->gzip_disable, prev->gzip_disable, NULL); +#endif + +#endif return NGX_CONF_OK; } @@ -2607,7 +2926,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx u.listen = 1; u.default_port = 80; - if (ngx_parse_url(cf, &u) != NGX_OK) { + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in \"%V\" of the \"listen\" directive", @@ -2751,30 +3070,12 @@ ngx_http_core_server_name(ngx_conf_t *cf ngx_str_t *value, name; ngx_uint_t i; ngx_http_server_name_t *sn; -#if (NGX_PCRE) - ngx_str_t err; - u_char errstr[NGX_MAX_CONF_ERRSTR]; -#endif value = cf->args->elts; ch = value[1].data[0]; if (cscf->server_name.data == NULL && value[1].len) { - if (ngx_strchr(value[1].data, '*')) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "first server name \"%V\" must not be wildcard", - &value[1]); - return NGX_CONF_ERROR; - } - - if (value[1].data[0] == '~') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "first server name \"%V\" " - "must not be regular expression", &value[1]); - return NGX_CONF_ERROR; - } - name = value[1]; if (ch == '.') { @@ -2793,11 +3094,6 @@ ngx_http_core_server_name(ngx_conf_t *cf ch = value[i].data[0]; - if (value[i].len == 1 && ch == '*') { - cscf->wildcard = 1; - continue; - } - if (value[i].len == 0 || (ch == '*' && (value[i].len < 3 || value[i].data[1] != '.')) || (ch == '.' && value[i].len < 2)) @@ -2813,6 +3109,13 @@ ngx_http_core_server_name(ngx_conf_t *cf &value[i]); } + if (value[i].len == 1 && ch == '*') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"server_name *\" is unsupported, use " + "\"server_name_in_redirect off\" instead"); + return NGX_CONF_ERROR; + } + sn = ngx_array_push(&cscf->server_names); if (sn == NULL) { return NGX_CONF_ERROR; @@ -2822,31 +3125,32 @@ ngx_http_core_server_name(ngx_conf_t *cf sn->regex = NULL; #endif sn->core_srv_conf = cscf; - sn->name.len = value[i].len; - sn->name.data = value[i].data; + sn->name = value[i]; if (value[i].data[0] != '~') { continue; } #if (NGX_PCRE) + { + ngx_str_t err; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + err.len = NGX_MAX_CONF_ERRSTR; err.data = errstr; value[i].len--; value[i].data++; - sn->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool, - &err); + sn->regex = ngx_regex_compile(&value[i], 0, cf->pool, &err); if (sn->regex == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_CONF_ERROR; } - sn->name.len = value[i].len; - sn->name.data = value[i].data; - + sn->name = value[i]; + } #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the using of the regex \"%V\" " @@ -2980,7 +3284,7 @@ static ngx_http_method_name_t ngx_metho static char * ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *clcf = conf; + ngx_http_core_loc_conf_t *pclcf = conf; char *rv; void *mconf; @@ -2990,13 +3294,13 @@ ngx_http_core_limit_except(ngx_conf_t *c ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; ngx_http_method_name_t *name; - ngx_http_core_loc_conf_t *lcf, **clcfp; - - if (clcf->limit_except) { + ngx_http_core_loc_conf_t *clcf; + + if (pclcf->limit_except) { return "duplicate"; } - clcf->limit_except = 0xffffffff; + pclcf->limit_except = 0xffffffff; value = cf->args->elts; @@ -3004,7 +3308,7 @@ ngx_http_core_limit_except(ngx_conf_t *c for (name = ngx_methods_names; name->name; name++) { if (ngx_strcasecmp(value[i].data, name->name) == 0) { - clcf->limit_except &= name->method; + pclcf->limit_except &= name->method; goto next; } } @@ -3017,8 +3321,8 @@ ngx_http_core_limit_except(ngx_conf_t *c continue; } - if (!(clcf->limit_except & NGX_HTTP_GET)) { - clcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD; + if (!(pclcf->limit_except & NGX_HTTP_GET)) { + pclcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD; } ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); @@ -3054,27 +3358,16 @@ ngx_http_core_limit_except(ngx_conf_t *c } - lcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; - clcf->limit_except_loc_conf = ctx->loc_conf; - lcf->loc_conf = ctx->loc_conf; - lcf->name = clcf->name; - lcf->noname = 1; - - if (clcf->locations == NULL) { - clcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *)); - if (clcf->locations == NULL) { - return NGX_CONF_ERROR; - } - } - - clcfp = ngx_array_push(clcf->locations); - if (clcfp == NULL) { + clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; + pclcf->limit_except_loc_conf = ctx->loc_conf; + clcf->loc_conf = ctx->loc_conf; + clcf->name = pclcf->name; + clcf->noname = 1; + + if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { return NGX_CONF_ERROR; } - *clcfp = lcf; - - save = *cf; cf->ctx = ctx; cf->cmd_type = NGX_HTTP_LMT_CONF; @@ -3088,10 +3381,38 @@ ngx_http_core_limit_except(ngx_conf_t *c static char * +ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_str_t *value; + + if (clcf->directio != NGX_CONF_UNSET) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + clcf->directio = NGX_MAX_OFF_T_VALUE; + return NGX_CONF_OK; + } + + clcf->directio = ngx_parse_offset(&value[1]); + if (clcf->directio == (off_t) NGX_ERROR) { + return "invalid value"; + } + + return NGX_CONF_OK; +} + + +static char * ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *lcf = conf; + u_char *args; ngx_int_t overwrite; ngx_str_t *value, uri; ngx_uint_t i, n, nvar; @@ -3160,6 +3481,8 @@ ngx_http_core_error_page(ngx_conf_t *cf, } } + args = (u_char *) ngx_strchr(uri.data, '?'); + for (i = 1; i < cf->args->nelts - n; i++) { err = ngx_array_push(lcf->error_pages); if (err == NULL) { @@ -3181,9 +3504,36 @@ ngx_http_core_error_page(ngx_conf_t *cf, return NGX_CONF_ERROR; } - err->overwrite = (overwrite >= 0) ? overwrite : err->status; - - err->uri = uri; + if (overwrite >= 0) { + err->overwrite = overwrite; + + } else { + 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; + } + } + + if (args) { + err->uri.len = args - uri.data; + err->uri.data = uri.data; + args++; + err->args.len = (uri.data + uri.len) - args; + err->args.data = args; + + } else { + err->uri = uri; + err->args.len = 0; + err->args.data = NULL; + } + err->uri_lengths = uri_lengths; err->uri_values = uri_values; } @@ -3217,7 +3567,7 @@ ngx_http_core_open_file_cache(ngx_conf_t max = ngx_atoi(value[i].data + 4, value[i].len - 4); if (max == NGX_ERROR) { - return NGX_CONF_ERROR; + goto failed; } continue; @@ -3230,7 +3580,7 @@ ngx_http_core_open_file_cache(ngx_conf_t inactive = ngx_parse_time(&s, 1); if (inactive < 0) { - return NGX_CONF_ERROR; + goto failed; } continue; @@ -3243,6 +3593,8 @@ ngx_http_core_open_file_cache(ngx_conf_t continue; } + failed: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid \"open_file_cache\" parameter \"%V\"", &value[i]); @@ -3339,6 +3691,96 @@ ngx_http_core_internal(ngx_conf_t *cf, n static char * +ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_url_t u; + ngx_str_t *value; + + if (clcf->resolver) { + return "is duplicate"; + } + + value = cf->args->elts; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.host = value[1]; + u.port = 53; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err); + return NGX_CONF_ERROR; + } + + clcf->resolver = ngx_resolver_create(cf, &u.addrs[0]); + if (clcf->resolver == NULL) { + return NGX_OK; + } + + return NGX_CONF_OK; +} + + +#if (NGX_HTTP_GZIP) + +static char * +ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ +#if (NGX_PCRE) + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_str_t err, *value; + ngx_uint_t i; + ngx_regex_elt_t *re; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) { + clcf->gzip_disable = ngx_array_create(cf->pool, 2, + sizeof(ngx_regex_elt_t)); + if (clcf->gzip_disable == NULL) { + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + + err.len = NGX_MAX_CONF_ERRSTR; + err.data = errstr; + + for (i = 1; i < cf->args->nelts; i++) { + + re = ngx_array_push(clcf->gzip_disable); + if (re == NULL) { + return NGX_CONF_ERROR; + } + + re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool, + &err); + + if (re->regex == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + return NGX_CONF_ERROR; + } + + re->name = value[i].data; + } + + return NGX_CONF_OK; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"gzip_disable\" requires PCRE library"); + + return NGX_CONF_ERROR; +#endif +} + +#endif + + +static char * ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data) { #if (NGX_FREEBSD) diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -13,6 +13,25 @@ #include +#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 +#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 +#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 +#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010 +#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020 +#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040 +#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080 +#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100 +#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 + + +#define NGX_HTTP_SATISFY_ALL 0 +#define NGX_HTTP_SATISFY_ANY 1 + + +typedef struct ngx_http_location_tree_node_s ngx_http_location_tree_node_t; +typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t; + + typedef struct { unsigned default_server:1; unsigned bind:1; @@ -112,37 +131,29 @@ typedef struct { typedef struct { - /* - * array of the ngx_http_core_loc_conf_t *, - * used in the ngx_http_core_find_location() and in the merge phase - */ - ngx_array_t locations; - - unsigned regex_start:15; - unsigned named_start:15; - unsigned wildcard:1; - /* array of the ngx_http_listen_t, "listen" directive */ - ngx_array_t listen; + ngx_array_t listen; /* array of the ngx_http_server_name_t, "server_name" directive */ - ngx_array_t server_names; + ngx_array_t server_names; /* server ctx */ - ngx_http_conf_ctx_t *ctx; + ngx_http_conf_ctx_t *ctx; + + ngx_str_t server_name; - ngx_str_t server_name; + size_t connection_pool_size; + size_t request_pool_size; + size_t client_header_buffer_size; - size_t connection_pool_size; - size_t request_pool_size; - size_t client_header_buffer_size; + ngx_bufs_t large_client_header_buffers; + + ngx_msec_t client_header_timeout; - ngx_bufs_t large_client_header_buffers; + ngx_flag_t ignore_invalid_headers; + ngx_flag_t merge_slashes; - ngx_msec_t client_header_timeout; - - ngx_flag_t optimize_server_names; - ngx_flag_t ignore_invalid_headers; + ngx_http_core_loc_conf_t **named_locations; } ngx_http_core_srv_conf_t; @@ -185,7 +196,6 @@ typedef struct { #if (NGX_PCRE) ngx_uint_t nregex; ngx_http_server_name_t *regex; - #endif /* the default server configuration for this address:port */ @@ -211,13 +221,12 @@ typedef struct { ngx_int_t status; ngx_int_t overwrite; ngx_str_t uri; + ngx_str_t args; ngx_array_t *uri_lengths; ngx_array_t *uri_values; } ngx_http_err_page_t; -typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t; - struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ @@ -225,8 +234,6 @@ struct ngx_http_core_loc_conf_s { ngx_regex_t *regex; #endif - unsigned regex_start:15; - unsigned noname:1; /* "if () {}" block or limit_except */ unsigned named:1; @@ -236,14 +243,14 @@ struct ngx_http_core_loc_conf_s { unsigned auto_redirect:1; unsigned alias:1; - /* array of inclusive ngx_http_core_loc_conf_t */ - ngx_array_t *locations; + ngx_http_location_tree_node_t *static_locations; + ngx_http_core_loc_conf_t **regex_locations; /* pointer to the modules' loc_conf */ - void **loc_conf ; + void **loc_conf; uint32_t limit_except; - void **limit_except_loc_conf ; + void **limit_except_loc_conf; ngx_http_handler_pt handler; @@ -258,6 +265,7 @@ struct ngx_http_core_loc_conf_s { ngx_str_t default_type; off_t client_max_body_size; /* client_max_body_size */ + off_t directio; /* directio */ size_t client_body_buffer_size; /* client_body_buffer_size */ size_t send_lowat; /* send_lowat */ @@ -270,28 +278,46 @@ struct ngx_http_core_loc_conf_s { ngx_msec_t keepalive_timeout; /* keepalive_timeout */ ngx_msec_t lingering_time; /* lingering_time */ ngx_msec_t lingering_timeout; /* lingering_timeout */ + ngx_msec_t resolver_timeout; /* resolver_timeout */ + + ngx_resolver_t *resolver; /* resolver */ time_t keepalive_header; /* keepalive_timeout */ - ngx_flag_t satisfy_any; /* satisfy_any */ + ngx_uint_t satisfy; /* satisfy */ + ngx_flag_t internal; /* internal */ ngx_flag_t client_body_in_file_only; /* client_body_in_file_only */ ngx_flag_t sendfile; /* sendfile */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ + ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */ ngx_flag_t port_in_redirect; /* port_in_redirect */ ngx_flag_t msie_padding; /* msie_padding */ ngx_flag_t msie_refresh; /* msie_refresh */ ngx_flag_t log_not_found; /* log_not_found */ ngx_flag_t recursive_error_pages; /* recursive_error_pages */ + ngx_flag_t server_tokens; /* server_tokens */ + +#if (NGX_HTTP_GZIP) + ngx_flag_t gzip_vary; /* gzip_vary */ + + ngx_uint_t gzip_http_version; /* gzip_http_version */ + ngx_uint_t gzip_proxied; /* gzip_proxied */ + +#if (NGX_PCRE) + ngx_array_t *gzip_disable; /* gzip_disable */ +#endif +#endif ngx_array_t *error_pages; /* error_page */ ngx_path_t *client_body_temp_path; /* client_body_temp_path */ ngx_open_file_cache_t *open_file_cache; - time_t open_file_cache_retest; + time_t open_file_cache_valid; + ngx_uint_t open_file_cache_min_uses; ngx_flag_t open_file_cache_errors; ngx_flag_t open_file_cache_events; @@ -300,12 +326,39 @@ struct ngx_http_core_loc_conf_s { ngx_uint_t types_hash_max_size; ngx_uint_t types_hash_bucket_size; + ngx_queue_t *locations; + #if 0 ngx_http_core_loc_conf_t *prev_location; #endif }; +typedef struct { + ngx_queue_t queue; + ngx_http_core_loc_conf_t *exact; + ngx_http_core_loc_conf_t *inclusive; + ngx_str_t *name; + u_char *file_name; + ngx_uint_t line; + ngx_queue_t list; +} ngx_http_location_queue_t; + + +struct ngx_http_location_tree_node_s { + ngx_http_location_tree_node_t *left; + ngx_http_location_tree_node_t *right; + ngx_http_location_tree_node_t *tree; + + ngx_http_core_loc_conf_t *exact; + ngx_http_core_loc_conf_t *inclusive; + + u_char auto_redirect; + u_char len; + u_char name[1]; +}; + + 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); @@ -320,11 +373,18 @@ ngx_int_t ngx_http_core_post_access_phas ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); + +void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash); ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); ngx_int_t ngx_http_set_exten(ngx_http_request_t *r); u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name, size_t *root_length, size_t reserved); ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r); +ngx_int_t ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s); +#if (NGX_HTTP_GZIP) +ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); +#endif + ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr, @@ -363,7 +423,7 @@ extern ngx_uint_t ngx_http_max_module; \ r->allow_ranges = 0; \ if (r->headers_out.accept_ranges) { \ - r->headers_out.accept_ranges->hash = 0 ; \ + r->headers_out.accept_ranges->hash = 0; \ r->headers_out.accept_ranges = NULL; \ } diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -45,7 +45,8 @@ ngx_module_t ngx_http_header_filter_mod }; -static char ngx_http_server_string[] = "Server: " NGINX_VER CRLF; +static char ngx_http_server_string[] = "Server: nginx" CRLF; +static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF; static ngx_str_t ngx_http_status_lines[] = { @@ -152,12 +153,16 @@ ngx_http_header_filter(ngx_http_request_ { u_char *p; size_t len; + ngx_str_t host; ngx_buf_t *b; ngx_uint_t status, i; ngx_chain_t out; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + /* AF_INET only */ + u_char addr[INET_ADDRSTRLEN]; r->header_sent = 1; @@ -237,8 +242,11 @@ ngx_http_header_filter(ngx_http_request_ len += ngx_http_status_lines[status].len; } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (r->headers_out.server == NULL) { - len += sizeof(ngx_http_server_string) - 1; + len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1: + sizeof(ngx_http_server_string) - 1; } if (r->headers_out.date == NULL) { @@ -268,18 +276,31 @@ ngx_http_header_filter(ngx_http_request_ len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') { r->headers_out.location->hash = 0; + if (clcf->server_name_in_redirect) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + host = cscf->server_name; + + } else if (r->headers_in.server.len) { + host = r->headers_in.server; + + } else { + host.data = addr; + + if (ngx_http_server_addr(r, &host) != NGX_OK) { + return NGX_ERROR; + } + } + #if (NGX_HTTP_SSL) if (r->connection->ssl) { len += sizeof("Location: https://") - 1 - + r->server_name.len + + host.len + r->headers_out.location->value.len + 2; if (clcf->port_in_redirect && r->port != 443) { @@ -290,13 +311,17 @@ ngx_http_header_filter(ngx_http_request_ #endif { len += sizeof("Location: http://") - 1 - + r->server_name.len + + host.len + r->headers_out.location->value.len + 2; if (clcf->port_in_redirect && r->port != 80) { len += r->port_text->len; } } + + } else { + host.len = 0; + host.data = NULL; } if (r->chunked) { @@ -322,6 +347,12 @@ ngx_http_header_filter(ngx_http_request_ len += sizeof("Connection: closed" CRLF) - 1; } +#if (NGX_HTTP_GZIP) + if (r->gzip && clcf->gzip_vary) { + len += sizeof("Vary: Accept-Encoding" CRLF) - 1; + } +#endif + part = &r->headers_out.headers.part; header = part->elts; @@ -365,8 +396,16 @@ ngx_http_header_filter(ngx_http_request_ *b->last++ = CR; *b->last++ = LF; if (r->headers_out.server == NULL) { - b->last = ngx_cpymem(b->last, ngx_http_server_string, - sizeof(ngx_http_server_string) - 1); + if (clcf->server_tokens) { + p = (u_char *) ngx_http_server_full_string; + len = sizeof(ngx_http_server_full_string) - 1; + + } else { + p = (u_char *) ngx_http_server_string; + len = sizeof(ngx_http_server_string) - 1; + } + + b->last = ngx_cpymem(b->last, p, len); } if (r->headers_out.date == NULL) { @@ -418,10 +457,8 @@ ngx_http_header_filter(ngx_http_request_ *b->last++ = CR; *b->last++ = LF; } - if (r->headers_out.location - && r->headers_out.location->value.len - && r->headers_out.location->value.data[0] == '/') - { + if (host.data) { + p = b->last + sizeof("Location: ") - 1; b->last = ngx_cpymem(b->last, "Location: http", @@ -434,7 +471,7 @@ ngx_http_header_filter(ngx_http_request_ #endif *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/'; - b->last = ngx_copy(b->last, r->server_name.data, r->server_name.len); + b->last = ngx_copy(b->last, host.data, host.len); if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) @@ -485,6 +522,13 @@ ngx_http_header_filter(ngx_http_request_ sizeof("Connection: close" CRLF) - 1); } +#if (NGX_HTTP_GZIP) + if (r->gzip && clcf->gzip_vary) { + b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF, + sizeof("Vary: Accept-Encoding" CRLF) - 1); + } +#endif + part = &r->headers_out.headers.part; header = part->elts; @@ -505,16 +549,14 @@ ngx_http_header_filter(ngx_http_request_ } b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); - *b->last++ = ':' ; *b->last++ = ' ' ; + *b->last++ = ':'; *b->last++ = ' '; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = CR; *b->last++ = LF; } -#if (NGX_DEBUG) - *b->last = '\0'; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%s\n", b->pos); -#endif + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "%*s\n", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -124,6 +124,7 @@ ngx_http_parse_request_line(ngx_http_req sw_major_digit, sw_first_minor_digit, sw_minor_digit, + sw_spaces_after_digit, sw_almost_done } state; @@ -335,18 +336,26 @@ ngx_http_parse_request_line(ngx_http_req break; } + r->host_end = p; + switch (ch) { case ':': - r->host_end = p; state = sw_port; break; case '/': - r->host_end = p; r->uri_start = p; state = sw_after_slash_in_uri; break; + case ' ': + /* + * use single "/" from request line to preserve pointers, + * if request line will be copied to large client buffer + */ + r->uri_start = r->schema_end + 1; + r->uri_end = r->schema_end + 2; + state = sw_http_09; + break; default: - r->host_end = p; return NGX_HTTP_PARSE_INVALID_REQUEST; } break; @@ -362,6 +371,16 @@ ngx_http_parse_request_line(ngx_http_req r->uri_start = p; state = sw_after_slash_in_uri; break; + case ' ': + r->port_end = p; + /* + * use single "/" from request line to preserve pointers, + * if request line will be copied to large client buffer + */ + r->uri_start = r->schema_end + 1; + r->uri_end = r->schema_end + 2; + state = sw_http_09; + break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -618,6 +637,11 @@ ngx_http_parse_request_line(ngx_http_req goto done; } + if (ch == ' ') { + state = sw_spaces_after_digit; + break; + } + if (ch < '0' || ch > '9') { return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -625,6 +649,20 @@ ngx_http_parse_request_line(ngx_http_req r->http_minor = r->http_minor * 10 + ch - '0'; break; + case sw_spaces_after_digit: + switch (ch) { + case ' ': + break; + case CR: + state = sw_almost_done; + break; + case LF: + goto done; + default: + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; + /* end of request line */ case sw_almost_done: r->request_end = p - 1; @@ -737,7 +775,7 @@ ngx_http_parse_header_line(ngx_http_requ if (c) { hash = ngx_hash(hash, c); r->lowcase_header[i++] = c; - i &= ~NGX_HTTP_LC_HEADER_LEN; + i &= (NGX_HTTP_LC_HEADER_LEN - 1); break; } @@ -844,10 +882,10 @@ ngx_http_parse_header_line(ngx_http_requ /* end of header line */ case sw_almost_done: switch (ch) { + case LF: + goto done; case CR: break; - case LF: - goto done; default: return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -890,7 +928,7 @@ header_done: ngx_int_t -ngx_http_parse_complex_uri(ngx_http_request_t *r) +ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) { u_char c, ch, decoded, *p, *u; enum { @@ -998,8 +1036,12 @@ ngx_http_parse_complex_uri(ngx_http_requ switch(ch) { #if (NGX_WIN32) case '\\': + break; #endif case '/': + if (!merge_slashes) { + *u++ = ch; + } break; case '.': state = sw_dot; diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -11,7 +11,8 @@ static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -time_t ngx_http_parse_time(u_char *value, size_t len) +time_t +ngx_http_parse_time(u_char *value, size_t len) { u_char *p, *end; int day, month, year, hour, min, sec; @@ -239,7 +240,7 @@ time_t ngx_http_parse_time(u_char *value /* * shift new year to March 1 and start months from 1 (not 0), - * it is needed for Gauss's formula + * it is needed for Gauss' formula */ if (--month <= 0) { @@ -247,11 +248,20 @@ time_t ngx_http_parse_time(u_char *value year -= 1; } - /* Gauss's formula for Grigorian days from 1 March 1 BC */ + /* Gauss' formula for Grigorian days since March 1, 1 BC */ + + return ( + /* days in years including leap years since March 1, 1 BC */ + + 365 * year + year / 4 - year / 100 + year / 400 - return (365 * year + year / 4 - year / 100 + year / 400 - + 367 * month / 12 - 31 - + day + /* days before the month */ + + + 367 * month / 12 - 30 + + /* days before the day */ + + + day - 1 /* * 719527 days were between March 1, 1 BC and March 1, 1970, diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -168,7 +168,7 @@ ngx_http_postpone_filter_output_postpone pr = r->postponed; if (pr == NULL) { - return NGX_OK; + break; } if (pr->request) { @@ -196,7 +196,7 @@ ngx_http_postpone_filter_output_postpone } if (pr == NULL) { - return NGX_OK; + break; } out = pr->out; @@ -215,6 +215,17 @@ ngx_http_postpone_filter_output_postpone r->postponed = r->postponed->next; } + + if (r->out) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter out again \"%V?%V\"", + &r->uri, &r->args); + + r->connection->data = r; + return NGX_AGAIN; + } + + return NGX_OK; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -21,15 +21,20 @@ static ngx_int_t ngx_http_process_header ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); static void ngx_http_process_request(ngx_http_request_t *r); -static void ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, - size_t len, ngx_uint_t hash); +static ssize_t ngx_http_validate_host(u_char *host, size_t len); +static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r, + u_char *host, size_t len); static void ngx_http_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); @@ -69,18 +74,15 @@ static char *ngx_http_client_errors[] = ngx_http_header_t ngx_http_headers_in[] = { - { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), - ngx_http_process_unique_header_line }, - - { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), - ngx_http_process_connection }, + { ngx_string("Host"), 0, ngx_http_process_host }, + + { ngx_string("Connection"), 0, ngx_http_process_connection }, { ngx_string("If-Modified-Since"), offsetof(ngx_http_headers_in_t, if_modified_since), ngx_http_process_unique_header_line }, - { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), - ngx_http_process_header_line }, + { ngx_string("User-Agent"), 0, ngx_http_process_user_agent }, { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), ngx_http_process_header_line }, @@ -96,10 +98,18 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range), ngx_http_process_header_line }, + { ngx_string("If-Range"), + offsetof(ngx_http_headers_in_t, if_range), + ngx_http_process_unique_header_line }, + { ngx_string("Transfer-Encoding"), offsetof(ngx_http_headers_in_t, transfer_encoding), ngx_http_process_header_line }, + { ngx_string("Expect"), + offsetof(ngx_http_headers_in_t, expect), + ngx_http_process_unique_header_line }, + #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), offsetof(ngx_http_headers_in_t, accept_encoding), @@ -169,7 +179,7 @@ ngx_http_init_connection(ngx_connection_ return; } - ctx->client = &c->addr_text; + ctx->connection = c; ctx->request = NULL; ctx->current_request = NULL; @@ -216,9 +226,7 @@ static void ngx_http_init_request(ngx_event_t *rev) { ngx_time_t *tp; - socklen_t len; ngx_uint_t i; - struct sockaddr_in sin; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_in_port_t *hip; @@ -228,9 +236,6 @@ ngx_http_init_request(ngx_event_t *rev) ngx_http_core_srv_conf_t *cscf; ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; -#if (NGX_HTTP_SSL) - ngx_http_ssl_srv_conf_t *sscf; -#endif #if (NGX_STAT_STUB) ngx_atomic_fetch_add(ngx_stat_reading, -1); @@ -294,6 +299,8 @@ ngx_http_init_request(ngx_event_t *rev) i = 0; + r->connection = c; + if (hip->naddrs > 1) { /* @@ -301,7 +308,7 @@ ngx_http_init_request(ngx_event_t *rev) * is the "*:port" wildcard so getsockname() is needed to determine * the server address. * - * AcceptEx() already gave this address. + * AcceptEx() already has given this address. */ #if (NGX_WIN32) @@ -312,15 +319,10 @@ ngx_http_init_request(ngx_event_t *rev) } else #endif { - len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { - ngx_connection_error(c, ngx_socket_errno, - "getsockname() failed"); + if (ngx_http_server_addr(r, NULL) != NGX_OK) { ngx_http_close_connection(c); return; } - - r->in_addr = sin.sin_addr.s_addr; } /* the last address is "*" */ @@ -344,12 +346,13 @@ ngx_http_init_request(ngx_event_t *rev) r->srv_conf = cscf->ctx->srv_conf; r->loc_conf = cscf->ctx->loc_conf; - r->server_name = cscf->server_name; - rev->handler = ngx_http_process_request_line; #if (NGX_HTTP_SSL) + { + ngx_http_ssl_srv_conf_t *sscf; + sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->enable) { @@ -366,6 +369,7 @@ ngx_http_init_request(ngx_event_t *rev) r->main_filter_need_in_memory = 1; } + } #endif @@ -421,8 +425,6 @@ ngx_http_init_request(ngx_event_t *rev) c->single_connection = 1; c->destroyed = 0; - r->connection = c; - r->main = r; tp = ngx_timeofday(); @@ -483,6 +485,15 @@ ngx_http_ssl_handshake(ngx_event_t *rev) n = recv(c->fd, (char *) buf, 1, MSG_PEEK); if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { + + if (!rev->timer_set) { + ngx_add_timer(rev, c->listening->post_accept_timeout); + } + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + return; } @@ -494,6 +505,11 @@ ngx_http_ssl_handshake(ngx_event_t *rev) rc = ngx_ssl_handshake(c); if (rc == NGX_AGAIN) { + + if (!rev->timer_set) { + ngx_add_timer(rev, c->listening->post_accept_timeout); + } + c->ssl->handler = ngx_http_ssl_handshake_handler; return; } @@ -552,8 +568,6 @@ ngx_http_ssl_handshake_handler(ngx_conne int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { - u_char *p; - ngx_uint_t hash; const char *servername; ngx_connection_t *c; ngx_http_request_t *r; @@ -572,21 +586,13 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * r = c->data; - if (r->virtual_names == NULL) { + if (ngx_http_find_virtual_server(r, (u_char *) servername, + ngx_strlen(servername)) + != NGX_OK) + { return SSL_TLSEXT_ERR_NOACK; } - /* it seems browsers send low case server name */ - - hash = 0; - - for (p = (u_char *) servername; *p; p++) { - hash = ngx_hash(hash, *p); - } - - ngx_http_find_virtual_server(r, (u_char *) servername, - p - (u_char *) servername, hash); - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx); @@ -602,10 +608,11 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * static void ngx_http_process_request_line(ngx_event_t *rev) { - ssize_t n; - ngx_int_t rc, rv; - ngx_connection_t *c; - ngx_http_request_t *r; + ssize_t n; + ngx_int_t rc, rv; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_core_srv_conf_t *cscf; c = rev->data; r = c->data; @@ -640,6 +647,7 @@ ngx_http_process_request_line(ngx_event_ r->request_line.len = r->request_end - r->request_start; r->request_line.data = r->request_start; + *r->request_end = '\0'; if (r->args_start) { @@ -651,13 +659,15 @@ ngx_http_process_request_line(ngx_event_ if (r->complex_uri || r->quoted_uri) { - r->uri.data = ngx_palloc(r->pool, r->uri.len + 1); + r->uri.data = ngx_pnalloc(r->pool, r->uri.len + 1); if (r->uri.data == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } - rc = ngx_http_parse_complex_uri(r); + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + rc = ngx_http_parse_complex_uri(r, cscf->merge_slashes); if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) { ngx_log_error(NGX_LOG_INFO, c->log, 0, @@ -713,7 +723,31 @@ ngx_http_process_request_line(ngx_event_ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http exten: \"%V\"", &r->exten); + if (r->host_start && r->host_end) { + n = ngx_http_validate_host(r->host_start, + r->host_end - r->host_start); + + if (n <= 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid host in request line"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; + } + + r->headers_in.server.len = n; + r->headers_in.server.data = r->host_start; + } + if (r->http_version < NGX_HTTP_VERSION_10) { + + if (ngx_http_find_virtual_server(r, r->headers_in.server.data, + r->headers_in.server.len) + == NGX_ERROR) + { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + ngx_http_process_request(r); return; } @@ -785,7 +819,6 @@ ngx_http_process_request_headers(ngx_eve ssize_t n; ngx_int_t rc, rv; ngx_str_t header; - ngx_uint_t i; ngx_table_elt_t *h; ngx_connection_t *c; ngx_http_header_t *hh; @@ -885,7 +918,7 @@ ngx_http_process_request_headers(ngx_eve h->value.data = r->header_start; h->value.data[h->value.len] = '\0'; - h->lowcase_key = ngx_palloc(r->pool, h->key.len); + h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -895,9 +928,7 @@ ngx_http_process_request_headers(ngx_eve ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { - for (i = 0; i < h->key.len; i++) { - h->lowcase_key[i] = ngx_tolower(h->key.data[i]); - } + ngx_strlow(h->lowcase_key, h->key.data, h->key.len); } hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, @@ -981,10 +1012,9 @@ ngx_http_read_request_header(ngx_http_re } if (n == NGX_AGAIN) { - if (!r->header_timeout_set) { + if (!rev->timer_set) { cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ngx_add_timer(rev, cscf->client_header_timeout); - r->header_timeout_set = 1; } if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { @@ -1147,6 +1177,10 @@ ngx_http_alloc_large_header_buffer(ngx_h r->args_start = new + (r->args_start - old); } + if (r->http_protocol.data) { + r->http_protocol.data = new + (r->http_protocol.data - old); + } + } else { r->header_name_start = new; r->header_name_end = new + (r->header_name_end - old); @@ -1201,13 +1235,43 @@ ngx_http_process_unique_header_line(ngx_ static ngx_int_t +ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ssize_t len; + + if (r->headers_in.host == NULL) { + r->headers_in.host = h; + } + + len = ngx_http_validate_host(h->value.data, h->value.len); + + if (len <= 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid host header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + if (r->headers_in.server.len) { + return NGX_OK; + } + + r->headers_in.server.len = len; + r->headers_in.server.data = h->value.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - if (ngx_strstr(h->value.data, "close")) { + if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; - } else if (ngx_strstr(h->value.data, "keep-alive")) { + } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) { r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; } @@ -1216,6 +1280,60 @@ ngx_http_process_connection(ngx_http_req static ngx_int_t +ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + u_char *ua, *user_agent; + + if (r->headers_in.user_agent) { + return NGX_OK; + } + + r->headers_in.user_agent = h; + + /* check some widespread browsers while the header is in CPU cache */ + + user_agent = h->value.data; + + ua = ngx_strstrn(user_agent, "MSIE", 4 - 1); + + if (ua && ua + 8 < user_agent + h->value.len) { + + r->headers_in.msie = 1; + + if (ua[4] == ' ' && ua[5] == '4' && ua[6] == '.') { + r->headers_in.msie4 = 1; + } + +#if 0 + /* MSIE ignores the SSL "close notify" alert */ + if (c->ssl) { + c->ssl->no_send_shutdown = 1; + } +#endif + } + + if (ngx_strstrn(user_agent, "Opera", 5 - 1)) { + r->headers_in.opera = 1; + r->headers_in.msie = 0; + r->headers_in.msie4 = 0; + } + + if (!r->headers_in.msie && !r->headers_in.opera) { + + if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { + r->headers_in.gecko = 1; + + } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { + r->headers_in.konqueror = 1; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { @@ -1236,57 +1354,19 @@ ngx_http_process_cookie(ngx_http_request static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) { - size_t len; - u_char *host, *ua, *user_agent, ch; - ngx_uint_t hash; - - if (r->headers_in.host) { - - hash = 0; - - for (len = 0; len < r->headers_in.host->value.len; len++) { - ch = r->headers_in.host->value.data[len]; - - if (ch == ':') { - break; - } - - ch = ngx_tolower(ch); - r->headers_in.host->value.data[len] = ch; - hash = ngx_hash(hash, ch); - } - - if (len && r->headers_in.host->value.data[len - 1] == '.') { - len--; - hash = ngx_hash_key(r->headers_in.host->value.data, len); - } - - r->headers_in.host_name_len = len; - - if (r->virtual_names) { - - host = r->host_start; - - if (host == NULL) { - host = r->headers_in.host->value.data; - len = r->headers_in.host_name_len; - - } else { - len = r->host_end - host; - } - - ngx_http_find_virtual_server(r, host, len, hash); - } - - } else { - if (r->http_version > NGX_HTTP_VERSION_10) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP/1.1 request without \"Host\" header"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return NGX_ERROR; - } - - r->headers_in.host_name_len = 0; + if (ngx_http_find_virtual_server(r, r->headers_in.server.data, + r->headers_in.server.len) + == NGX_ERROR) + { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/1.1 request without \"Host\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; } if (r->headers_in.content_length) { @@ -1306,7 +1386,8 @@ ngx_http_process_request_header(ngx_http && r->headers_in.content_length_n == -1) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent POST method without \"Content-Length\" header"); + "client sent %V method without \"Content-Length\" header", + &r->method_name); ngx_http_finalize_request(r, NGX_HTTP_LENGTH_REQUIRED); return NGX_ERROR; } @@ -1319,7 +1400,8 @@ ngx_http_process_request_header(ngx_http } if (r->headers_in.transfer_encoding - && ngx_strstr(r->headers_in.transfer_encoding->value.data, "chunked")) + && ngx_strcasestrn(r->headers_in.transfer_encoding->value.data, + "chunked", 7 - 1)) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent \"Transfer-Encoding: chunked\" header"); @@ -1327,13 +1409,6 @@ ngx_http_process_request_header(ngx_http return NGX_ERROR; } - if (r->plain_http) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent plain HTTP request to HTTPS port"); - ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); - return NGX_ERROR; - } - if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) { if (r->headers_in.keep_alive) { r->headers_in.keep_alive_n = @@ -1342,50 +1417,6 @@ ngx_http_process_request_header(ngx_http } } - if (r->headers_in.user_agent) { - - /* - * check some widespread browsers while the headers are still - * in CPU cache - */ - - user_agent = r->headers_in.user_agent->value.data; - - ua = (u_char *) ngx_strstr(user_agent, "MSIE"); - - if (ua && ua + 8 < user_agent + r->headers_in.user_agent->value.len) { - - r->headers_in.msie = 1; - - if (ua[4] == ' ' && ua[5] == '4' && ua[6] == '.') { - r->headers_in.msie4 = 1; - } - -#if 0 - /* MSIE ignores the SSL "close notify" alert */ - if (c->ssl) { - c->ssl->no_send_shutdown = 1; - } -#endif - } - - if (ngx_strstr(user_agent, "Opera")) { - r->headers_in.opera = 1; - r->headers_in.msie = 0; - r->headers_in.msie4 = 0; - } - - if (!r->headers_in.msie && !r->headers_in.opera) { - - if (ngx_strstr(user_agent, "Gecko/")) { - r->headers_in.gecko = 1; - - } else if (ngx_strstr(user_agent, "Konqueror")) { - r->headers_in.konqueror = 1; - } - } - } - return NGX_OK; } @@ -1393,38 +1424,55 @@ ngx_http_process_request_header(ngx_http static void ngx_http_process_request(ngx_http_request_t *r) { - ngx_connection_t *c; -#if (NGX_HTTP_SSL) - long rc; - ngx_http_ssl_srv_conf_t *sscf; -#endif + ngx_connection_t *c; c = r->connection; + if (r->plain_http) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent plain HTTP request to HTTPS port"); + ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); + return; + } + #if (NGX_HTTP_SSL) if (c->ssl) { + long rc; + X509 *cert; + ngx_http_ssl_srv_conf_t *sscf; + sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->verify) { + if (sscf->verify == 1) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client SSL certificate verify error: (%l:%s)", rc, X509_verify_cert_error_string(rc)); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, + (SSL_get0_session(c->ssl->connection))); + ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); return; } - if (SSL_get_peer_certificate(c->ssl->connection) - == NULL) - { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, + (SSL_get0_session(c->ssl->connection))); + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); return; } + + X509_free(cert); } } @@ -1451,20 +1499,80 @@ ngx_http_process_request(ngx_http_reques } -static void -ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, - ngx_uint_t hash) +static ssize_t +ngx_http_validate_host(u_char *host, size_t len) { + u_char ch; + size_t i, last; + ngx_uint_t dot; + + last = len; + dot = 0; + + for (i = 0; i < len; i++) { + ch = host[i]; + + if (ch == '.') { + if (dot) { + return -1; + } + + dot = 1; + continue; + } + + dot = 0; + + if (ch == ':') { + last = i; + continue; + } + + if (ch == '/' || ch == '\0') { + return -1; + } + +#if (NGX_WIN32) + if (ch == '\\') { + return -1; + } +#endif + } + + if (dot) { + last--; + } + + return last; +} + + +static ngx_int_t +ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len) +{ + u_char *server; + ngx_uint_t hash; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; -#if (NGX_PCRE) - ngx_int_t n; - ngx_uint_t i; - ngx_str_t name; - ngx_http_server_name_t *sn; -#endif - - cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, host, len); + u_char buf[32]; + + if (len == 0 || r->virtual_names == NULL) { + return NGX_DECLINED; + } + + if (len <= 32) { + server = buf; + + } else { + server = ngx_pnalloc(r->pool, len); + if (server == NULL) { + return NGX_ERROR; + } + } + + hash = ngx_hash_strlow(server, host, len); + + cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len); if (cscf) { goto found; @@ -1473,9 +1581,13 @@ ngx_http_find_virtual_server(ngx_http_re #if (NGX_PCRE) if (r->virtual_names->nregex) { + ngx_int_t n; + ngx_uint_t i; + ngx_str_t name; + ngx_http_server_name_t *sn; name.len = len; - name.data = host; + name.data = server; sn = r->virtual_names->regex; @@ -1492,7 +1604,7 @@ ngx_http_find_virtual_server(ngx_http_re ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", n, &name, &sn[i].name); - return; + return NGX_ERROR; } /* match */ @@ -1505,20 +1617,10 @@ ngx_http_find_virtual_server(ngx_http_re #endif - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - if (cscf->wildcard) { - r->server_name.len = len; - r->server_name.data = host; - } - - return; + return NGX_OK; found: - r->server_name.len = len; - r->server_name.data = host; - r->srv_conf = cscf->ctx->srv_conf; r->loc_conf = cscf->ctx->loc_conf; @@ -1529,7 +1631,7 @@ found: r->connection->log->log_level = clcf->err_log->log_level; } - return; + return NGX_OK; } @@ -1585,7 +1687,11 @@ ngx_http_finalize_request(ngx_http_reque rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc); } - if (rc == NGX_ERROR || rc == NGX_HTTP_REQUEST_TIME_OUT || c->error) { + if (rc == NGX_ERROR + || rc == NGX_HTTP_REQUEST_TIME_OUT + || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST + || c->error) + { if (rc > 0 && r->headers_out.status == 0) { r->headers_out.status = rc; } @@ -1667,8 +1773,8 @@ ngx_http_finalize_request(ngx_http_reque } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http fast subrequest: \"%V?%V\" done", - &r->uri, &r->args); + "http fast subrequest: \"%V?%V\" done", + &r->uri, &r->args); return; } @@ -1723,7 +1829,7 @@ ngx_http_finalize_request(ngx_http_reque if (!ngx_terminate && !ngx_exiting - && r->keepalive != 0 + && r->keepalive && clcf->keepalive_timeout > 0) { ngx_http_set_keepalive(r); @@ -2044,7 +2150,8 @@ ngx_http_set_keepalive(ngx_http_request_ hc->pipeline = 1; c->log->action = "reading client pipelined request line"; - ngx_http_init_request(rev); + rev->handler = ngx_http_init_request; + ngx_post_event(rev, &ngx_posted_events); return; } @@ -2083,7 +2190,7 @@ ngx_http_set_keepalive(ngx_http_request_ if (hc->free) { for (i = 0; i < hc->nfree; i++) { - ngx_pfree(c->pool, hc->free[i]); + ngx_pfree(c->pool, hc->free[i]->start); hc->free[i] = NULL; } @@ -2095,13 +2202,19 @@ ngx_http_set_keepalive(ngx_http_request_ if (hc->busy) { for (i = 0; i < hc->nbusy; i++) { - ngx_pfree(c->pool, hc->busy[i]); + ngx_pfree(c->pool, hc->busy[i]->start); hc->busy[i] = NULL; } hc->nbusy = 0; } +#if (NGX_HTTP_SSL) + if (c->ssl) { + ngx_ssl_free_buffer(c); + } +#endif + rev->handler = ngx_http_keepalive_handler; if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { @@ -2154,7 +2267,7 @@ ngx_http_set_keepalive(ngx_http_request_ c->idle = 1; if (rev->ready) { - ngx_http_keepalive_handler(rev); + ngx_post_event(rev, &ngx_posted_events); } } @@ -2333,7 +2446,7 @@ ngx_http_lingering_close_handler(ngx_eve return; } - timer = r->lingering_time - ngx_time(); + timer = (ngx_msec_t) (r->lingering_time - ngx_time()); if (timer <= 0) { ngx_http_close_request(r, 0); return; @@ -2433,7 +2546,12 @@ ngx_http_post_action(ngx_http_request_t r->read_event_handler = ngx_http_block_reading; - ngx_http_internal_redirect(r, &clcf->post_action, NULL); + if (clcf->post_action.data[0] == '/') { + ngx_http_internal_redirect(r, &clcf->post_action, NULL); + + } else { + ngx_http_named_location(r, &clcf->post_action); + } return NGX_OK; } @@ -2494,6 +2612,8 @@ ngx_http_request_done(ngx_http_request_t r->headers_out.status = error; } + log->action = "logging request"; + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts; @@ -2502,6 +2622,8 @@ ngx_http_request_done(ngx_http_request_t log_handler[i](r); } + log->action = "closing request"; + if (r->connection->timedout) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -2578,13 +2700,17 @@ ngx_http_log_error(ngx_log_t *log, u_cha ctx = log->data; - p = ngx_snprintf(buf, len, ", client: %V", ctx->client); + p = ngx_snprintf(buf, len, ", client: %V", &ctx->connection->addr_text); len -= p - buf; r = ctx->request; if (r) { return r->log_handler(r, ctx->current_request, p, len); + + } else { + p = ngx_snprintf(p, len, ", server: %V", + &ctx->connection->listening->addr_text); } return p; @@ -2595,38 +2721,32 @@ static u_char * ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, u_char *buf, size_t len) { - char *uri_separator; - u_char *p; - ngx_http_upstream_t *u; - - if (r->server_name.data) { - p = ngx_snprintf(buf, len, ", server: %V", &r->server_name); - len -= p - buf; - buf = p; + char *uri_separator; + u_char *p; + ngx_http_upstream_t *u; + ngx_http_core_srv_conf_t *cscf; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + p = ngx_snprintf(buf, len, ", server: %V", &cscf->server_name); + len -= p - buf; + buf = p; + + if (r->request_line.data == NULL && r->request_start) { + for (p = r->request_start; p < r->header_in->last; p++) { + if (*p == CR || *p == LF) { + break; + } + } + + r->request_line.len = p - r->request_start; + r->request_line.data = r->request_start; } - if (r->unparsed_uri.data) { - p = ngx_snprintf(buf, len, ", URL: \"%V\"", &r->unparsed_uri); + if (r->request_line.len) { + p = ngx_snprintf(buf, len, ", request: \"%V\"", &r->request_line); len -= p - buf; buf = p; - - } else { - if (r->request_line.data == NULL && r->request_start) { - for (p = r->request_start; p < r->header_in->last; p++) { - if (*p == CR || *p == LF) { - break; - } - } - - r->request_line.len = p - r->request_start; - r->request_line.data = r->request_start; - } - - if (r->request_line.len) { - p = ngx_snprintf(buf, len, ", request: \"%V\"", &r->request_line); - len -= p - buf; - buf = p; - } } if (r != sr) { @@ -2648,7 +2768,7 @@ ngx_http_log_error_handler(ngx_http_requ #endif p = ngx_snprintf(buf, len, ", upstream: \"%V%V%s%V\"", - &u->conf->schema, u->peer.name, + &u->schema, u->peer.name, uri_separator, &u->uri); len -= p - buf; buf = p; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -168,8 +168,10 @@ typedef struct { ngx_table_elt_t *content_type; ngx_table_elt_t *range; + ngx_table_elt_t *if_range; ngx_table_elt_t *transfer_encoding; + ngx_table_elt_t *expect; #if (NGX_HTTP_GZIP) ngx_table_elt_t *accept_encoding; @@ -205,7 +207,7 @@ typedef struct { ngx_array_t cookies; - size_t host_name_len; + ngx_str_t server; off_t content_length_n; time_t keep_alive_n; @@ -229,6 +231,7 @@ typedef struct { ngx_table_elt_t *content_length; ngx_table_elt_t *content_encoding; ngx_table_elt_t *location; + ngx_table_elt_t *refresh; ngx_table_elt_t *last_modified; ngx_table_elt_t *content_range; ngx_table_elt_t *accept_ranges; @@ -241,6 +244,8 @@ typedef struct { size_t content_type_len; ngx_str_t content_type; ngx_str_t charset; + u_char *content_type_lowcase; + ngx_uint_t content_type_hash; ngx_array_t cache_control; @@ -371,7 +376,6 @@ struct ngx_http_request_s { uint32_t in_addr; ngx_uint_t port; ngx_str_t *port_text; /* ":80" */ - ngx_str_t server_name; ngx_http_virtual_names_t *virtual_names; ngx_int_t phase_handler; @@ -426,7 +430,7 @@ struct ngx_http_request_s { unsigned fast_subrequest:1; unsigned subrequest_in_memory:1; - unsigned header_timeout_set:1; + unsigned gzip:2; unsigned proxy:1; unsigned bypass_cache:1; @@ -449,7 +453,7 @@ struct ngx_http_request_s { unsigned limit_zone_set:1; #if 0 - unsigned cachable:1; + unsigned cacheable:1; #endif unsigned pipeline:1; @@ -466,6 +470,8 @@ struct ngx_http_request_s { unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; + unsigned expect_tested:1; + unsigned root_tested:1; unsigned done:1; unsigned utf8:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -442,7 +442,7 @@ ngx_http_discard_request_body(ngx_http_r ngx_del_timer(rev); } - if (r->headers_in.content_length_n <= 0) { + if (r->headers_in.content_length_n <= 0 || r->request_body) { return NGX_OK; } @@ -493,7 +493,7 @@ ngx_http_read_discarded_request_body_han } if (r->lingering_time) { - timer = r->lingering_time - ngx_time(); + timer = (ngx_msec_t) (r->lingering_time - ngx_time()); if (timer <= 0) { r->discard_body = 0; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -221,6 +221,14 @@ ngx_http_script_compile(ngx_http_script_ sc->args = 1; sc->compile_args = 0; + code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) ngx_http_script_mark_args_code; + code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main); if (code == NULL) { @@ -314,7 +322,7 @@ ngx_http_script_run(ngx_http_request_t * cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); for (i = 0; i < cmcf->variables.nelts; i++) { - if (r->variables[i].no_cachable) { + if (r->variables[i].no_cacheable) { r->variables[i].valid = 0; r->variables[i].not_found = 0; } @@ -333,7 +341,7 @@ ngx_http_script_run(ngx_http_request_t * value->len = len; - value->data = ngx_palloc(r->pool, len); + value->data = ngx_pnalloc(r->pool, len); if (value->data == NULL) { return NULL; } @@ -351,7 +359,7 @@ ngx_http_script_run(ngx_http_request_t * void -ngx_http_script_flush_no_cachable_variables(ngx_http_request_t *r, +ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r, ngx_array_t *indices) { ngx_uint_t n, *index; @@ -359,7 +367,7 @@ ngx_http_script_flush_no_cachable_variab if (indices) { index = indices->elts; for (n = 0; n < indices->nelts; n++) { - if (r->variables[index[n]].no_cachable) { + if (r->variables[index[n]].no_cacheable) { r->variables[index[n]].valid = 0; r->variables[index[n]].not_found = 0; } @@ -504,7 +512,7 @@ ngx_http_script_copy_capture_len_code(ng e->ip += sizeof(ngx_http_script_copy_capture_code_t); if (code->n < e->ncaptures) { - if ((e->args || e->quote) + if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) { return e->captures[code->n + 1] - e->captures[code->n] @@ -531,7 +539,7 @@ ngx_http_script_copy_capture_code(ngx_ht e->ip += sizeof(ngx_http_script_copy_capture_code_t); if (code->n < e->ncaptures) { - if ((e->args || e->quote) + if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) { e->pos = (u_char *) ngx_escape_uri(e->pos, @@ -550,6 +558,16 @@ ngx_http_script_copy_capture_code(ngx_ht } +size_t +ngx_http_script_mark_args_code(ngx_http_script_engine_t *e) +{ + e->is_args = 1; + e->ip += sizeof(uintptr_t); + + return 1; +} + + void ngx_http_script_start_args_code(ngx_http_script_engine_t *e) { @@ -700,7 +718,7 @@ ngx_http_script_regex_start_code(ngx_htt le.ncaptures = e->ncaptures; le.quote = code->redirect; - len = 1; /* reserve 1 byte for possible "?" */ + len = 0; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; @@ -708,13 +726,14 @@ ngx_http_script_regex_start_code(ngx_htt } e->buf.len = len; + e->is_args = le.is_args; } if (code->add_args && r->args.len) { e->buf.len += r->args.len + 1; } - e->buf.data = ngx_palloc(r->pool, e->buf.len); + e->buf.data = ngx_pnalloc(r->pool, e->buf.len); if (e->buf.data == NULL) { e->ip = ngx_http_script_exit; e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -750,7 +769,8 @@ ngx_http_script_regex_end_code(ngx_http_ dst = e->buf.data; src = e->buf.data; - ngx_unescape_uri(&dst, &src, e->pos - e->buf.data, NGX_UNESCAPE_URI); + ngx_unescape_uri(&dst, &src, e->pos - e->buf.data, + NGX_UNESCAPE_REDIRECT); if (src < e->pos) { dst = ngx_copy(dst, src, e->pos - src); @@ -974,13 +994,16 @@ ngx_http_script_file_code(ngx_http_scrip clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) - == NGX_ERROR) + != NGX_OK) { if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, @@ -993,69 +1016,69 @@ ngx_http_script_file_code(ngx_http_scrip case ngx_http_script_file_dir: case ngx_http_script_file_exists: case ngx_http_script_file_exec: - goto false; + goto false_value; case ngx_http_script_file_not_plain: case ngx_http_script_file_not_dir: case ngx_http_script_file_not_exists: case ngx_http_script_file_not_exec: - goto true; + goto true_value; } - goto false; + goto false_value; } switch (code->op) { case ngx_http_script_file_plain: if (of.is_file) { - goto true; + goto true_value; } - goto false; + goto false_value; case ngx_http_script_file_not_plain: if (of.is_file) { - goto false; + goto false_value; } - goto true; + goto true_value; case ngx_http_script_file_dir: if (of.is_dir) { - goto true; + goto true_value; } - goto false; + goto false_value; case ngx_http_script_file_not_dir: if (of.is_dir) { - goto false; + goto false_value; } - goto true; + goto true_value; case ngx_http_script_file_exists: if (of.is_file || of.is_dir || of.is_link) { - goto true; + goto true_value; } - goto false; + goto false_value; case ngx_http_script_file_not_exists: if (of.is_file || of.is_dir || of.is_link) { - goto false; + goto false_value; } - goto true; + goto true_value; case ngx_http_script_file_exec: if (of.is_exec) { - goto true; + goto true_value; } - goto false; + goto false_value; case ngx_http_script_file_not_exec: if (of.is_exec) { - goto false; + goto false_value; } - goto true; + goto true_value; } -false: +false_value: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http script file op false"); @@ -1063,7 +1086,7 @@ false: *value = ngx_http_variable_null_value; return; -true: +true_value: *value = ngx_http_variable_true_value; return; @@ -1099,7 +1122,7 @@ ngx_http_script_complex_value_code(ngx_h } e->buf.len = len; - e->buf.data = ngx_palloc(e->request->pool, len); + e->buf.data = ngx_pnalloc(e->request->pool, len); if (e->buf.data == NULL) { e->ip = ngx_http_script_exit; e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1127,7 +1150,7 @@ ngx_http_script_value_code(ngx_http_scri e->sp->data = (u_char *) code->text_data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http script value: \"%V\"", e->sp); + "http script value: \"%v\"", e->sp); e->sp++; } @@ -1152,7 +1175,7 @@ ngx_http_script_set_var_code(ngx_http_sc r->variables[code->index].len = e->sp->len; r->variables[code->index].valid = 1; - r->variables[code->index].no_cachable = 0; + r->variables[code->index].no_cacheable = 0; r->variables[code->index].not_found = 0; r->variables[code->index].data = e->sp->data; } diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -27,6 +27,7 @@ typedef struct { unsigned flushed:1; unsigned skip:1; unsigned quote:1; + unsigned is_args:1; unsigned log:1; int *captures; @@ -181,7 +182,7 @@ ngx_uint_t ngx_http_script_variables_cou ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, void *code_lengths, size_t reserved, void *code_values); -void ngx_http_script_flush_no_cachable_variables(ngx_http_request_t *r, +void ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r, ngx_array_t *indices); void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, @@ -194,6 +195,7 @@ size_t ngx_http_script_copy_var_len_code void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e); size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e); +size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e); void ngx_http_script_start_args_code(ngx_http_script_engine_t *e); #if (NGX_PCRE) void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e); diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -10,13 +10,27 @@ #include -static u_char error_tail[] = +static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, + ngx_http_err_page_t *err_page); +static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_uint_t err); +static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r); + + +static u_char ngx_http_error_full_tail[] = "
" NGINX_VER "
" CRLF "" CRLF "" CRLF ; +static u_char ngx_http_error_tail[] = +"
nginx
" CRLF +"" CRLF +"" CRLF +; + + static u_char ngx_http_msie_stub[] = "" CRLF "" CRLF @@ -35,7 +49,7 @@ static u_char ngx_http_msie_refresh_tail "\">" CRLF; -static char error_301_page[] = +static char ngx_http_error_301_page[] = "" CRLF "301 Moved Permanently" CRLF "" CRLF @@ -43,7 +57,7 @@ static char error_301_page[] = ; -static char error_302_page[] = +static char ngx_http_error_302_page[] = "" CRLF "302 Found" CRLF "" CRLF @@ -51,7 +65,7 @@ static char error_302_page[] = ; -static char error_400_page[] = +static char ngx_http_error_400_page[] = "" CRLF "400 Bad Request" CRLF "" CRLF @@ -59,7 +73,7 @@ static char error_400_page[] = ; -static char error_401_page[] = +static char ngx_http_error_401_page[] = "" CRLF "401 Authorization Required" CRLF "" CRLF @@ -67,7 +81,7 @@ static char error_401_page[] = ; -static char error_402_page[] = +static char ngx_http_error_402_page[] = "" CRLF "402 Payment Required" CRLF "" CRLF @@ -75,7 +89,7 @@ static char error_402_page[] = ; -static char error_403_page[] = +static char ngx_http_error_403_page[] = "" CRLF "403 Forbidden" CRLF "" CRLF @@ -83,7 +97,7 @@ static char error_403_page[] = ; -static char error_404_page[] = +static char ngx_http_error_404_page[] = "" CRLF "404 Not Found" CRLF "" CRLF @@ -91,7 +105,7 @@ static char error_404_page[] = ; -static char error_405_page[] = +static char ngx_http_error_405_page[] = "" CRLF "405 Not Allowed" CRLF "" CRLF @@ -99,7 +113,7 @@ static char error_405_page[] = ; -static char error_406_page[] = +static char ngx_http_error_406_page[] = "" CRLF "406 Not Acceptable" CRLF "" CRLF @@ -107,7 +121,7 @@ static char error_406_page[] = ; -static char error_408_page[] = +static char ngx_http_error_408_page[] = "" CRLF "408 Request Time-out" CRLF "" CRLF @@ -115,7 +129,7 @@ static char error_408_page[] = ; -static char error_409_page[] = +static char ngx_http_error_409_page[] = "" CRLF "409 Conflict" CRLF "" CRLF @@ -123,7 +137,7 @@ static char error_409_page[] = ; -static char error_410_page[] = +static char ngx_http_error_410_page[] = "" CRLF "410 Gone" CRLF "" CRLF @@ -131,7 +145,7 @@ static char error_410_page[] = ; -static char error_411_page[] = +static char ngx_http_error_411_page[] = "" CRLF "411 Length Required" CRLF "" CRLF @@ -139,7 +153,7 @@ static char error_411_page[] = ; -static char error_412_page[] = +static char ngx_http_error_412_page[] = "" CRLF "412 Precondition Failed" CRLF "" CRLF @@ -147,7 +161,7 @@ static char error_412_page[] = ; -static char error_413_page[] = +static char ngx_http_error_413_page[] = "" CRLF "413 Request Entity Too Large" CRLF "" CRLF @@ -155,7 +169,7 @@ static char error_413_page[] = ; -static char error_414_page[] = +static char ngx_http_error_414_page[] = "" CRLF "414 Request-URI Too Large" CRLF "" CRLF @@ -163,7 +177,7 @@ static char error_414_page[] = ; -static char error_415_page[] = +static char ngx_http_error_415_page[] = "" CRLF "415 Unsupported Media Type" CRLF "" CRLF @@ -171,7 +185,7 @@ static char error_415_page[] = ; -static char error_416_page[] = +static char ngx_http_error_416_page[] = "" CRLF "416 Requested Range Not Satisfiable" CRLF "" CRLF @@ -179,7 +193,7 @@ static char error_416_page[] = ; -static char error_495_page[] = +static char ngx_http_error_495_page[] = "" CRLF "400 The SSL certificate error" CRLF @@ -189,7 +203,7 @@ CRLF ; -static char error_496_page[] = +static char ngx_http_error_496_page[] = "" CRLF "400 No required SSL certificate was sent" CRLF @@ -199,7 +213,7 @@ CRLF ; -static char error_497_page[] = +static char ngx_http_error_497_page[] = "" CRLF "400 The plain HTTP request was sent to HTTPS port" CRLF @@ -209,7 +223,7 @@ CRLF ; -static char error_500_page[] = +static char ngx_http_error_500_page[] = "" CRLF "500 Internal Server Error" CRLF "" CRLF @@ -217,7 +231,7 @@ static char error_500_page[] = ; -static char error_501_page[] = +static char ngx_http_error_501_page[] = "" CRLF "501 Method Not Implemented" CRLF "" CRLF @@ -225,7 +239,7 @@ static char error_501_page[] = ; -static char error_502_page[] = +static char ngx_http_error_502_page[] = "" CRLF "502 Bad Gateway" CRLF "" CRLF @@ -233,7 +247,7 @@ static char error_502_page[] = ; -static char error_503_page[] = +static char ngx_http_error_503_page[] = "" CRLF "503 Service Temporarily Unavailable" CRLF "" CRLF @@ -241,7 +255,7 @@ static char error_503_page[] = ; -static char error_504_page[] = +static char ngx_http_error_504_page[] = "" CRLF "504 Gateway Time-out" CRLF "" CRLF @@ -249,7 +263,7 @@ static char error_504_page[] = ; -static char error_507_page[] = +static char ngx_http_error_507_page[] = "" CRLF "507 Insufficient Storage" CRLF "" CRLF @@ -257,53 +271,53 @@ static char error_507_page[] = ; -static ngx_str_t error_pages[] = { +static ngx_str_t ngx_http_error_pages[] = { - ngx_null_string, /* 201, 204 */ + ngx_null_string, /* 201, 204 */ #define NGX_HTTP_LEVEL_200 1 - /* ngx_null_string, */ /* 300 */ - ngx_string(error_301_page), - ngx_string(error_302_page), - ngx_null_string, /* 303 */ + /* ngx_null_string, */ /* 300 */ + ngx_string(ngx_http_error_301_page), + ngx_string(ngx_http_error_302_page), + ngx_null_string, /* 303 */ #define NGX_HTTP_LEVEL_300 3 - ngx_string(error_400_page), - ngx_string(error_401_page), - ngx_string(error_402_page), - ngx_string(error_403_page), - ngx_string(error_404_page), - ngx_string(error_405_page), - ngx_string(error_406_page), - ngx_null_string, /* 407 */ - ngx_string(error_408_page), - ngx_string(error_409_page), - ngx_string(error_410_page), - ngx_string(error_411_page), - ngx_string(error_412_page), - ngx_string(error_413_page), - ngx_string(error_414_page), - ngx_string(error_415_page), - ngx_string(error_416_page), + ngx_string(ngx_http_error_400_page), + ngx_string(ngx_http_error_401_page), + ngx_string(ngx_http_error_402_page), + ngx_string(ngx_http_error_403_page), + ngx_string(ngx_http_error_404_page), + ngx_string(ngx_http_error_405_page), + ngx_string(ngx_http_error_406_page), + ngx_null_string, /* 407 */ + ngx_string(ngx_http_error_408_page), + ngx_string(ngx_http_error_409_page), + ngx_string(ngx_http_error_410_page), + ngx_string(ngx_http_error_411_page), + ngx_string(ngx_http_error_412_page), + ngx_string(ngx_http_error_413_page), + ngx_string(ngx_http_error_414_page), + ngx_string(ngx_http_error_415_page), + ngx_string(ngx_http_error_416_page), #define NGX_HTTP_LEVEL_400 17 - ngx_string(error_495_page), /* 495, https certificate error */ - ngx_string(error_496_page), /* 496, https no certificate */ - ngx_string(error_497_page), /* 497, http to https */ - ngx_string(error_404_page), /* 498, invalid host name */ - ngx_null_string, /* 499, client had closed connection */ + 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 */ + ngx_string(ngx_http_error_404_page), /* 498, canceled */ + ngx_null_string, /* 499, client has closed connection */ - ngx_string(error_500_page), - ngx_string(error_501_page), - ngx_string(error_502_page), - ngx_string(error_503_page), - ngx_string(error_504_page), - ngx_null_string, /* 505 */ - ngx_null_string, /* 506 */ - ngx_string(error_507_page) + ngx_string(ngx_http_error_500_page), + ngx_string(ngx_http_error_501_page), + ngx_string(ngx_http_error_502_page), + ngx_string(ngx_http_error_503_page), + ngx_string(ngx_http_error_504_page), + ngx_null_string, /* 505 */ + ngx_null_string, /* 506 */ + ngx_string(ngx_http_error_507_page) }; @@ -313,19 +327,14 @@ static ngx_str_t ngx_http_get_name = { ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) { - u_char *p; - size_t msie_refresh; - uintptr_t escape; ngx_int_t rc; - ngx_buf_t *b; - ngx_str_t *uri, *location; - ngx_uint_t i, n, err, msie_padding; - ngx_chain_t *out, *cl; + ngx_uint_t i, err; ngx_http_err_page_t *err_page; ngx_http_core_loc_conf_t *clcf; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http special response: %d, \"%V\"", error, &r->uri); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http special response: %d, \"%V?%V\"", + error, &r->uri, &r->args); rc = ngx_http_discard_request_body(r); @@ -335,7 +344,7 @@ ngx_http_special_response_handler(ngx_ht r->err_status = error; - if (r->keepalive != 0) { + if (r->keepalive) { switch (error) { case NGX_HTTP_BAD_REQUEST: case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE: @@ -371,68 +380,20 @@ ngx_http_special_response_handler(ngx_ht err_page = clcf->error_pages->elts; for (i = 0; i < clcf->error_pages->nelts; i++) { - if (err_page[i].status == error) { - r->err_status = err_page[i].overwrite; - - r->method = NGX_HTTP_GET; - r->method_name = ngx_http_get_name; - - uri = &err_page[i].uri; - - if (err_page[i].uri_lengths) { - if (ngx_http_script_run(r, uri, - err_page[i].uri_lengths->elts, 0, - err_page[i].uri_values->elts) - == NULL) - { - return NGX_ERROR; - } - - if (r->zero_in_uri) { - for (n = 0; n < uri->len; n++) { - if (uri->data[n] == '\0') { - goto zero; - } - } - - r->zero_in_uri = 0; - } - - } else { - r->zero_in_uri = 0; - } - - zero: - - if (uri->data[0] == '/') { - return ngx_http_internal_redirect(r, uri, NULL); - } - - if (uri->data[0] == '@') { - return ngx_http_named_location(r, uri); - } - - r->headers_out.location = - ngx_list_push(&r->headers_out.headers); - - if (r->headers_out.location) { - error = NGX_HTTP_MOVED_TEMPORARILY; - - r->err_status = NGX_HTTP_MOVED_TEMPORARILY; - - r->headers_out.location->hash = 1; - r->headers_out.location->key.len = sizeof("Location") - 1; - r->headers_out.location->key.data = (u_char *) "Location"; - r->headers_out.location->value = *uri; - - } else { - return NGX_ERROR; - } + return ngx_http_send_error_page(r, &err_page[i]); } } } + if (clcf->msie_refresh + && r->headers_in.msie + && (error == NGX_HTTP_MOVED_PERMANENTLY + || error == NGX_HTTP_MOVED_TEMPORARILY)) + { + return ngx_http_send_refresh(r); + } + if (error == NGX_HTTP_CREATED) { /* 201 */ err = 0; @@ -461,29 +422,151 @@ ngx_http_special_response_handler(ngx_ht case NGX_HTTPS_CERT_ERROR: case NGX_HTTPS_NO_CERT: r->err_status = NGX_HTTP_BAD_REQUEST; - error = NGX_HTTP_BAD_REQUEST; break; } } + return ngx_http_send_special_response(r, clcf, err); +} + + +static ngx_int_t +ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) +{ + u_char ch, *p, *last; + ngx_str_t *uri, *args, u, a; + ngx_table_elt_t *location; + ngx_http_core_loc_conf_t *clcf; + + r->err_status = err_page->overwrite; + + r->zero_in_uri = 0; + + if (err_page->uri_lengths) { + if (ngx_http_script_run(r, &u, err_page->uri_lengths->elts, 0, + err_page->uri_values->elts) + == NULL) + { + return NGX_ERROR; + } + + p = u.data; + uri = &u; + args = NULL; + + if (*p == '/') { + + last = p + uri->len; + + while (p < last) { + + ch = *p++; + + if (ch == '?') { + a.len = last - p; + a.data = p; + args = &a; + + u.len = p - 1 - u.data; + + while (p < last) { + if (*p++ == '\0') { + r->zero_in_uri = 1; + break; + } + } + + break; + } + + if (ch == '\0') { + r->zero_in_uri = 1; + continue; + } + } + } + + } else { + uri = &err_page->uri; + args = &err_page->args; + } + + if (uri->data[0] == '/') { + + r->method = NGX_HTTP_GET; + r->method_name = ngx_http_get_name; + + return ngx_http_internal_redirect(r, uri, args); + } + + if (uri->data[0] == '@') { + return ngx_http_named_location(r, uri); + } + + location = ngx_list_push(&r->headers_out.headers); + + if (location == NULL) { + return NGX_ERROR; + } + + r->err_status = NGX_HTTP_MOVED_TEMPORARILY; + + location->hash = 1; + location->key.len = sizeof("Location") - 1; + location->key.data = (u_char *) "Location"; + location->value = *uri; + + r->headers_out.location = location; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->msie_refresh && r->headers_in.msie) { + return ngx_http_send_refresh(r); + } + + return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY + - NGX_HTTP_MOVED_PERMANENTLY + + NGX_HTTP_LEVEL_200); +} + + +static ngx_int_t +ngx_http_send_special_response(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_uint_t err) +{ + u_char *tail; + size_t len; + ngx_int_t rc; + ngx_buf_t *b; + ngx_uint_t msie_padding; + ngx_chain_t out[3]; + + if (clcf->server_tokens) { + len = sizeof(ngx_http_error_full_tail) - 1; + tail = ngx_http_error_full_tail; + + } else { + len = sizeof(ngx_http_error_tail) - 1; + tail = ngx_http_error_tail; + } + msie_padding = 0; if (!r->zero_body) { - if (error_pages[err].len) { - r->headers_out.content_length_n = error_pages[err].len - + sizeof(error_tail) - 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->http_version >= NGX_HTTP_VERSION_10 - && error >= NGX_HTTP_BAD_REQUEST - && error != NGX_HTTP_REQUEST_URI_TOO_LARGE) + && err >= NGX_HTTP_LEVEL_300) { r->headers_out.content_length_n += sizeof(ngx_http_msie_stub) - 1; msie_padding = 1; } + r->headers_out.content_type_len = sizeof("text/html") - 1; r->headers_out.content_type.len = sizeof("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; @@ -501,31 +584,102 @@ ngx_http_special_response_handler(ngx_ht r->headers_out.content_length = NULL; } - if (clcf->msie_refresh - && r->headers_in.msie - && (error == NGX_HTTP_MOVED_PERMANENTLY - || error == NGX_HTTP_MOVED_TEMPORARILY)) - { + ngx_http_clear_accept_ranges(r); + ngx_http_clear_last_modified(r); + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || r->header_only) { + return rc; + } + + if (ngx_http_error_pages[err].len == 0) { + return NGX_OK; + } + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = ngx_http_error_pages[err].data; + b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len; - location = &r->headers_out.location->value; + out[0].buf = b; + out[0].next = &out[1]; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + + b->pos = tail; + b->last = tail + len; - escape = 2 * ngx_escape_uri(NULL, location->data, location->len, - NGX_ESCAPE_REFRESH); + out[1].buf = b; + out[1].next = NULL; + + if (msie_padding) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = ngx_http_msie_stub; + b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; - msie_refresh = sizeof(ngx_http_msie_refresh_head) - 1 - + escape + location->len - + sizeof(ngx_http_msie_refresh_tail) - 1; + out[1].next = &out[2]; + out[2].buf = b; + out[2].next = NULL; + } + + if (r == r->main) { + b->last_buf = 1; + } + + b->last_in_chain = 1; + + return ngx_http_output_filter(r, &out[0]); +} + - r->err_status = NGX_HTTP_OK; - r->headers_out.content_type_len = sizeof("text/html") - 1; - r->headers_out.content_length_n = msie_refresh; - r->headers_out.location->hash = 0; - r->headers_out.location = NULL; +static ngx_int_t +ngx_http_send_refresh(ngx_http_request_t *r) +{ + u_char *p, *location; + size_t len, size; + uintptr_t escape; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + + len = r->headers_out.location->value.len; + location = r->headers_out.location->value.data; + + escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH); - } else { - location = NULL; - escape = 0; - msie_refresh = 0; + size = sizeof(ngx_http_msie_refresh_head) - 1 + + escape + len + + sizeof(ngx_http_msie_refresh_tail) - 1; + + 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"; + + r->headers_out.location->hash = 0; + r->headers_out.location = NULL; + + r->headers_out.content_length_n = size; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; } ngx_http_clear_accept_ranges(r); @@ -537,103 +691,29 @@ ngx_http_special_response_handler(ngx_ht return rc; } - - if (msie_refresh == 0) { - - if (error_pages[err].len == 0) { - return NGX_OK; - } - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = error_pages[err].data; - b->last = error_pages[err].data + error_pages[err].len; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - out = cl; - - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_ERROR; + } - b->memory = 1; - b->pos = error_tail; - b->last = error_tail + sizeof(error_tail) - 1; - - cl->next = ngx_alloc_chain_link(r->pool); - if (cl->next == NULL) { - return NGX_ERROR; - } - - cl = cl->next; - cl->buf = b; + p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, + sizeof(ngx_http_msie_refresh_head) - 1); - if (msie_padding) { - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = ngx_http_msie_stub; - b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; - - cl->next = ngx_alloc_chain_link(r->pool); - if (cl->next == NULL) { - return NGX_ERROR; - } - - cl = cl->next; - cl->buf = b; - } + if (escape == 0) { + p = ngx_cpymem(p, location, len); } else { - b = ngx_create_temp_buf(r->pool, msie_refresh); - if (b == NULL) { - return NGX_ERROR; - } - - p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, - sizeof(ngx_http_msie_refresh_head) - 1); - - if (escape == 0) { - p = ngx_cpymem(p, location->data, location->len); - - } else { - p = (u_char *) ngx_escape_uri(p, location->data, location->len, - NGX_ESCAPE_REFRESH); - } - - b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, - sizeof(ngx_http_msie_refresh_tail) - 1); - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - out = cl; + p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH); } - if (r == r->main) { - b->last_buf = 1; - } + b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, + sizeof(ngx_http_msie_refresh_tail) - 1); + b->last_buf = 1; b->last_in_chain = 1; - cl->next = NULL; + out.buf = b; + out.next = NULL; - return ngx_http_output_filter(r, out); + return ngx_http_output_filter(r, &out); } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -9,6 +9,7 @@ #include +static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx); static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r); static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, @@ -136,7 +137,8 @@ ngx_http_upstream_header_t ngx_http_ups ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("Location"), - ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, location), ngx_http_upstream_rewrite_location, 0, 0 }, { ngx_string("Refresh"), @@ -283,10 +285,15 @@ static ngx_http_variable_t ngx_http_ups void ngx_http_upstream_init(ngx_http_request_t *r) { - ngx_connection_t *c; - ngx_http_cleanup_t *cln; - ngx_http_upstream_t *u; - ngx_http_core_loc_conf_t *clcf; + ngx_str_t *host; + ngx_uint_t i; + ngx_connection_t *c; + ngx_resolver_ctx_t *ctx, temp; + ngx_http_cleanup_t *cln; + ngx_http_upstream_t *u; + ngx_http_core_loc_conf_t *clcf; + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; c = r->connection; @@ -320,11 +327,6 @@ ngx_http_upstream_init(ngx_http_request_ u->request_bufs = r->request_body->bufs; } - if (u->conf->upstream->peer.init(r, u->conf->upstream) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - if (u->create_request(r) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -332,7 +334,6 @@ ngx_http_upstream_init(ngx_http_request_ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - u->output.sendfile = r->connection->sendfile; u->output.pool = r->pool; u->output.bufs.num = 1; u->output.bufs.size = clcf->client_body_buffer_size; @@ -374,11 +375,129 @@ ngx_http_upstream_init(ngx_http_request_ u->store = (u->conf->store || u->conf->store_lengths); + if (u->resolved == NULL) { + + uscf = u->conf->upstream; + + } else { + + host = &u->resolved->host; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->default_port) + || uscf->port == u->resolved->port) + && ngx_memcmp(uscf->host.data, host->data, host->len) == 0) + { + goto found; + } + } + + temp.name = *host; + + ctx = ngx_resolve_start(clcf->resolver, &temp); + if (ctx == NULL) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + if (ctx == NGX_NO_RESOLVER) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no resolver defined to resolve %V", host); + + ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY); + return; + } + + ctx->name = *host; + ctx->type = NGX_RESOLVE_A; + ctx->handler = ngx_http_upstream_resolve_handler; + ctx->data = r; + ctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = ctx; + + if (ngx_resolve_name(ctx) != NGX_OK) { + u->resolved->ctx = NULL; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + +found: + + if (uscf->peer.init(r, uscf) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + ngx_http_upstream_connect(r, u); } static void +ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) +{ + ngx_http_request_t *r; + ngx_http_upstream_resolved_t *ur; + + r = ctx->data; + + r->upstream->resolved->ctx = NULL; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "%V could not be resolved (%i: %s)", + &ctx->name, ctx->state, + ngx_resolver_strerror(ctx->state)); + + ngx_resolve_name_done(ctx); + ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY); + return; + } + + ur = r->upstream->resolved; + ur->naddrs = ctx->naddrs; + ur->addrs = ctx->addrs; + +#if (NGX_DEBUG) + { + in_addr_t addr; + ngx_uint_t i; + + for (i = 0; i < ctx->naddrs; i++) { + addr = ntohl(ur->addrs[i]); + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "name was resolved to %ud.%ud.%ud.%ud", + (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); + } + } +#endif + + if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) { + ngx_resolve_name_done(ctx); + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_resolve_name_done(ctx); + + ngx_http_upstream_connect(r, r->upstream); +} + + +static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r) { ngx_http_upstream_check_broken_connection(r, r->connection->read); @@ -434,7 +553,7 @@ ngx_http_upstream_check_broken_connectio ev->error = 1; } - if (!u->cachable && !u->store && u->peer.connection) { + if (!u->cacheable && !u->store && u->peer.connection) { ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, "kevent() reported that client closed prematurely " "connection, so upstream connection is closed too"); @@ -500,7 +619,7 @@ ngx_http_upstream_check_broken_connectio ev->eof = 1; c->error = 1; - if (!u->cachable && !u->store && u->peer.connection) { + if (!u->cacheable && !u->store && u->peer.connection) { ngx_log_error(NGX_LOG_INFO, ev->log, err, "client closed prematurely connection, " "so upstream connection is closed too"); @@ -584,6 +703,7 @@ ngx_http_upstream_connect(ngx_http_reque c->read->handler = ngx_http_upstream_process_header; c->sendfile &= r->connection->sendfile; + u->output.sendfile = c->sendfile; c->pool = r->pool; c->read->log = c->write->log = c->log = r->connection->log; @@ -638,7 +758,7 @@ ngx_http_upstream_connect(ngx_http_reque #if (NGX_HTTP_SSL) - if (u->conf->ssl && c->ssl == NULL) { + if (u->ssl && c->ssl == NULL) { ngx_http_upstream_ssl_init_connection(r, u, c); return; } @@ -725,10 +845,9 @@ ngx_http_upstream_reinit(ngx_http_reques return NGX_ERROR; } - ngx_memzero(&r->upstream->headers_in, - sizeof(ngx_http_upstream_headers_in_t)); - - if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, + ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); + + if (ngx_list_init(&u->headers_in.headers, r->pool, 8, sizeof(ngx_table_elt_t)) != NGX_OK) { @@ -893,7 +1012,7 @@ ngx_http_upstream_send_request_handler(n #if (NGX_HTTP_SSL) - if (u->conf->ssl && c->ssl == NULL) { + if (u->ssl && c->ssl == NULL) { ngx_http_upstream_ssl_init_connection(r, u, c); return; } @@ -963,7 +1082,7 @@ ngx_http_upstream_process_header(ngx_eve u->buffer.tag = u->output.tag; - if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, + if (ngx_list_init(&u->headers_in.headers, r->pool, 8, sizeof(ngx_table_elt_t)) != NGX_OK) { @@ -980,8 +1099,7 @@ ngx_http_upstream_process_header(ngx_eve #endif } - n = u->peer.connection->recv(u->peer.connection, u->buffer.last, - u->buffer.end - u->buffer.last); + n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last); if (n == NGX_AGAIN) { #if 0 @@ -1044,7 +1162,7 @@ ngx_http_upstream_process_header(ngx_eve return; } - if (rc == NGX_ERROR || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { + if (rc == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -1133,11 +1251,11 @@ ngx_http_upstream_process_header(ngx_eve umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); - if (r->upstream->headers_in.x_accel_redirect) { + if (u->headers_in.x_accel_redirect) { ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); - part = &r->upstream->headers_in.headers.part; + part = &u->headers_in.headers.part; h = part->elts; for (i = 0; /* void */; i++) { @@ -1164,7 +1282,7 @@ ngx_http_upstream_process_header(ngx_eve } } - uri = &r->upstream->headers_in.x_accel_redirect->value; + uri = &u->headers_in.x_accel_redirect->value; args.len = 0; args.data = NULL; flags = 0; @@ -1186,7 +1304,7 @@ ngx_http_upstream_process_header(ngx_eve return; } - part = &r->upstream->headers_in.headers.part; + part = &u->headers_in.headers.part; h = part->elts; for (i = 0; /* void */; i++) { @@ -1238,6 +1356,8 @@ ngx_http_upstream_process_header(ngx_eve r->headers_out.status = u->headers_in.status_n; r->headers_out.status_line = u->headers_in.status_line; + u->headers_in.content_length_n = r->headers_out.content_length_n; + if (r->headers_out.content_length_n != -1) { u->length = (size_t) r->headers_out.content_length_n; @@ -1514,7 +1634,7 @@ ngx_http_upstream_send_response(ngx_http } } - if (u->cachable) { + if (u->cacheable) { header = (ngx_http_cache_header_t *) u->buffer->start; header->expires = u->cache->ctx.expires; @@ -1542,7 +1662,7 @@ ngx_http_upstream_send_response(ngx_http p->pool = r->pool; p->log = c->log; - p->cachable = u->cachable || u->store; + p->cacheable = u->cacheable || u->store; p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (p->temp_file == NULL) { @@ -1555,7 +1675,7 @@ ngx_http_upstream_send_response(ngx_http p->temp_file->path = u->conf->temp_path; p->temp_file->pool = r->pool; - if (u->cachable || u->store) { + if (u->cacheable || u->store) { p->temp_file->persistent = 1; } else { @@ -1579,7 +1699,7 @@ ngx_http_upstream_send_response(ngx_http p->preread_size = u->buffer.last - u->buffer.pos; - if (u->cachable) { + if (u->cacheable) { p->buf_to_file = ngx_calloc_buf(r->pool); if (p->buf_to_file == NULL) { @@ -1820,6 +1940,7 @@ ngx_http_upstream_non_buffered_filter(vo cl->buf->pos = b->last; b->last += bytes; cl->buf->last = b->last; + cl->buf->tag = u->output.tag; if (u->length == NGX_MAX_SIZE_T_VALUE) { return NGX_OK; @@ -1841,6 +1962,7 @@ ngx_http_upstream_process_downstream(ngx static void ngx_http_upstream_process_body(ngx_event_t *ev) { + ngx_temp_file_t *tf; ngx_event_pipe_t *p; ngx_connection_t *c, *downstream; ngx_http_log_ctx_t *ctx; @@ -1935,18 +2057,22 @@ ngx_http_upstream_process_body(ngx_event if (u->store) { - if (p->upstream_eof && u->headers_in.status_n == NGX_HTTP_OK) { - + tf = u->pipe->temp_file; + + if (p->upstream_eof + && u->headers_in.status_n == NGX_HTTP_OK + && (u->headers_in.content_length_n == -1 + || (u->headers_in.content_length_n == tf->offset))) + { ngx_http_upstream_store(r, u); } else if ((p->upstream_error || (p->upstream_eof && u->headers_in.status_n != NGX_HTTP_OK)) - && u->pipe->temp_file->file.fd != NGX_INVALID_FILE) + && tf->file.fd != NGX_INVALID_FILE) { - if (ngx_delete_file(u->pipe->temp_file->file.name.data) - == NGX_FILE_ERROR) - { + if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", u->pipe->temp_file->file.name.data); @@ -1956,14 +2082,14 @@ ngx_http_upstream_process_body(ngx_event #if (NGX_HTTP_FILE_CACHE) - if (p->upstream_done && u->cachable) { + if (p->upstream_done && u->cacheable) { if (ngx_http_cache_update(r) == NGX_ERROR) { ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); ngx_http_upstream_finalize_request(r, u, 0); return; } - } else if (p->upstream_eof && u->cachable) { + } else if (p->upstream_eof && u->cacheable) { /* TODO: check length & update cache */ @@ -1991,7 +2117,7 @@ ngx_http_upstream_process_body(ngx_event ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream downstream error"); - if (!u->cachable && u->peer.connection) { + if (!u->cacheable && u->peer.connection) { ngx_http_upstream_finalize_request(r, u, 0); } } @@ -2001,15 +2127,15 @@ ngx_http_upstream_process_body(ngx_event static void ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u) { - char *failed; - u_char *name; - size_t root; - time_t lm; - ngx_err_t err; - ngx_str_t *temp, path, *last_modified; - ngx_temp_file_t *tf; - - if (u->pipe->temp_file->file.fd == NGX_INVALID_FILE) { + size_t root; + time_t lm; + ngx_str_t path; + ngx_temp_file_t *tf; + ngx_ext_rename_file_t ext; + + tf = u->pipe->temp_file; + + if (tf->file.fd == NGX_INVALID_FILE) { /* create file for empty 200 response */ @@ -2034,38 +2160,20 @@ ngx_http_upstream_store(ngx_http_request u->pipe->temp_file = tf; } - temp = &u->pipe->temp_file->file.name; - -#if !(NGX_WIN32) - - if (ngx_change_file_access(temp->data, u->conf->store_access) - == NGX_FILE_ERROR) - { - err = ngx_errno; - failed = ngx_change_file_access_n; - name = temp->data; - - goto failed; - } - -#endif - - if (r->upstream->headers_in.last_modified) { - - last_modified = &r->upstream->headers_in.last_modified->value; - - lm = ngx_http_parse_time(last_modified->data, last_modified->len); + ext.access = u->conf->store_access; + ext.time = -1; + ext.create_path = 1; + ext.delete_file = 1; + ext.log = r->connection->log; + + if (u->headers_in.last_modified) { + + lm = ngx_http_parse_time(u->headers_in.last_modified->value.data, + u->headers_in.last_modified->value.len); if (lm != NGX_ERROR) { - if (ngx_set_file_time(temp->data, u->pipe->temp_file->file.fd, lm) - != NGX_OK) - { - err = ngx_errno; - failed = ngx_set_file_time_n; - name = temp->data; - - goto failed; - } + ext.time = lm; + ext.fd = tf->file.fd; } } @@ -2083,55 +2191,10 @@ ngx_http_upstream_store(ngx_http_request } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "upstream stores \"%s\" to \"%s\"", temp->data, path.data); - - failed = ngx_rename_file_n; - name = path.data; - - if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { - return; - } - - err = ngx_errno; - - if (err == NGX_ENOENT) { - - err = ngx_create_full_path(path.data, - ngx_dir_access(u->conf->store_access)); - if (err == 0) { - if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { - return; - } - - err = ngx_errno; - } - } - -#if (NGX_WIN32) - - if (err == NGX_EEXIST) { - if (ngx_win32_rename_file(temp, &path, r->pool) != NGX_ERROR) { - - if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { - return; - } - } - - err = ngx_errno; - } - -#endif - -failed: - - if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", - temp->data); - } - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - "%s \"%s\" failed", failed, name); + "upstream stores \"%s\" to \"%s\"", + tf->file.name.data, path.data); + + (void) ngx_ext_rename_file(&tf->file.name, &path, &ext); } @@ -2258,10 +2321,18 @@ ngx_http_upstream_cleanup(void *data) { ngx_http_request_t *r = data; + ngx_http_upstream_t *u; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "cleanup http upstream request: \"%V\"", &r->uri); - ngx_http_upstream_finalize_request(r, r->upstream, NGX_DONE); + u = r->upstream; + + if (u->resolved && u->resolved->ctx) { + ngx_resolve_name_done(u->resolved->ctx); + } + + ngx_http_upstream_finalize_request(r, u, NGX_DONE); } @@ -2276,7 +2347,7 @@ ngx_http_upstream_finalize_request(ngx_h *u->cleanup = NULL; - if (u->state->response_sec) { + if (u->state && u->state->response_sec) { tp = ngx_timeofday(); u->state->response_sec = tp->sec - u->state->response_sec; u->state->response_msec = tp->msec - u->state->response_msec; @@ -2284,7 +2355,9 @@ ngx_http_upstream_finalize_request(ngx_h u->finalize_request(r, rc); - u->peer.free(&u->peer, u->peer.data, 0); + if (u->peer.free) { + u->peer.free(&u->peer, u->peer.data, 0); + } if (u->peer.connection) { @@ -2541,6 +2614,10 @@ ngx_http_upstream_copy_content_type(ngx_ while (*++p == ' ') { /* void */ } + if (*p == '\0') { + return NGX_OK; + } + if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) { continue; } @@ -2610,6 +2687,10 @@ ngx_http_upstream_rewrite_location(ngx_h return rc; } + if (ho->value.data[0] != '/') { + r->headers_out.location = ho; + } + /* * we do not set r->headers_out.location here to avoid the handling * the local redirects without a host name by ngx_http_header_filter() @@ -2636,7 +2717,7 @@ ngx_http_upstream_rewrite_refresh(ngx_ht if (r->upstream->rewrite_redirect) { - p = (u_char *) ngx_strstr(ho->value.data, "url="); + p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1); if (p) { rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data); @@ -2649,16 +2730,18 @@ ngx_http_upstream_rewrite_refresh(ngx_ht return NGX_OK; } -#if (NGX_DEBUG) if (rc == NGX_OK) { + r->headers_out.refresh = ho; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "rewritten refresh: \"%V\"", &ho->value); } -#endif return rc; } + r->headers_out.refresh = ho; + return NGX_OK; } @@ -2715,7 +2798,7 @@ ngx_http_upstream_addr_variable(ngx_http ngx_http_upstream_state_t *state; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; if (r->upstream_states == NULL || r->upstream_states->nelts == 0) { @@ -2735,7 +2818,7 @@ ngx_http_upstream_addr_variable(ngx_http } } - p = ngx_palloc(r->pool, len); + p = ngx_pnalloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } @@ -2786,7 +2869,7 @@ ngx_http_upstream_status_variable(ngx_ht ngx_http_upstream_state_t *state; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; if (r->upstream_states == NULL || r->upstream_states->nelts == 0) { @@ -2796,7 +2879,7 @@ ngx_http_upstream_status_variable(ngx_ht len = r->upstream_states->nelts * (3 + 2); - p = ngx_palloc(r->pool, len); + p = ngx_pnalloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } @@ -2852,7 +2935,7 @@ ngx_http_upstream_response_time_variable ngx_http_upstream_state_t *state; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; if (r->upstream_states == NULL || r->upstream_states->nelts == 0) { @@ -2862,7 +2945,7 @@ ngx_http_upstream_response_time_variable len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2); - p = ngx_palloc(r->pool, len); + p = ngx_pnalloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } @@ -2874,7 +2957,8 @@ ngx_http_upstream_response_time_variable for ( ;; ) { if (state[i].status) { - ms = state[i].response_sec * 1000 + state[i].response_msec; + ms = (ngx_msec_int_t) + (state[i].response_sec * 1000 + state[i].response_msec); ms = (ms >= 0) ? ms : 0; p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000); @@ -3066,7 +3150,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, u.url = value[1]; u.default_port = 80; - if (ngx_parse_url(cf, &u) != NGX_OK) { + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in upstream \"%V\"", u.err, &u.url); @@ -3122,7 +3206,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, fail_timeout = ngx_parse_time(&s, 1); - if (fail_timeout < 0) { + if (fail_timeout == NGX_ERROR) { goto invalid; } @@ -3181,7 +3265,7 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) { - if (ngx_parse_url(cf, u) != NGX_OK) { + if (ngx_parse_url(cf->pool, u) != NGX_OK) { if (u->err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in upstream \"%V\"", u->err, &u->url); @@ -3281,6 +3365,113 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng } +ngx_int_t +ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, + ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, + ngx_str_t *default_hide_headers, ngx_hash_init_t *hash) +{ + ngx_str_t *h; + ngx_uint_t i, j; + ngx_array_t hide_headers; + ngx_hash_key_t *hk; + + if (conf->hide_headers == NGX_CONF_UNSET_PTR + && conf->pass_headers == NGX_CONF_UNSET_PTR) + { + conf->hide_headers_hash = prev->hide_headers_hash; + + if (conf->hide_headers_hash.buckets) { + return NGX_OK; + } + + conf->hide_headers = prev->hide_headers; + conf->pass_headers = prev->pass_headers; + + } else { + if (conf->hide_headers == NGX_CONF_UNSET_PTR) { + conf->hide_headers = prev->hide_headers; + } + + if (conf->pass_headers == NGX_CONF_UNSET_PTR) { + conf->pass_headers = prev->pass_headers; + } + } + + if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (h = default_hide_headers; h->len; h++) { + hk = ngx_array_push(&hide_headers); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *h; + hk->key_hash = ngx_hash_key_lc(h->data, h->len); + hk->value = (void *) 1; + } + + if (conf->hide_headers != NGX_CONF_UNSET_PTR) { + + h = conf->hide_headers->elts; + + for (i = 0; i < conf->hide_headers->nelts; i++) { + + hk = hide_headers.elts; + + for (j = 0; j < hide_headers.nelts; j++) { + if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) { + goto exist; + } + } + + hk = ngx_array_push(&hide_headers); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = h[i]; + hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len); + hk->value = (void *) 1; + + exist: + + continue; + } + } + + if (conf->pass_headers != NGX_CONF_UNSET_PTR) { + + h = conf->pass_headers->elts; + hk = hide_headers.elts; + + for (i = 0; i < conf->pass_headers->nelts; i++) { + for (j = 0; j < hide_headers.nelts; j++) { + + if (hk[j].key.data == NULL) { + continue; + } + + if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) { + hk[j].key.data = NULL; + break; + } + } + } + } + + hash->hash = &conf->hide_headers_hash; + hash->key = ngx_hash_key_lc; + hash->pool = cf->pool; + hash->temp_pool = NULL; + + return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts); +} + + static void * ngx_http_upstream_create_main_conf(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -138,9 +138,6 @@ typedef struct { ngx_array_t *pass_headers; ngx_str_t schema; - ngx_str_t uri; - ngx_str_t location; - ngx_str_t url; /* used in proxy_rewrite_location */ ngx_array_t *store_lengths; ngx_array_t *store_values; @@ -195,10 +192,22 @@ typedef struct { ngx_table_elt_t *content_encoding; #endif + off_t content_length_n; + ngx_array_t cache_control; } ngx_http_upstream_headers_in_t; +typedef struct { + ngx_str_t host; + in_port_t port; + ngx_uint_t default_port; /* unsigned default_port:1 */ + ngx_uint_t naddrs; + in_addr_t *addrs; + ngx_resolver_ctx_t *ctx; +} ngx_http_upstream_resolved_t; + + struct ngx_http_upstream_s { ngx_peer_connection_t peer; @@ -213,6 +222,8 @@ struct ngx_http_upstream_s { ngx_http_upstream_headers_in_t headers_in; + ngx_http_upstream_resolved_t *resolved; + ngx_buf_t buffer; size_t length; @@ -235,17 +246,18 @@ struct ngx_http_upstream_s { ngx_msec_t timeout; - ngx_str_t method; - ngx_http_upstream_state_t *state; + ngx_str_t method; + ngx_str_t schema; ngx_str_t uri; ngx_http_cleanup_pt *cleanup; unsigned store:1; - unsigned cachable:1; + unsigned cacheable:1; unsigned accel:1; + unsigned ssl:1; unsigned buffering:1; @@ -260,6 +272,9 @@ ngx_int_t ngx_http_upstream_header_varia void ngx_http_upstream_init(ngx_http_request_t *r); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); +ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, + ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, + ngx_str_t *default_hide_headers, ngx_hash_init_t *hash); #define ngx_http_conf_upstream_srv_conf(uscf, module) \ diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -9,7 +9,8 @@ #include -static int ngx_http_upstream_cmp_servers(const void *one, const void *two); +static ngx_int_t ngx_http_upstream_cmp_servers(const void *one, + const void *two); static ngx_uint_t ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers); @@ -145,7 +146,7 @@ ngx_http_upstream_init_round_robin(ngx_c u.host = us->host; u.port = (in_port_t) (us->port ? us->port : us->default_port); - if (ngx_inet_resolve_host(cf, &u) != NGX_OK) { + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%s in upstream \"%V\" in %s:%ui", @@ -167,17 +168,14 @@ ngx_http_upstream_init_round_robin(ngx_c peers->number = n; peers->name = &us->host; - n = 0; - for (i = 0; i < u.naddrs; i++) { - peers->peer[n].sockaddr = u.addrs[i].sockaddr; - peers->peer[n].socklen = u.addrs[i].socklen; - peers->peer[n].name = u.addrs[i].name; - peers->peer[n].weight = 1; - peers->peer[n].current_weight = 1; - peers->peer[n].max_fails = 1; - peers->peer[n].fail_timeout = 10; - n++; + peers->peer[i].sockaddr = u.addrs[i].sockaddr; + peers->peer[i].socklen = u.addrs[i].socklen; + peers->peer[i].name = u.addrs[i].name; + peers->peer[i].weight = 1; + peers->peer[i].current_weight = 1; + peers->peer[i].max_fails = 1; + peers->peer[i].fail_timeout = 10; } us->peer.data = peers; @@ -188,7 +186,7 @@ ngx_http_upstream_init_round_robin(ngx_c } -static int +static ngx_int_t ngx_http_upstream_cmp_servers(const void *one, const void *two) { ngx_http_upstream_rr_peer_t *first, *second; @@ -250,6 +248,100 @@ ngx_http_upstream_init_round_robin_peer( ngx_int_t +ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, + ngx_http_upstream_resolved_t *ur) +{ + u_char *p; + size_t len; + ngx_uint_t i, n; + struct sockaddr_in *sin; + ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_rr_peer_data_t *rrp; + + rrp = r->upstream->peer.data; + + if (rrp == NULL) { + rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t)); + if (rrp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = rrp; + } + + peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t) + + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1)); + if (peers == NULL) { + return NGX_ERROR; + } + + peers->single = (ur->naddrs == 1); + peers->number = ur->naddrs; + peers->name = &ur->host; + + for (i = 0; i < ur->naddrs; i++) { + + len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, INET_ADDRSTRLEN); + len = ngx_sprintf(&p[len], ":%d", ur->port) - p; + + sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NGX_ERROR; + } + + sin->sin_family = AF_INET; + sin->sin_port = htons(ur->port); + sin->sin_addr.s_addr = ur->addrs[i]; + + peers->peer[i].sockaddr = (struct sockaddr *) sin; + peers->peer[i].socklen = sizeof(struct sockaddr_in); + peers->peer[i].name.len = len; + peers->peer[i].name.data = p; + peers->peer[i].weight = 1; + peers->peer[i].current_weight = 1; + peers->peer[i].max_fails = 1; + peers->peer[i].fail_timeout = 10; + } + + rrp->peers = peers; + rrp->current = 0; + + if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { + rrp->tried = &rrp->data; + rrp->data = 0; + + } else { + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + + rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t)); + if (rrp->tried == NULL) { + return NGX_ERROR; + } + } + + r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; + r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; + r->upstream->peer.tries = rrp->peers->number; +#if (NGX_HTTP_SSL) + r->upstream->peer.set_session = + ngx_http_upstream_set_round_robin_peer_session; + r->upstream->peer.save_session = + ngx_http_upstream_save_round_robin_peer_session; +#endif + + return NGX_OK; +} + + +ngx_int_t ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) { ngx_http_upstream_rr_peer_data_t *rrp = data; @@ -514,13 +606,7 @@ ngx_http_upstream_get_peer(ngx_http_upst } for (i = 0; i < peers->number; i++) { - if (peer->max_fails == 0 || peer->fails < peer->max_fails) { - peer[i].current_weight += peer[i].weight; - - } else { - /* 1 allows to go to quick recovery when all peers failed */ - peer[i].current_weight = 1; - } + peer[i].current_weight = peer[i].weight; } } } diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -65,6 +65,8 @@ ngx_int_t ngx_http_upstream_init_round_r ngx_http_upstream_srv_conf_t *us); ngx_int_t ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us); +ngx_int_t ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, + ngx_http_upstream_resolved_t *ur); ngx_int_t ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data); void ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -26,6 +26,8 @@ static ngx_int_t ngx_http_variable_unkno ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -47,6 +49,8 @@ static ngx_int_t ngx_http_variable_docum ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r, @@ -73,6 +77,8 @@ static ngx_int_t ngx_http_variable_sent_ static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); /* * TODO: @@ -143,37 +149,36 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("uri"), NULL, ngx_http_variable_request, offsetof(ngx_http_request_t, uri), - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("document_uri"), NULL, ngx_http_variable_request, offsetof(ngx_http_request_t, uri), - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("request"), NULL, ngx_http_variable_request, offsetof(ngx_http_request_t, request_line), 0, 0 }, { ngx_string("document_root"), NULL, - ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHABLE, 0 }, + ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("query_string"), NULL, ngx_http_variable_request, offsetof(ngx_http_request_t, args), - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("args"), ngx_http_variable_request_set, ngx_http_variable_request, offsetof(ngx_http_request_t, args), - NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("is_args"), NULL, ngx_http_variable_is_args, - 0, NGX_HTTP_VAR_NOCACHABLE, 0 }, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("request_filename"), NULL, ngx_http_variable_request_filename, 0, - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_string("server_name"), NULL, ngx_http_variable_request, - offsetof(ngx_http_request_t, server_name), 0, 0 }, + { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 }, { ngx_string("request_method"), NULL, ngx_http_variable_request_method, 0, 0, 0 }, @@ -215,11 +220,14 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("limit_rate"), ngx_http_variable_request_set_size, ngx_http_variable_request, offsetof(ngx_http_request_t, limit_rate), - NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version, 0, 0, 0 }, + { ngx_string("hostname"), NULL, ngx_http_variable_hostname, + 0, 0, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -251,7 +259,7 @@ ngx_http_add_variable(ngx_conf_t *cf, ng v = key[i].value; - if (!(v->flags & NGX_HTTP_VAR_CHANGABLE)) { + if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the duplicate \"%V\" variable", name); return NULL; @@ -266,14 +274,12 @@ ngx_http_add_variable(ngx_conf_t *cf, ng } v->name.len = name->len; - v->name.data = ngx_palloc(cf->pool, name->len); + v->name.data = ngx_pnalloc(cf->pool, name->len); if (v->name.data == NULL) { return NULL; } - for (i = 0; i < name->len; i++) { - v->name.data[i] = ngx_tolower(name->data[i]); - } + ngx_strlow(v->name.data, name->data, name->len); v->set_handler = NULL; v->get_handler = NULL; @@ -333,14 +339,12 @@ ngx_http_get_variable_index(ngx_conf_t * } v->name.len = name->len; - v->name.data = ngx_palloc(cf->pool, name->len); + v->name.data = ngx_pnalloc(cf->pool, name->len); if (v->name.data == NULL) { return NGX_ERROR; } - for (i = 0; i < name->len; i++) { - v->name.data[i] = ngx_tolower(name->data[i]); - } + ngx_strlow(v->name.data, name->data, name->len); v->set_handler = NULL; v->get_handler = NULL; @@ -375,8 +379,8 @@ ngx_http_get_indexed_variable(ngx_http_r if (v[index].get_handler(r, &r->variables[index], v[index].data) == NGX_OK) { - if (v[index].flags & NGX_HTTP_VAR_NOCACHABLE) { - r->variables[index].no_cachable = 1; + if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) { + r->variables[index].no_cacheable = 1; } return &r->variables[index]; @@ -397,7 +401,7 @@ ngx_http_get_flushed_variable(ngx_http_r v = &r->variables[index]; if (v->valid) { - if (!v->no_cachable) { + if (!v->no_cacheable) { return v; } @@ -475,6 +479,15 @@ ngx_http_get_variable(ngx_http_request_t return NULL; } + if (ngx_strncmp(name->data, "arg_", 4) == 0) { + + if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) { + return vv; + } + + return NULL; + } + vv->not_found = 1; if (nowarn == 0) { @@ -497,7 +510,7 @@ ngx_http_variable_request(ngx_http_reque if (s->data) { v->len = s->len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = s->data; @@ -559,7 +572,7 @@ ngx_http_variable_header(ngx_http_reques if (h) { v->len = h->value.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = h->value.data; @@ -591,7 +604,7 @@ ngx_http_variable_headers(ngx_http_reque } v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; h = a->elts; @@ -609,7 +622,7 @@ ngx_http_variable_headers(ngx_http_reque len += h[i]->value.len + sizeof("; ") - 1; } - p = ngx_palloc(r->pool, len); + p = ngx_pnalloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } @@ -691,7 +704,7 @@ ngx_http_variable_unknown_header(ngx_htt if (n + prefix == var->len && n == header[i].key.len) { v->len = header[i].value.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = header[i].value.data; @@ -706,31 +719,80 @@ ngx_http_variable_unknown_header(ngx_htt static ngx_int_t +ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_str_t *name = (ngx_str_t *) data; + + u_char *p, *arg; + size_t len; + + if (r->args.len == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = name->len - 1 - (sizeof("arg_") - 1); + arg = name->data + sizeof("arg_") - 1; + + for (p = r->args.data; *p && *p != ' '; p++) { + + /* + * although r->args.data is not null-terminated by itself, + * however, there is null in the end of request line + */ + + p = ngx_strcasestrn(p, (char *) arg, len); + + if (p == NULL) { + v->not_found = 1; + return NGX_OK; + } + + if ((p == r->args.data || *(p - 1) == '&') && *(p + len + 1) == '=') { + + v->data = p + len + 2; + + p = (u_char *) ngx_strchr(p, '&'); + + if (p == NULL) { + p = r->args.data + r->args.len; + } + + v->len = p - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + } + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - if (r->host_start == NULL) { - - if (r->headers_in.host) { - v->len = r->headers_in.host_name_len; - v->data = r->headers_in.host->value.data; + ngx_http_core_srv_conf_t *cscf; - } else { - v->len = r->server_name.len; - v->data = r->server_name.data; - } - - } else if (r->host_end) { - v->len = r->host_end - r->host_start; - v->data = r->host_start; + if (r->headers_in.server.len) { + v->len = r->headers_in.server.len; + v->data = r->headers_in.server.data; } else { - v->not_found = 1; - return NGX_OK; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + v->len = cscf->server_name.len; + v->data = cscf->server_name.data; } v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; return NGX_OK; @@ -749,7 +811,7 @@ ngx_http_variable_binary_remote_addr(ngx v->len = sizeof(in_addr_t); v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) &sin->sin_addr.s_addr; @@ -763,7 +825,7 @@ ngx_http_variable_remote_addr(ngx_http_r { v->len = r->connection->addr_text.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->connection->addr_text.data; @@ -780,10 +842,10 @@ ngx_http_variable_remote_port(ngx_http_r v->len = 0; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; - v->data = ngx_palloc(r->pool, sizeof("65535") - 1); + v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1); if (v->data == NULL) { return NGX_ERROR; } @@ -808,32 +870,22 @@ static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - socklen_t len; - ngx_connection_t *c; - struct sockaddr_in sin; + ngx_str_t s; - v->data = ngx_palloc(r->pool, INET_ADDRSTRLEN); - if (v->data == NULL) { + s.data = ngx_pnalloc(r->pool, INET_ADDRSTRLEN); + if (s.data == NULL) { return NGX_ERROR; } - c = r->connection; - - if (r->in_addr == 0) { - len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { - ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); - return NGX_ERROR; - } - - r->in_addr = sin.sin_addr.s_addr; + if (ngx_http_server_addr(r, &s) != NGX_OK) { + return NGX_ERROR; } - v->len = ngx_inet_ntop(c->listening->family, &r->in_addr, - v->data, INET_ADDRSTRLEN); + v->len = s.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; + v->data = s.data; return NGX_OK; } @@ -845,7 +897,7 @@ ngx_http_variable_server_port(ngx_http_r { v->len = r->port_text->len - 1; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->port_text->data + 1; @@ -862,7 +914,7 @@ ngx_http_variable_scheme(ngx_http_reques if (r->connection->ssl) { v->len = sizeof("https") - 1; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) "https"; @@ -873,7 +925,7 @@ ngx_http_variable_scheme(ngx_http_reques v->len = sizeof("http") - 1; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) "http"; @@ -886,7 +938,7 @@ ngx_http_variable_is_args(ngx_http_reque ngx_http_variable_value_t *v, uintptr_t data) { v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; if (r->args.len == 0) { @@ -914,7 +966,7 @@ ngx_http_variable_document_root(ngx_http if (clcf->root_lengths == NULL) { v->len = clcf->root.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = clcf->root.data; @@ -934,7 +986,7 @@ ngx_http_variable_document_root(ngx_http v->len = path.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = path.data; } @@ -958,7 +1010,7 @@ ngx_http_variable_request_filename(ngx_h v->len = path.len - 1; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = path.data; @@ -967,13 +1019,31 @@ ngx_http_variable_request_filename(ngx_h static ngx_int_t +ngx_http_variable_server_name(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_core_srv_conf_t *cscf; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + v->len = cscf->server_name.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = cscf->server_name.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { if (r->main->method_name.data) { v->len = r->main->method_name.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->main->method_name.data; @@ -1004,7 +1074,7 @@ ngx_http_variable_remote_user(ngx_http_r v->len = r->headers_in.user.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->headers_in.user.data; @@ -1025,14 +1095,14 @@ ngx_http_variable_body_bytes_sent(ngx_ht sent = 0; } - p = ngx_palloc(r->pool, NGX_OFF_T_LEN); + p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { return NGX_ERROR; } v->len = ngx_sprintf(p, "%O", sent) - p; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = p; @@ -1047,7 +1117,7 @@ ngx_http_variable_sent_content_type(ngx_ if (r->headers_out.content_type.len) { v->len = r->headers_out.content_type.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->headers_out.content_type.data; @@ -1068,7 +1138,7 @@ ngx_http_variable_sent_content_length(ng if (r->headers_out.content_length) { v->len = r->headers_out.content_length->value.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->headers_out.content_length->value.data; @@ -1076,14 +1146,14 @@ ngx_http_variable_sent_content_length(ng } if (r->headers_out.content_length_n >= 0) { - p = ngx_palloc(r->pool, NGX_OFF_T_LEN); + p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { return NGX_ERROR; } v->len = ngx_sprintf(p, "%O", r->headers_out.content_length_n) - p; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = p; @@ -1105,7 +1175,7 @@ ngx_http_variable_sent_last_modified(ngx if (r->headers_out.last_modified) { v->len = r->headers_out.last_modified->value.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->headers_out.last_modified->value.data; @@ -1113,7 +1183,7 @@ ngx_http_variable_sent_last_modified(ngx } if (r->headers_out.last_modified_time >= 0) { - p = ngx_palloc(r->pool, + p = ngx_pnalloc(r->pool, sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1); if (p == NULL) { return NGX_ERROR; @@ -1121,7 +1191,7 @@ ngx_http_variable_sent_last_modified(ngx v->len = ngx_http_time(p, r->headers_out.last_modified_time) - p; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = p; @@ -1152,7 +1222,7 @@ ngx_http_variable_sent_connection(ngx_ht v->len = len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) p; @@ -1172,14 +1242,14 @@ ngx_http_variable_sent_keep_alive(ngx_ht if (clcf->keepalive_header) { - p = ngx_palloc(r->pool, sizeof("timeout=") - 1 + NGX_TIME_T_LEN); + p = ngx_pnalloc(r->pool, sizeof("timeout=") - 1 + NGX_TIME_T_LEN); if (p == NULL) { return NGX_ERROR; } v->len = ngx_sprintf(p, "timeout=%T", clcf->keepalive_header) - p; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = p; @@ -1200,7 +1270,7 @@ ngx_http_variable_sent_transfer_encoding if (r->chunked) { v->len = sizeof("chunked") - 1; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) "chunked"; @@ -1219,7 +1289,7 @@ ngx_http_variable_request_completion(ngx if (r->request_complete) { v->len = 2; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) "OK"; @@ -1228,7 +1298,7 @@ ngx_http_variable_request_completion(ngx v->len = 0; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) ""; @@ -1248,7 +1318,7 @@ ngx_http_variable_request_body_file(ngx_ v->len = r->request_body->temp_file->file.name.len; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = r->request_body->temp_file->file.name.data; @@ -1262,7 +1332,7 @@ ngx_http_variable_nginx_version(ngx_http { v->len = sizeof(NGINX_VERSION) - 1; v->valid = 1; - v->no_cachable = 0; + v->no_cacheable = 0; v->not_found = 0; v->data = (u_char *) NGINX_VERSION; @@ -1270,6 +1340,20 @@ ngx_http_variable_nginx_version(ngx_http } +static ngx_int_t +ngx_http_variable_hostname(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + v->len = ngx_cycle->hostname.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_cycle->hostname.data; + + return NGX_OK; +} + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf) { @@ -1370,7 +1454,14 @@ ngx_http_variables_init_vars(ngx_conf_t if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) { v[i].get_handler = ngx_http_upstream_header_variable; v[i].data = (uintptr_t) &v[i].name; - v[i].flags = NGX_HTTP_VAR_NOCACHABLE; + v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; + + continue; + } + + 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; continue; } diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -16,7 +16,7 @@ typedef ngx_variable_value_t ngx_http_variable_value_t; -#define ngx_http_variable(v) { sizeof(v) - 1, 1, 0, 0, (u_char *) v } +#define ngx_http_variable(v) { sizeof(v) - 1, 1, 0, 0, 0, (u_char *) v } typedef struct ngx_http_variable_s ngx_http_variable_t; @@ -26,10 +26,10 @@ typedef ngx_int_t (*ngx_http_get_variabl ngx_http_variable_value_t *v, uintptr_t data); -#define NGX_HTTP_VAR_CHANGABLE 1 -#define NGX_HTTP_VAR_NOCACHABLE 2 -#define NGX_HTTP_VAR_INDEXED 4 -#define NGX_HTTP_VAR_NOHASH 8 +#define NGX_HTTP_VAR_CHANGEABLE 1 +#define NGX_HTTP_VAR_NOCACHEABLE 2 +#define NGX_HTTP_VAR_INDEXED 4 +#define NGX_HTTP_VAR_NOHASH 8 struct ngx_http_variable_s { diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -49,6 +49,7 @@ ngx_http_write_filter(ngx_http_request_t { off_t size, sent, limit; ngx_uint_t last, flush; + ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; @@ -245,14 +246,17 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - sent = c->sent - sent; - c->write->delayed = 1; - ngx_add_timer(c->write, (ngx_msec_t) (sent * 1000 / r->limit_rate + 1)); + delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1); + + if (delay > 0) { + c->write->delayed = 1; + ngx_add_timer(c->write, delay); + } } else if (c->write->ready && clcf->sendfile_max_chunk && (size_t) (c->sent - sent) - >= clcf->sendfile_max_chunk - 2 * ngx_pagesize) + >= clcf->sendfile_max_chunk - 2 * ngx_pagesize) { c->write->delayed = 1; ngx_add_timer(c->write, 1); diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -11,7 +11,7 @@ static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static int ngx_mail_cmp_conf_in_addrs(const void *one, const void *two); +static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two); ngx_uint_t ngx_mail_max_module; @@ -357,8 +357,8 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma imip->addrs[i].addr = in_addr[i].addr; imip->addrs[i].ctx = in_addr[i].ctx; - text = ngx_palloc(cf->pool, - INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); + text = ngx_pnalloc(cf->pool, + INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); if (text == NULL) { return NGX_CONF_ERROR; } @@ -388,7 +388,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma } -static int +static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two) { ngx_mail_conf_in_addr_t *first, *second; diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -81,6 +81,7 @@ typedef struct { ngx_mail_protocol_t *protocol; ngx_msec_t timeout; + ngx_msec_t resolver_timeout; ngx_flag_t so_keepalive; @@ -89,6 +90,8 @@ typedef struct { u_char *file_name; ngx_int_t line; + ngx_resolver_t *resolver; + /* server ctx */ ngx_mail_conf_ctx_t *ctx; } ngx_mail_core_srv_conf_t; @@ -102,7 +105,7 @@ typedef enum { ngx_pop3_auth_login_password, ngx_pop3_auth_plain, ngx_pop3_auth_cram_md5 -} ngx_po3_state_e; +} ngx_pop3_state_e; typedef enum { @@ -151,6 +154,8 @@ typedef struct { void **main_conf; void **srv_conf; + ngx_resolver_ctx_t *resolver_ctx; + ngx_mail_proxy_ctx_t *proxy; ngx_uint_t mail_state; @@ -175,6 +180,7 @@ typedef struct { ngx_str_t text; ngx_str_t *addr_text; + ngx_str_t host; ngx_str_t smtp_helo; ngx_str_t smtp_from; ngx_str_t smtp_to; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -529,7 +529,7 @@ ngx_mail_auth_http_process_headers(ngx_m continue; } - p = ngx_pcalloc(s->connection->pool, size); + p = ngx_pnalloc(s->connection->pool, size); if (p == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); @@ -594,7 +594,7 @@ ngx_mail_auth_http_process_headers(ngx_m { s->login.len = ctx->header_end - ctx->header_start; - s->login.data = ngx_palloc(s->connection->pool, s->login.len); + s->login.data = ngx_pnalloc(s->connection->pool, s->login.len); if (s->login.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); @@ -615,7 +615,8 @@ ngx_mail_auth_http_process_headers(ngx_m { s->passwd.len = ctx->header_end - ctx->header_start; - s->passwd.data = ngx_palloc(s->connection->pool, s->passwd.len); + s->passwd.data = ngx_pnalloc(s->connection->pool, + s->passwd.len); if (s->passwd.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); @@ -652,8 +653,8 @@ ngx_mail_auth_http_process_headers(ngx_m { ctx->errcode.len = ctx->header_end - ctx->header_start; - ctx->errcode.data = ngx_palloc(s->connection->pool, - ctx->errcode.len); + ctx->errcode.data = ngx_pnalloc(s->connection->pool, + ctx->errcode.len); if (ctx->errcode.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); @@ -692,7 +693,7 @@ ngx_mail_auth_http_process_headers(ngx_m ctx->err.len = ctx->errcode.len + ctx->errmsg.len + sizeof(" " CRLF) - 1; - p = ngx_palloc(s->connection->pool, ctx->err.len); + p = ngx_pnalloc(s->connection->pool, ctx->err.len); if (p == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); @@ -719,7 +720,7 @@ ngx_mail_auth_http_process_headers(ngx_m return; } - ngx_add_timer(s->connection->read, timer * 1000); + ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); s->connection->read->handler = ngx_mail_auth_sleep_handler; @@ -736,7 +737,7 @@ ngx_mail_auth_http_process_headers(ngx_m return; } - ngx_add_timer(s->connection->read, timer * 1000); + ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); s->connection->read->handler = ngx_mail_auth_sleep_handler; @@ -811,7 +812,7 @@ ngx_mail_auth_http_process_headers(ngx_m peer->name.len = len; - peer->name.data = ngx_palloc(s->connection->pool, len); + peer->name.data = ngx_pnalloc(s->connection->pool, len); if (peer->name.data == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); @@ -1280,7 +1281,7 @@ ngx_mail_auth_http_escape(ngx_pool_t *po escaped->len = text->len + n * 2; - p = ngx_palloc(pool, escaped->len); + p = ngx_pnalloc(pool, escaped->len); if (p == NULL) { return NGX_ERROR; } @@ -1351,7 +1352,7 @@ ngx_mail_auth_http_merge_conf(ngx_conf_t len += header[i].key.len + 2 + header[i].value.len + 2; } - p = ngx_palloc(cf->pool, len); + p = ngx_pnalloc(cf->pool, len); if (p == NULL) { return NGX_CONF_ERROR; } @@ -1393,7 +1394,7 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c u.url.data += 7; } - if (ngx_parse_url(cf, &u) != NGX_OK) { + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in auth_http \"%V\"", u.err, &u.url); diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -20,6 +20,8 @@ static char *ngx_mail_core_listen(ngx_co void *conf); static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_mail_core_commands[] = { @@ -66,6 +68,20 @@ static ngx_command_t ngx_mail_core_comm offsetof(ngx_mail_core_srv_conf_t, server_name), NULL }, + { ngx_string("resolver"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_core_resolver, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("resolver_timeout"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), + NULL }, + ngx_null_command }; @@ -141,8 +157,14 @@ ngx_mail_core_create_srv_conf(ngx_conf_t */ cscf->timeout = NGX_CONF_UNSET_MSEC; + cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; cscf->so_keepalive = NGX_CONF_UNSET; + cscf->resolver = NGX_CONF_UNSET_PTR; + + cscf->file_name = cf->conf_file->file.name.data; + cscf->line = cf->conf_file->line; + return cscf; } @@ -154,6 +176,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t ngx_mail_core_srv_conf_t *conf = child; ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, + 30000); ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); @@ -161,20 +185,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); if (conf->server_name.len == 0) { - conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN); - if (conf->server_name.data == NULL) { - return NGX_CONF_ERROR; - } - - if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN) - == -1) - { - ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, - "gethostname() failed"); - return NGX_CONF_ERROR; - } - - conf->server_name.len = ngx_strlen(conf->server_name.data); + conf->server_name = cf->cycle->hostname; } if (conf->protocol == NULL) { @@ -184,6 +195,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t return NGX_CONF_ERROR; } + ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL); + return NGX_CONF_OK; } @@ -237,9 +250,6 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index]; cscf->ctx = ctx; - cscf->file_name = cf->conf_file->file.name.data; - cscf->line = cf->conf_file->line; - cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; cscfp = ngx_array_push(&cmcf->servers); @@ -285,7 +295,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx u.url = value[1]; u.listen = 1; - if (ngx_parse_url(cf, &u) != NGX_OK) { + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in \"%V\" of the \"listen\" directive", @@ -389,6 +399,44 @@ ngx_mail_core_protocol(ngx_conf_t *cf, n } +static char * +ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_core_srv_conf_t *cscf = conf; + + ngx_url_t u; + ngx_str_t *value; + + value = cf->args->elts; + + if (cscf->resolver != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + cscf->resolver = NULL; + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.host = value[1]; + u.port = 53; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err); + return NGX_CONF_ERROR; + } + + cscf->resolver = ngx_resolver_create(cf, &u.addrs[0]); + if (cscf->resolver == NULL) { + return NGX_CONF_OK; + } + + return NGX_CONF_OK; +} + + char * ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -29,10 +29,6 @@ ngx_mail_init_connection(ngx_connection_ ngx_mail_in_port_t *imip; ngx_mail_in_addr_t *imia; ngx_mail_session_t *s; -#if (NGX_MAIL_SSL) - ngx_mail_ssl_conf_t *sslcf; -#endif - /* find the server configuration for the address:port */ @@ -116,6 +112,8 @@ ngx_mail_init_connection(ngx_connection_ c->log_error = NGX_ERROR_INFO; #if (NGX_MAIL_SSL) + { + ngx_mail_ssl_conf_t *sslcf; sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); @@ -123,7 +121,7 @@ ngx_mail_init_connection(ngx_connection_ ngx_mail_ssl_init_connection(&sslcf->ssl, c); return; } - + } #endif ngx_mail_init_session(c); @@ -238,10 +236,10 @@ ngx_int_t ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c, ngx_mail_core_srv_conf_t *cscf) { - s->salt.data = ngx_palloc(c->pool, - sizeof(" <18446744073709551616.@>" CRLF) - 1 - + NGX_TIME_T_LEN - + cscf->server_name.len); + s->salt.data = ngx_pnalloc(c->pool, + sizeof(" <18446744073709551616.@>" CRLF) - 1 + + NGX_TIME_T_LEN + + cscf->server_name.len); if (s->salt.data == NULL) { return NGX_ERROR; } @@ -290,7 +288,7 @@ ngx_mail_auth_plain(ngx_mail_session_t * "mail auth plain: \"%V\"", &arg[n]); #endif - plain.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[n].len)); + plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len)); if (plain.data == NULL){ return NGX_ERROR; } @@ -346,7 +344,7 @@ ngx_mail_auth_login_username(ngx_mail_se ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail auth login username: \"%V\"", &arg[0]); - s->login.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len)); + s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len)); if (s->login.data == NULL){ return NGX_ERROR; } @@ -376,7 +374,8 @@ ngx_mail_auth_login_password(ngx_mail_se "mail auth login password: \"%V\"", &arg[0]); #endif - s->passwd.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len)); + s->passwd.data = ngx_pnalloc(c->pool, + ngx_base64_decoded_length(arg[0].len)); if (s->passwd.data == NULL){ return NGX_ERROR; } @@ -404,7 +403,7 @@ ngx_mail_auth_cram_md5_salt(ngx_mail_ses ngx_str_t salt; ngx_uint_t n; - p = ngx_palloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2); + p = ngx_pnalloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2); if (p == NULL) { return NGX_ERROR; } @@ -436,7 +435,7 @@ ngx_mail_auth_cram_md5(ngx_mail_session_ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail auth cram-md5: \"%V\"", &arg[0]); - s->login.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len)); + s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len)); if (s->login.data == NULL){ return NGX_ERROR; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -259,7 +259,7 @@ ngx_mail_imap_auth_state(ngx_event_t *re if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) { s->tagged_line.len = s->tag.len + s->text.len + s->out.len; - s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len); + s->tagged_line.data = ngx_pnalloc(c->pool, s->tagged_line.len); if (s->tagged_line.data == NULL) { ngx_mail_close_connection(c); return; @@ -302,7 +302,7 @@ ngx_mail_imap_auth_state(ngx_event_t *re static ngx_int_t ngx_mail_imap_login(ngx_mail_session_t *s, ngx_connection_t *c) { - ngx_str_t *arg; + ngx_str_t *arg; #if (NGX_MAIL_SSL) if (ngx_mail_starttls_only(s, c)) { @@ -317,7 +317,7 @@ ngx_mail_imap_login(ngx_mail_session_t * } s->login.len = arg[0].len; - s->login.data = ngx_palloc(c->pool, s->login.len); + s->login.data = ngx_pnalloc(c->pool, s->login.len); if (s->login.data == NULL) { return NGX_ERROR; } @@ -325,7 +325,7 @@ ngx_mail_imap_login(ngx_mail_session_t * ngx_memcpy(s->login.data, arg[0].data, s->login.len); s->passwd.len = arg[1].len; - s->passwd.data = ngx_palloc(c->pool, s->passwd.len); + s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len); if (s->passwd.data == NULL) { return NGX_ERROR; } @@ -410,15 +410,14 @@ static ngx_int_t ngx_mail_imap_capability(ngx_mail_session_t *s, ngx_connection_t *c) { ngx_mail_imap_srv_conf_t *iscf; -#if (NGX_MAIL_SSL) - ngx_mail_ssl_conf_t *sslcf; -#endif iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module); #if (NGX_MAIL_SSL) if (c->ssl == NULL) { + ngx_mail_ssl_conf_t *sslcf; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c --- a/src/mail/ngx_mail_imap_module.c +++ b/src/mail/ngx_mail_imap_module.c @@ -184,7 +184,7 @@ ngx_mail_imap_merge_srv_conf(ngx_conf_t } } - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -217,7 +217,7 @@ ngx_mail_imap_merge_srv_conf(ngx_conf_t size += sizeof(" STARTTLS") - 1; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -234,7 +234,7 @@ ngx_mail_imap_merge_srv_conf(ngx_conf_t size = (auth - conf->capability.data) + sizeof(CRLF) - 1 + sizeof(" STARTTLS LOGINDISABLED") - 1; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -46,7 +46,7 @@ ngx_mail_pop3_init_session(ngx_mail_sess return; } - s->out.data = ngx_palloc(c->pool, sizeof(pop3_greeting) + s->salt.len); + s->out.data = ngx_pnalloc(c->pool, sizeof(pop3_greeting) + s->salt.len); if (s->out.data == NULL) { ngx_mail_session_internal_server_error(s); return; @@ -283,7 +283,7 @@ ngx_mail_pop3_auth_state(ngx_event_t *re static ngx_int_t ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c) { - ngx_str_t *arg; + ngx_str_t *arg; #if (NGX_MAIL_SSL) if (ngx_mail_starttls_only(s, c)) { @@ -297,7 +297,7 @@ ngx_mail_pop3_user(ngx_mail_session_t *s arg = s->args.elts; s->login.len = arg[0].len; - s->login.data = ngx_palloc(c->pool, s->login.len); + s->login.data = ngx_pnalloc(c->pool, s->login.len); if (s->login.data == NULL) { return NGX_ERROR; } @@ -324,7 +324,7 @@ ngx_mail_pop3_pass(ngx_mail_session_t *s arg = s->args.elts; s->passwd.len = arg[0].len; - s->passwd.data = ngx_palloc(c->pool, s->passwd.len); + s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len); if (s->passwd.data == NULL) { return NGX_ERROR; } @@ -344,15 +344,14 @@ static ngx_int_t ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c, ngx_int_t stls) { ngx_mail_pop3_srv_conf_t *pscf; -#if (NGX_MAIL_SSL) - ngx_mail_ssl_conf_t *sslcf; -#endif pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module); #if (NGX_MAIL_SSL) if (stls && c->ssl == NULL) { + ngx_mail_ssl_conf_t *sslcf; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { @@ -418,7 +417,7 @@ ngx_mail_pop3_apop(ngx_mail_session_t *s arg = s->args.elts; s->login.len = arg[0].len; - s->login.data = ngx_palloc(c->pool, s->login.len); + s->login.data = ngx_pnalloc(c->pool, s->login.len); if (s->login.data == NULL) { return NGX_ERROR; } @@ -426,7 +425,7 @@ ngx_mail_pop3_apop(ngx_mail_session_t *s ngx_memcpy(s->login.data, arg[0].data, s->login.len); s->passwd.len = arg[1].len; - s->passwd.data = ngx_palloc(c->pool, s->passwd.len); + s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len); if (s->passwd.data == NULL) { return NGX_ERROR; } diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -183,7 +183,7 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t size += sizeof("SASL LOGIN PLAIN" CRLF) - 1; } - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -213,7 +213,7 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t size += sizeof("STLS" CRLF) - 1; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -236,7 +236,7 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t } - p = ngx_palloc(cf->pool, stls_only_size); + p = ngx_pnalloc(cf->pool, stls_only_size); if (p == NULL) { return NGX_CONF_ERROR; } diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -172,6 +172,8 @@ ngx_mail_proxy_init(ngx_mail_session_t * return; } + s->out.len = 0; + switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: @@ -252,7 +254,7 @@ ngx_mail_proxy_pop3_handler(ngx_event_t s->connection->log->action = "sending user name to upstream"; line.len = sizeof("USER ") - 1 + s->login.len + 2; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -271,7 +273,7 @@ ngx_mail_proxy_pop3_handler(ngx_event_t s->connection->log->action = "sending password to upstream"; line.len = sizeof("PASS ") - 1 + s->passwd.len + 2; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -368,7 +370,7 @@ ngx_mail_proxy_imap_handler(ngx_event_t line.len = s->tag.len + sizeof("LOGIN ") - 1 + 1 + NGX_SIZE_T_LEN + 1 + 2; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -387,7 +389,7 @@ ngx_mail_proxy_imap_handler(ngx_event_t s->connection->log->action = "sending user name to upstream"; line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -407,7 +409,7 @@ ngx_mail_proxy_imap_handler(ngx_event_t s->connection->log->action = "sending password to upstream"; line.len = s->passwd.len + 2; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -504,7 +506,7 @@ ngx_mail_proxy_smtp_handler(ngx_event_t cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); line.len = sizeof("HELO ") - 1 + cscf->server_name.len + 2; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -531,12 +533,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t s->connection->log->action = "sending XCLIENT to upstream"; - line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= " - "NAME=[UNAVAILABLE]" CRLF) - 1 + line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= NAME=" + CRLF) - 1 + s->esmtp + s->smtp_helo.len - + s->connection->addr_text.len + s->login.len; + + s->connection->addr_text.len + s->login.len + s->host.len; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -544,11 +546,11 @@ ngx_mail_proxy_smtp_handler(ngx_event_t line.len = ngx_sprintf(line.data, "XCLIENT PROTO=%sSMTP%s%V ADDR=%V%s%V " - "NAME=[UNAVAILABLE]" CRLF, + "NAME=%V" CRLF, (s->esmtp ? "E" : ""), (s->smtp_helo.len ? " HELO=" : ""), &s->smtp_helo, &s->connection->addr_text, - (s->login.len ? " LOGIN=" : ""), &s->login) + (s->login.len ? " LOGIN=" : ""), &s->login, &s->host) - line.data; s->mail_state = s->auth_method == NGX_MAIL_AUTH_NONE ? @@ -564,7 +566,7 @@ ngx_mail_proxy_smtp_handler(ngx_event_t s->connection->log->action = "sending MAIL FROM to upstream"; line.len = s->smtp_from.len + sizeof(CRLF) - 1; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; @@ -584,7 +586,7 @@ ngx_mail_proxy_smtp_handler(ngx_event_t s->connection->log->action = "sending RCPT TO to upstream"; line.len = s->smtp_to.len + sizeof(CRLF) - 1; - line.data = ngx_palloc(c->pool, line.len); + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -11,6 +11,9 @@ #include +static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c); @@ -31,6 +34,7 @@ static void ngx_mail_smtp_log_rejected_c static u_char smtp_ok[] = "250 2.0.0 OK" CRLF; static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF; +static u_char smtp_starttls[] = "220 2.0.0 Start TLS" CRLF; static u_char smtp_next[] = "334 " CRLF; static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; @@ -42,13 +46,182 @@ static u_char smtp_auth_required[] = "5 static u_char smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF; +static ngx_str_t smtp_unavailable = ngx_string("[UNAVAILABLE]"); +static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]"); + + void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) { + struct sockaddr_in *sin; + ngx_resolver_ctx_t *ctx; + ngx_mail_core_srv_conf_t *cscf; + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + if (cscf->resolver == NULL) { + s->host = smtp_unavailable; + ngx_mail_smtp_greeting(s, c); + return; + } + + c->log->action = "in resolving client address"; + + ctx = ngx_resolve_start(cscf->resolver, NULL); + if (ctx == NULL) { + ngx_mail_close_connection(c); + return; + } + + /* AF_INET only */ + + sin = (struct sockaddr_in *) c->sockaddr; + + ctx->addr = sin->sin_addr.s_addr; + ctx->handler = ngx_mail_smtp_resolve_addr_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + if (ngx_resolve_addr(ctx) != NGX_OK) { + ngx_mail_close_connection(c); + } +} + + +static void +ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx) +{ + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; + + s = ctx->data; + c = s->connection; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%V could not be resolved (%i: %s)", + &c->addr_text, ctx->state, + ngx_resolver_strerror(ctx->state)); + + if (ctx->state == NGX_RESOLVE_NXDOMAIN) { + s->host = smtp_unavailable; + + } else { + s->host = smtp_tempunavail; + } + + ngx_resolve_addr_done(ctx); + + ngx_mail_smtp_greeting(s, s->connection); + + return; + } + + c->log->action = "in resolving client hostname"; + + s->host.data = ngx_pstrdup(c->pool, &ctx->name); + if (s->host.data == NULL) { + ngx_resolve_addr_done(ctx); + ngx_mail_close_connection(c); + return; + } + + s->host.len = ctx->name.len; + + ngx_resolve_addr_done(ctx); + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "address resolved: %V", &s->host); + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + ctx = ngx_resolve_start(cscf->resolver, NULL); + if (ctx == NULL) { + ngx_mail_close_connection(c); + return; + } + + ctx->name = s->host; + ctx->type = NGX_RESOLVE_A; + ctx->handler = ngx_mail_smtp_resolve_name_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + if (ngx_resolve_name(ctx) != NGX_OK) { + ngx_mail_close_connection(c); + } +} + + +static void +ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx) +{ + in_addr_t addr; + ngx_uint_t i; + ngx_connection_t *c; + struct sockaddr_in *sin; + ngx_mail_session_t *s; + + s = ctx->data; + c = s->connection; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%V could not be resolved (%i: %s)", + &ctx->name, ctx->state, + ngx_resolver_strerror(ctx->state)); + + if (ctx->state == NGX_RESOLVE_NXDOMAIN) { + s->host = smtp_unavailable; + + } else { + s->host = smtp_tempunavail; + } + + } else { + + /* AF_INET only */ + + sin = (struct sockaddr_in *) c->sockaddr; + + for (i = 0; i < ctx->naddrs; i++) { + + addr = ctx->addrs[i]; + + ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, + "name was resolved to %ud.%ud.%ud.%ud", + (ntohl(addr) >> 24) & 0xff, + (ntohl(addr) >> 16) & 0xff, + (ntohl(addr) >> 8) & 0xff, + ntohl(addr) & 0xff); + + if (addr == sin->sin_addr.s_addr) { + goto found; + } + } + + s->host = smtp_unavailable; + } + +found: + + ngx_resolve_name_done(ctx); + + ngx_mail_smtp_greeting(s, c); +} + + +static void +ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) +{ ngx_msec_t timeout; ngx_mail_core_srv_conf_t *cscf; ngx_mail_smtp_srv_conf_t *sscf; + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "smtp greeting for \"%V\"", &s->host); + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); @@ -260,6 +433,8 @@ 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; break; default: @@ -329,9 +504,6 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s { ngx_str_t *arg; ngx_mail_smtp_srv_conf_t *sscf; -#if (NGX_MAIL_SSL) - ngx_mail_ssl_conf_t *sslcf; -#endif if (s->args.nelts != 1) { s->out.len = sizeof(smtp_invalid_argument) - 1; @@ -344,7 +516,7 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s s->smtp_helo.len = arg[0].len; - s->smtp_helo.data = ngx_palloc(c->pool, arg[0].len); + s->smtp_helo.data = ngx_pnalloc(c->pool, arg[0].len); if (s->smtp_helo.data == NULL) { return NGX_ERROR; } @@ -367,6 +539,8 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s #if (NGX_MAIL_SSL) if (c->ssl == NULL) { + ngx_mail_ssl_conf_t *sslcf; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -162,7 +162,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t size = sizeof("220 ESMTP ready" CRLF) - 1 + cscf->server_name.len; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -177,7 +177,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t size = sizeof("250 " CRLF) - 1 + cscf->server_name.len; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -216,7 +216,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t size += sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1; } - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -263,7 +263,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t size += sizeof("250 STARTTLS" CRLF) - 1; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } @@ -284,7 +284,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t size = (auth - conf->capability.data) + sizeof("250 STARTTLS" CRLF) - 1; - p = ngx_palloc(cf->pool, size); + p = ngx_pnalloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; } diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -9,9 +9,9 @@ #include -#define NGX_DEFLAUT_CERTIFICATE "cert.pem" -#define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" -#define NGX_DEFLAUT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" +#define NGX_DEFAULT_CERTIFICATE "cert.pem" +#define NGX_DEFAULT_CERTIFICATE_KEY "cert.pem" +#define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); @@ -76,6 +76,13 @@ static ngx_command_t ngx_mail_ssl_comma offsetof(ngx_mail_ssl_conf_t, certificate_key), NULL }, + { ngx_string("ssl_dhparam"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, dhparam), + NULL }, + { ngx_string("ssl_protocols"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -163,10 +170,9 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * scf->protocols = 0; - * scf->certificate.len = 0; - * scf->certificate.data = NULL; - * scf->certificate_key.len = 0; - * scf->certificate_key.data = NULL; + * scf->certificate = { 0, NULL }; + * scf->certificate_key = { 0, NULL }; + * scf->dhparam = { 0, NULL }; * scf->ciphers.len = 0; * scf->ciphers.data = NULL; * scf->shm_zone = NULL; @@ -208,12 +214,14 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFLAUT_CERTIFICATE); + NGX_DEFAULT_CERTIFICATE); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFLAUT_CERTIFICATE_KEY); + NGX_DEFAULT_CERTIFICATE_KEY); - ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS); + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); + + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); conf->ssl.log = cf->log; @@ -260,9 +268,12 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, return NGX_CONF_ERROR; } + if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { + return NGX_CONF_ERROR; + } + ngx_conf_merge_value(conf->builtin_session_cache, - prev->builtin_session_cache, - NGX_SSL_DFLT_BUILTIN_SCACHE); + prev->builtin_session_cache, NGX_SSL_NONE_SCACHE); if (conf->shm_zone == NULL) { conf->shm_zone = prev->shm_zone; @@ -294,6 +305,16 @@ ngx_mail_ssl_session_cache(ngx_conf_t *c for (i = 1; i < cf->args->nelts; i++) { + if (ngx_strcmp(value[i].data, "off") == 0) { + scf->builtin_session_cache = NGX_SSL_NO_SCACHE; + continue; + } + + if (ngx_strcmp(value[i].data, "none") == 0) { + scf->builtin_session_cache = NGX_SSL_NONE_SCACHE; + continue; + } + if (ngx_strcmp(value[i].data, "builtin") == 0) { scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -34,6 +34,7 @@ typedef struct { ngx_str_t certificate; ngx_str_t certificate_key; + ngx_str_t dhparam; ngx_str_t ciphers; diff --git a/src/misc/ngx_google_perftools_module.c b/src/misc/ngx_google_perftools_module.c new file mode 100644 --- /dev/null +++ b/src/misc/ngx_google_perftools_module.c @@ -0,0 +1,127 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + +/* + * declare Profiler here interface because + * is C++ header file + */ + +int ProfilerStart(u_char* fname); +void ProfilerStop(void); +void ProfilerRegisterThread(void); + + +static void *ngx_google_perftools_create_conf(ngx_cycle_t *cycle); +static ngx_int_t ngx_google_perftools_worker(ngx_cycle_t *cycle); + + +typedef struct { + ngx_str_t profiles; +} ngx_google_perftools_conf_t; + + +static ngx_command_t ngx_google_perftools_commands[] = { + + { ngx_string("google_perftools_profiles"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + 0, + offsetof(ngx_google_perftools_conf_t, profiles), + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_google_perftools_module_ctx = { + ngx_string("google_perftools"), + ngx_google_perftools_create_conf, + NULL +}; + + +ngx_module_t ngx_google_perftools_module = { + NGX_MODULE_V1, + &ngx_google_perftools_module_ctx, /* module context */ + ngx_google_perftools_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_google_perftools_worker, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static void * +ngx_google_perftools_create_conf(ngx_cycle_t *cycle) +{ + ngx_google_perftools_conf_t *gptcf; + + gptcf = ngx_pcalloc(cycle->pool, sizeof(ngx_google_perftools_conf_t)); + if (gptcf == NULL) { + return NULL; + } + + /* + * set by pcalloc() + * + * gptcf->profiles = { 0, NULL }; + */ + + return gptcf; +} + + +static ngx_int_t +ngx_google_perftools_worker(ngx_cycle_t *cycle) +{ + u_char *profile; + ngx_google_perftools_conf_t *gptcf; + + gptcf = (ngx_google_perftools_conf_t *) + ngx_get_conf(cycle->conf_ctx, ngx_google_perftools_module); + + if (gptcf->profiles.len == 0) { + return NGX_OK; + } + + profile = ngx_alloc(gptcf->profiles.len + NGX_INT_T_LEN + 2, cycle->log); + if (profile == NULL) { + return NGX_OK; + } + + if (getenv("CPUPROFILE")) { + + /* disable inherited Profiler enabled in master process */ + ProfilerStop(); + } + + ngx_sprintf(profile, "%V.%d%Z", &gptcf->profiles, ngx_pid); + + if (ProfilerStart(profile)) { + + /* start ITIMER_PROF timer */ + ProfilerRegisterThread(); + + } else { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno, + "ProfilerStart(%s) failed", profile); + } + + ngx_free(profile); + + return NGX_OK; +} + + +/* ProfilerStop() is called on Profiler destruction */ diff --git a/src/os/unix/ngx_alloc.h b/src/os/unix/ngx_alloc.h --- a/src/os/unix/ngx_alloc.h +++ b/src/os/unix/ngx_alloc.h @@ -21,8 +21,8 @@ void *ngx_calloc(size_t size, ngx_log_t /* * Linux has memalign() or posix_memalign() * Solaris has memalign() - * FreeBSD has not memalign() or posix_memalign() but its malloc() alignes - * allocations bigger than page size at the page boundary. + * FreeBSD 7.0 has posix_memalign(), besides, early version's malloc() + * aligns allocations bigger than page size at the page boundary */ #if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN) diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -21,13 +21,8 @@ #include -/* "bool" conflicts with perl's CORE/handy.h - * "true" and "false" conflict with nginx, and of course we can rename them, - * but we need to undef "bool" anyway - */ +/* "bool" conflicts with perl's CORE/handy.h */ #undef bool -#undef true -#undef false #define NGX_HAVE_ATOMIC_OPS 1 diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -33,7 +33,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = sizeof(cmsg); - cmsg.cm.cmsg_len = sizeof(cmsg); + cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.cm.cmsg_level = SOL_SOCKET; cmsg.cm.cmsg_type = SCM_RIGHTS; *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; @@ -138,7 +138,7 @@ ngx_read_channel(ngx_socket_t s, ngx_cha if (ch->command == NGX_CMD_OPEN_CHANNEL) { - if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) { + if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) { ngx_log_error(NGX_LOG_ALERT, log, 0, "recvmsg() returned too small ancillary data"); return NGX_ERROR; diff --git a/src/os/unix/ngx_darwin.h b/src/os/unix/ngx_darwin.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_darwin.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_DARWIN_H_INCLUDED_ +#define _NGX_DARWIN_H_INCLUDED_ + + +ngx_chain_t *ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +extern int ngx_darwin_kern_osreldate; +extern int ngx_darwin_hw_ncpu; +extern u_long ngx_darwin_net_inet_tcp_sendspace; + + +#endif /* _NGX_DARWIN_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_darwin_config.h b/src/os/unix/ngx_darwin_config.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_darwin_config.h @@ -0,0 +1,87 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_DARWIN_CONFIG_H_INCLUDED_ +#define _NGX_DARWIN_CONFIG_H_INCLUDED_ + + + +#include +#include +#include +#include +#include +#include /* offsetof() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* FIONBIO */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include /* TCP_NODELAY */ +#include +#include +#include + +#include +#include + + +#ifndef IOV_MAX +#define IOV_MAX 64 +#endif + + +#include + + +#if (NGX_HAVE_POLL) +#include +#endif + + +#if (NGX_HAVE_KQUEUE) +#include +#endif + + +#define NGX_LISTEN_BACKLOG -1 + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 1 +#endif + + +#ifndef NGX_HAVE_CASELESS_FILESYSTEM +#define NGX_HAVE_CASELESS_FILESYSTEM 1 +#endif + + +#define NGX_HAVE_OS_SPECIFIC_INIT 1 + + +extern char **environ; + + +#endif /* _NGX_DARWIN_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_darwin_init.c b/src/os/unix/ngx_darwin_init.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_darwin_init.c @@ -0,0 +1,155 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + + +char ngx_darwin_kern_ostype[16]; +char ngx_darwin_kern_osrelease[128]; +int ngx_darwin_hw_ncpu; +int ngx_darwin_kern_ipc_somaxconn; +u_long ngx_darwin_net_inet_tcp_sendspace; + + +static ngx_os_io_t ngx_darwin_io = { + ngx_unix_recv, + ngx_readv_chain, + ngx_udp_unix_recv, + ngx_unix_send, +#if (NGX_HAVE_SENDFILE) + ngx_darwin_sendfile_chain, + NGX_IO_SENDFILE +#else + ngx_writev_chain, + 0 +#endif +}; + + +typedef struct { + char *name; + void *value; + size_t size; + ngx_uint_t exists; +} sysctl_t; + + +sysctl_t sysctls[] = { + { "hw.ncpu", + &ngx_darwin_hw_ncpu, + sizeof(ngx_darwin_hw_ncpu), 0 }, + + { "net.inet.tcp.sendspace", + &ngx_darwin_net_inet_tcp_sendspace, + sizeof(ngx_darwin_net_inet_tcp_sendspace), 0 }, + + { "kern.ipc.somaxconn", + &ngx_darwin_kern_ipc_somaxconn, + sizeof(ngx_darwin_kern_ipc_somaxconn), 0 }, + + { NULL, NULL, 0, 0 } +}; + + +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) +{ + int somaxconn; + size_t size; + ngx_err_t err; + ngx_uint_t i; + + size = sizeof(ngx_darwin_kern_ostype); + if (sysctlbyname("kern.ostype", + ngx_darwin_kern_ostype, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysctlbyname(kern.ostype) failed"); + + if (ngx_errno != NGX_ENOMEM) { + return NGX_ERROR; + } + + ngx_darwin_kern_ostype[size - 1] = '\0'; + } + + size = sizeof(ngx_darwin_kern_osrelease); + if (sysctlbyname("kern.osrelease", + ngx_darwin_kern_osrelease, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysctlbyname(kern.osrelease) failed"); + + if (ngx_errno != NGX_ENOMEM) { + return NGX_ERROR; + } + + ngx_darwin_kern_osrelease[size - 1] = '\0'; + } + + + for (i = 0; sysctls[i].name; i++) { + size = sysctls[i].size; + + if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0) + == 0) + { + sysctls[i].exists = 1; + continue; + } + + err = ngx_errno; + + if (err == NGX_ENOENT) { + continue; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, + "sysctlbyname(%s) failed", sysctls[i].name); + return NGX_ERROR; + } + + ngx_ncpu = ngx_darwin_hw_ncpu; + + somaxconn = 32676; + + if (ngx_darwin_kern_ipc_somaxconn > somaxconn) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "sysctl kern.ipc.somaxconn must be no more than %d", + somaxconn); + return NGX_ERROR; + } + + ngx_tcp_nodelay_and_tcp_nopush = 1; + + ngx_os_io = ngx_darwin_io; + + return NGX_OK; +} + + +void +ngx_os_specific_status(ngx_log_t *log) +{ + u_long value; + ngx_uint_t i; + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", + ngx_darwin_kern_ostype, ngx_darwin_kern_osrelease); + + for (i = 0; sysctls[i].name; i++) { + if (sysctls[i].exists) { + if (sysctls[i].size == sizeof(long)) { + value = *(long *) sysctls[i].value; + + } else { + value = *(int *) sysctls[i].value; + } + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "%s: %l", + sysctls[i].name, value); + } + } +} diff --git a/src/os/unix/ngx_darwin_sendfile_chain.c b/src/os/unix/ngx_darwin_sendfile_chain.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_darwin_sendfile_chain.c @@ -0,0 +1,363 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +/* + * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same + * old bug as early FreeBSD sendfile() syscall: + * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 + * + * Besides sendfile() has another bug: if one calls sendfile() + * with both a header and a trailer, then sendfile() ignores a file part + * at all and sends only the header and the trailer together. + * For this reason we send a trailer only if there is no a header. + * + * Although sendfile() allows to pass a header or a trailer, + * it may send the header or the trailer and a part of the file + * in different packets. And FreeBSD workaround (TCP_NOPUSH option) + * does not help. + */ + + +#if (IOV_MAX > 64) +#define NGX_HEADERS 64 +#define NGX_TRAILERS 64 +#else +#define NGX_HEADERS IOV_MAX +#define NGX_TRAILERS IOV_MAX +#endif + + +ngx_chain_t * +ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int rc; + u_char *prev; + off_t size, send, prev_send, aligned, sent, fprev; + off_t header_size, file_size; + ngx_uint_t eintr, eagain, complete; + ngx_err_t err; + ngx_buf_t *file; + ngx_array_t header, trailer; + ngx_event_t *wev; + ngx_chain_t *cl; + struct sf_hdtr hdtr; + struct iovec *iov, headers[NGX_HEADERS], trailers[NGX_TRAILERS]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_CHAIN_ERROR; + } + +#endif + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + send = 0; + eagain = 0; + + header.elts = headers; + header.size = sizeof(struct iovec); + header.nalloc = NGX_HEADERS; + header.pool = c->pool; + + trailer.elts = trailers; + trailer.size = sizeof(struct iovec); + trailer.nalloc = NGX_TRAILERS; + trailer.pool = c->pool; + + for ( ;; ) { + file = NULL; + file_size = 0; + header_size = 0; + eintr = 0; + complete = 0; + prev_send = send; + + header.nelts = 0; + trailer.nelts = 0; + + /* create the header iovec and coalesce the neighbouring bufs */ + + prev = NULL; + iov = NULL; + + for (cl = in; + cl && header.nelts < IOV_MAX && send < limit; + cl = cl->next) + { + if (ngx_buf_special(cl->buf)) { + continue; + } + + if (!ngx_buf_in_memory_only(cl->buf)) { + break; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } + + if (prev == cl->buf->pos) { + iov->iov_len += (size_t) size; + + } else { + iov = ngx_array_push(&header); + if (iov == NULL) { + return NGX_CHAIN_ERROR; + } + + iov->iov_base = (void *) cl->buf->pos; + iov->iov_len = (size_t) size; + } + + prev = cl->buf->pos + (size_t) size; + header_size += size; + send += size; + } + + + if (cl && cl->buf->in_file && send < limit) { + file = cl->buf; + + /* coalesce the neighbouring file bufs */ + + do { + size = cl->buf->file_last - cl->buf->file_pos; + + if (send + size > limit) { + size = limit - send; + + aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) + & ~((off_t) ngx_pagesize - 1); + + if (aligned <= cl->buf->file_last) { + size = aligned - cl->buf->file_pos; + } + } + + file_size += size; + send += size; + fprev = cl->buf->file_pos + size; + cl = cl->next; + + } while (cl + && cl->buf->in_file + && send < limit + && file->file->fd == cl->buf->file->fd + && fprev == cl->buf->file_pos); + } + + if (file && header.nelts == 0) { + + /* create the tailer iovec and coalesce the neighbouring bufs */ + + prev = NULL; + iov = NULL; + + while (cl && header.nelts < IOV_MAX && send < limit) { + + if (ngx_buf_special(cl->buf)) { + cl = cl->next; + continue; + } + + if (!ngx_buf_in_memory_only(cl->buf)) { + break; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } + + if (prev == cl->buf->pos) { + iov->iov_len += (size_t) size; + + } else { + iov = ngx_array_push(&trailer); + if (iov == NULL) { + return NGX_CHAIN_ERROR; + } + + iov->iov_base = (void *) cl->buf->pos; + iov->iov_len = (size_t) size; + } + + prev = cl->buf->pos + (size_t) size; + send += size; + cl = cl->next; + } + } + + if (file) { + + /* + * sendfile() returns EINVAL if sf_hdtr's count is 0, + * but corresponding pointer is not NULL + */ + + hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; + hdtr.hdr_cnt = header.nelts; + hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; + hdtr.trl_cnt = trailer.nelts; + + sent = header_size + file_size; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile: @%O %O h:%O", + file->file_pos, sent, header_size); + + rc = sendfile(file->file->fd, c->fd, file->file_pos, + &sent, &hdtr, 0); + + if (rc == -1) { + err = ngx_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + if (err == NGX_EINTR) { + eintr = 1; + + } else { + eagain = 1; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() sent only %O bytes", sent); + + } else { + wev->error = 1; + (void) ngx_connection_error(c, err, "sendfile() failed"); + return NGX_CHAIN_ERROR; + } + } + + if (rc == 0 && sent == 0) { + + /* + * if rc and sent equal to zero, then someone + * has truncated the file, so the offset became beyond + * the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated", + file->file->name.data); + + return NGX_CHAIN_ERROR; + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile: %d, @%O %O:%O", + rc, file->file_pos, sent, file_size + header_size); + + } else { + rc = writev(c->fd, header.elts, header.nelts); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "writev: %d of %uz", rc, send); + + if (rc == -1) { + err = ngx_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + if (err == NGX_EINTR) { + eintr = 1; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); + + } else { + wev->error = 1; + ngx_connection_error(c, err, "writev() failed"); + return NGX_CHAIN_ERROR; + } + } + + sent = rc > 0 ? rc : 0; + } + + if (send - prev_send == sent) { + complete = 1; + } + + c->sent += sent; + + for (cl = in; cl; cl = cl->next) { + + if (ngx_buf_special(cl->buf)) { + continue; + } + + if (sent == 0) { + break; + } + + size = ngx_buf_size(cl->buf); + + if (sent >= size) { + sent -= size; + + if (ngx_buf_in_memory(cl->buf)) { + cl->buf->pos = cl->buf->last; + } + + if (cl->buf->in_file) { + cl->buf->file_pos = cl->buf->file_last; + } + + continue; + } + + if (ngx_buf_in_memory(cl->buf)) { + cl->buf->pos += (size_t) sent; + } + + if (cl->buf->in_file) { + cl->buf->file_pos += sent; + } + + break; + } + + if (eintr) { + continue; + } + + if (!complete) { + wev->ready = 0; + return cl; + } + + if (send >= limit || cl == NULL) { + return cl; + } + + in = cl; + } +} diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -37,6 +37,9 @@ typedef int ngx_err_t; #define NGX_ETIMEDOUT ETIMEDOUT #define NGX_ECONNREFUSED ECONNREFUSED #define NGX_ENAMETOOLONG ENAMETOOLONG +#define NGX_ENETDOWN ENETDOWN +#define NGX_ENETUNREACH ENETUNREACH +#define NGX_EHOSTDOWN EHOSTDOWN #define NGX_EHOSTUNREACH EHOSTUNREACH #define NGX_ENOSYS ENOSYS #define NGX_ECANCELED ECANCELED diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -257,7 +257,15 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t ngx_int_t ngx_open_glob(ngx_glob_t *gl) { - if (glob((char *) gl->pattern, GLOB_NOSORT, NULL, &gl->pglob) == 0) { + int n; + + n = glob((char *) gl->pattern, GLOB_NOSORT, NULL, &gl->pglob); + + if (n == 0) { + return NGX_OK; + } + + if (n == GLOB_NOMATCH && gl->test) { return NGX_OK; } @@ -343,3 +351,22 @@ ngx_unlock_fd(ngx_fd_t fd) return 0; } + + +#if (NGX_HAVE_O_DIRECT) + +ngx_int_t +ngx_directio(ngx_fd_t fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + + if (flags == -1) { + return -1; + } + + return fcntl(fd, F_SETFL, flags | O_DIRECT); +} + +#endif diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -17,8 +17,20 @@ +#ifdef __CYGWIN__ + +#define NGX_HAVE_CASELESS_FILESYSTEM 1 + +#define ngx_open_file(name, mode, create, access) \ + open((const char *) name, mode|create|O_BINARY, access) + +#else + #define ngx_open_file(name, mode, create, access) \ open((const char *) name, mode|create, access) + +#endif + #define ngx_open_file_n "open()" #define NGX_FILE_RDONLY O_RDONLY @@ -93,6 +105,16 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_file_uniq(sb) (sb)->st_ino +#if (NGX_HAVE_CASELESS_FILESYSTEM) + +#define ngx_filename_cmp(s1, s2, n) strncasecmp((char *) s1, (char *) s2, n) + +#else + +#define ngx_filename_cmp ngx_memcmp + +#endif + #define ngx_getcwd(buf, size) (getcwd(buf, size) != NULL) #define ngx_getcwd_n "getcwd()" @@ -144,10 +166,11 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, typedef struct { - size_t n; - glob_t pglob; - u_char *pattern; - ngx_log_t *log; + size_t n; + glob_t pglob; + u_char *pattern; + ngx_log_t *log; + ngx_uint_t test; } ngx_glob_t; @@ -166,4 +189,27 @@ ngx_err_t ngx_unlock_fd(ngx_fd_t fd); #define ngx_unlock_fd_n "fcntl(F_SETLK, F_UNLCK)" +#if (NGX_HAVE_O_DIRECT) + +ngx_int_t ngx_directio(ngx_fd_t fd); +#define ngx_directio_n "fcntl(O_DIRECT)" + +#elif (NGX_HAVE_F_NOCACHE) + +#define ngx_directio(fd) fcntl(fd, F_NOCACHE, 1) +#define ngx_directio_n "fcntl(F_NOCACHE)" + +#elif (NGX_HAVE_DIRECTIO) + +#define ngx_directio(fd) directio(fd, DIRECTIO_ON) +#define ngx_directio_n "directio(DIRECTIO_ON)" + +#else + +#define ngx_directio(fd) 0 +#define ngx_directio_n "ngx_directio_n" + +#endif + + #endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd.h b/src/os/unix/ngx_freebsd.h --- a/src/os/unix/ngx_freebsd.h +++ b/src/os/unix/ngx_freebsd.h @@ -11,13 +11,14 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); -extern int ngx_freebsd_kern_osreldate; -extern int ngx_freebsd_hw_ncpu; -extern u_long ngx_freebsd_net_inet_tcp_sendspace; -extern int ngx_freebsd_kern_ipc_zero_copy_send; +extern int ngx_freebsd_kern_osreldate; +extern int ngx_freebsd_hw_ncpu; +extern u_long ngx_freebsd_net_inet_tcp_sendspace; +extern int ngx_freebsd_kern_ipc_zero_copy_send; -extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; -extern ngx_uint_t ngx_freebsd_use_tcp_nopush; +extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; +extern ngx_uint_t ngx_freebsd_use_tcp_nopush; +extern ngx_uint_t ngx_freebsd_debug_malloc; #endif /* _NGX_FREEBSD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -48,11 +48,16 @@ #if __FreeBSD_version < 400017 -/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */ +/* + * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA() + */ #undef CMSG_SPACE #define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) +#undef CMSG_LEN +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + #undef CMSG_DATA #define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr))) diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -23,13 +23,15 @@ int ngx_freebsd_machdep_hlt_logical_ int ngx_freebsd_kern_ipc_zero_copy_send; -ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; -ngx_uint_t ngx_freebsd_use_tcp_nopush; +ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; +ngx_uint_t ngx_freebsd_use_tcp_nopush; +ngx_uint_t ngx_freebsd_debug_malloc; static ngx_os_io_t ngx_freebsd_io = { ngx_unix_recv, ngx_readv_chain, + ngx_udp_unix_recv, ngx_unix_send, #if (NGX_HAVE_SENDFILE) ngx_freebsd_sendfile_chain, @@ -85,6 +87,16 @@ ngx_debug_init() malloc_options = "J"; #endif + ngx_freebsd_debug_malloc = 1; + +#else + char *mo; + + mo = getenv("MALLOC_OPTIONS"); + + if (mo && ngx_strchr(mo, 'J')) { + ngx_freebsd_debug_malloc = 1; + } #endif } diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -47,9 +47,11 @@ #include /* tzset() */ #include /* memalign() */ +#include /* IOV_MAX */ #include #include #include +#include /* uname() */ #include @@ -68,7 +70,7 @@ extern ssize_t sendfile(int s, int fd, i #endif -#if (NGX_HAVE_POLL) +#if (NGX_HAVE_POLL || NGX_HAVE_RTSIG) #include #endif diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -8,19 +8,16 @@ #include -static ngx_int_t ngx_linux_procfs(char *name, char *buf, size_t len, - ngx_log_t *log); - +u_char ngx_linux_kern_ostype[50]; +u_char ngx_linux_kern_osrelease[50]; -char ngx_linux_kern_ostype[50]; -char ngx_linux_kern_osrelease[50]; - -int ngx_linux_rtsig_max; +int ngx_linux_rtsig_max; static ngx_os_io_t ngx_linux_io = { ngx_unix_recv, ngx_readv_chain, + ngx_udp_unix_recv, ngx_unix_send, #if (NGX_HAVE_SENDFILE) ngx_linux_sendfile_chain, @@ -35,27 +32,25 @@ static ngx_os_io_t ngx_linux_io = { ngx_int_t ngx_os_specific_init(ngx_log_t *log) { + struct utsname u; + + if (uname(&u) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "uname() failed"); + return NGX_ERROR; + } + + (void) ngx_cpystrn(ngx_linux_kern_ostype, (u_char *) u.sysname, + sizeof(ngx_linux_kern_ostype)); + + (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release, + sizeof(ngx_linux_kern_osrelease)); + +#if (NGX_HAVE_RTSIG) + { int name[2]; size_t len; ngx_err_t err; - if (ngx_linux_procfs("/proc/sys/kernel/ostype", - ngx_linux_kern_ostype, - sizeof(ngx_linux_kern_ostype), log) - == -1) - { - return NGX_ERROR; - } - - if (ngx_linux_procfs("/proc/sys/kernel/osrelease", - ngx_linux_kern_osrelease, - sizeof(ngx_linux_kern_osrelease), log) - == -1) - { - return NGX_ERROR; - } - - name[0] = CTL_KERN; name[1] = KERN_RTSIGMAX; len = sizeof(ngx_linux_rtsig_max); @@ -73,6 +68,8 @@ ngx_os_specific_init(ngx_log_t *log) ngx_linux_rtsig_max = 0; } + } +#endif ngx_os_io = ngx_linux_io; @@ -86,39 +83,8 @@ ngx_os_specific_status(ngx_log_t *log) ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", ngx_linux_kern_ostype, ngx_linux_kern_osrelease); +#if (NGX_HAVE_RTSIG) ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d", ngx_linux_rtsig_max); +#endif } - - -static ngx_int_t -ngx_linux_procfs(char *name, char *buf, size_t len, ngx_log_t *log) -{ - int n; - ngx_fd_t fd; - - fd = open(name, O_RDONLY); - - if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "open(\"%s\") failed", name); - - return NGX_ERROR; - } - - n = read(fd, buf, len); - - if (n == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "read(\"%s\") failed", name); - - } else { - if (buf[n - 1] == '\n') { - buf[--n] = '\0'; - } - } - - ngx_close_file(fd); - - return n; -} diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -25,6 +25,7 @@ typedef ngx_chain_t *(*ngx_send_chain_pt typedef struct { ngx_recv_pt recv; ngx_recv_chain_pt recv_chain; + ngx_recv_pt udp_recv; ngx_send_pt send; ngx_send_chain_pt send_chain; ngx_uint_t flags; @@ -41,6 +42,7 @@ ngx_int_t ngx_daemon(ngx_log_t *log); ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry); +ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size); ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); @@ -64,6 +66,10 @@ extern ngx_uint_t ngx_tcp_nodelay_and_ #elif (NGX_SOLARIS) #include + + +#elif (NGX_DARWIN) +#include #endif diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -19,6 +19,12 @@ #endif +#ifdef __CYGWIN__ +#define timezonevar /* timezone is variable */ +#define NGX_BROKEN_SCM_RIGHTS 1 +#endif + + #include #include #if (NGX_HAVE_UNISTD_H) @@ -64,6 +70,15 @@ #include /* IOV_MAX */ #endif +#ifdef __CYGWIN__ +#include /* memalign() */ +#endif + +#if (NGX_HAVE_CRYPT_H) +#include +#endif + + #ifndef IOV_MAX #define IOV_MAX 16 #endif @@ -95,11 +110,16 @@ #include /* ALIGN() */ -/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */ +/* + * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA() + */ #undef CMSG_SPACE #define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) +#undef CMSG_LEN +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + #undef CMSG_DATA #define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr))) diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -21,6 +21,7 @@ struct rlimit rlmt; ngx_os_io_t ngx_os_io = { ngx_unix_recv, ngx_readv_chain, + ngx_udp_unix_recv, NULL, ngx_writev_chain, 0 diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -452,7 +452,7 @@ ngx_process_get_status(void) * * When several processes exit at the same time FreeBSD may * erroneously call the signal handler for exited process - * despite waitpid() may be already called for this process + * despite waitpid() may be already called for this process. */ if (err == NGX_ECHILD) { @@ -507,8 +507,9 @@ ngx_process_get_status(void) if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "%s %P exited with fatal code %d and could not respawn", - process, pid, WEXITSTATUS(status)); + "%s %P exited with fatal code %d " + "and can not be respawn", + process, pid, WEXITSTATUS(status)); ngx_processes[i].respawn = 0; } } diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -14,7 +14,7 @@ static void ngx_start_worker_processes(n ngx_int_t type); static void ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); -static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle); +static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle); static void ngx_master_process_exit(ngx_cycle_t *cycle); static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority); @@ -108,7 +108,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy size += ngx_strlen(ngx_argv[i]) + 1; } - title = ngx_palloc(cycle->pool, size); + title = ngx_pnalloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { @@ -157,9 +157,9 @@ ngx_master_process_cycle(ngx_cycle_t *cy if (ngx_reap) { ngx_reap = 0; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap childs"); + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); - live = ngx_reap_childs(cycle); + live = ngx_reap_children(cycle); } if (!live && (ngx_terminate || ngx_quit)) { @@ -409,6 +409,12 @@ ngx_signal_worker_processes(ngx_cycle_t ngx_err_t err; ngx_channel_t ch; +#if (NGX_BROKEN_SCM_RIGHTS) + + ch.command = 0; + +#else + switch (signo) { case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): @@ -427,6 +433,8 @@ ngx_signal_worker_processes(ngx_cycle_t ch.command = 0; } +#endif + ch.fd = -1; @@ -496,7 +504,7 @@ ngx_signal_worker_processes(ngx_cycle_t static ngx_uint_t -ngx_reap_childs(ngx_cycle_t *cycle) +ngx_reap_children(ngx_cycle_t *cycle) { ngx_int_t i, n; ngx_uint_t live; @@ -679,17 +687,16 @@ ngx_worker_process_cycle(ngx_cycle_t *cy { ngx_uint_t i; ngx_connection_t *c; -#if (NGX_THREADS) - ngx_int_t n; - ngx_err_t err; - ngx_core_conf_t *ccf; -#endif ngx_worker_process_init(cycle, 1); ngx_setproctitle("worker process"); #if (NGX_THREADS) + { + ngx_int_t n; + ngx_err_t err; + ngx_core_conf_t *ccf; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); @@ -728,7 +735,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cy } } } - + } #endif for ( ;; ) { @@ -987,18 +994,18 @@ ngx_worker_process_exit(ngx_cycle_t *cyc } } - if (ngx_quit) { + if (ngx_exiting) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 && c[i].read && !c[i].read->accept - && !c[i].read->channel) + && !c[i].read->channel + && !c[i].read->resolver) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in %ui connection, " - "aborting", - c[i].fd, i); + "open socket #%d left in %ui connection %s", + c[i].fd, i, ngx_debug_quit ? ", aborting" : ""); ngx_debug_point(); } } @@ -1035,7 +1042,6 @@ static void ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n; - ngx_socket_t fd; ngx_channel_t ch; ngx_connection_t *c; @@ -1048,75 +1054,74 @@ ngx_channel_handler(ngx_event_t *ev) ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler"); - n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); + for ( ;; ) { - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); + n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); - if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); - ngx_free_connection(c); + if (n == NGX_ERROR) { - fd = c->fd; - c->fd = (ngx_socket_t) -1; + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_del_conn(c, 0); + } - if (close(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, - "close() channel failed"); + ngx_close_connection(c); + return; } - return; - } + if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { + if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { + return; + } + } - if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { - if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { + if (n == NGX_AGAIN) { return; } - } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, + "channel command: %d", ch.command); - if (n == NGX_AGAIN) { - return; - } + switch (ch.command) { - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, - "channel command: %d", ch.command); - - switch (ch.command) { + case NGX_CMD_QUIT: + ngx_quit = 1; + break; - case NGX_CMD_QUIT: - ngx_quit = 1; - break; + case NGX_CMD_TERMINATE: + ngx_terminate = 1; + break; - case NGX_CMD_TERMINATE: - ngx_terminate = 1; - break; + case NGX_CMD_REOPEN: + ngx_reopen = 1; + break; - case NGX_CMD_REOPEN: - ngx_reopen = 1; - break; + case NGX_CMD_OPEN_CHANNEL: - case NGX_CMD_OPEN_CHANNEL: - - ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, - "get channel s:%i pid:%P fd:%d", ch.slot, ch.pid, ch.fd); + ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, + "get channel s:%i pid:%P fd:%d", + ch.slot, ch.pid, ch.fd); - ngx_processes[ch.slot].pid = ch.pid; - ngx_processes[ch.slot].channel[0] = ch.fd; - break; + ngx_processes[ch.slot].pid = ch.pid; + ngx_processes[ch.slot].channel[0] = ch.fd; + break; - case NGX_CMD_CLOSE_CHANNEL: + case NGX_CMD_CLOSE_CHANNEL: - ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, - "close channel s:%i pid:%P our:%P fd:%d", - ch.slot, ch.pid, ngx_processes[ch.slot].pid, - ngx_processes[ch.slot].channel[0]); + ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, + "close channel s:%i pid:%P our:%P fd:%d", + ch.slot, ch.pid, ngx_processes[ch.slot].pid, + ngx_processes[ch.slot].channel[0]); - if (close(ngx_processes[ch.slot].channel[0]) == -1) { - ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, - "close() channel failed"); + if (close(ngx_processes[ch.slot].channel[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + "close() channel failed"); + } + + ngx_processes[ch.slot].channel[0] = -1; + break; } - - ngx_processes[ch.slot].channel[0] = -1; - break; } } diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -11,7 +11,8 @@ #if (NGX_HAVE_KQUEUE) -ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) +ssize_t +ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) { ssize_t n; ngx_err_t err; @@ -40,6 +41,7 @@ ssize_t ngx_unix_recv(ngx_connection_t * return 0; } else { + rev->ready = 0; return NGX_AGAIN; } } @@ -77,12 +79,6 @@ ssize_t ngx_unix_recv(ngx_connection_t * * even if kqueue reported about available data */ -#if 0 - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "recv() returned 0 while kevent() reported " - "%d available bytes", rev->available); -#endif - rev->eof = 1; rev->available = 0; } @@ -126,7 +122,8 @@ ssize_t ngx_unix_recv(ngx_connection_t * #else /* ! NGX_HAVE_KQUEUE */ -ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) +ssize_t +ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) { ssize_t n; ngx_err_t err; diff --git a/src/os/unix/ngx_send.c b/src/os/unix/ngx_send.c --- a/src/os/unix/ngx_send.c +++ b/src/os/unix/ngx_send.c @@ -9,7 +9,8 @@ #include -ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size) +ssize_t +ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size) { ssize_t n; ngx_err_t err; diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c --- a/src/os/unix/ngx_solaris_init.c +++ b/src/os/unix/ngx_solaris_init.c @@ -16,6 +16,7 @@ char ngx_solaris_version[50]; static ngx_os_io_t ngx_solaris_io = { ngx_unix_recv, ngx_readv_chain, + ngx_udp_unix_recv, ngx_unix_send, #if (NGX_HAVE_SENDFILE) ngx_solaris_sendfilev_chain, @@ -57,7 +58,7 @@ ngx_os_specific_init(ngx_log_t *log) ngx_os_io = ngx_solaris_io; - return NGX_OK;; + return NGX_OK; } diff --git a/src/os/unix/ngx_udp_recv.c b/src/os/unix/ngx_udp_recv.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_udp_recv.c @@ -0,0 +1,114 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +#if (NGX_HAVE_KQUEUE) + +ssize_t +ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = recv(c->fd, buf, size, 0); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: fd:%d %d of %d", c->fd, n, size); + + if (n >= 0) { + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available -= n; + + /* + * rev->available may be negative here because some additional + * bytes may be received between kevent() and recv() + */ + + if (rev->available <= 0) { + rev->ready = 0; + rev->available = 0; + } + } + + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "recv() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "recv() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR){ + rev->error = 1; + } + + return n; +} + +#else /* ! NGX_HAVE_KQUEUE */ + +ssize_t +ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = recv(c->fd, buf, size, 0); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: fd:%d %d of %d", c->fd, n, size); + + if (n >= 0) { + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "recv() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "recv() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR){ + rev->error = 1; + } + + return n; +} + +#endif /* NGX_HAVE_KQUEUE */ diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -43,7 +43,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, if (err == 0) { len = ngx_strlen(value); - *encrypted = ngx_palloc(pool, len); + *encrypted = ngx_pnalloc(pool, len); if (*encrypted) { ngx_memcpy(*encrypted, value, len + 1); return NGX_OK; @@ -81,7 +81,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, if (value) { len = ngx_strlen(value); - *encrypted = ngx_palloc(pool, len); + *encrypted = ngx_pnalloc(pool, len); if (*encrypted) { ngx_memcpy(*encrypted, value, len + 1); }