# HG changeset patch # User Maxim Dounin # Date 1253913907 -14400 # Node ID 9773720b845e15edf0c72aa1d51b268161361aef # Parent 1e91f9968443b54f42346d445a2a2c90362e1503# Parent b8ac674b0ec95cf1d655aeb716a95101c39456f0 Merge with 0.8.16. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -241,3 +241,32 @@ c8cfb6c462efa1a49e51fd193e4c645a5cfb212c 9eda3153223b42932fec477da26be67a8a33b781 NGINX_0_7_45 56baf312c1b57b425c331a325b7875fd92aff5b8 NGINX_0_7_46 6866b490272ef912cd285ce6edc2c393546ea947 NGINX_0_7_47 +09f0ef15d5446d925a7b556925235563ef7932f7 NGINX_0_7_48 +3a4102b00f9753c6b851becebe0d04996b7ff50e NGINX_0_7_49 +09b45263c8178db911e60992a21df9278736dfe4 NGINX_0_7_50 +f2c6a737327477de6844021269e95333e03eba19 NGINX_0_7_51 +549994537f15f7212b5f09f1f4d6e00f2dc562f9 NGINX_0_7_52 +392c16f2d85815c32add2715607598013ce58014 NGINX_0_7_53 +ed5e10fb40fc02b64d6c5719141e33f74cccd02a NGINX_0_7_54 +6484cbba022236c1cd094abfa117dd3aa1b70181 NGINX_0_7_55 +829f9a66a65923d1765961bf1c5075869d421633 NGINX_0_7_56 +e66f886a83052c6a09dfbd77bfc78310dd7fd2d9 NGINX_0_7_57 +98143f74eb3d9d87babc0934c9cd7c40b7af277a NGINX_0_7_58 +499474178a112350895b502f16a2d1abe1b5b532 NGINX_0_7_59 +f39b9e29530de0464264608c33d84abf2e10b9f2 NGINX_0_8_0 +207ae3ff044452b1fb8ad28951ff566615a51939 NGINX_0_8_1 +13b908d5338a1db8365c33efc6189569bb9d58a7 NGINX_0_8_2 +f0cac61857ae53b080bb44fa899762c901079dee NGINX_0_8_3 +c178dbab489a192d9e40f7747777a0890e35e93b NGINX_0_8_4 +e8b686f230a83ac654d963d1d8e0f96893e0c372 NGINX_0_8_5 +4b0d7f0bf22b653698898aad108bf5452e25e65c NGINX_0_8_6 +24b676623d4fb72bb90fc2ad251e5c3220009a11 NGINX_0_8_7 +6557aef8a4b2479c0ae5d887e92c311150f75215 NGINX_0_8_8 +43cc6f0b77ce54e4e03b33189a34f99beecffe34 NGINX_0_8_9 +7efcdb93775276c87bcea0e51c889bd3e078430a NGINX_0_8_10 +86dad910eeb6b626d7f37123b464c89bdc110f66 NGINX_0_8_11 +d41628eb4d0a5a82c915b2684a4299f32b0ded22 NGINX_0_8_12 +1bc8c12d80ecec4f7f88c35359585ca5139248e3 NGINX_0_8_13 +80f7156c296569546cf57fa286749d84e0cc8b9d NGINX_0_8_14 +0161f31978175e258b8bb4989262b2ccb5fa9207 NGINX_0_8_15 +005a70f9573bc6bcf760786cb0573a62f1e570f3 NGINX_0_8_16 diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,469 @@ +Changes with nginx 0.8.16 22 Sep 2009 + + *) Feature: the "image_filter_transparency" directive. + + *) Bugfix: "addition_types" directive was incorrectly named + "addtion_types". + + *) Bugfix: resolver cache poisoning. + Thanks to Matthew Dempsky. + + *) Bugfix: memory leak in resolver. + Thanks to Matthew Dempsky. + + *) Bugfix: invalid request line in $request variable was written in + access_log only if error_log was set to "info" or "debug" level. + + *) Bugfix: in PNG alpha-channel support in the + ngx_http_image_filter_module. + + *) Bugfix: nginx always added "Vary: Accept-Encoding" response header + line, if both "gzip_static" and "gzip_vary" were on. + + *) Bugfix: in UTF-8 encoding support by "try_files" directive in + nginx/Windows. + + *) Bugfix: in "post_action" directive usage; the bug had appeared in + 0.8.11. + Thanks to Igor Artemiev. + + +Changes with nginx 0.8.15 14 Sep 2009 + + *) Security: a segmentation fault might occur in worker process while + specially crafted request handling. + Thanks to Chris Ries. + + *) Bugfix: if names .domain.tld, .sub.domain.tld, and .domain-some.tld + were defined, then the name .sub.domain.tld was matched by + .domain.tld. + + *) Bugfix: in transparency support in the ngx_http_image_filter_module. + + *) Bugfix: in file AIO. + + *) Bugfix: in X-Accel-Redirect usage; the bug had appeared in 0.8.11. + + *) Bugfix: in embedded perl module; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.14 07 Sep 2009 + + *) Bugfix: an expired cached response might stick in the "UPDATING" + state. + + *) Bugfix: a segmentation fault might occur in worker process, if + error_log was set to info or debug level. + Thanks to Sergey Bochenkov. + + *) Bugfix: in embedded perl module; the bug had appeared in 0.8.11. + + *) Bugfix: an "error_page" directive did not redirect a 413 error; the + bug had appeared in 0.6.10. + + +Changes with nginx 0.8.13 31 Aug 2009 + + *) Bugfix: in the "aio sendfile" directive; the bug had appeared in + 0.8.12. + + *) Bugfix: nginx could not be built without the --with-file-aio option + on FreeBSD; the bug had appeared in 0.8.12. + + +Changes with nginx 0.8.12 31 Aug 2009 + + *) Feature: the "sendfile" parameter in the "aio" directive on FreeBSD. + + *) Bugfix: in try_files; the bug had appeared in 0.8.11. + + *) Bugfix: in memcached; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.11 28 Aug 2009 + + *) Change: now directive "gzip_disable msie6" does not disable gzipping + for MSIE 6.0 SV1. + + *) Feature: file AIO support on FreeBSD and Linux. + + *) Feature: the "directio_alignment" directive. + + +Changes with nginx 0.8.10 24 Aug 2009 + + *) Bugfix: memory leaks if GeoIP City database was used. + + *) Bugfix: in copying temporary files to permanent storage area; the + bug had appeared in 0.8.9. + + +Changes with nginx 0.8.9 17 Aug 2009 + + *) Feature: now the start cache loader runs in a separate process; this + should improve large caches handling. + + *) Feature: now temporary files and permanent storage area may reside + at different file systems. + + +Changes with nginx 0.8.8 10 Aug 2009 + + *) Bugfix: in handling FastCGI headers split in records. + + *) Bugfix: a segmentation fault occurred in worker process, if a + request was handled in two proxied or FastCGIed locations and a + caching was enabled in the first location; the bug had appeared in + 0.8.7. + + +Changes with nginx 0.8.7 27 Jul 2009 + + *) Change: minimum supported OpenSSL version is 0.9.7. + + *) Change: the "ask" parameter of the "ssl_verify_client" directive was + changed to the "optional" parameter and now it checks a client + certificate if it was offered. + Thanks to Brice Figureau. + + *) Feature: the $ssl_client_verify variable. + Thanks to Brice Figureau. + + *) Feature: the "ssl_crl" directive. + Thanks to Brice Figureau. + + *) Feature: the "proxy" parameter of the "geo" directive. + + *) Feature: the "image_filter" directive supports variables for setting + size. + + *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the + bug had appeared in 0.7.7. + Thanks to Sergey Zhuravlev. + + *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did + not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", + "X-Accel-Buffering", and "X-Accel-Charset" lines from backend + response header. + Thanks to Maxim Dounin. + + *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend + response header lines; the bug had appeared in 0.7.44. + Thanks to Maxim Dounin. + + *) Bugfix: the "[alert] zero size buf" error if subrequest returns an + empty response; the bug had appeared in 0.8.5. + + +Changes with nginx 0.8.6 20 Jul 2009 + + *) Feature: the ngx_http_geoip_module. + + *) Bugfix: XSLT filter may fail with message "not well formed XML + document" for valid XML document. + Thanks to Kuramoto Eiji. + + *) Bugfix: now in MacOSX, Cygwin, and nginx/Windows locations given by + a regular expression are always tested in case insensitive mode. + + *) Bugfix: now nginx/Windows ignores trailing dots in URI. + Thanks to Hugo Leisink. + + *) Bugfix: name of file specified in --conf-path was not honored during + installation; the bug had appeared in 0.6.6. + Thanks to Maxim Dounin. + + +Changes with nginx 0.8.5 13 Jul 2009 + + *) Bugfix: now nginx allows underscores in a request method. + + *) Bugfix: a 500 error code was returned for invalid login/password + while HTTP Basic authentication on Windows. + + *) Bugfix: ngx_http_perl_module responses did not work in subrequests. + + *) Bugfix: in ngx_http_limit_req_module. + Thanks to Maxim Dounin. + + +Changes with nginx 0.8.4 22 Jun 2009 + + *) Bugfix: nginx could not be built --without-http-cache; the bug had + appeared in 0.8.3. + + +Changes with nginx 0.8.3 19 Jun 2009 + + *) Feature: the $upstream_cache_status variable. + + *) Bugfix: nginx could not be built on MacOSX 10.6. + + *) Bugfix: nginx could not be built --without-http-cache; the bug had + appeared in 0.8.2. + + *) Bugfix: a segmentation fault occurred in worker process, if a + backend 401 error was intercepted and the backend did not set the + "WWW-Authenticate" response header line. + Thanks to Eugene Mychlo. + + +Changes with nginx 0.8.2 15 Jun 2009 + + *) Bugfix: in open_file_cache and proxy/fastcgi cache interaction on + start up. + + *) Bugfix: open_file_cache might cache open file descriptors too long; + the bug had appeared in 0.7.4. + + +Changes with nginx 0.8.1 08 Jun 2009 + + *) Feature: the "updating" parameter in "proxy_cache_use_stale" and + "fastcgi_cache_use_stale" directives. + + *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request + header lines were passed to backend while caching if no + "proxy_set_header" directive was used with any parameters. + + *) Bugfix: the "Set-Cookie" and "P3P" response header lines were not + hidden while caching if no "proxy_hide_header/fastcgi_hide_header" + directives were used with any parameters. + + *) Bugfix: the ngx_http_image_filter_module did not support GIF87a + format. + Thanks to Denis Ilyinyh. + + *) Bugfix: nginx could not be built modules on Solaris 10 and early; + the bug had appeared in 0.7.56. + + +Changes with nginx 0.8.0 02 Jun 2009 + + *) Feature: the "keepalive_requests" directive. + + *) Feature: the "limit_rate_after" directive. + Thanks to Ivan Debnar. + + *) Bugfix: XLST filter did not work in subrequests. + + *) Bugfix: in relative paths handling in nginx/Windows. + + *) Bugfix: in proxy_store, fastcgi_store, proxy_cache, and + fastcgi_cache in nginx/Windows. + + *) Bugfix: in memory allocation error handling. + Thanks to Maxim Dounin and Kirill A. Korinskiy. + + +Changes with nginx 0.7.59 25 May 2009 + + *) Feature: the "proxy_cache_methods" and "fastcgi_cache_methods" + directives. + + *) Bugfix: socket leak; the bug had appeared in 0.7.25. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault occurred in worker process, + if a request had no body and the $request_body variable was used; + the bug had appeared in 0.7.58. + + *) Bugfix: the SSL modules might not built on Solaris and Linux; + the bug had appeared in 0.7.56. + + *) Bugfix: ngx_http_xslt_filter_module responses were not handled by + SSI, charset, and gzip filters. + + *) Bugfix: a "charset" directive did not set a charset to + ngx_http_gzip_static_module responses. + + +Changes with nginx 0.7.58 18 May 2009 + + *) Feature: a "listen" directive of the mail proxy module supports IPv6. + + *) Feature: the "image_filter_jpeg_quality" directive. + + *) Feature: the "client_body_in_single_buffer" directive. + + *) Feature: the $request_body variable. + + *) Bugfix: in ngx_http_autoindex_module in file name links having a ":" + symbol in the name. + + *) Bugfix: "make upgrade" procedure did not work; the bug had appeared + in 0.7.53. + Thanks to Denis F. Latypoff. + + +Changes with nginx 0.7.57 12 May 2009 + + *) Bugfix: a floating-point fault occurred in worker process, if the + ngx_http_image_filter_module errors were redirected to named + location; the bug had appeared in 0.7.56. + + +Changes with nginx 0.7.56 11 May 2009 + + *) Feature: nginx/Windows supports IPv6 in a "listen" directive of the + HTTP module. + + *) Bugfix: in ngx_http_image_filter_module. + + +Changes with nginx 0.7.55 06 May 2009 + + *) Bugfix: the http_XXX parameters in "proxy_cache_use_stale" and + "fastcgi_cache_use_stale" directives did not work. + + *) Bugfix: fastcgi cache did not cache header only responses. + + *) Bugfix: of "select() failed (9: Bad file descriptor)" error in + nginx/Unix and "select() failed (10038: ...)" error in nginx/Windows. + + *) Bugfix: a segmentation fault might occur in worker process, if an + "debug_connection" directive was used; the bug had appeared in + 0.7.54. + + *) Bugfix: fix ngx_http_image_filter_module building errors. + + *) Bugfix: the files bigger than 2G could not be transferred using + $r->sendfile. + Thanks to Maxim Dounin. + + +Changes with nginx 0.7.54 01 May 2009 + + *) Feature: the ngx_http_image_filter_module. + + *) Feature: the "proxy_ignore_headers" and "fastcgi_ignore_headers" + directives. + + *) Bugfix: a segmentation fault might occur in worker process, if an + "open_file_cache_errors off" directive was used; the bug had + appeared in 0.7.53. + + *) Bugfix: the "port_in_redirect off" directive did not work; the bug + had appeared in 0.7.39. + + *) Bugfix: improve handling of "select" method errors. + + *) Bugfix: of "select() failed (10022: ...)" error in nginx/Windows. + + *) Bugfix: in error text descriptions in nginx/Windows; the bug had + appeared in 0.7.53. + + +Changes with nginx 0.7.53 27 Apr 2009 + + *) Change: now a log set by --error-log-path is created from the very + start-up. + + *) Feature: now the start up errors and warnings are outputted to an + error_log and stderr. + + *) Feature: the empty --prefix= configure parameter forces nginx to use + a directory where it was run as prefix. + + *) Feature: the -p switch. + + *) Feature: the -s switch on Unix platforms. + + *) Feature: the -? and -h switches. + Thanks to Jerome Loyet. + + *) Feature: now switches may be set in condensed form. + + *) Bugfix: nginx/Windows did not work if configuration file was given + by the -c switch. + + *) Bugfix: temporary files might be not removed if the "proxy_store", + "fastcgi_store", "proxy_cache", or "fastcgi_cache" were used. + Thanks to Maxim Dounin. + + *) Bugfix: an incorrect value was passed to mail proxy authentication + server in "Auth-Method" header line; the bug had appeared + in 0.7.34. + Thanks to Simon Lecaille. + + *) Bugfix: system error text descriptions were not logged on Linux; + the bug had appeared in 0.7.45. + + *) Bugfix: the "fastcgi_cache_min_uses" directive did not work. + Thanks to Andrew Vorobyoff. + + +Changes with nginx 0.7.52 20 Apr 2009 + + *) Feature: the first native Windows binary release. + + *) Bugfix: in processing HEAD method while caching. + + *) Bugfix: in processing the "If-Modified-Since", "If-Range", etc. + client request header lines while caching. + + *) Bugfix: now the "Set-Cookie" and "P3P" header lines are hidden in + cacheable responses. + + *) Bugfix: if nginx was built with the ngx_http_perl_module and with a + perl which supports threads, then during a master process exit the + message "panic: MUTEX_LOCK" might be issued. + + *) Bugfix: nginx could not be built --without-http-cache; the bug had + appeared in 0.7.48. + + *) Bugfix: nginx could not be built on platforms different from i386, + amd64, sparc, and ppc; the bug had appeared in 0.7.42. + + +Changes with nginx 0.7.51 12 Apr 2009 + + *) Feature: the "try_files" directive supports a response code in the + fallback parameter. + + *) Feature: now any response code can be used in the "return" directive. + + *) Bugfix: the "error_page" directive made an external redirect without + query string; the bug had appeared in 0.7.44. + + *) Bugfix: if servers listened on several defined explicitly addresses, + then virtual servers might not work; the bug had appeared in 0.7.39. + + +Changes with nginx 0.7.50 06 Apr 2009 + + *) Bugfix: the $arg_... variables did not work; the bug had appeared in + 0.7.49. + + +Changes with nginx 0.7.49 06 Apr 2009 + + *) Bugfix: a segmentation fault might occur in worker process, if the + $arg_... variables were used; the bug had appeared in 0.7.48. + + +Changes with nginx 0.7.48 06 Apr 2009 + + *) Feature: the "proxy_cache_key" directive. + + *) Bugfix: now nginx takes into account the "X-Accel-Expires", + "Expires", and "Cache-Control" header lines in a backend response. + + *) Bugfix: now nginx caches responses for the GET requests only. + + *) Bugfix: the "fastcgi_cache_key" directive was not inherited. + + *) Bugfix: the $arg_... variables did not work with SSI subrequests. + Thanks to Maxim Dounin. + + *) Bugfix: nginx could not be built with uclibc library. + Thanks to Timothy Redaelli. + + *) Bugfix: nginx could not be built on OpenBSD; the bug had + appeared in 0.7.46. + + Changes with nginx 0.7.47 01 Apr 2009 *) Bugfix: nginx could not be built on FreeBSD 6 and early versions; @@ -180,7 +645,7 @@ Changes with nginx 0.7.35 original request extension. *) Bugfix: "*domain.tld" names were handled incorrectly in - "server_name", "valid_referers", and "map" directives, if an + "server_name", "valid_referers", and "map" directives, if ".domain.tld" and ".subdomain.domain.tld" wildcards were used; the bug had appeared in 0.7.9. @@ -198,7 +663,7 @@ Changes with nginx 0.7.34 Thanks to Maxim Dounin. *) Bugfix: in a redirect rewrite directive original arguments were - concatenated with new arguments by an "?" rather than an "&"; + concatenated with new arguments by a "?" rather than an "&"; the bug had appeared in 0.1.18. Thanks to Maxim Dounin. @@ -1572,8 +2037,8 @@ Changes with nginx 0.5.12 amd64, sparc, and ppc; the bug had appeared in 0.5.8. *) Bugfix: a segmentation fault might occur in worker process if the - temporarily files were used while working with FastCGI server; the - bug had appeared in 0.5.8. + temporary files were used while working with FastCGI server; the bug + had appeared in 0.5.8. *) Bugfix: a segmentation fault might occur in worker process if the $fastcgi_script_name variable was logged. @@ -2476,8 +2941,8 @@ Changes with nginx 0.3.31 in 0.3.18. *) Bugfix: if the HTTPS protocol was used in the "proxy_pass" directive - and the request body was in temporarily file then the request was - not transferred. + and the request body was in temporary file then the request was not + transferred. *) Bugfix: perl 5.8.8 compatibility. @@ -3630,7 +4095,7 @@ Changes with nginx 0.1.18 inherited. *) Bugfix: in a redirect rewrite directive arguments were concatenated - with URI by an "&" rather than an "?". + with URI by an "&" rather than a "?". *) Bugfix: the lines without trailing ";" in the file being included by the ngx_http_geo_module were silently ignored. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,481 @@ +Изменения в nginx 0.8.16 22.09.2009 + + *) Добавление: директива image_filter_transparency. + + *) Исправление: директива "addition_types" была неверно названа + "addtion_types". + + *) Исправление: порчи кэша resolver'а. + Спасибо Matthew Dempsky. + + *) Исправление: утечки памяти в resolver'е. + Спасибо Matthew Dempsky. + + *) Исправление: неверная строка запроса в переменной $request + записывалась в access_log только при использовании error_log на + уровне info или debug. + + *) Исправление: в поддержке альфа-канала PNG в модуле + ngx_http_image_filter_module. + + *) Исправление: nginx всегда добавлял строку "Vary: Accept-Encoding" в + заголовок ответа, если обе директивы gzip_static и gzip_vary были + включены. + + *) Исправление: в поддержке кодировки UTF-8 директивой try_files в + nginx/Windows. + + *) Исправление: ошибки при использовании post_action; ошибка появилась + в 0.8.11. + Спасибо Игорю Артемьеву. + + +Изменения в nginx 0.8.15 14.09.2009 + + *) Безопасность: при обработке специально созданного запроса в рабочем + процессе мог произойти segmentation fault. + Спасибо Chris Ries. + + *) Исправление: если были описаны имена .domain.tld, .sub.domain.tld и + .domain-some.tld, то имя .sub.domain.tld попадало под маску + .domain.tld. + + *) Исправление: в поддержке прозрачности в модуле + ngx_http_image_filter_module. + + *) Исправление: в файловом AIO. + + *) Исправление: ошибки при использовании X-Accel-Redirect; ошибка + появилась в 0.8.11. + + *) Исправление: ошибки при использовании встроенного перла; ошибка + появилась в 0.8.11. + + +Изменения в nginx 0.8.14 07.09.2009 + + *) Исправление: устаревший закэшированный запрос мог залипнуть в + состоянии "UPDATING". + + *) Исправление: при использовании error_log на уровне info или debug в + рабочем процессе мог произойти segmentation fault. + Спасибо Сергею Боченкову. + + *) Исправление: ошибки при использовании встроенного перла; ошибка + появилась в 0.8.11. + + *) Исправление: директива error_page не перенаправляла ошибку 413; + ошибка появилась в 0.6.10. + + +Изменения в nginx 0.8.13 31.08.2009 + + *) Исправление: в директиве "aio sendfile"; ошибка появилась в 0.8.12. + + *) Исправление: nginx не собирался без параметра --with-file-aio на + FreeBSD; ошибка появилась в 0.8.12. + + +Изменения в nginx 0.8.12 31.08.2009 + + *) Добавление: параметр sendfile в директиве aio во FreeBSD. + + *) Исправление: ошибки при использовании try_files; ошибка появилась в + 0.8.11. + + *) Исправление: ошибки при использовании memcached; ошибка появилась в + 0.8.11. + + +Изменения в nginx 0.8.11 28.08.2009 + + *) Изменение: теперь директива "gzip_disable msie6" не запрещает сжатие + для MSIE 6.0 SV1. + + *) Добавление: поддержка файлового AIO во FreeBSD и Linux. + + *) Добавление: директива directio_alignment. + + +Изменения в nginx 0.8.10 24.08.2009 + + *) Исправление: утечек памяти при использовании базы GeoIP City. + + *) Исправление: ошибки при копировании временных файлов в постоянное + место хранения; ошибка появилась в 0.8.9. + + +Изменения в nginx 0.8.9 17.08.2009 + + *) Добавление: теперь стартовый загрузчик кэша работает в отдельном + процесс; это должно улучшить обработку больших кэшей. + + *) Добавление: теперь временные файлы и постоянное место хранения могут + располагаться на разных файловых системах. + + +Изменения в nginx 0.8.8 10.08.2009 + + *) Исправление: в обработке заголовков ответа, разделённых в + FastCGI-записях. + + *) Исправление: если запрос обрабатывался в двух проксированных или + FastCGI location'ах и в первом из них использовалось кэширование, то + в рабочем процессе происходил segmentation fault; ошибка появилась в + 0.8.7. + + +Изменения в nginx 0.8.7 27.07.2009 + + *) Изменение: минимальная поддерживаемая версия OpenSSL - 0.9.7. + + *) Изменение: параметр ask директивы ssl_verify_client изменён на + параметр optional и теперь он проверяет клиентский сертификат, если + он был предложен. + Спасибо Brice Figureau. + + *) Добавление: переменная $ssl_client_verify. + Спасибо Brice Figureau. + + *) Добавление: директива ssl_crl. + Спасибо Brice Figureau. + + *) Добавление: параметр proxy директивы geo. + + *) Добавление: директива image_filter поддерживает переменные для + задания размеров. + + *) Исправление: использование переменной $ssl_client_cert портило + память; ошибка появилась в 0.7.7. + Спасибо Сергею Журавлёву. + + *) Исправление: директивы proxy_pass_header и fastcgi_pass_header" не + передавали клиенту строки "X-Accel-Redirect", "X-Accel-Limit-Rate", + "X-Accel-Buffering" и "X-Accel-Charset" из заголовка ответа + бэкенда. + Спасибо Максиму Дунину. + + *) Исправление: в обработке строк "Last-Modified" и "Accept-Ranges" в + заголовке ответа бэкенда; ошибка появилась в 0.7.44 + Спасибо Максиму Дунину. + + *) Исправление: ошибки "[alert] zero size buf" при получении пустых + ответы в подзапросах; ошибка появилась в 0.8.5. + + +Изменения в nginx 0.8.6 20.07.2009 + + *) Добавление: модуль ngx_http_geoip_module. + + *) Исправление: XSLT-фильтр мог выдавать ошибку "not well formed XML + document" для правильного документа. + Спасибо Kuramoto Eiji. + + *) Исправление: в MacOSX, Cygwin и nginx/Windows при проверке + location'ов, заданных регулярным выражением, теперь всегда делается + сравнение без учёта регистра символов. + + *) Исправление: теперь nginx/Windows игнорирует точки в конце URI. + Спасибо Hugo Leisink. + + *) Исправление: имя файла указанного в --conf-path игнорировалось при + установке; ошибка появилась в 0.6.6. + Спасибо Максиму Дунину. + + +Изменения в nginx 0.8.5 13.07.2009 + + *) Исправление: теперь nginx разрешает подчёркивания в методе запроса. + + *) Исправление: при использовании HTTP Basic-аутентификации на Windows + для неверных имени/пароля возвращалась 500-ая ошибка. + + *) Исправление: ответы модуля ngx_http_perl_module не работали в + подзапросах. + + *) Исправление: в модуле ngx_http_limit_req_module. + Спасибо Максиму Дунину. + + +Изменения в nginx 0.8.4 22.06.2009 + + *) Исправление: nginx не собирался с параметром --without-http-cache; + ошибка появилась в 0.8.3. + + +Изменения в nginx 0.8.3 19.06.2009 + + *) Добавление: переменная $upstream_cache_status. + + *) Исправление: nginx не собирался на MacOSX 10.6. + + *) Исправление: nginx не собирался с параметром --without-http-cache; + ошибка появилась в 0.8.2. + + *) Исправление: если использовался перехват 401 ошибки от бэкенда и + бэкенд не возвращал строку "WWW-Authenticate" в заголовке ответа, то + в рабочем процессе происходил segmentation fault. + Спасибо Евгению Мычло. + + +Изменения в nginx 0.8.2 15.06.2009 + + *) Исправление: во взаимодействии open_file_cache и proxy/fastcgi кэша + на старте. + + *) Исправление: open_file_cache мог кэшировать открытые файлы очень + долго; ошибка появилась в 0.7.4. + + +Изменения в nginx 0.8.1 08.06.2009 + + *) Добавление: параметр updating в директивах proxy_cache_use_stale и + fastcgi_cache_use_stale. + + *) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в + заголовке запроса клиента передавались бэкенду при кэшировании, если + не использовалась директива proxy_set_header с любыми параметрами. + + *) Исправление: строки "Set-Cookie" и "P3P" в заголовке ответа бэкенда + не скрывались при кэшировании, если не использовались директивы + proxy_hide_header/fastcgi_hide_header с любыми параметрами. + + *) Исправление: модуль ngx_http_image_filter_module не понимал формат + GIF87a. + Спасибо Денису Ильиных. + + *) Исправление: nginx не собирался на Solaris 10 и более ранних; ошибка + появилась в 0.7.56. + + +Изменения в nginx 0.8.0 02.06.2009 + + *) Добавление: директива keepalive_requests. + + *) Добавление: директива limit_rate_after. + Спасибо Ivan Debnar. + + *) Исправление: XSLT-фильтр не работал в подзапросах. + + *) Исправление: обработке относительных путей в nginx/Windows. + + *) Исправление: в proxy_store, fastcgi_store, proxy_cache и + fastcgi_cache в nginx/Windows. + + *) Исправление: в обработке ошибок выделения памяти. + Спасибо Максиму Дунину и Кириллу Коринскому. + + +Изменения в nginx 0.7.59 25.05.2009 + + *) Добавление: директивы proxy_cache_methods и fastcgi_cache_methods. + + *) Исправление: утечки сокетов; ошибка появилась в 0.7.25. + Спасибо Максиму Дунину. + + *) Исправление: при использовании переменной $request_body в рабочем + процессе происходил segmentation fault, если в запросе не было тела; + ошибка появилась в 0.7.58. + + *) Исправление: SSL-модули могли не собираться на Solaris и Linux; + ошибка появилась в 0.7.56. + + *) Исправление: ответы модуля ngx_http_xslt_filter_module не + обрабатывались SSI-, charset- и gzip-фильтрами. + + *) Исправление: директива charset не ставила кодировку для ответов + модуля ngx_http_gzip_static_module. + + +Изменения в nginx 0.7.58 18.05.2009 + + *) Добавление: директива listen почтового прокси-сервера поддерживает + IPv6. + + *) Добавление: директива image_filter_jpeg_quality. + + *) Добавление: директива client_body_in_single_buffer. + + *) Добавление: переменная $request_body. + + *) Исправление: в модуле ngx_http_autoindex_module в ссылках на имена + файлов, содержащих символ ":". + + *) Исправление: процедура "make upgrade" не работала; ошибка появилась + в 0.7.53. + Спасибо Денису Латыпову. + + +Изменения в nginx 0.7.57 12.05.2009 + + *) Исправление: при перенаправлении ошибок модуля + ngx_http_image_filter_module в именованный location в рабочем + процессе происходил floating-point fault; ошибка появилась в 0.7.56. + + +Изменения в nginx 0.7.56 11.05.2009 + + *) Добавление: nginx/Windows поддерживает IPv6 в директиве listen + модуля HTTP. + + *) Исправление: в модуле ngx_http_image_filter_module. + + +Изменения в nginx 0.7.55 06.05.2009 + + *) Исправление: параметры http_XXX в директивах proxy_cache_use_stale и + fastcgi_cache_use_stale не работали. + + *) Исправление: fastcgi кэш не кэшировал ответы, состоящие только из + заголовка. + + *) Исправление: ошибки "select() failed (9: Bad file descriptor)" в + nginx/Unix и "select() failed (10038: ...)" в nginx/Windows. + + *) Исправление: при использовании директивы debug_connection в рабочем + процессе мог произойти segmentation fault; ошибка появилась в 0.7.54. + + *) Исправление: в сборке модуля ngx_http_image_filter_module. + + *) Исправление: файлы больше 2G не передавались с использованием + $r->sendfile. + Спасибо Максиму Дунину. + + +Изменения в nginx 0.7.54 01.05.2009 + + *) Добавление: модуль ngx_http_image_filter_module. + + *) Добавление: директивы proxy_ignore_headers и fastcgi_ignore_headers. + + *) Исправление: при использовании переменных "open_file_cache_errors + on" в рабочем процессе мог произойти segmentation fault; ошибка + появилась в 0.7.53. + + *) Исправление: директива "port_in_redirect off" не работала; ошибка + появилась в 0.7.39. + + *) Исправление: улучшение обработки ошибок метода select. + + *) Исправление: ошибки "select() failed (10022: ...)" в nginx/Windows. + + *) Исправление: в текстовых сообщениях об ошибках в nginx/Windows; + ошибка появилась в 0.7.53. + + +Изменения в nginx 0.7.53 27.04.2009 + + *) Изменение: теперь лог, указанный в --error-log-path, создаётся с + самого начала работы. + + *) Добавление: теперь ошибки и предупреждения при старте записываются в + error_log и выводятся на stderr. + + *) Добавление: при сборке с пустым параметром --prefix= nginx + использует как префикс каталог, в котором он был запущен. + + *) Добавление: ключ -p. + + *) Добавление: ключ -s на Unix-платформах. + + *) Добавление: ключи -? и -h. + Спасибо Jerome Loyet. + + *) Добавление: теперь ключи можно задавать в сжатой форме. + + *) Исправление: nginx/Windows не работал, если файл конфигурации был + задан ключом -c. + + *) Исправление: при использовании директив proxy_store, fastcgi_store, + proxy_cache или fastcgi_cache временные файлы могли не удаляться. + Спасибо Максиму Дунину. + + *) Исправление: в заголовке Auth-Method запроса серверу аутентификации + почтового прокси-сервера передавалось неверное значение; ошибка + появилась в 0.7.34. + Спасибо Simon Lecaille. + + *) Исправление: при логгировании на Linux не писались текстовые + описания системных ошибок; ошибка появилась в 0.7.45. + + *) Исправление: директива fastcgi_cache_min_uses не работала. + Спасибо Андрею Воробьёву. + + +Изменения в nginx 0.7.52 20.04.2009 + + *) Добавление: первая бинарная версия под Windows. + + *) Исправление: корректная обработка метода HEAD при кэшировании. + + *) Исправление: корректная обработка строк "If-Modified-Since", + "If-Range" и им подобных в заголовке запроса клиента при кэшировании. + + *) Исправление: теперь строки "Set-Cookie" и "P3P" скрываются в + заголовке ответа для закэшированных ответов. + + *) Исправление: если nginx был собран с модулем ngx_http_perl_module и + perl поддерживал потоки, то при выходе основного процесса могла + выдаваться ошибка "panic: MUTEX_LOCK". + + *) Исправление: nginx не собирался с параметром --without-http-cache; + ошибка появилась в 0.7.48. + + *) Исправление: nginx не собирался на платформах, отличных от i386, + amd64, sparc и ppc; ошибка появилась в 0.7.42. + + +Изменения в nginx 0.7.51 12.04.2009 + + *) Добавление: директива try_files поддерживает код ответа в последнем + параметре. + + *) Добавление: теперь в директиве return можно использовать любой код + ответа. + + *) Исправление: директива error_page делала внешний редирект без строки + запроса; ошибка появилась в 0.7.44. + + *) Исправление: если сервера слушали на нескольких явно описанных + адресах, то виртуальные сервера могли не работать; ошибка появилась + в 0.7.39. + + +Изменения в nginx 0.7.50 06.04.2009 + + *) Исправление: переменные $arg_... не работали; ошибка появилась в + 0.7.49. + + +Изменения в nginx 0.7.49 06.04.2009 + + *) Исправление: при использовании переменных $arg_... в рабочем + процессе мог произойти segmentation fault; ошибка появилась в 0.7.48. + + +Изменения в nginx 0.7.48 06.04.2009 + + *) Добавление: директива proxy_cache_key. + + *) Исправление: теперь nginx учитывает при кэшировании строки + "X-Accel-Expires", "Expires" и "Cache-Control" в заголовке ответа + бэкенда. + + *) Исправление: теперь nginx кэширует только ответы на запросы GET. + + *) Исправление: директива fastcgi_cache_key не наследовалась. + + *) Исправление: переменные $arg_... не работали с SSI-подзапросами. + Спасибо Максиму Дунину. + + *) Исправление: nginx не собирался с библиотекой uclibc. + Спасибо Timothy Redaelli. + + *) Исправление: nginx не собирался на OpenBSD; ошибка появилась + в 0.7.46. + + Изменения в nginx 0.7.47 01.04.2009 *) Исправление: nginx не собирался на FreeBSD 6 и более ранних версиях; @@ -1193,7 +1670,7 @@ *) Добавление: директивы open_file_cache, open_file_cache_retest и open_file_cache_errors. - *) Исправление: утечка сокетов; ошибка появилась в 0.6.7. + *) Исправление: утечки сокетов; ошибка появилась в 0.6.7. *) Исправление: В строку заголовка ответа "Content-Type", указанную в методе $r->send_http_header(), не добавлялась кодировка, указанная в diff --git a/auto/cc/bcc b/auto/cc/bcc --- a/auto/cc/bcc +++ b/auto/cc/bcc @@ -24,7 +24,7 @@ esac # __stdcall #CPU_OPT="$CPU_OPT -ps" # __fastcall -CPU_OPT="$CPU_OPT -pr" +#CPU_OPT="$CPU_OPT -pr" CFLAGS="$CFLAGS $CPU_OPT" @@ -46,7 +46,7 @@ NGX_USE_PCH="-Hu -H=$NGX_OBJS/ngx_config # Win32 GUI mode application -LINK="\$(CC) -laa" +#LINK="\$(CC) -laa" # the resource file diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -158,9 +158,10 @@ case "$NGX_GCC_VER" in 3.* | 4.* ) # we have a lot of the unused function arguments CFLAGS="$CFLAGS -Wno-unused-parameter" - CFLAGS="$CFLAGS -Wno-unused-function" + CFLAGS="$CFLAGS -Wunused-function" CFLAGS="$CFLAGS -Wunused-variable" CFLAGS="$CFLAGS -Wunused-value" + # 4.2.1 shows the warning in wrong places #CFLAGS="$CFLAGS -Wunreachable-code" ;; diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -51,12 +51,12 @@ case $CPU in ;; esac -# __cdecl, use with OpenSSL, md5 asm, and sha1 asm +# __cdecl, default, must be used with OpenSSL, md5 asm, and sha1 asm #CPU_OPT="$CPU_OPT -Gd" # __stdcall #CPU_OPT="$CPU_OPT -Gz" # __fastcall -CPU_OPT="$CPU_OPT -Gr" +#CPU_OPT="$CPU_OPT -Gr" CFLAGS="$CFLAGS $CPU_OPT" @@ -86,17 +86,26 @@ LIBC="-MT" CFLAGS="$CFLAGS $LIBC" +CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" + # Win32 GUI mode application -CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" -CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" +#CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" # debug +# msvc8 under Wine issues +# Program database manager mismatch; please check your installation if [ $NGX_CC_NAME != msvc8 ]; then CFLAGS="$CFLAGS -Zi" CORE_LINK="$CORE_LINK -debug" fi +# MSVC 2005 supports C99 variadic macros +if [ $NGX_CC_NAME = msvc8 ]; then + have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have +fi + + # precompiled headers CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" NGX_PCH="$NGX_OBJS/ngx_config.pch" @@ -115,24 +124,13 @@ ngx_binout="-Fe" ngx_objext="obj" ngx_binext=".exe" -if [ "$BMAKE" = nmake ]; then - # MS nmake - - ngx_long_start='@<< - ' - ngx_long_end='<<' - ngx_long_regex_cont=' \ +ngx_long_start='@<< ' - ngx_long_cont=' +ngx_long_end='<<' +ngx_long_regex_cont=' \ ' - -else - # Borland make - - ngx_long_start='@&&| - ' - ngx_long_end='|' -fi +ngx_long_cont=' + ' # MSVC understand / in path #ngx_regex_dirsep='\\' diff --git a/auto/cc/owc b/auto/cc/owc --- a/auto/cc/owc +++ b/auto/cc/owc @@ -71,7 +71,7 @@ NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pc # the link flags, built target is NT GUI mode application -CORE_LINK="$CORE_LINK -l=nt_win" +#CORE_LINK="$CORE_LINK -l=nt_win" # the resource file @@ -87,3 +87,17 @@ ngx_binext=".exe" ngx_regex_dirsep='\\' ngx_dirsep="\\" + +ngx_long_start=' ' +ngx_long_end=' ' +ngx_long_regex_cont=' \&\ + ' +ngx_long_cont=' & + ' + +ngx_regex_cont=' \&\ + ' +ngx_cont=' & + ' +ngx_tab=' & + ' diff --git a/auto/cc/sunc b/auto/cc/sunc --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -45,21 +45,6 @@ fi case "$NGX_MACHINE" in i86pc) - ngx_feature="PAUSE hardware capability bug" - ngx_feature_name= - ngx_feature_run=bug - ngx_feature_incs= - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test='__asm ("pause")' - - . auto/feature - - if [ $ngx_found = yes ]; then - # disable [ PAUSE ] hwcap for Sun Studio 11 - CORE_LINK="$CORE_LINK -Msrc/os/unix/ngx_sunpro_x86.map" - fi - NGX_AUX=" src/os/unix/ngx_sunpro_x86.il" ;; diff --git a/auto/init b/auto/init --- a/auto/init +++ b/auto/init @@ -43,36 +43,8 @@ fi cat << END > Makefile -build: - \$(MAKE) -f $NGX_MAKEFILE - -install: - \$(MAKE) -f $NGX_MAKEFILE install +default: build clean: rm -rf Makefile $NGX_OBJS - -upgrade: - $NGX_SBIN_PATH -t - - kill -USR2 \`cat $NGX_PID_PATH\` - sleep 1 - test -f $NGX_PID_PATH.oldbin - - kill -QUIT \`cat $NGX_PID_PATH.oldbin\` - -upgrade1: - # upgrade 0.1.x to 0.2+ - - $NGX_SBIN_PATH -t - - cp $NGX_PID_PATH $NGX_PID_PATH.oldbin - - kill -USR2 \`cat $NGX_PID_PATH\` - sleep 1 - test -f $NGX_PID_PATH.oldbin - - cp $NGX_PID_PATH $NGX_PID_PATH.newbin - - kill -QUIT \`cat $NGX_PID_PATH.oldbin\` END diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -15,6 +15,63 @@ END fi +case ".$NGX_SBIN_PATH" in + ./*) + ;; + + .) + NGX_SBIN_PATH=$NGX_PREFIX/sbin/nginx + ;; + + *) + NGX_SBIN_PATH=$NGX_PREFIX/$NGX_SBIN_PATH + ;; +esac + + +case ".$NGX_CONF_PATH" in + ./*) + ;; + + *) + NGX_CONF_PATH=$NGX_PREFIX/$NGX_CONF_PATH + ;; +esac + + +NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH` + + +case ".$NGX_PID_PATH" in + ./*) + ;; + + *) + NGX_PID_PATH=$NGX_PREFIX/$NGX_PID_PATH + ;; +esac + + +case ".$NGX_ERROR_LOG_PATH" in + ./*) + ;; + + *) + NGX_ERROR_LOG_PATH=$NGX_PREFIX/$NGX_ERROR_LOG_PATH + ;; +esac + + +case ".$NGX_HTTP_LOG_PATH" in + ./*) + ;; + + *) + NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH + ;; +esac + + cat << END >> $NGX_MAKEFILE install: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \ @@ -45,7 +102,7 @@ install: $NGX_OBJS${ngx_dirsep}nginx${ng '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default' test -f '\$(DESTDIR)$NGX_CONF_PATH' \ - || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX' + || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH' cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default' test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \ @@ -67,3 +124,39 @@ if test -n "\$(DESTDIR)$NGX_ERROR_LOG_PA END fi + + +# create Makefile + +cat << END >> Makefile + +build: + \$(MAKE) -f $NGX_MAKEFILE + +install: + \$(MAKE) -f $NGX_MAKEFILE install + +upgrade: + $NGX_SBIN_PATH -t + + kill -USR2 \`cat $NGX_PID_PATH\` + sleep 1 + test -f $NGX_PID_PATH.oldbin + + kill -QUIT \`cat $NGX_PID_PATH.oldbin\` + +upgrade1: + # upgrade 0.1.x to 0.2+ + + $NGX_SBIN_PATH -t + + cp $NGX_PID_PATH $NGX_PID_PATH.oldbin + + kill -USR2 \`cat $NGX_PID_PATH\` + sleep 1 + test -f $NGX_PID_PATH.oldbin + + cp $NGX_PID_PATH $NGX_PID_PATH.newbin + + kill -QUIT \`cat $NGX_PID_PATH.oldbin\` +END diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -4,15 +4,29 @@ if [ $USE_PCRE = YES -o $PCRE != NONE ]; then . auto/lib/pcre/conf + +else + if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then + +cat << END + +$0: error: the HTTP rewrite module requires the PCRE library. +You can either disable the module by using --without-http_rewrite_module +option or you have to enable the PCRE support. + +END + exit 1 + fi fi + if [ $USE_OPENSSL = YES ]; then . auto/lib/openssl/conf fi if [ $USE_MD5 = YES ]; then - if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then + if [ $USE_OPENSSL = YES ]; then have=NGX_HAVE_OPENSSL_MD5_H . auto/have have=NGX_OPENSSL_MD5 . auto/have MD5=YES @@ -26,7 +40,7 @@ fi if [ $USE_SHA1 = YES ]; then - if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then + if [ $USE_OPENSSL = YES ]; then have=NGX_HAVE_OPENSSL_SHA1_H . auto/have SHA1=YES SHA1_LIB=OpenSSL @@ -45,10 +59,17 @@ if [ $USE_LIBXSLT = YES ]; then . auto/lib/libxslt/conf fi +if [ $USE_LIBGD = YES ]; then + . auto/lib/libgd/conf +fi + if [ $USE_PERL = YES ]; then . auto/lib/perl/conf fi +if [ $HTTP_GEOIP = YES ]; then + . auto/lib/geoip/conf +fi if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then . auto/lib/google-perftools/conf fi diff --git a/auto/lib/geoip/conf b/auto/lib/geoip/conf new file mode 100644 --- /dev/null +++ b/auto/lib/geoip/conf @@ -0,0 +1,78 @@ + +# Copyright (C) Igor Sysoev + + + ngx_feature="GeoIP library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs="-lGeoIP" + ngx_feature_test="GeoIP_open(NULL, 0)" + . auto/feature + + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="GeoIP library in /usr/local/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lGeoIP" + else + ngx_feature_libs="-L/usr/local/lib -lGeoIP" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="GeoIP library in /usr/pkg/" + ngx_feature_path="/usr/pkg/include/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lGeoIP" + else + ngx_feature_libs="-L/usr/pkg/lib -lGeoIP" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="GeoIP library in /opt/local/" + ngx_feature_path="/opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lGeoIP" + else + ngx_feature_libs="-L/opt/local/lib -lGeoIP" + fi + + . auto/feature +fi + + +if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + +else + +cat << END + +$0: error: the GeoIP module requires the GeoIP library. +You can either do not enable the module or install the library. + +END + + exit 1 +fi diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf --- a/auto/lib/google-perftools/conf +++ b/auto/lib/google-perftools/conf @@ -30,4 +30,15 @@ fi if [ $ngx_found = yes ]; then CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + +else + +cat << END + +$0: error: the Google perftool module requires the Google perftools +library. You can either do not enable the module or install the library. + +END + + exit 1 fi diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf new file mode 100644 --- /dev/null +++ b/auto/lib/libgd/conf @@ -0,0 +1,82 @@ + +# Copyright (C) Igor Sysoev + + + ngx_feature="GD library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs="-lgd" + ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);" + . auto/feature + + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="GD library in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lgd" + else + ngx_feature_libs="-L/usr/local/lib -lgd" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="GD library in /usr/pkg/" + ngx_feature_path="/usr/pkg/include/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lgd" + else + ngx_feature_libs="-L/usr/pkg/lib -lgd" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="GD library in /opt/local/" + ngx_feature_path="/opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lgd" + else + ngx_feature_libs="-L/opt/local/lib -lgd" + fi + + . auto/feature +fi + + +if [ $ngx_found = yes ]; then + + CORE_INCS="$CORE_INCS $ngx_feature_path" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + +else + +cat << END + +$0: error: the HTTP image filter module requires the GD library. +You can either do not enable the module or install the libraries. + +END + + exit 1 + +fi diff --git a/auto/lib/md5/conf b/auto/lib/md5/conf --- a/auto/lib/md5/conf +++ b/auto/lib/md5/conf @@ -4,7 +4,7 @@ if [ $MD5 != NONE ]; then - if grep MD5_Init $MD5/md5.h >/dev/null; then + if grep MD5_Init $MD5/md5.h 2>&1 >/dev/null; then # OpenSSL md5 OPENSSL_MD5=YES have=NGX_HAVE_OPENSSL_MD5 . auto/have @@ -46,30 +46,30 @@ else if [ "$NGX_PLATFORM" != win32 ]; then - MD5=NO + MD5=NO - # Solaris 8/9 + # FreeBSD, Solaris 10 - ngx_feature="rsaref md5 library" - ngx_feature_name= - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs="-lmd5" - ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" - . auto/feature + ngx_feature="system md library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs="-lmd" + ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" + . auto/feature - ngx_md5_lib="system md5" + ngx_md5_lib="system md" if [ $ngx_found = no ]; then - # FreeBSD + # Solaris 8/9 - ngx_feature="rsaref md library" - ngx_feature_libs="-lmd" + ngx_feature="system md5 library" + ngx_feature_libs="-lmd5" . auto/feature - ngx_md5_lib="system md" + ngx_md5_lib="system md5" fi if [ $ngx_found = no ]; then @@ -94,6 +94,18 @@ else CORE_LIBS="$CORE_LIBS $ngx_feature_libs" MD5=YES MD5_LIB=$ngx_md5_lib + else + +cat << END + +$0: error: the HTTP cache module requires md5 functions +from OpenSSL library. You can either disable the module by using +--without-http-cache option, or install the OpenSSL library into the system, +or build the OpenSSL library statically from the source with nginx by using +--with-http_ssl_module --with-openssl= options. + +END + exit 1 fi fi diff --git a/auto/lib/md5/make b/auto/lib/md5/make --- a/auto/lib/md5/make +++ b/auto/lib/md5/make @@ -7,16 +7,19 @@ case "$NGX_CC_NAME" in msvc*) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC MD5_ASM=$MD5_ASM" + ngx_md5="MD5=\"$MD5\"" ;; owc*) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ngx_md5=`echo MD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; bcc) ngx_makefile=makefile.bcc ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DMD5_ASM=$MD5_ASM" + ngx_md5=`echo \-DMD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; esac @@ -28,14 +31,10 @@ done=NO case "$NGX_PLATFORM" in win32) - cp auto/lib/md5/$ngx_makefile $MD5 - cat << END >> $NGX_MAKEFILE `echo "$MD5/md5.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` - cd `echo $MD5 | sed -e "s/\//$ngx_regex_dirsep/g"` - \$(MAKE) -f $ngx_makefile $ngx_opt - cd ..\\..\\.. + \$(MAKE) -f auto/lib/md5/$ngx_makefile $ngx_opt $ngx_md5 END diff --git a/auto/lib/md5/makefile.bcc b/auto/lib/md5/makefile.bcc --- a/auto/lib/md5/makefile.bcc +++ b/auto/lib/md5/makefile.bcc @@ -7,12 +7,14 @@ CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDI !if "$(MD5_ASM)" == "YES" md5.lib: + cd $(MD5) bcc32 -c $(CFLAGS) -DMD5_ASM md5_dgst.c tlib md5.lib +md5_dgst.obj +"asm\m-win32.obj" !else md5.lib: + cd $(MD5) bcc32 -c $(CFLAGS) md5_dgst.c tlib md5.lib +md5_dgst.obj diff --git a/auto/lib/md5/makefile.msvc b/auto/lib/md5/makefile.msvc --- a/auto/lib/md5/makefile.msvc +++ b/auto/lib/md5/makefile.msvc @@ -7,12 +7,14 @@ CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC !IF "$(MD5_ASM)" == "YES" md5.lib: + cd $(MD5) cl -c $(CFLAGS) -D MD5_ASM md5_dgst.c link -lib -out:md5.lib md5_dgst.obj asm/m-win32.obj !ELSE md5.lib: + cd $(MD5) cl -c $(CFLAGS) md5_dgst.c link -lib -out:md5.lib md5_dgst.obj diff --git a/auto/lib/md5/makefile.owc b/auto/lib/md5/makefile.owc --- a/auto/lib/md5/makefile.owc +++ b/auto/lib/md5/makefile.owc @@ -5,5 +5,6 @@ CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT) md5.lib: + cd $(MD5) wcl386 -c $(CFLAGS) -dL_ENDIAN md5_dgst.c wlib -n md5.lib md5_dgst.obj diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -3,24 +3,36 @@ if [ $OPENSSL != NONE ]; then - CORE_INCS="$CORE_INCS $OPENSSL/include" case "$CC" in + + cl | bcc32) + have=NGX_OPENSSL . auto/have + have=NGX_SSL . auto/have + + CFLAGS="$CFLAGS -DNO_SYS_TYPES_H" + + CORE_INCS="$CORE_INCS $OPENSSL/openssl/include" + CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h" + CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/ssleay32.lib" + CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libeay32.lib" + + # libeay32.lib requires gdi32.lib + CORE_LIBS="$CORE_LIBS gdi32.lib" + ;; + *) have=NGX_OPENSSL . auto/have have=NGX_SSL . auto/have - LINK_DEPS="$LINK_DEPS $OPENSSL/libssl.a $OPENSSL/libcrypto.a" - CORE_LIBS="$CORE_LIBS $OPENSSL/libssl.a $OPENSSL/libcrypto.a" + + CORE_INCS="$CORE_INCS $OPENSSL/openssl/include" + CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h" + CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libssl.a" + CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libcrypto.a" + CORE_LIBS="$CORE_LIBS $NGX_LIBDL" ;; esac - case "$NGX_SYSTEM" in - SunOS|Linux) - CORE_LIBS="$CORE_LIBS -ldl" - ;; - esac - - else case "$NGX_PLATFORM" in @@ -36,8 +48,6 @@ else # libeay32.lib requires gdi32.lib CORE_LIBS="$CORE_LIBS gdi32.lib" - # OpenSSL 0.8's libeay32.lib requires advapi32.lib - CORE_LIBS="$CORE_LIBS advapi32.lib" ;; *) @@ -54,14 +64,19 @@ else if [ $ngx_found = yes ]; then have=NGX_SSL . auto/have - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL" OPENSSL=YES + else + +cat << END - case "$NGX_SYSTEM" in - SunOS) - CORE_LIBS="$CORE_LIBS -ldl" - ;; - esac +$0: error: SSL modules require the OpenSSL library. +You can either do not enable the modules, or install the OpenSSL library +into the system, or build the OpenSSL library statically from the source +with nginx by using --with-openssl= option. + +END + exit 1 fi ;; diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -2,26 +2,62 @@ # Copyright (C) Igor Sysoev -if test -n "$OPENSSL_OPT"; then - NGX_OPENSSL_CONFIG="./Configure \"$OPENSSL_OPT\"" -else - NGX_OPENSSL_CONFIG="./config" -fi +case "$CC" in + + cl) + + cat << END >> $NGX_MAKEFILE + +$OPENSSL/openssl/include/openssl/ssl.h: $NGX_MAKEFILE + \$(MAKE) -f auto/lib/openssl/makefile.msvc \ + OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT" -case $USE_THREADS in - NO) NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG no-threads" ;; - *) NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads" ;; -esac +END + + ;; -case "$NGX_PLATFORM" in - *) + bcc32) + + ngx_opt=`echo "-DOPENSSL=\"$OPENSSL\" -DOPENSSL_OPT=\"$OPENSSL_OPT\"" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + cat << END >> $NGX_MAKEFILE -$OPENSSL/libssl.a: +`echo "$OPENSSL\\openssl\\lib\\libeay32.lib: \ + $OPENSSL\\openssl\\include\\openssl\\ssl.h" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + +`echo "$OPENSSL\\openssl\\lib\\ssleay32.lib: \ + $OPENSSL\\openssl\\include\\openssl\\ssl.h" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + +`echo "$OPENSSL\\openssl\\include\\openssl\\ssl.h: $NGX_MAKEFILE" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + \$(MAKE) -f auto/lib/openssl/makefile.bcc $ngx_opt + +END + + ;; + + *) + case $USE_THREADS in + NO) OPENSSL_OPT="$OPENSSL_OPT no-threads" ;; + *) OPENSSL_OPT="$OPENSSL_OPT threads" ;; + esac + + case $OPENSSL in + /*) ngx_prefix="$OPENSSL/openssl" ;; + *) ngx_prefix="$PWD/$OPENSSL/openssl" ;; + esac + + cat << END >> $NGX_MAKEFILE + +$OPENSSL/openssl/include/openssl/ssl.h: $NGX_MAKEFILE cd $OPENSSL \\ && \$(MAKE) clean \\ - && $NGX_OPENSSL_CONFIG no-shared \\ - && \$(MAKE) + && ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\ + && \$(MAKE) \\ + && \$(MAKE) install END diff --git a/auto/lib/openssl/makefile.bcc b/auto/lib/openssl/makefile.bcc new file mode 100644 --- /dev/null +++ b/auto/lib/openssl/makefile.bcc @@ -0,0 +1,18 @@ + +# Copyright (C) Igor Sysoev + + +all: + cd $(OPENSSL) + + perl Configure BC-32 no-shared --prefix=openssl -DNO_SYS_TYPES_H \ + $(OPENSSL_OPT) + + ms\do_nasm + + $(MAKE) -f ms\bcb.mak + $(MAKE) -f ms\bcb.mak install + + # Borland's make does not expand "[ch]" in + # copy "inc32\openssl\*.[ch]" "openssl\include\openssl" + copy inc32\openssl\*.h openssl\include\openssl diff --git a/auto/lib/openssl/makefile.msvc b/auto/lib/openssl/makefile.msvc new file mode 100644 --- /dev/null +++ b/auto/lib/openssl/makefile.msvc @@ -0,0 +1,14 @@ + +# Copyright (C) Igor Sysoev + + +all: + cd $(OPENSSL) + + perl Configure VC-WIN32 no-shared --prefix=openssl -DNO_SYS_TYPES_H \ + $(OPENSSL_OPT) + + ms\do_ms + + $(MAKE) -f ms\nt.mak + $(MAKE) -f ms\nt.mak install diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -161,6 +161,18 @@ else CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" PCRE=YES + else + +cat << END + +$0: error: the HTTP rewrite module requires the PCRE library. +You can either disable the module by using --without-http_rewrite_module +option, or install the PCRE library into the system, or build the PCRE library +statically from the source with nginx by using --with-pcre= option. + +END + exit 1 + fi fi diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -7,16 +7,19 @@ case "$NGX_CC_NAME" in msvc*) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" + ngx_pcre="PCRE=\"$PCRE\"" ;; owc*) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; bcc) ngx_makefile=makefile.bcc ngx_opt="-DCPU_OPT=\"$CPU_OPT\"" + ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; esac @@ -25,26 +28,14 @@ esac case "$NGX_PLATFORM" in win32) - cp auto/lib/pcre/patch.pcre.in $PCRE - cp auto/lib/pcre/patch.pcre.in.owc $PCRE - cp auto/lib/pcre/patch.config.in $PCRE - cp auto/lib/pcre/patch.pcre.c $PCRE - cp auto/lib/pcre/$ngx_makefile $PCRE - - ngx_pcre=`echo $PCRE | sed -e "s/\//$ngx_regex_dirsep/g"` cat << END >> $NGX_MAKEFILE -`echo "$PCRE/pcre.h: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` - cd $ngx_pcre - \$(MAKE) -f $ngx_makefile pcre.h - cd ..\\..\\.. +`echo "$PCRE/pcre.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` + \$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre $ngx_opt - -`echo "$PCRE/pcre.lib: $PCRE/pcre.h" | sed -e "s/\//$ngx_regex_dirsep/g"` - cd $ngx_pcre - \$(MAKE) -f $ngx_makefile $ngx_opt - cd ..\\..\\.. +`echo "$PCRE/pcre.h:" | sed -e "s/\//$ngx_regex_dirsep/g"` + \$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre pcre.h END @@ -61,7 +52,6 @@ END && CC="\$(CC)" CFLAGS="$PCRE_OPT" \\ ./configure --disable-shared - $PCRE/.libs/libpcre.a: $PCRE/Makefile cd $PCRE \\ && \$(MAKE) libpcre.la diff --git a/auto/lib/pcre/makefile.bcc b/auto/lib/pcre/makefile.bcc --- a/auto/lib/pcre/makefile.bcc +++ b/auto/lib/pcre/makefile.bcc @@ -3,19 +3,23 @@ CFLAGS = -q -O2 -tWM -w-8004 $(CPU_OPT) -PCREFLAGS = -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 +PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 -pcre.lib: pcre.h - bcc32 -q -edftables dftables.c +pcre.lib: + cd $(PCRE) + + bcc32 -c $(CFLAGS) -I. $(PCREFLAGS) pcre_*.c - dftables > chartables.c + > pcre.lst + for %n in (*.obj) do @echo +%n & >> pcre.lst + echo + >> pcre.lst - bcc32 -c $(CFLAGS) $(PCREFLAGS) maketables.c get.c study.c pcre.c - - tlib pcre.lib +maketables.obj +get.obj +study.obj +pcre.obj + tlib pcre.lib @pcre.lst pcre.h: - patch -o pcre.h pcre.in patch.pcre.in - patch -o config.h config.in patch.config.in - patch -o pcre.c pcre.c patch.pcre.c + cd $(PCRE) + + copy /y pcre.h.generic pcre.h + copy /y config.h.generic config.h + copy /y pcre_chartables.c.dist pcre_chartables.c diff --git a/auto/lib/pcre/makefile.msvc b/auto/lib/pcre/makefile.msvc --- a/auto/lib/pcre/makefile.msvc +++ b/auto/lib/pcre/makefile.msvc @@ -3,21 +3,19 @@ CFLAGS = -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -PCREFLAGS = -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 +PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 -pcre.lib: pcre.h - cl -Fedftables dftables.c - - dftables > chartables.c +pcre.lib: + cd $(PCRE) - cl -nologo -c $(CFLAGS) $(PCREFLAGS) \ - maketables.c get.c study.c pcre.c + cl -nologo -c $(CFLAGS) -I . $(PCREFLAGS) pcre_*.c - link -lib -out:pcre.lib -verbose:lib \ - maketables.obj get.obj study.obj pcre.obj + link -lib -out:pcre.lib -verbose:lib pcre_*.obj pcre.h: - patch -o pcre.h pcre.in patch.pcre.in - patch -o config.h config.in patch.config.in - patch -o pcre.c pcre.c patch.pcre.c + cd $(PCRE) + + copy /y pcre.h.generic pcre.h + copy /y config.h.generic config.h + copy /y pcre_chartables.c.dist pcre_chartables.c diff --git a/auto/lib/pcre/makefile.owc b/auto/lib/pcre/makefile.owc --- a/auto/lib/pcre/makefile.owc +++ b/auto/lib/pcre/makefile.owc @@ -3,17 +3,21 @@ CFLAGS = -c -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT) -PCREFLAGS = -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 +PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 -pcre.lib: pcre.h - wcl386 -zq -bt=nt -l=nt -fe=dftables dftables.c - dftables > chartables.c +pcre.lib: + cd $(PCRE) - wcl386 $(CFLAGS) $(PCREFLAGS) maketables.c get.c study.c pcre.c - wlib -n pcre.lib maketables.obj get.obj study.obj pcre.obj + wcl386 $(CFLAGS) -i=. $(PCREFLAGS) pcre_*.c + dir /b *.obj > pcre.lst + + wlib -n pcre.lib @pcre.lst pcre.h: - patch -o pcre.h pcre.in patch.pcre.in.owc - patch -o config.h config.in patch.config.in + cd $(PCRE) + + copy /y pcre.h.generic pcre.h + copy /y config.h.generic config.h + copy /y pcre_chartables.c.dist pcre_chartables.c diff --git a/auto/lib/pcre/patch.config.in b/auto/lib/pcre/patch.config.in deleted file mode 100644 --- a/auto/lib/pcre/patch.config.in +++ /dev/null @@ -1,11 +0,0 @@ ---- config.in Thu Aug 21 14:43:07 2003 -+++ config.in Sun Mar 7 02:37:24 2004 -@@ -28,7 +28,7 @@ - found. */ - - #define HAVE_STRERROR 0 --#define HAVE_MEMMOVE 0 -+#define HAVE_MEMMOVE 1 - - /* There are some non-Unix systems that don't even have bcopy(). If this macro - is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of diff --git a/auto/lib/pcre/patch.pcre.c b/auto/lib/pcre/patch.pcre.c deleted file mode 100644 --- a/auto/lib/pcre/patch.pcre.c +++ /dev/null @@ -1,13 +0,0 @@ ---- pcre.c Thu Aug 21 14:43:07 2003 -+++ pcre.c Tue Mar 22 12:56:59 2005 -@@ -246,8 +246,8 @@ - extern "C" void (*pcre_free)(void *) = free; - extern "C" int (*pcre_callout)(pcre_callout_block *) = NULL; - #else --void *(*pcre_malloc)(size_t) = malloc; --void (*pcre_free)(void *) = free; -+void *(__cdecl *pcre_malloc)(size_t) = malloc; -+void (__cdecl *pcre_free)(void *) = free; - int (*pcre_callout)(pcre_callout_block *) = NULL; - #endif - #endif diff --git a/auto/lib/pcre/patch.pcre.in b/auto/lib/pcre/patch.pcre.in deleted file mode 100644 --- a/auto/lib/pcre/patch.pcre.in +++ /dev/null @@ -1,26 +0,0 @@ ---- pcre.in Thu Aug 21 14:43:07 2003 -+++ pcre.h Tue Mar 22 12:56:59 2005 -@@ -10,9 +10,9 @@ - /* The file pcre.h is build by "configure". Do not edit it; instead - make changes to pcre.in. */ - --#define PCRE_MAJOR @PCRE_MAJOR@ --#define PCRE_MINOR @PCRE_MINOR@ --#define PCRE_DATE @PCRE_DATE@ -+#define PCRE_MAJOR 4 -+#define PCRE_MINOR 4 -+#define PCRE_DATE 21-August-2003 - - /* Win32 uses DLL by default */ - -@@ -143,8 +143,8 @@ - have to be different again. */ - - #ifndef VPCOMPAT --PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t); --PCRE_DATA_SCOPE void (*pcre_free)(void *); -+PCRE_DATA_SCOPE void *(__cdecl *pcre_malloc)(size_t); -+PCRE_DATA_SCOPE void (__cdecl *pcre_free)(void *); - PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *); - #else /* VPCOMPAT */ - extern void *pcre_malloc(size_t); diff --git a/auto/lib/pcre/patch.pcre.in.owc b/auto/lib/pcre/patch.pcre.in.owc deleted file mode 100644 --- a/auto/lib/pcre/patch.pcre.in.owc +++ /dev/null @@ -1,15 +0,0 @@ ---- pcre.in Thu Aug 21 14:43:07 2003 -+++ pcre.h Tue Mar 22 12:56:59 2005 -@@ -10,9 +10,9 @@ - /* The file pcre.h is build by "configure". Do not edit it; instead - make changes to pcre.in. */ - --#define PCRE_MAJOR @PCRE_MAJOR@ --#define PCRE_MINOR @PCRE_MINOR@ --#define PCRE_DATE @PCRE_DATE@ -+#define PCRE_MAJOR 4 -+#define PCRE_MINOR 4 -+#define PCRE_DATE 21-August-2003 - - /* Win32 uses DLL by default */ - diff --git a/auto/lib/sha1/make b/auto/lib/sha1/make --- a/auto/lib/sha1/make +++ b/auto/lib/sha1/make @@ -7,16 +7,19 @@ case "$NGX_CC_NAME" in msvc*) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC SHA1_ASM=$SHA1_ASM" + ngx_sha1="SHA1=\"$SHA1\"" ;; owc*) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ngx_sha1=`echo SHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; bcc) ngx_makefile=makefile.bcc ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DSHA1_ASM=$SHA1_ASM" + ngx_sha1=`echo \-DSHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; esac @@ -28,14 +31,10 @@ done=NO case "$NGX_PLATFORM" in win32) - cp auto/lib/sha1/$ngx_makefile $SHA1 - cat << END >> $NGX_MAKEFILE `echo "$SHA1/sha1.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` - cd `echo $SHA1 | sed -e "s/\//$ngx_regex_dirsep/g"` - \$(MAKE) -f $ngx_makefile $ngx_opt - cd ..\\..\\.. + \$(MAKE) -f auto/lib/sha1/$ngx_makefile $ngx_opt $ngx_sha1 END diff --git a/auto/lib/sha1/makefile.bcc b/auto/lib/sha1/makefile.bcc --- a/auto/lib/sha1/makefile.bcc +++ b/auto/lib/sha1/makefile.bcc @@ -7,12 +7,14 @@ CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDI !if "$(SHA1_ASM)" == "YES" sha1.lib: + cd $(SHA1) bcc32 -c $(CFLAGS) -DSHA1_ASM sha1dgst.c tlib sha1.lib +sha1dgst.obj +"asm\s-win32.obj" !else sha1.lib: + cd $(SHA1) bcc32 -c $(CFLAGS) sha1dgst.c tlib sha1.lib +sha1dgst.obj diff --git a/auto/lib/sha1/makefile.msvc b/auto/lib/sha1/makefile.msvc --- a/auto/lib/sha1/makefile.msvc +++ b/auto/lib/sha1/makefile.msvc @@ -7,12 +7,14 @@ CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC !IF "$(SHA1_ASM)" == "YES" sha1.lib: + cd $(SHA1) cl -c $(CFLAGS) -D SHA1_ASM sha1dgst.c link -lib -out:sha1.lib sha1dgst.obj asm/s-win32.obj !ELSE sha1.lib: + cd $(SHA1) cl -c $(CFLAGS) sha1dgst.c link -lib -out:sha1.lib sha1dgst.obj diff --git a/auto/lib/sha1/makefile.owc b/auto/lib/sha1/makefile.owc --- a/auto/lib/sha1/makefile.owc +++ b/auto/lib/sha1/makefile.owc @@ -5,5 +5,6 @@ CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT) sha1.lib: + cd $(SHA1) wcl386 -c $(CFLAGS) -dL_ENDIAN sha1dgst.c wlib -n sha1.lib sha1dgst.obj diff --git a/auto/lib/zlib/conf b/auto/lib/zlib/conf --- a/auto/lib/zlib/conf +++ b/auto/lib/zlib/conf @@ -57,6 +57,17 @@ else CORE_LIBS="$CORE_LIBS $ngx_feature_libs" ZLIB=YES ngx_found=no + else + +cat << END + +$0: error: the HTTP gzip module requires the zlib library. +You can either disable the module by using --without-http_gzip_module +option, or install the zlib library into the system, or build the zlib library +statically from the source with nginx by using --with-zlib= option. + +END + exit 1 fi fi diff --git a/auto/lib/zlib/make b/auto/lib/zlib/make --- a/auto/lib/zlib/make +++ b/auto/lib/zlib/make @@ -7,17 +7,20 @@ case "$NGX_CC_NAME" in msvc*) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" + ngx_zlib="ZLIB=\"$ZLIB\"" ;; owc*) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ngx_zlib=`echo ZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; bcc) ngx_makefile=makefile.bcc ngx_opt="-DCPU_OPT=\"$CPU_OPT\"" + ngx_zlib=`echo \-DZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; esac @@ -29,14 +32,10 @@ done=NO case "$NGX_PLATFORM" in win32) - cp auto/lib/zlib/$ngx_makefile $ZLIB - cat << END >> $NGX_MAKEFILE `echo "$ZLIB/zlib.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` - cd `echo $ZLIB | sed -e "s/\//$ngx_regex_dirsep/g"` - \$(MAKE) -f $ngx_makefile $ngx_opt - cd ..\\..\\.. + \$(MAKE) -f auto/lib/zlib/$ngx_makefile $ngx_opt $ngx_zlib END diff --git a/auto/lib/zlib/makefile.bcc b/auto/lib/zlib/makefile.bcc --- a/auto/lib/zlib/makefile.bcc +++ b/auto/lib/zlib/makefile.bcc @@ -5,6 +5,8 @@ CFLAGS = -q -O2 -tWM -w-8004 -w-8012 $(CPU_OPT) zlib.lib: + cd $(ZLIB) + bcc32 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c \ compress.c diff --git a/auto/lib/zlib/makefile.msvc b/auto/lib/zlib/makefile.msvc --- a/auto/lib/zlib/makefile.msvc +++ b/auto/lib/zlib/makefile.msvc @@ -5,6 +5,8 @@ CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) zlib.lib: + cd $(ZLIB) + cl -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c compress.c link -lib -out:zlib.lib adler32.obj crc32.obj deflate.obj \ diff --git a/auto/lib/zlib/makefile.owc b/auto/lib/zlib/makefile.owc --- a/auto/lib/zlib/makefile.owc +++ b/auto/lib/zlib/makefile.owc @@ -5,5 +5,9 @@ CFLAGS = -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT) zlib.lib: - wcl386 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c compress.c - wlib -n zlib.lib adler32.obj crc32.obj deflate.obj trees.obj zutil.obj compress.obj + cd $(ZLIB) + + wcl386 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c & + compress.c + wlib -n zlib.lib adler32.obj crc32.obj deflate.obj trees.obj & + zutil.obj compress.obj diff --git a/auto/make b/auto/make --- a/auto/make +++ b/auto/make @@ -2,6 +2,8 @@ # Copyright (C) Igor Sysoev +echo "creating $NGX_MAKEFILE" + mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \ $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \ $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \ @@ -23,22 +25,12 @@ LINK = $LINK END + if test -n "$NGX_PERL_CFLAGS"; then echo NGX_PERL_CFLAGS = $NGX_PERL_CFLAGS >> $NGX_MAKEFILE echo NGX_PM_CFLAGS = $NGX_PM_CFLAGS >> $NGX_MAKEFILE fi -if [ "$BMAKE" = wmake ]; then - echo MAKE = wmake >> $NGX_MAKEFILE - - ngx_regex_cont=' ' - ngx_long_regex_cont=' ' - ngx_cont=' ' - ngx_long_cont=' ' - ngx_tab=' ' - -fi - # ALL_INCS, required by the addons and by OpenWatcom C precompiled headers diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -41,6 +41,7 @@ fi if [ $NGX_TEST_BUILD_EPOLL = YES ]; then have=NGX_HAVE_EPOLL . auto/have + have=NGX_HAVE_EVENTFD . auto/have have=NGX_TEST_BUILD_EPOLL . auto/have EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE" CORE_SRCS="$CORE_SRCS $EPOLL_SRCS" @@ -104,6 +105,7 @@ fi # ngx_http_charset_filter # ngx_http_ssi_filter # ngx_http_xslt_filter +# ngx_http_image_filter_filter # ngx_http_sub_filter # ngx_http_addition_filter # ngx_http_userid_filter @@ -148,6 +150,12 @@ if [ $HTTP_XSLT = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_XSLT_SRCS" fi +if [ $HTTP_IMAGE_FILTER = YES ]; then + USE_LIBGD=YES + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_IMAGE_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_IMAGE_SRCS" +fi + if [ $HTTP_SUB = YES ]; then HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SUB_FILTER_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_SUB_SRCS" @@ -233,6 +241,12 @@ if [ $HTTP_GEO = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_GEO_SRCS" fi +if [ $HTTP_GEOIP = YES ]; then + have=NGX_HTTP_GEOIP . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_GEOIP_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_GEOIP_SRCS" +fi + if [ $HTTP_MAP = YES ]; then have=NGX_HTTP_MAP . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_MAP_MODULE" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -43,6 +43,7 @@ EVENT_AIO=NO USE_THREADS=NO +NGX_FILE_AIO=NO NGX_IPV6=NO HTTP=YES @@ -60,6 +61,7 @@ HTTP_SSI=YES HTTP_POSTPONE=NO HTTP_REALIP=NO HTTP_XSLT=NO +HTTP_IMAGE_FILTER=NO HTTP_SUB=NO HTTP_ADDITION=NO HTTP_DAV=NO @@ -70,6 +72,7 @@ HTTP_AUTOINDEX=YES HTTP_RANDOM_INDEX=NO HTTP_STATUS=NO HTTP_GEO=YES +HTTP_GEOIP=NO HTTP_MAP=YES HTTP_REFERER=YES HTTP_REWRITE=YES @@ -123,15 +126,19 @@ USE_PERL=NO NGX_PERL=perl USE_LIBXSLT=NO +USE_LIBGD=NO NGX_GOOGLE_PERFTOOLS=NO NGX_CPP_TEST=NO NGX_CPU_CACHE_LINE= +opt= for option do + opt="$opt `echo $option | sed -e \"s/\(--[^=]*=\)\(.* .*\)/\1'\2'/\"`" + case "$option" in -*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) value="" ;; @@ -140,6 +147,7 @@ do case "$option" in --help) help=yes ;; + --prefix=) NGX_PREFIX="!" ;; --prefix=*) NGX_PREFIX="$value" ;; --sbin-path=*) NGX_SBIN_PATH="$value" ;; --conf-path=*) NGX_CONF_PATH="$value" ;; @@ -163,6 +171,7 @@ do #--with-threads=*) USE_THREADS="$value" ;; #--with-threads) USE_THREADS="pthreads" ;; + --with-file-aio) NGX_FILE_AIO=YES ;; --with-ipv6) NGX_IPV6=YES ;; --without-http) HTTP=NO ;; @@ -177,6 +186,8 @@ do --with-http_realip_module) HTTP_REALIP=YES ;; --with-http_addition_module) HTTP_ADDITION=YES ;; --with-http_xslt_module) HTTP_XSLT=YES ;; + --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES ;; + --with-http_geoip_module) HTTP_GEOIP=YES ;; --with-http_sub_module) HTTP_SUB=YES ;; --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; @@ -267,6 +278,9 @@ do done +NGX_CONFIGURE="$opt" + + if [ $help = yes ]; then cat << END @@ -293,12 +307,15 @@ cat << END --with-poll_module enable poll module --without-poll_module disable poll module + --with-file-aio enable file aio support --with-ipv6 enable ipv6 support --with-http_ssl_module enable ngx_http_ssl_module --with-http_realip_module enable ngx_http_realip_module --with-http_addition_module enable ngx_http_addition_module --with-http_xslt_module enable ngx_http_xslt_module + --with-http_image_filter_module enable ngx_http_image_filter_module + --with-http_geoip_module enable ngx_http_geoip_module --with-http_sub_module enable ngx_http_sub_module --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module @@ -409,141 +426,21 @@ if [ ".$NGX_PLATFORM" = ".win32" ]; then fi -NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx} - - -case ".$NGX_SBIN_PATH" in - ./*) - ;; - - .) - NGX_SBIN_PATH=$NGX_PREFIX/sbin/nginx - ;; - - *) - NGX_SBIN_PATH=$NGX_PREFIX/$NGX_SBIN_PATH - ;; -esac - - -case ".$NGX_CONF_PATH" in - ./*) - ;; - - .) - NGX_CONF_PATH=$NGX_PREFIX/conf/nginx.conf - ;; - - *) - NGX_CONF_PATH=$NGX_PREFIX/$NGX_CONF_PATH - ;; -esac - - +NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf} NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH` - - -case ".$NGX_PID_PATH" in - ./*) - ;; - - .) - NGX_PID_PATH=$NGX_PREFIX/logs/nginx.pid - ;; - - *) - NGX_PID_PATH=$NGX_PREFIX/$NGX_PID_PATH - ;; -esac - - -case ".$NGX_LOCK_PATH" in - ./*) - ;; - - .) - NGX_LOCK_PATH=$NGX_PREFIX/logs/nginx.lock - ;; - - *) - NGX_LOCK_PATH=$NGX_PREFIX/$NGX_LOCK_PATH - ;; -esac - - -case ".$NGX_ERROR_LOG_PATH" in - ./*) - ;; +NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid} +NGX_LOCK_PATH=${NGX_LOCK_PATH:-logs/nginx.lock} - .) - NGX_ERROR_LOG_PATH=$NGX_PREFIX/logs/error.log - ;; - - .stderr) - NGX_ERROR_LOG_PATH= - ;; - - *) - NGX_ERROR_LOG_PATH=$NGX_PREFIX/$NGX_ERROR_LOG_PATH - ;; -esac - - -case ".$NGX_HTTP_LOG_PATH" in - ./*) - ;; - - .) - NGX_HTTP_LOG_PATH=$NGX_PREFIX/logs/access.log - ;; - - *) - NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH - ;; -esac - - -case ".$NGX_HTTP_CLIENT_TEMP_PATH" in - ./*) - ;; +if [ ".$NGX_ERROR_LOG_PATH" = ".stderr" ]; then + NGX_ERROR_LOG_PATH= +else + NGX_ERROR_LOG_PATH=${NGX_ERROR_LOG_PATH:-logs/error.log} +fi - .) - NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/client_body_temp - ;; - - *) - NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_CLIENT_TEMP_PATH - ;; -esac - - -case ".$NGX_HTTP_PROXY_TEMP_PATH" in - ./*) - ;; - - .) - NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/proxy_temp - ;; - - *) - NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_PROXY_TEMP_PATH - ;; -esac - - -case ".$NGX_HTTP_FASTCGI_TEMP_PATH" in - ./*) - ;; - - .) - NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/fastcgi_temp - ;; - - *) - NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_FASTCGI_TEMP_PATH - ;; -esac - +NGX_HTTP_LOG_PATH=${NGX_HTTP_LOG_PATH:-logs/access.log} +NGX_HTTP_CLIENT_TEMP_PATH=${NGX_HTTP_CLIENT_TEMP_PATH:-client_body_temp} +NGX_HTTP_PROXY_TEMP_PATH=${NGX_HTTP_PROXY_TEMP_PATH:-proxy_temp} +NGX_HTTP_FASTCGI_TEMP_PATH=${NGX_HTTP_FASTCGI_TEMP_PATH:-fastcgi_temp} case ".$NGX_PERL_MODULES" in ./*) diff --git a/auto/os/features b/auto/os/features --- a/auto/os/features +++ b/auto/os/features @@ -230,3 +230,96 @@ ngx_feature_libs= ngx_feature_test="struct statvfs fs; statvfs(NULL, &fs);" . auto/feature + + +ngx_feature="dlopen()" +ngx_feature_name= +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="dlopen(NULL, 0)" +. auto/feature + + +if [ $ngx_found != yes ]; then + + ngx_feature="dlopen() in libdl" + ngx_feature_libs="-ldl" + . auto/feature + + if [ $ngx_found = yes ]; then + NGX_LIBDL="-ldl" + fi +fi + + +ngx_feature="sched_yield()" +ngx_feature_name="NGX_HAVE_SCHED_YIELD" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="sched_yield()" +. auto/feature + + +if [ $ngx_found != yes ]; then + + ngx_feature="sched_yield() in librt" + ngx_feature_libs="-lrt" + . auto/feature + + if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS -lrt" + fi +fi + + +if [ $NGX_FILE_AIO = YES ]; then + + ngx_feature="kqueue AIO support" + ngx_feature_name="NGX_HAVE_FILE_AIO" + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="int n; struct aiocb iocb; + iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; + n = aio_read(&iocb)" + . auto/feature + + if [ $ngx_found = yes ]; then + CORE_SRCS="$CORE_SRCS $FILE_AIO_SRCS" + + elif [ $ngx_found = no ]; then + + ngx_feature="Linux AIO support" + ngx_feature_name="NGX_HAVE_FILE_AIO" + ngx_feature_run=no + ngx_feature_incs="#include + #include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="int n = SYS_eventfd; + struct iocb iocb; + iocb.aio_lio_opcode = IOCB_CMD_PREAD; + iocb.aio_flags = IOCB_FLAG_RESFD; + iocb.aio_resfd = -1;" + . auto/feature + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_EVENTFD . auto/have + CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS" + + else + cat << END + +$0: no supported file AIO was found +Currently file AIO is supported on FreeBSD 4.3+ and Linux 2.6.22+ only + +END + exit 1 + fi + fi +fi diff --git a/auto/os/freebsd b/auto/os/freebsd --- a/auto/os/freebsd +++ b/auto/os/freebsd @@ -43,6 +43,12 @@ if [ $osreldate -gt 300007 ]; then CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS" fi +if [ $osreldate -gt 502103 ]; then + echo " + sendfile()'s SF_NODISKIO found" + + have=NGX_HAVE_AIO_SENDFILE . auto/have +fi + # kqueue diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -18,7 +18,7 @@ CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURC # Linux kernel version version=$((`uname -r \ - | sed 's/^\([^.]*\)\.\([^.]*\)\.\([^.-]*\).*/\1*256*256+\2*256+\3/'`)) + | sed 's/^\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1*256*256+\2*256+\3/'`)) version=${version:-0} @@ -124,7 +124,20 @@ ngx_feature_test="long mask = 0; . auto/feature +# crypt_r() + +ngx_feature="crypt_r()" +ngx_feature_name="NGX_HAVE_GNU_CRYPT_R" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs=-lcrypt +ngx_feature_test="struct crypt_data cd; + crypt_r(NULL, NULL, &cd);" +. auto/feature + + ngx_include="sys/vfs.h"; . auto/include -CC_AUX_FLAGS=$cc_aux_flags +CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" diff --git a/auto/os/solaris b/auto/os/solaris --- a/auto/os/solaris +++ b/auto/os/solaris @@ -7,14 +7,14 @@ have=NGX_SOLARIS . auto/have_headers CORE_INCS="$UNIX_INCS" CORE_DEPS="$UNIX_DEPS $SOLARIS_DEPS" CORE_SRCS="$UNIX_SRCS $SOLARIS_SRCS " -CORE_LIBS="$CORE_LIBS -lsocket -lnsl -lrt" +CORE_LIBS="$CORE_LIBS -lsocket -lnsl" NGX_RPATH=YES # Solaris's make does not support a blank line between target and rules ngx_spacer= -CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64 -lsocket -lnsl -lrt" +CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64 -lsocket -lnsl" if [ $ZLIB_ASM != NO ]; then diff --git a/auto/os/win32 b/auto/os/win32 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -8,8 +8,9 @@ CORE_INCS="$WIN32_INCS" CORE_DEPS="$WIN32_DEPS" CORE_SRCS="$WIN32_SRCS $IOCP_SRCS" OS_CONFIG="$WIN32_CONFIG" -CORE_LIBS="$CORE_LIBS shell32.lib ws2_32.lib" +CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib" NGX_ICONS="$NGX_WIN32_ICONS" +SELECT_SRCS=$WIN32_SELECT_SRCS EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE" EVENT_FOUND=YES @@ -19,5 +20,9 @@ if [ $EVENT_SELECT = NO ]; then EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE" fi +if [ $NGX_IPV6 = YES ]; then + have=NGX_HAVE_INET6 . auto/have +fi + have=NGX_HAVE_AIO . auto/have have=NGX_HAVE_IOCP . auto/have diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -95,6 +95,7 @@ EVENT_SRCS="src/event/ngx_event.c \ SELECT_MODULE=ngx_select_module SELECT_SRCS=src/event/modules/ngx_select_module.c +WIN32_SELECT_SRCS=src/event/modules/ngx_win32_select_module.c POLL_MODULE=ngx_poll_module POLL_SRCS=src/event/modules/ngx_poll_module.c @@ -124,6 +125,8 @@ AIO_SRCS="src/event/modules/ngx_aio_modu src/os/unix/ngx_aio_read_chain.c \ src/os/unix/ngx_aio_write_chain.c" +FILE_AIO_SRCS="src/os/unix/ngx_file_aio_read.c" +LINUX_AIO_SRCS="src/os/unix/ngx_linux_aio_read.c" UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix" @@ -215,8 +218,6 @@ WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/win32/ngx_socket.h \ src/os/win32/ngx_os.h \ src/os/win32/ngx_user.h \ - src/os/win32/ngx_gui.h \ - src/os/win32/ngx_gui_resources.h \ src/os/win32/ngx_process_cycle.h" WIN32_CONFIG=src/os/win32/ngx_win32_config.h @@ -233,14 +234,15 @@ WIN32_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/win32/ngx_wsarecv.c \ src/os/win32/ngx_wsarecv_chain.c \ src/os/win32/ngx_udp_wsarecv.c \ + src/os/win32/ngx_wsasend.c \ src/os/win32/ngx_wsasend_chain.c \ src/os/win32/ngx_win32_init.c \ src/os/win32/ngx_user.c \ - src/os/win32/ngx_gui.c \ + src/os/win32/ngx_event_log.c \ src/os/win32/ngx_process_cycle.c \ src/event/ngx_event_acceptex.c" -NGX_WIN32_ICONS="src/os/win32/nginx.ico src/os/win32/nginx_tray.ico" +NGX_WIN32_ICONS="src/os/win32/nginx.ico" NGX_WIN32_RC="src/os/win32/nginx.rc" @@ -329,6 +331,10 @@ HTTP_XSLT_FILTER_MODULE=ngx_http_xslt_fi HTTP_XSLT_SRCS=src/http/modules/ngx_http_xslt_filter_module.c +HTTP_IMAGE_FILTER_MODULE=ngx_http_image_filter_module +HTTP_IMAGE_SRCS=src/http/modules/ngx_http_image_filter_module.c + + HTTP_SUB_FILTER_MODULE=ngx_http_sub_filter_module HTTP_SUB_SRCS=src/http/modules/ngx_http_sub_filter_module.c @@ -373,6 +379,10 @@ HTTP_GEO_MODULE=ngx_http_geo_module HTTP_GEO_SRCS=src/http/modules/ngx_http_geo_module.c +HTTP_GEOIP_MODULE=ngx_http_geoip_module +HTTP_GEOIP_SRCS=src/http/modules/ngx_http_geoip_module.c + + HTTP_MAP_MODULE=ngx_http_map_module HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c diff --git a/auto/stubs b/auto/stubs --- a/auto/stubs +++ b/auto/stubs @@ -2,7 +2,6 @@ # Copyright (C) Igor Sysoev -have=NGX_USE_HTTP_FILE_CACHE_UNIQ . auto/have have=NGX_SUPPRESS_WARN . auto/have have=NGX_SMP . auto/have diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -74,65 +74,6 @@ esac echo -if [ $HTTP_REWRITE = YES ]; then - if [ $USE_PCRE = DISABLED ]; then - -cat << END -$0: error: the HTTP rewrite module requires the PCRE library. -You can either disable the module by using --without-http_rewrite_module -option or you have to enable the PCRE support. - -END - exit 1 - fi - - if [ $PCRE = NONE -o $PCRE = NO ]; then - -cat << END -$0: error: the HTTP rewrite module requires the PCRE library. -You can either disable the module by using --without-http_rewrite_module -option, or install the PCRE library into the system, or build the PCRE library -statically from the source with nginx by using --with-pcre= option. - -END - - exit 1 - fi -fi - - -if [ $HTTP_GZIP = YES ]; then - if [ $ZLIB = NONE -o $ZLIB = NO ]; then - -cat << END -$0: error: the HTTP gzip module requires the zlib library. -You can either disable the module by using --without-http_gzip_module -option, or install the zlib library into the system, or build the zlib library -statically from the source with nginx by using --with-zlib= option. - -END - - exit 1 - fi -fi - - -if [ $HTTP_SSL = YES ]; then - if [ $OPENSSL = NONE -o $OPENSSL = NO ]; then - -cat << END -$0: error: the HTTP SSL module requires the OpenSSL library. -You can either do not enable the module, or install the OpenSSL library -into the system, or build the OpenSSL library statically from the source -with nginx by using --with-openssl= option. - -END - - exit 1 - fi -fi - - cat << END nginx path prefix: "$NGX_PREFIX" nginx binary file: "$NGX_SBIN_PATH" diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -163,16 +163,6 @@ ngx_feature_test="void *p; p = memalign( . auto/feature -ngx_feature="sched_yield()" -ngx_feature_name="NGX_HAVE_SCHED_YIELD" -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_path= -ngx_feature_libs= -ngx_feature_test="sched_yield()" -. auto/feature - - ngx_feature="mmap(MAP_ANON|MAP_SHARED)" ngx_feature_name="NGX_HAVE_MAP_ANON" ngx_feature_run=yes diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -19,7 +19,7 @@ http { default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - # '"$status" $body_bytes_sent "$http_referer" ' + # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; diff --git a/configure b/configure --- a/configure +++ b/configure @@ -3,8 +3,6 @@ # Copyright (C) Igor Sysoev -NGX_CONFIGURE=`echo $@ | sed 's/"/\\\\"/g'` - . auto/options . auto/init . auto/sources @@ -33,6 +31,12 @@ if test -z "$NGX_PLATFORM"; then NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE"; + case "$NGX_SYSTEM" in + MINGW32_*) + NGX_PLATFORM=win32 + ;; + esac + else echo "building for $NGX_PLATFORM" NGX_SYSTEM=$NGX_PLATFORM @@ -54,6 +58,39 @@ fi . auto/modules . auto/lib/conf +case ".$NGX_PREFIX" in + .) + NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx} + have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define + ;; + + .!) + NGX_PREFIX= + ;; + + *) + have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define + ;; +esac + +if [ ".$NGX_CONF_PREFIX" != "." ]; then + have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define +fi + +have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define +have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define +have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define +have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define +have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define + +have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define +have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" +. auto/define +have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\"" +. auto/define +have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\"" +. auto/define + . auto/make . auto/lib/make . auto/install @@ -65,24 +102,6 @@ fi # STUB . auto/stubs -have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define -have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define -have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define -have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define -have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define -have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define -if test -n "$NGX_ERROR_LOG_PATH"; then - have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define -fi - -have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define -have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" -. auto/define -have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\"" -. auto/define -have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\"" -. auto/define - have=NGX_USER value="\"$NGX_USER\"" . auto/define have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -10,7 +10,8 @@ static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); -static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv); +static ngx_int_t ngx_get_options(int argc, char *const *argv); +static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv); static void *ngx_core_module_create_conf(ngx_cycle_t *cycle); static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf); @@ -180,10 +181,16 @@ ngx_module_t ngx_core_module = { }; -ngx_uint_t ngx_max_module; +ngx_uint_t ngx_max_module; -static ngx_uint_t ngx_show_version; -static ngx_uint_t ngx_show_configure; +static ngx_uint_t ngx_show_help; +static ngx_uint_t ngx_show_version; +static ngx_uint_t ngx_show_configure; +static u_char *ngx_prefix; +static u_char *ngx_conf_file; +static u_char *ngx_conf_params; +static char *ngx_signal; + static char **ngx_os_environ; @@ -191,13 +198,55 @@ static char **ngx_os_environ; int ngx_cdecl main(int argc, char *const *argv) { - char *p; - ssize_t n; ngx_int_t i; ngx_log_t *log; ngx_cycle_t *cycle, init_cycle; ngx_core_conf_t *ccf; + if (ngx_get_options(argc, argv) != NGX_OK) { + return 1; + } + + if (ngx_show_version) { + ngx_log_stderr(0, "nginx version: " NGINX_VER); + + if (ngx_show_help) { + ngx_log_stderr(0, + "Usage: nginx [-?hvVt] [-s signal] [-c filename] " + "[-p prefix] [-g directives]" CRLF CRLF + "Options:" CRLF + " -?,-h : this help" CRLF + " -v : show version and exit" CRLF + " -V : show version and configure options then exit" + CRLF + " -t : test configuration and exit" CRLF + " -s signal : send signal to a master process: " + "stop, quit, reopen, reload" CRLF +#ifdef NGX_PREFIX + " -p prefix : set prefix path (default: " + NGX_PREFIX ")" CRLF +#else + " -p prefix : set prefix path (default: NONE)" CRLF +#endif + " -c filename : set configuration file (default: " + NGX_CONF_PATH ")" CRLF + " -g directives : set global directives out of configuration " + "file" CRLF + ); + } + + if (ngx_show_configure) { +#ifdef NGX_COMPILER + ngx_log_stderr(0, "built by " NGX_COMPILER); +#endif + ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE); + } + + if (!ngx_test_config) { + return 0; + } + } + #if (NGX_FREEBSD) ngx_debug_init(); #endif @@ -212,7 +261,7 @@ main(int argc, char *const *argv) ngx_pid = ngx_getpid(); - log = ngx_log_init(); + log = ngx_log_init(ngx_prefix); if (log == NULL) { return 1; } @@ -222,7 +271,10 @@ main(int argc, char *const *argv) ngx_ssl_init(log); #endif - /* init_cycle->log is required for signal handlers and ngx_getopt() */ + /* + * init_cycle->log is required for signal handlers and + * ngx_process_options() + */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); init_cycle.log = log; @@ -237,46 +289,10 @@ main(int argc, char *const *argv) return 1; } - if (ngx_getopt(&init_cycle, argc, ngx_argv) != NGX_OK) { + if (ngx_process_options(&init_cycle) != NGX_OK) { return 1; } - if (ngx_show_version) { - - p = "nginx version: " NGINX_VER CRLF; - n = sizeof("nginx version: " NGINX_VER CRLF) - 1; - - if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) { - return 1; - } - - if (ngx_show_configure) { -#ifdef NGX_COMPILER - p = "built by " NGX_COMPILER CRLF; - n = sizeof("built by " NGX_COMPILER CRLF) - 1; - - if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) { - return 1; - } -#endif - - p = "configure arguments: " NGX_CONFIGURE CRLF; - n = sizeof("configure arguments :" NGX_CONFIGURE CRLF) - 1; - - if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) { - return 1; - } - } - - if (!ngx_test_config) { - return 0; - } - } - - if (ngx_test_config) { - log->log_level = NGX_LOG_INFO; - } - if (ngx_os_init(log) != NGX_OK) { return 1; } @@ -301,45 +317,34 @@ main(int argc, char *const *argv) cycle = ngx_init_cycle(&init_cycle); if (cycle == NULL) { if (ngx_test_config) { - ngx_log_error(NGX_LOG_EMERG, log, 0, - "the configuration file %s test failed", - init_cycle.conf_file.data); + ngx_log_stderr(0, "configuration file %s test failed", + init_cycle.conf_file.data); } return 1; } if (ngx_test_config) { - ngx_log_error(NGX_LOG_INFO, log, 0, - "the configuration file %s was tested successfully", - cycle->conf_file.data); + ngx_log_stderr(0, "configuration file %s test is successful", + cycle->conf_file.data); return 0; } + if (ngx_signal) { + return ngx_signal_process(cycle, ngx_signal); + } + ngx_os_status(cycle->log); ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); - ngx_process = ccf->master ? NGX_PROCESS_MASTER : NGX_PROCESS_SINGLE; - -#if (NGX_WIN32) - -#if 0 - - TODO: + if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { + ngx_process = NGX_PROCESS_MASTER; + } - if (ccf->run_as_service) { - if (ngx_service(cycle->log) != NGX_OK) { - return 1; - } - - return 0; - } -#endif - -#else +#if !(NGX_WIN32) if (ngx_init_signals(cycle->log) != NGX_OK) { return 1; @@ -353,17 +358,28 @@ main(int argc, char *const *argv) ngx_daemonized = 1; } +#endif + if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { return 1; } -#endif + if (cycle->log->file->fd != ngx_stderr) { - if (ngx_process == NGX_PROCESS_MASTER) { - ngx_master_process_cycle(cycle); + if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_set_stderr_n " failed"); + return 1; + } + } + + ngx_use_stderr = 0; + + if (ngx_process == NGX_PROCESS_SINGLE) { + ngx_single_process_cycle(cycle); } else { - ngx_single_process_cycle(cycle); + ngx_master_process_cycle(cycle); } return 0; @@ -533,6 +549,8 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, ngx_core_conf_t *ccf; ngx_listening_t *ls; + ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t)); + ctx.path = argv[0]; ctx.name = "new binary process"; ctx.argv = argv; @@ -616,64 +634,118 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, static ngx_int_t -ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv) +ngx_get_options(int argc, char *const *argv) { - ngx_int_t i; + u_char *p; + ngx_int_t i; for (i = 1; i < argc; i++) { - if (argv[i][0] != '-') { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "invalid option: \"%s\"", argv[i]); + + p = (u_char *) argv[i]; + + if (*p++ != '-') { + ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]); return NGX_ERROR; } - switch (argv[i][1]) { + while (*p) { + + switch (*p++) { + + case '?': + case 'h': + ngx_show_version = 1; + ngx_show_help = 1; + break; + + case 'v': + ngx_show_version = 1; + break; + + case 'V': + ngx_show_version = 1; + ngx_show_configure = 1; + break; - case 'v': - ngx_show_version = 1; - break; + case 't': + ngx_test_config = 1; + break; + + case 'p': + if (*p) { + ngx_prefix = p; + goto next; + } + + if (argv[++i]) { + ngx_prefix = (u_char *) argv[i]; + goto next; + } + + ngx_log_stderr(0, "option \"-p\" requires directory name"); + return NGX_ERROR; + + case 'c': + if (*p) { + ngx_conf_file = p; + goto next; + } - case 'V': - ngx_show_version = 1; - ngx_show_configure = 1; - break; + if (argv[++i]) { + ngx_conf_file = (u_char *) argv[i]; + goto next; + } + + ngx_log_stderr(0, "option \"-c\" requires file name"); + return NGX_ERROR; + + case 'g': + if (*p) { + ngx_conf_params = p; + goto next; + } + + if (argv[++i]) { + ngx_conf_params = (u_char *) argv[i]; + goto next; + } + + ngx_log_stderr(0, "option \"-g\" requires parameter"); + return NGX_ERROR; - case 't': - ngx_test_config = 1; - break; + case 's': + if (*p) { + ngx_signal = (char *) p; + + } else if (argv[++i]) { + ngx_signal = argv[i]; + + } else { + ngx_log_stderr(0, "option \"-s\" requires parameter"); + return NGX_ERROR; + } - case 'c': - if (argv[i + 1] == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "the option \"-c\" requires file name"); + if (ngx_strcmp(ngx_signal, "stop") == 0 + || ngx_strcmp(ngx_signal, "quit") == 0 + || ngx_strcmp(ngx_signal, "reopen") == 0 + || ngx_strcmp(ngx_signal, "reload") == 0) + { + ngx_process = NGX_PROCESS_SIGNALLER; + goto next; + } + + ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal); + return NGX_ERROR; + + default: + ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1)); return NGX_ERROR; } - - cycle->conf_file.data = (u_char *) argv[++i]; - cycle->conf_file.len = ngx_strlen(cycle->conf_file.data); - break; - - case 'g': - if (argv[i + 1] == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "the option \"-g\" requires parameter"); - return NGX_ERROR; - } + } - cycle->conf_param.data = (u_char *) argv[++i]; - cycle->conf_param.len = ngx_strlen(cycle->conf_param.data); - break; + next: - default: - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "invalid option: \"%s\"", argv[i]); - return NGX_ERROR; - } - } - - if (cycle->conf_file.data == NULL) { - cycle->conf_file.len = sizeof(NGX_CONF_PATH) - 1; - cycle->conf_file.data = (u_char *) NGX_CONF_PATH; + continue; } return NGX_OK; @@ -722,6 +794,106 @@ ngx_save_argv(ngx_cycle_t *cycle, int ar } +static ngx_int_t +ngx_process_options(ngx_cycle_t *cycle) +{ + u_char *p; + size_t len; + + if (ngx_prefix) { + len = ngx_strlen(ngx_prefix); + p = ngx_prefix; + + if (!ngx_path_separator(*p)) { + p = ngx_pnalloc(cycle->pool, len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, ngx_prefix, len); + p[len++] = '/'; + } + + cycle->conf_prefix.len = len; + cycle->conf_prefix.data = p; + cycle->prefix.len = len; + cycle->prefix.data = p; + + } else { + +#ifndef NGX_PREFIX + + p = ngx_pnalloc(cycle->pool, NGX_MAX_PATH); + if (p == NULL) { + return NGX_ERROR; + } + + if (ngx_getcwd(p, NGX_MAX_PATH) == 0) { + ngx_log_stderr(ngx_errno, "[emerg]: " ngx_getcwd_n " failed"); + return NGX_ERROR; + } + + len = ngx_strlen(p); + + p[len++] = '/'; + + cycle->conf_prefix.len = len; + cycle->conf_prefix.data = p; + cycle->prefix.len = len; + cycle->prefix.data = p; + +#else + +#ifdef NGX_CONF_PREFIX + cycle->conf_prefix.len = sizeof(NGX_CONF_PREFIX) - 1; + cycle->conf_prefix.data = (u_char *) NGX_CONF_PREFIX; +#else + cycle->conf_prefix.len = sizeof(NGX_PREFIX) - 1; + cycle->conf_prefix.data = (u_char *) NGX_PREFIX; +#endif + cycle->prefix.len = sizeof(NGX_PREFIX) - 1; + cycle->prefix.data = (u_char *) NGX_PREFIX; + +#endif + } + + if (ngx_conf_file) { + cycle->conf_file.len = ngx_strlen(ngx_conf_file); + cycle->conf_file.data = ngx_conf_file; + + } else { + cycle->conf_file.len = sizeof(NGX_CONF_PATH) - 1; + cycle->conf_file.data = (u_char *) NGX_CONF_PATH; + } + + if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) { + return NGX_ERROR; + } + + for (p = cycle->conf_file.data + cycle->conf_file.len - 1; + p > cycle->conf_file.data; + p--) + { + if (ngx_path_separator(*p)) { + cycle->conf_prefix.len = p - ngx_cycle->conf_file.data + 1; + cycle->conf_prefix.data = ngx_cycle->conf_file.data; + break; + } + } + + if (ngx_conf_params) { + cycle->conf_param.len = ngx_strlen(ngx_conf_params); + cycle->conf_param.data = ngx_conf_params; + } + + if (ngx_test_config) { + cycle->log->log_level = NGX_LOG_INFO; + } + + return NGX_OK; +} + + static void * ngx_core_module_create_conf(ngx_cycle_t *cycle) { @@ -805,6 +977,27 @@ ngx_core_module_init_conf(ngx_cycle_t *c #endif + + if (ccf->pid.len == 0) { + ccf->pid.len = sizeof(NGX_PID_PATH) - 1; + ccf->pid.data = (u_char *) NGX_PID_PATH; + } + + if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); + + ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); + if (ccf->oldpid.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), + NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); + + #if !(NGX_WIN32) if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) { @@ -833,25 +1026,6 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->group = grp->gr_gid; } - if (ccf->pid.len == 0) { - ccf->pid.len = sizeof(NGX_PID_PATH) - 1; - ccf->pid.data = (u_char *) NGX_PID_PATH; - } - - if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { - return NGX_CONF_ERROR; - } - - ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); - - ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); - if (ccf->oldpid.data == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), - NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); - if (ccf->lock_file.len == 0) { ccf->lock_file.len = sizeof(NGX_LOCK_PATH) - 1; diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 007047 -#define NGINX_VERSION "0.7.47" +#define nginx_version 8016 +#define NGINX_VERSION "0.8.16" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -67,21 +67,35 @@ typedef struct { } ngx_bufs_t; +typedef struct ngx_output_chain_ctx_s ngx_output_chain_ctx_t; + typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in); -typedef struct { +#if (NGX_HAVE_FILE_AIO) +typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx, + ngx_file_t *file); +#endif + +struct ngx_output_chain_ctx_s { ngx_buf_t *buf; ngx_chain_t *in; ngx_chain_t *free; ngx_chain_t *busy; - unsigned sendfile; - unsigned directio; + unsigned sendfile:1; + unsigned directio:1; #if (NGX_HAVE_ALIGNED_DIRECTIO) - unsigned unaligned; + unsigned unaligned:1; #endif - unsigned need_in_memory; - unsigned need_in_temp; + unsigned need_in_memory:1; + unsigned need_in_temp:1; +#if (NGX_HAVE_FILE_AIO) + unsigned aio:1; + + ngx_output_chain_aio_pt aio_handler; +#endif + + off_t alignment; ngx_pool_t *pool; ngx_int_t allocated; @@ -90,7 +104,7 @@ typedef struct { ngx_output_chain_filter_pt output_filter; void *filter_ctx; -} ngx_output_chain_ctx_t; +}; typedef struct { 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 @@ -12,6 +12,7 @@ static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name); static void ngx_conf_flush_files(ngx_cycle_t *cycle); @@ -61,6 +62,7 @@ static ngx_uint_t argument_number[] = { char * ngx_conf_param(ngx_conf_t *cf) { + char *rv; ngx_str_t *param; ngx_buf_t b; ngx_conf_file_t conf_file; @@ -82,13 +84,17 @@ ngx_conf_param(ngx_conf_t *cf) b.temporary = 1; conf_file.file.fd = NGX_INVALID_FILE; - conf_file.file.name.data = (u_char *) "command line"; - conf_file.line = 1; + conf_file.file.name.data = NULL; + conf_file.line = 0; cf->conf_file = &conf_file; cf->conf_file->buffer = &b; - return ngx_conf_parse(cf, NULL); + rv = ngx_conf_parse(cf, NULL); + + cf->conf_file = NULL; + + return rv; } @@ -441,7 +447,9 @@ ngx_conf_read_token(ngx_conf_t *cf) last_space = 1; sharp_comment = 0; variable = 0; - quoted = s_quoted = d_quoted = 0; + quoted = 0; + s_quoted = 0; + d_quoted = 0; cf->args->nelts = 0; b = cf->conf_file->buffer; @@ -795,46 +803,94 @@ ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix) { size_t len; - u_char *p, *prefix; - ngx_str_t old; + u_char *p, *n, *prefix; + ngx_int_t rc; + + rc = ngx_conf_test_full_name(name); + + if (rc == NGX_OK) { + return rc; + } + + if (conf_prefix) { + len = cycle->conf_prefix.len; + prefix = cycle->conf_prefix.data; + + } else { + len = cycle->prefix.len; + prefix = cycle->prefix.data; + } + +#if (NGX_WIN32) + + if (rc == 2) { + len = rc; + } + +#endif + + n = ngx_pnalloc(cycle->pool, len + name->len + 1); + if (n == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(n, prefix, len); + ngx_cpystrn(p, name->data, name->len + 1); + + name->len += len; + name->data = n; + + return NGX_OK; +} + + +static ngx_int_t +ngx_conf_test_full_name(ngx_str_t *name) +{ +#if (NGX_WIN32) + u_char c0, c1; + + c0 = name->data[0]; + + if (name->len < 2) { + if (c0 == '/') { + return 2; + } + + return NGX_DECLINED; + } + + c1 = name->data[1]; + + if (c1 == ':') { + c0 |= 0x20; + + if ((c0 >= 'a' && c0 <= 'z')) { + return NGX_OK; + } + + return NGX_DECLINED; + } + + if (c1 == '/') { + return NGX_OK; + } + + if (c0 == '/') { + return 2; + } + + return NGX_DECLINED; + +#else if (name->data[0] == '/') { return NGX_OK; } -#if (NGX_WIN32) - - if (name->len > 2 - && name->data[1] == ':' - && ((name->data[0] >= 'a' && name->data[0] <= 'z') - || (name->data[0] >= 'A' && name->data[0] <= 'Z'))) - { - return NGX_OK; - } + return NGX_DECLINED; #endif - - old = *name; - - if (conf_prefix) { - len = sizeof(NGX_CONF_PREFIX) - 1; - prefix = (u_char *) NGX_CONF_PREFIX; - - } else { - len = cycle->root.len; - prefix = cycle->root.data; - } - - name->len = len + old.len; - name->data = ngx_pnalloc(cycle->pool, name->len + 1); - if (name->data == NULL) { - return NGX_ERROR; - } - - p = ngx_cpymem(name->data, prefix, len); - ngx_cpystrn(p, old.data, old.len + 1); - - return NGX_OK; } @@ -851,7 +907,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n full.data = NULL; #endif - if (name) { + if (name->len) { full = *name; if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) { @@ -887,14 +943,13 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n return NULL; } - if (name) { + if (name->len) { file->fd = NGX_INVALID_FILE; file->name = full; } else { - file->fd = ngx_stderr_fileno; - file->name.len = 0; - file->name.data = NULL; + file->fd = ngx_stderr; + file->name = *name; } file->buffer = NULL; @@ -959,31 +1014,11 @@ ngx_conf_log_error(ngx_uint_t level, ngx last = errstr + NGX_MAX_CONF_ERRSTR; va_start(args, fmt); - p = ngx_vsnprintf(errstr, last - errstr, fmt, args); + p = ngx_vslprintf(errstr, last, fmt, args); va_end(args); if (err) { - - if (p > last - 50) { - - /* leave a space for an error code */ - - p = last - 50; - *p++ = '.'; - *p++ = '.'; - *p++ = '.'; - } - -#if (NGX_WIN32) - p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) - ? " (%d: " : " (%Xd: ", err); -#else - p = ngx_snprintf(p, last - p, " (%d: ", err); -#endif - - p = ngx_strerror_r(err, p, last - p); - - *p++ = ')'; + p = ngx_log_errno(p, last, err); } if (cf->conf_file == NULL) { @@ -991,6 +1026,12 @@ ngx_conf_log_error(ngx_uint_t level, ngx return; } + if (cf->conf_file->file.fd == NGX_INVALID_FILE) { + ngx_log_error(level, cf->log, 0, "%*s in command line", + p - errstr, errstr); + return; + } + ngx_log_error(level, cf->log, 0, "%*s in %s:%ui", p - errstr, errstr, cf->conf_file->file.name.data, cf->conf_file->line); 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 @@ -13,11 +13,11 @@ ngx_os_io_t ngx_io; ngx_listening_t * -ngx_listening_inet_stream_socket(ngx_conf_t *cf, in_addr_t addr, in_port_t port) +ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) { - size_t len; - ngx_listening_t *ls; - struct sockaddr_in *sin; + ngx_listening_t *ls; + struct sockaddr *sa; + u_char text[NGX_SOCKADDR_STRLEN]; ls = ngx_array_push(&cf->cycle->listening); if (ls == NULL) { @@ -26,33 +26,45 @@ ngx_listening_inet_stream_socket(ngx_con ngx_memzero(ls, sizeof(ngx_listening_t)); - sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { + sa = ngx_palloc(cf->pool, socklen); + if (sa == NULL) { return NULL; } - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = addr; - sin->sin_port = htons(port); + ngx_memcpy(sa, sockaddr, socklen); + ls->sockaddr = sa; + ls->socklen = socklen; - ls->addr_text.data = ngx_pnalloc(cf->pool, - NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1); + ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); + + ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len); if (ls->addr_text.data == NULL) { return NULL; } - len = ngx_inet_ntop(AF_INET, &addr, ls->addr_text.data, - NGX_INET_ADDRSTRLEN); - - ls->addr_text.len = ngx_sprintf(ls->addr_text.data + len, ":%d", port) - - ls->addr_text.data; + ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len); ls->fd = (ngx_socket_t) -1; ls->type = SOCK_STREAM; - ls->sockaddr = (struct sockaddr *) sin; - ls->socklen = sizeof(struct sockaddr_in); - ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; + + switch (ls->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; + break; +#endif + case AF_INET: + ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; + break; + default: + ls->addr_text_max_len = NGX_SOCKADDR_STRLEN; + break; + } + + ls->backlog = NGX_LISTEN_BACKLOG; + ls->rcvbuf = -1; + ls->sndbuf = -1; return ls; } @@ -293,7 +305,7 @@ ngx_open_listening_sockets(ngx_cycle_t * (const void *) &ipv6only, sizeof(int)) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(IPV6_V6ONLY) %V failed, ignored", &ls[i].addr_text); } @@ -317,7 +329,7 @@ ngx_open_listening_sockets(ngx_cycle_t * } } - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, "bind() %V #%d ", &ls[i].addr_text, s); if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { @@ -386,7 +398,7 @@ ngx_open_listening_sockets(ngx_cycle_t * void -ngx_configure_listening_socket(ngx_cycle_t *cycle) +ngx_configure_listening_sockets(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; @@ -401,6 +413,8 @@ ngx_configure_listening_socket(ngx_cycle ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { + ls[i].log = *ls[i].logp; + if (ls[i].rcvbuf != -1) { if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (const void *) &ls[i].rcvbuf, sizeof(int)) @@ -557,29 +571,31 @@ ngx_close_listening_sockets(ngx_cycle_t c = ls[i].connection; - if (c->read->active) { - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - ngx_del_conn(c, NGX_CLOSE_EVENT); + if (c) { + if (c->read->active) { + if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { + ngx_del_conn(c, NGX_CLOSE_EVENT); - } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { - /* - * it seems that Linux-2.6.x OpenVZ sends events - * for closed shared listening sockets unless - * the events was explicity deleted - */ + /* + * it seems that Linux-2.6.x OpenVZ sends events + * for closed shared listening sockets unless + * the events was explicity deleted + */ - ngx_del_event(c->read, NGX_READ_EVENT, 0); + ngx_del_event(c->read, NGX_READ_EVENT, 0); - } else { - ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } else { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } } + + ngx_free_connection(c); + + c->fd = (ngx_socket_t) -1; } - ngx_free_connection(c); - - c->fd = (ngx_socket_t) -1; - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, "close listening %V #%d ", &ls[i].addr_text, ls[i].fd); @@ -587,6 +603,8 @@ ngx_close_listening_sockets(ngx_cycle_t ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } + + ls[i].fd = (ngx_socket_t) -1; } } @@ -795,11 +813,78 @@ ngx_close_connection(ngx_connection_t *c ngx_int_t +ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, + ngx_uint_t port) +{ + socklen_t len; + ngx_uint_t addr; + u_char sa[NGX_SOCKADDRLEN]; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + ngx_uint_t i; + struct sockaddr_in6 *sin6; +#endif + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + + for (addr = 0, i = 0; addr == 0 && i < 16; i++) { + addr |= sin6->sin6_addr.s6_addr[i]; + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + addr = sin->sin_addr.s_addr; + break; + } + + if (addr == 0) { + + len = NGX_SOCKADDRLEN; + + if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) { + ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); + return NGX_ERROR; + } + + c->local_sockaddr = ngx_palloc(c->pool, len); + if (c->local_sockaddr == NULL) { + return NGX_ERROR; + } + + c->local_socklen = len; + ngx_memcpy(c->local_sockaddr, &sa, len); + } + + if (s == NULL) { + return NGX_OK; + } + + s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, port); + + return NGX_OK; +} + + +ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) { ngx_uint_t level; - if (err == NGX_ECONNRESET && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) { + /* Winsock may return NGX_ECONNABORTED instead of NGX_ECONNRESET */ + + if ((err == NGX_ECONNRESET +#if (NGX_WIN32) + || err == NGX_ECONNABORTED +#endif + ) && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) + { return 0; } @@ -811,7 +896,9 @@ ngx_connection_error(ngx_connection_t *c if (err == 0 || err == NGX_ECONNRESET -#if !(NGX_WIN32) +#if (NGX_WIN32) + || err == NGX_ECONNABORTED +#else || err == NGX_EPIPE #endif || err == NGX_ENOTCONN diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -34,6 +34,7 @@ struct ngx_listening_s { void *servers; /* array of ngx_http_in_addr_t, for example */ ngx_log_t log; + ngx_log_t *logp; size_t pool_size; /* should be here because of the AcceptEx() preread */ @@ -134,6 +135,8 @@ struct ngx_connection_s { ngx_atomic_uint_t number; + ngx_uint_t requests; + unsigned buffered:8; unsigned log_error:3; /* ngx_connection_log_error_e */ @@ -156,24 +159,26 @@ struct ngx_connection_s { unsigned accept_context_updated:1; #endif +#if (NGX_HAVE_AIO_SENDFILE) + unsigned aio_sendfile:1; + ngx_buf_t *busy_sendfile; +#endif + #if (NGX_THREADS) ngx_atomic_t lock; #endif }; -#ifndef ngx_ssl_set_nosendshut -#define ngx_ssl_set_nosendshut(ssl) -#endif - - -ngx_listening_t *ngx_listening_inet_stream_socket(ngx_conf_t *cf, - in_addr_t addr, in_port_t port); +ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, void *sockaddr, + socklen_t socklen); ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle); ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); -void ngx_configure_listening_socket(ngx_cycle_t *cycle); +void ngx_configure_listening_sockets(ngx_cycle_t *cycle); void ngx_close_listening_sockets(ngx_cycle_t *cycle); void ngx_close_connection(ngx_connection_t *c); +ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, + ngx_uint_t port); ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text); ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log); 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 @@ -19,6 +19,7 @@ typedef struct ngx_open_file_s ngx_ope typedef struct ngx_command_s ngx_command_t; typedef struct ngx_file_s ngx_file_t; typedef struct ngx_event_s ngx_event_t; +typedef struct ngx_event_aio_s ngx_event_aio_t; typedef struct ngx_connection_s ngx_connection_t; typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); 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 @@ -9,9 +9,11 @@ #include -static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log); static void ngx_destroy_cycle_pools(ngx_conf_t *conf); static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2); +static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, + ngx_shm_zone_t *shm_zone); +static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log); static void ngx_clean_old_cycles(ngx_event_t *ev); @@ -32,11 +34,7 @@ ngx_tls_key_t ngx_core_tls_key; static ngx_connection_t dumb; /* STUB */ -#ifdef NGX_ERROR_LOG_PATH static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); -#else -static ngx_str_t error_log = ngx_null_string; -#endif ngx_cycle_t * @@ -44,7 +42,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) { void *rv; char **senv, **env; - u_char *lock_file; ngx_uint_t i, n; ngx_log_t *log; ngx_time_t *tp; @@ -52,7 +49,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ngx_pool_t *pool; ngx_cycle_t *cycle, **old; ngx_shm_zone_t *shm_zone, *oshm_zone; - ngx_slab_pool_t *shpool; ngx_list_part_t *part, *opart; ngx_open_file_t *file; ngx_listening_t *ls, *nls; @@ -86,10 +82,22 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->pool = pool; cycle->log = log; + cycle->new_log.log_level = NGX_LOG_ERR; cycle->old_cycle = old_cycle; - cycle->root.len = sizeof(NGX_PREFIX) - 1; - cycle->root.data = (u_char *) NGX_PREFIX; + cycle->conf_prefix.len = old_cycle->conf_prefix.len; + cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix); + if (cycle->conf_prefix.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + + cycle->prefix.len = old_cycle->prefix.len; + cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix); + if (cycle->prefix.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } cycle->conf_file.len = old_cycle->conf_file.len; cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); @@ -100,15 +108,12 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data, old_cycle->conf_file.len + 1); - cycle->conf_param.len = old_cycle->conf_param.len; - cycle->conf_param.data = ngx_pnalloc(pool, old_cycle->conf_param.len); + cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param); if (cycle->conf_param.data == NULL) { ngx_destroy_pool(pool); return NULL; } - ngx_memcpy(cycle->conf_param.data, old_cycle->conf_param.data, - old_cycle->conf_param.len); n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; @@ -161,16 +166,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } - - cycle->new_log = ngx_log_create_errlog(cycle, NULL); - if (cycle->new_log == NULL) { - ngx_destroy_pool(pool); - return NULL; - } - - cycle->new_log->file->name = error_log; - - n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); @@ -221,7 +216,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) if (module->create_conf) { rv = module->create_conf(cycle); - if (rv == NGX_CONF_ERROR) { + if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } @@ -260,22 +255,22 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #endif if (ngx_conf_param(&conf) != NGX_CONF_OK) { + environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { + environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_test_config) { - ngx_log_error(NGX_LOG_INFO, log, 0, - "the configuration file %s syntax is ok", - cycle->conf_file.data); + ngx_log_stderr(0, "the configuration file %s syntax is ok", + cycle->conf_file.data); } - for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; @@ -287,17 +282,19 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) == NGX_CONF_ERROR) { + environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } } } + if (ngx_process == NGX_PROCESS_SIGNALLER) { + return cycle; + } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); -#if !(NGX_WIN32) - if (ngx_test_config) { if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { @@ -326,8 +323,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } } -#endif - if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) { goto failed; @@ -339,6 +334,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } + if (cycle->new_log.file == NULL) { + cycle->new_log.file = ngx_conf_open_file(cycle, &error_log); + if (cycle->new_log.file == NULL) { + goto failed; + } + } + /* open the new files */ part = &cycle->open_files.part; @@ -355,7 +357,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) i = 0; } - if (file[i].name.data == NULL) { + if (file[i].name.len == 0) { continue; } @@ -375,14 +377,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) goto failed; } -#if (NGX_WIN32) - if (ngx_file_append_mode(file[i].fd) != NGX_OK) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - ngx_file_append_mode_n " \"%s\" failed", - file[i].name.data); - goto failed; - } -#else +#if !(NGX_WIN32) if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fcntl(FD_CLOEXEC) \"%s\" failed", @@ -392,12 +387,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #endif } - cycle->log = cycle->new_log; - pool->log = cycle->new_log; - - if (cycle->log->log_level == 0) { - cycle->log->log_level = NGX_LOG_ERR; - } + cycle->log = &cycle->new_log; + pool->log = &cycle->new_log; /* create shared memory */ @@ -419,7 +410,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) if (shm_zone[i].shm.size == 0) { ngx_log_error(NGX_LOG_EMERG, log, 0, "zero size shared memory zone \"%V\"", - &shm_zone[i].name); + &shm_zone[i].shm.name); goto failed; } @@ -444,12 +435,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) n = 0; } - if (shm_zone[i].name.len != oshm_zone[n].name.len) { + if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { continue; } - if (ngx_strncmp(shm_zone[i].name.data, oshm_zone[n].name.data, - shm_zone[i].name.len) + if (ngx_strncmp(shm_zone[i].shm.name.data, + oshm_zone[n].shm.name.data, + shm_zone[i].shm.name.len) != 0) { continue; @@ -476,38 +468,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) goto failed; } - shpool = (ngx_slab_pool_t *) shm_zone[i].shm.addr; - - shpool->end = shm_zone[i].shm.addr + shm_zone[i].shm.size; - shpool->min_shift = 3; - -#if (NGX_HAVE_ATOMIC_OPS) - - lock_file = NULL; - -#else - - lock_file = ngx_pnalloc(cycle->pool, - cycle->lock_file.len + shm_zone[i].name.len); - - if (lock_file == NULL) { + if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) { goto failed; } - (void) ngx_cpystrn(ngx_cpymem(lock_file, cycle->lock_file.data, - cycle->lock_file.len), - shm_zone[i].name.data, shm_zone[i].name.len + 1); - -#endif - - if (ngx_shmtx_create(&shpool->mutex, (void *) &shpool->lock, lock_file) - != NGX_OK) - { - goto failed; - } - - ngx_slab_init(shpool); - if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) { goto failed; } @@ -610,31 +574,20 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } if (!ngx_test_config) { - ngx_configure_listening_socket(cycle); + ngx_configure_listening_sockets(cycle); } /* commit the new cycle configuration */ -#if !(NGX_WIN32) - - if (!ngx_test_config && cycle->log->file->fd != STDERR_FILENO) { + if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) { - ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0, - "dup2: %p %d \"%s\"", - cycle->log->file, - cycle->log->file->fd, cycle->log->file->name.data); - - if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - "dup2(STDERR) failed"); - /* fatal */ - exit(1); + if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_set_stderr_n " failed"); } } -#endif - pool->log = cycle->log; for (i = 0; ngx_modules[i]; i++) { @@ -679,10 +632,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) n = 0; } - if (oshm_zone[i].name.len == shm_zone[n].name.len - && ngx_strncmp(oshm_zone[i].name.data, - shm_zone[n].name.data, - oshm_zone[i].name.len) + if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len + && ngx_strncmp(oshm_zone[i].shm.name.data, + shm_zone[n].shm.name.data, + oshm_zone[i].shm.name.len) == 0) { goto live_shm_zone; @@ -703,7 +656,8 @@ old_shm_zone_done: ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { - if (ls[i].remain) { + + if (ls[i].remain || ls[i].fd == -1) { continue; } @@ -731,7 +685,7 @@ old_shm_zone_done: i = 0; } - if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) { + if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { continue; } @@ -747,8 +701,8 @@ old_shm_zone_done: if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { /* - * perl_destruct() frees environ if it is not the same as it was at - * perl_construct() time. So we have saved an previous cycle + * perl_destruct() frees environ, if it is not the same as it was at + * perl_construct() time, therefore we save the previous cycle * environment before ngx_conf_parse() where it will be changed. */ @@ -831,7 +785,7 @@ failed: i = 0; } - if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) { + if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { continue; } @@ -924,26 +878,76 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s } -#if !(NGX_WIN32) +static ngx_int_t +ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) +{ + u_char *file; + ngx_slab_pool_t *sp; + + sp = (ngx_slab_pool_t *) zn->shm.addr; + + if (zn->shm.exists) { + + if (sp == sp->addr) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "shared zone \"%V\" has no equal addresses: %p vs %p", + &zn->shm.name, sp->addr, sp); + return NGX_ERROR; + } + + sp->end = zn->shm.addr + zn->shm.size; + sp->min_shift = 3; + sp->addr = zn->shm.addr; + +#if (NGX_HAVE_ATOMIC_OPS) + + file = NULL; + +#else + + file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len); + if (file == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(file, "%V%V%Z", &cycle->lock_file, &zn->shm.name); + +#endif + + if (ngx_shmtx_create(&sp->mutex, (void *) &sp->lock, file) != NGX_OK) { + return NGX_ERROR; + } + + ngx_slab_init(sp); + + return NGX_OK; +} + ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) { - size_t len; - ngx_uint_t trunc; - ngx_file_t file; - u_char pid[NGX_INT64_LEN + 2]; + size_t len; + ngx_uint_t create; + ngx_file_t file; + u_char pid[NGX_INT64_LEN + 2]; + + if (ngx_process > NGX_PROCESS_MASTER) { + return NGX_OK; + } ngx_memzero(&file, sizeof(ngx_file_t)); file.name = *name; file.log = log; - trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE; + create = ngx_test_config ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE; file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|trunc, - NGX_FILE_DEFAULT_ACCESS); + create, NGX_FILE_DEFAULT_ACCESS); if (file.fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, @@ -984,7 +988,57 @@ ngx_delete_pidfile(ngx_cycle_t *cycle) } } -#endif + +ngx_int_t +ngx_signal_process(ngx_cycle_t *cycle, char *sig) +{ + ssize_t n; + ngx_int_t pid; + ngx_file_t file; + ngx_core_conf_t *ccf; + u_char buf[NGX_INT64_LEN + 2]; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started"); + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + file.name = ccf->pid; + file.log = cycle->log; + + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, + NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS); + + if (file.fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", file.name.data); + return 1; + } + + n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0); + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file.name.data); + } + + if (n == NGX_ERROR) { + return 1; + } + + while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ } + + pid = ngx_atoi(buf, ++n); + + if (pid == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, cycle->log, 0, + "invalid PID number \"%*s\" in \"%s\"", + n, buf, file.name.data); + return 1; + } + + return ngx_os_signal_process(cycle, sig, pid); + +} static ngx_int_t @@ -1041,7 +1095,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx i = 0; } - if (file[i].name.data == NULL) { + if (file[i].name.len == 0) { continue; } @@ -1078,25 +1132,13 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx continue; } -#if (NGX_WIN32) - if (ngx_file_append_mode(fd) == NGX_ERROR) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - ngx_file_append_mode_n " \"%s\" failed", - file[i].name.data); - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - file[i].name.data); - } - - continue; - } -#else +#if !(NGX_WIN32) if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) { ngx_file_info_t fi; - if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) { + if (ngx_file_info((const char *) file[i].name.data, &fi) + == NGX_FILE_ERROR) + { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed", file[i].name.data); @@ -1197,27 +1239,29 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng i = 0; } - if (name->len != shm_zone[i].name.len) { + if (name->len != shm_zone[i].shm.name.len) { continue; } - if (ngx_strncmp(name->data, shm_zone[i].name.data, name->len) != 0) { + if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) + != 0) + { continue; } if (size && size != shm_zone[i].shm.size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the size %uz of shared memory zone \"%V\" " - "conflicts with already declared size %uz", - size, &shm_zone[i].name, shm_zone[i].shm.size); + "the size %uz of shared memory zone \"%V\" " + "conflicts with already declared size %uz", + size, &shm_zone[i].shm.name, shm_zone[i].shm.size); return NULL; } if (tag != shm_zone[i].tag) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the shared memory zone \"%V\" is " - "already declared for a different use", - &shm_zone[i].name); + "the shared memory zone \"%V\" is " + "already declared for a different use", + &shm_zone[i].shm.name); return NULL; } @@ -1233,8 +1277,9 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng shm_zone->data = NULL; shm_zone->shm.log = cf->cycle->log; shm_zone->shm.size = size; + shm_zone->shm.name = *name; + shm_zone->shm.exists = 0; shm_zone->init = NULL; - shm_zone->name = *name; shm_zone->tag = tag; return shm_zone; 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 @@ -29,7 +29,6 @@ struct ngx_shm_zone_s { void *data; ngx_shm_t shm; ngx_shm_zone_init_pt init; - ngx_str_t name; void *tag; }; @@ -39,7 +38,7 @@ struct ngx_cycle_s { ngx_pool_t *pool; ngx_log_t *log; - ngx_log_t *new_log; + ngx_log_t new_log; ngx_connection_t **files; ngx_connection_t *free_connections; @@ -61,7 +60,8 @@ struct ngx_cycle_s { ngx_str_t conf_file; ngx_str_t conf_param; - ngx_str_t root; + ngx_str_t conf_prefix; + ngx_str_t prefix; ngx_str_t lock_file; ngx_str_t hostname; }; @@ -117,6 +117,7 @@ typedef struct { ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle); ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log); void ngx_delete_pidfile(ngx_cycle_t *cycle); +ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig); void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user); char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last); ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv); 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 @@ -8,8 +8,9 @@ #include -static ngx_atomic_uint_t ngx_temp_number; -static ngx_atomic_uint_t ngx_random_number; +static ngx_atomic_t temp_number = 0; +ngx_atomic_t *ngx_temp_number = &temp_number; +ngx_atomic_int_t ngx_random_number = 123456; ssize_t @@ -99,13 +100,7 @@ ngx_create_temp_file(ngx_file_t *file, n continue; } - if ((path->level[0] == 0) - || (err != NGX_ENOENT -#if (NGX_WIN32) - && err != NGX_ENOTDIR -#endif - )) - { + if ((path->level[0] == 0) || (err != NGX_ENOPATH)) { ngx_log_error(NGX_LOG_CRIT, file->log, err, ngx_open_tempfile_n " \"%s\" failed", file->name.data); @@ -211,22 +206,16 @@ ngx_create_full_path(u_char *dir, ngx_ui } -void -ngx_init_temp_number(void) -{ - ngx_temp_number = 0; - ngx_random_number = 123456; -} - - ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision) { - if (collision) { - ngx_temp_number += ngx_random_number; - } + ngx_atomic_uint_t n, add; + + add = collision ? ngx_random_number : 1; - return ngx_temp_number++; + n = ngx_atomic_fetch_add(ngx_temp_number, add); + + return n + add; } @@ -264,7 +253,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n } path->len = 0; - path->manager = (ngx_path_manager_pt) cmd->post; + path->manager = NULL; + path->loader = NULL; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -325,6 +315,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf + init->level[2] + (init->level[2] ? 1 : 0); (*path)->manager = NULL; + (*path)->loader = NULL; (*path)->conf_file = NULL; if (ngx_add_path(cf, path) != NGX_OK) { @@ -489,7 +480,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng { ngx_file_info_t fi; - if (ngx_file_info((const char *) path[i]->name.data, &fi) == -1) { + if (ngx_file_info((const char *) path[i]->name.data, &fi) + == NGX_FILE_ERROR) + { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed", path[i]->name.data); return NGX_ERROR; @@ -526,7 +519,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) { - ngx_err_t err; + u_char *name; + ngx_err_t err; + ngx_copy_file_t cf; #if !(NGX_WIN32) @@ -556,7 +551,7 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ err = ngx_errno; - if (err == NGX_ENOENT) { + if (err == NGX_ENOPATH) { if (!ext->create_path) { goto failed; @@ -576,7 +571,6 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ } err = ngx_errno; - goto failed; } #if (NGX_WIN32) @@ -597,6 +591,53 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ #endif + if (err == NGX_EXDEV) { + + cf.size = -1; + cf.buf_size = 0; + cf.access = ext->access; + cf.time = ext->time; + cf.log = ext->log; + + name = ngx_alloc(to->len + 1 + 10 + 1, ext->log); + if (name == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data, + (uint32_t) ngx_next_temp_number(0)); + + if (ngx_copy_file(src->data, name, &cf) == NGX_OK) { + + if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) { + ngx_free(name); + + if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", + src->data); + return NGX_ERROR; + } + + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_rename_file_n " \"%s\" to \"%s\" failed", + name, to->data); + + if (ngx_delete_file(name) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", name); + + } + } + + ngx_free(name); + + err = 0; + } + failed: if (ext->delete_file) { @@ -606,15 +647,141 @@ failed: } } - if (err && ext->log_rename_error) { + if (err) { ngx_log_error(NGX_LOG_CRIT, ext->log, err, ngx_rename_file_n " \"%s\" to \"%s\" failed", src->data, to->data); } - ext->rename_error = err; + return NGX_ERROR; +} + + +ngx_int_t +ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) +{ + char *buf; + off_t size; + size_t len; + ssize_t n; + ngx_fd_t fd, nfd; + ngx_int_t rc; + ngx_file_info_t fi; + + rc = NGX_ERROR; + buf = NULL; + nfd = NGX_INVALID_FILE; + + fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", from); + goto failed; + } + + if (cf->size != -1) { + size = cf->size; + + } else { + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", from); + + goto failed; + } + + size = ngx_file_size(&fi); + } + + len = cf->buf_size ? cf->buf_size : 65536; + + if ((off_t) len > size) { + len = (size_t) size; + } + + buf = ngx_alloc(len, cf->log); + if (buf == NULL) { + goto failed; + } + + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, + cf->access); + + if (nfd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", to); + goto failed; + } + + while (size > 0) { - return NGX_ERROR; + if ((off_t) len > size) { + len = (size_t) size; + } + + n = ngx_read_fd(fd, buf, len); + + if (n == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " \"%s\" failed", from); + goto failed; + } + + if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " has read only %z of %uz from %s", + n, size, from); + goto failed; + } + + n = ngx_write_fd(nfd, buf, len); + + if (n == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_write_fd_n " \"%s\" failed", to); + goto failed; + } + + if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_write_fd_n " has written only %z of %uz to %s", + n, size, to); + goto failed; + } + + size -= n; + } + + if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; + } + + rc = NGX_OK; + +failed: + + if (nfd != NGX_INVALID_FILE) { + if (ngx_close_file(nfd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", to); + } + } + + if (fd != NGX_INVALID_FILE) { + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", from); + } + } + + if (buf) { + ngx_free(buf); + } + + return rc; } 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 @@ -22,14 +22,20 @@ struct ngx_file_s { ngx_log_t *log; +#if (NGX_HAVE_FILE_AIO) + ngx_event_aio_t *aio; +#endif + unsigned valid_info:1; unsigned directio:1; }; + #define NGX_MAX_PATH_LEVEL 3 typedef time_t (*ngx_path_manager_pt) (void *data); +typedef void (*ngx_path_loader_pt) (void *data); typedef struct { @@ -38,6 +44,7 @@ typedef struct { size_t level[3]; ngx_path_manager_pt manager; + ngx_path_loader_pt loader; void *data; u_char *conf_file; @@ -71,16 +78,25 @@ typedef struct { ngx_uint_t path_access; time_t time; ngx_fd_t fd; - ngx_err_t rename_error; unsigned create_path:1; unsigned delete_file:1; - unsigned log_rename_error:1; ngx_log_t *log; } ngx_ext_rename_file_t; +typedef struct { + off_t size; + size_t buf_size; + + ngx_uint_t access; + time_t time; + + ngx_log_t *log; +} ngx_copy_file_t; + + typedef struct ngx_tree_ctx_s ngx_tree_ctx_t; typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev); @@ -115,9 +131,9 @@ ngx_int_t ngx_add_path(ngx_conf_t *cf, n ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext); +ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf); ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree); -void ngx_init_temp_number(void); ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision); char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -126,4 +142,8 @@ char *ngx_conf_merge_path_value(ngx_conf char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +extern ngx_atomic_t *ngx_temp_number; +extern ngx_atomic_int_t ngx_random_number; + + #endif /* _NGX_FILE_H_INCLUDED_ */ 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 @@ -534,7 +534,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * next_name->key.len = names[n].key.len - len; next_name->key.data = names[n].key.data + len; - next_name->key_hash= 0; + next_name->key_hash = 0; next_name->value = names[n].value; #if 0 @@ -562,7 +562,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * next_name->key.len = names[i].key.len - dot_len; next_name->key.data = names[i].key.data + dot_len; - next_name->key_hash= 0; + next_name->key_hash = 0; next_name->value = names[i].value; #if 0 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 @@ -518,7 +518,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx (void) ngx_cpystrn(p, host, len); - u->addr.in_addr = inet_addr((const char *) p); sin->sin_addr.s_addr = inet_addr((const char *) p); if (sin->sin_addr.s_addr == INADDR_NONE) { @@ -530,7 +529,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx return NGX_ERROR; } - u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]); sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]); } @@ -541,7 +539,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx ngx_free(p); } else { - u->addr.in_addr = INADDR_ANY; sin->sin_addr.s_addr = INADDR_ANY; u->wildcard = 1; } @@ -649,8 +646,22 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng (void) ngx_cpystrn(p, host, len); +#if (NGX_WIN32) + + rc = WSAStringToAddress((char *) p, AF_INET6, NULL, + (SOCKADDR *) sin6, &u->socklen); + rc = !rc; + + if (u->port) { + sin6->sin6_port = htons(u->port); + } + +#else + rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr); +#endif + ngx_free(p); if (rc == 0) { 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 @@ -61,11 +61,6 @@ typedef struct { } ngx_cidr_t; -typedef union { - in_addr_t in_addr; -} ngx_url_addr_t; - - typedef struct { struct sockaddr *sockaddr; socklen_t socklen; @@ -91,8 +86,6 @@ typedef struct { unsigned no_port:1; unsigned wildcard:1; - ngx_url_addr_t addr; - socklen_t socklen; u_char sockaddr[NGX_SOCKADDRLEN]; diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -8,14 +8,14 @@ #include -static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_command_t ngx_errlog_commands[] = { {ngx_string("error_log"), NGX_MAIN_CONF|NGX_CONF_1MORE, - ngx_set_error_log, + ngx_error_log, 0, 0, NULL}, @@ -48,12 +48,20 @@ ngx_module_t ngx_errlog_module = { static ngx_log_t ngx_log; -static ngx_open_file_t ngx_stderr; +static ngx_open_file_t ngx_log_file; +ngx_uint_t ngx_use_stderr = 1; -static const char *err_levels[] = { - "stderr", "emerg", "alert", "crit", "error", - "warn", "notice", "info", "debug" +static ngx_str_t err_levels[] = { + ngx_null_string, + ngx_string("emerg"), + ngx_string("alert"), + ngx_string("crit"), + ngx_string("error"), + ngx_string("warn"), + ngx_string("notice"), + ngx_string("info"), + ngx_string("debug") }; static const char *debug_levels[] = { @@ -79,7 +87,8 @@ ngx_log_error_core(ngx_uint_t level, ngx #if (NGX_HAVE_VARIADIC_MACROS) va_list args; #endif - u_char errstr[NGX_MAX_ERROR_STR], *p, *last; + u_char *p, *last, *msg; + u_char errstr[NGX_MAX_ERROR_STR]; if (log->file->fd == NGX_INVALID_FILE) { return; @@ -92,52 +101,32 @@ ngx_log_error_core(ngx_uint_t level, ngx p = errstr + ngx_cached_err_log_time.len; - p = ngx_snprintf(p, last - p, " [%s] ", err_levels[level]); + p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]); /* pid#tid */ - p = ngx_snprintf(p, last - p, "%P#" NGX_TID_T_FMT ": ", + p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ", ngx_log_pid, ngx_log_tid); if (log->connection) { - p = ngx_snprintf(p, last - p, "*%uA ", log->connection); + p = ngx_slprintf(p, last, "*%uA ", log->connection); } + msg = p; + #if (NGX_HAVE_VARIADIC_MACROS) va_start(args, fmt); - p = ngx_vsnprintf(p, last - p, fmt, args); + p = ngx_vslprintf(p, last, fmt, args); va_end(args); #else - p = ngx_vsnprintf(p, last - p, fmt, args); + p = ngx_vslprintf(p, last, fmt, args); #endif if (err) { - - if (p > last - 50) { - - /* leave a space for an error code */ - - p = last - 50; - *p++ = '.'; - *p++ = '.'; - *p++ = '.'; - } - -#if (NGX_WIN32) - p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) - ? " (%d: " : " (%Xd: ", err); -#else - p = ngx_snprintf(p, last - p, " (%d: ", err); -#endif - - p = ngx_strerror_r(err, p, last - p); - - if (p < last) { - *p++ = ')'; - } + p = ngx_log_errno(p, last, err); } if (level != NGX_LOG_DEBUG && log->handler) { @@ -151,6 +140,19 @@ ngx_log_error_core(ngx_uint_t level, ngx ngx_linefeed(p); (void) ngx_write_fd(log->file->fd, errstr, p - errstr); + + if (!ngx_use_stderr + || level > NGX_LOG_WARN + || log->file->fd == ngx_stderr) + { + return; + } + + msg -= (err_levels[level].len + 4); + + (void) ngx_sprintf(msg, "[%V]: ", &err_levels[level]); + + (void) ngx_write_console(ngx_stderr, msg, p - msg); } @@ -183,58 +185,169 @@ ngx_log_debug_core(ngx_log_t *log, ngx_e #endif -void -ngx_log_abort(ngx_err_t err, const char *text) +void ngx_cdecl +ngx_log_abort(ngx_err_t err, const char *fmt, ...) +{ + u_char *p; + va_list args; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + va_start(args, fmt); + p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); + va_end(args); + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, + "%*s", p - errstr, errstr); +} + + +void ngx_cdecl +ngx_log_stderr(ngx_err_t err, const char *fmt, ...) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, text); + u_char *p, *last; + va_list args; + u_char errstr[NGX_MAX_ERROR_STR]; + + last = errstr + NGX_MAX_ERROR_STR; + + va_start(args, fmt); + p = ngx_vslprintf(errstr, last, fmt, args); + va_end(args); + + if (err) { + p = ngx_log_errno(p, last, err); + } + + if (p > last - NGX_LINEFEED_SIZE) { + p = last - NGX_LINEFEED_SIZE; + } + + ngx_linefeed(p); + + (void) ngx_write_console(ngx_stderr, errstr, p - errstr); +} + + +u_char * +ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err) +{ + if (buf > last - 50) { + + /* leave a space for an error code */ + + buf = last - 50; + *buf++ = '.'; + *buf++ = '.'; + *buf++ = '.'; + } + +#if (NGX_WIN32) + buf = ngx_slprintf(buf, last, ((unsigned) err < 0x80000000) + ? " (%d: " : " (%Xd: ", err); +#else + buf = ngx_slprintf(buf, last, " (%d: ", err); +#endif + + buf = ngx_strerror_r(err, buf, last - buf); + + if (buf < last) { + *buf++ = ')'; + } + + return buf; } ngx_log_t * -ngx_log_init(void) +ngx_log_init(u_char *prefix) { - ngx_log.file = &ngx_stderr; + u_char *p, *name; + size_t nlen, plen; + + ngx_log.file = &ngx_log_file; ngx_log.log_level = NGX_LOG_NOTICE; + name = (u_char *) NGX_ERROR_LOG_PATH; + + /* + * we use ngx_strlen() here since BCC warns about + * condition is always false and unreachable code + */ + + nlen = ngx_strlen(name); + + if (nlen == 0) { + ngx_log_file.fd = ngx_stderr; + return &ngx_log; + } + + p = NULL; + #if (NGX_WIN32) + if (name[1] != ':') { +#else + if (name[0] != '/') { +#endif - ngx_stderr_fileno = GetStdHandle(STD_ERROR_HANDLE); + if (prefix) { + plen = ngx_strlen(prefix); + + } else { +#ifdef NGX_PREFIX + prefix = (u_char *) NGX_PREFIX; + plen = ngx_strlen(prefix); +#else + plen = 0; +#endif + } - ngx_stderr.fd = ngx_open_file((u_char *) NGX_ERROR_LOG_PATH, - NGX_FILE_APPEND, - NGX_FILE_CREATE_OR_OPEN, - NGX_FILE_DEFAULT_ACCESS); + if (plen) { + name = malloc(plen + nlen + 2); + if (name == NULL) { + return NULL; + } + + p = ngx_cpymem(name, prefix, plen); - if (ngx_stderr.fd == NGX_INVALID_FILE) { - ngx_message_box("nginx", MB_OK, ngx_errno, - "Could not open error log file: " - ngx_open_file_n " \"" NGX_ERROR_LOG_PATH "\" failed"); - return NULL; + if (!ngx_path_separator(*(p - 1))) { + *p++ = '/'; + } + + ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1); + + p = name; + } } -#else + ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND, + NGX_FILE_CREATE_OR_OPEN, + NGX_FILE_DEFAULT_ACCESS); - ngx_stderr.fd = STDERR_FILENO; + if (ngx_log_file.fd == NGX_INVALID_FILE) { + ngx_log_stderr(ngx_errno, + "[alert]: could not open error log file: " + ngx_open_file_n " \"%s\" failed", name); +#if (NGX_WIN32) + ngx_event_log(ngx_errno, + "could not open error log file: " + ngx_open_file_n " \"%s\" failed", name); +#endif -#endif + ngx_log_file.fd = ngx_stderr; + } + + if (p) { + ngx_free(p); + } return &ngx_log; } ngx_log_t * -ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args) +ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name) { ngx_log_t *log; - ngx_str_t *value, *name; - - if (args) { - value = args->elts; - name = &value[1]; - - } else { - name = NULL; - } log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); if (log == NULL) { @@ -251,7 +364,7 @@ ngx_log_create_errlog(ngx_cycle_t *cycle char * -ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log) +ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) { ngx_uint_t i, n, d; ngx_str_t *value; @@ -261,12 +374,12 @@ ngx_set_error_log_levels(ngx_conf_t *cf, for (i = 2; i < cf->args->nelts; i++) { for (n = 1; n <= NGX_LOG_DEBUG; n++) { - if (ngx_strcmp(value[i].data, err_levels[n]) == 0) { + if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) { if (log->log_level != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate log level \"%s\"", - value[i].data); + "duplicate log level \"%V\"", + &value[i]); return NGX_CONF_ERROR; } @@ -279,8 +392,8 @@ ngx_set_error_log_levels(ngx_conf_t *cf, if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) { if (log->log_level & ~NGX_LOG_DEBUG_ALL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid log level \"%s\"", - value[i].data); + "invalid log level \"%V\"", + &value[i]); return NGX_CONF_ERROR; } @@ -291,15 +404,12 @@ ngx_set_error_log_levels(ngx_conf_t *cf, if (log->log_level == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid log level \"%s\"", value[i].data); + "invalid log level \"%V\"", &value[i]); return NGX_CONF_ERROR; } } - if (log->log_level == 0) { - log->log_level = NGX_LOG_ERR; - - } else if (log->log_level == NGX_LOG_DEBUG) { + if (log->log_level == NGX_LOG_DEBUG) { log->log_level = NGX_LOG_DEBUG_ALL; } @@ -308,26 +418,35 @@ ngx_set_error_log_levels(ngx_conf_t *cf, static char * -ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_str_t *value; + ngx_str_t *value, name; + + if (cf->cycle->new_log.file) { + return "is duplicate"; + } value = cf->args->elts; - if (value[1].len == 6 && ngx_strcmp(value[1].data, "stderr") == 0) { - cf->cycle->new_log->file->fd = ngx_stderr.fd; - cf->cycle->new_log->file->name.len = 0; - cf->cycle->new_log->file->name.data = NULL; + if (ngx_strcmp(value[1].data, "stderr") == 0) { + name.len = 0; + name.data = NULL; } else { - cf->cycle->new_log->file->name = value[1]; + name = value[1]; + } - if (ngx_conf_full_name(cf->cycle, &cf->cycle->new_log->file->name, 0) - != NGX_OK) - { - return NGX_CONF_ERROR; - } + cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name); + if (cf->cycle->new_log.file == NULL) { + return NULL; } - return ngx_set_error_log_levels(cf, cf->cycle->new_log); + if (cf->args->nelts == 2) { + cf->cycle->new_log.log_level = NGX_LOG_ERR; + return NGX_CONF_OK; + } + + cf->cycle->new_log.log_level = 0; + + return ngx_log_set_levels(cf, &cf->cycle->new_log); } 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,13 +195,16 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo /*********************************/ -ngx_log_t *ngx_log_init(void); -ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args); -char *ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log); -void ngx_log_abort(ngx_err_t err, const char *text); +ngx_log_t *ngx_log_init(u_char *prefix); +ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name); +char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); +void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...); +void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...); +u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); extern ngx_module_t ngx_errlog_module; +extern ngx_uint_t ngx_use_stderr; #endif /* _NGX_LOG_H_INCLUDED_ */ 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 @@ -130,6 +130,7 @@ ngx_open_cached_file(ngx_open_file_cache time_t now; uint32_t hash; ngx_int_t rc; + ngx_file_info_t fi; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; ngx_pool_cleanup_file_t *clnf; @@ -140,6 +141,25 @@ ngx_open_cached_file(ngx_open_file_cache if (cache == NULL) { + if (of->test_only) { + + if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) { + of->err = ngx_errno; + of->failed = ngx_file_info_n; + return NGX_ERROR; + } + + of->uniq = ngx_file_uniq(&fi); + of->mtime = ngx_file_mtime(&fi); + of->size = ngx_file_size(&fi); + of->is_dir = ngx_is_dir(&fi); + of->is_file = ngx_is_file(&fi); + of->is_link = ngx_is_link(&fi); + of->is_exec = ngx_is_exec(&fi); + + return NGX_OK; + } + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return NGX_ERROR; @@ -214,6 +234,7 @@ ngx_open_cached_file(ngx_open_file_cache } else { of->err = file->err; + of->failed = ngx_open_file_n; } goto found; @@ -339,6 +360,7 @@ create: file->uses = 1; file->count = 0; + file->use_event = 0; file->event = NULL; add_event: @@ -443,7 +465,8 @@ ngx_open_and_stat_file(u_char *name, ngx if (of->fd != NGX_INVALID_FILE) { - if (ngx_file_info(name, &fi) == -1) { + if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { + of->failed = ngx_file_info_n; goto failed; } @@ -453,7 +476,8 @@ ngx_open_and_stat_file(u_char *name, ngx } else if (of->test_dir) { - if (ngx_file_info(name, &fi) == -1) { + if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { + of->failed = ngx_file_info_n; goto failed; } @@ -471,6 +495,7 @@ ngx_open_and_stat_file(u_char *name, ngx } if (fd == NGX_INVALID_FILE) { + of->failed = ngx_open_file_n; goto failed; } 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 @@ -21,13 +21,16 @@ typedef struct { time_t mtime; off_t size; off_t directio; + ngx_err_t err; + char *failed; time_t valid; ngx_uint_t min_uses; unsigned test_dir:1; + unsigned test_only:1; unsigned log:1; unsigned errors:1; unsigned events:1; 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 @@ -16,14 +16,12 @@ /* * When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly * to an application memory from a device if parameters are aligned - * to device sector boundary(512 bytes). They fallback to usual read + * to device sector boundary (512 bytes). They fallback to usual read * operation if the parameters are not aligned. * Linux allows DIRECTIO only if the parameters are aligned to a filesystem * sector boundary, otherwise it returns EINVAL. The sector size is * usually 512 bytes, however, on XFS it may be 4096 bytes. */ -#define NGX_DIRECTIO_BLOCK 4096 - #define NGX_NONE 1 @@ -76,6 +74,12 @@ ngx_output_chain(ngx_output_chain_ctx_t } } +#if (NGX_HAVE_FILE_AIO) + if (ctx->aio) { + return NGX_AGAIN; + } +#endif + out = NULL; last_out = &out; last = NGX_NONE; @@ -314,12 +318,11 @@ ngx_output_chain_add_copy(ngx_pool_t *po #endif + cl->next = NULL; *ll = cl; ll = &cl->next; } - *ll = NULL; - return NGX_OK; } @@ -338,7 +341,7 @@ ngx_output_chain_align_file_buf(ngx_outp ctx->directio = 1; - size = (size_t) (in->file_pos - (in->file_pos & ~(NGX_DIRECTIO_BLOCK - 1))); + size = (size_t) (in->file_pos - (in->file_pos & ~(ctx->alignment - 1))); if (size == 0) { @@ -349,7 +352,7 @@ ngx_output_chain_align_file_buf(ngx_outp size = (size_t) bsize; } else { - size = NGX_DIRECTIO_BLOCK - size; + size = (size_t) ctx->alignment - size; if ((off_t) size > bsize) { size = (size_t) bsize; @@ -424,7 +427,7 @@ ngx_output_chain_get_buf(ngx_output_chai * userland buffer direct usage conjunctly with directio */ - b->start = ngx_pmemalign(ctx->pool, size, NGX_DIRECTIO_BLOCK); + b->start = ngx_pmemalign(ctx->pool, size, (size_t) ctx->alignment); if (b->start == NULL) { return NGX_ERROR; } @@ -503,6 +506,7 @@ ngx_output_chain_copy_buf(ngx_output_cha if (src->pos == src->last) { dst->flush = src->flush; dst->last_buf = src->last_buf; + dst->last_in_chain = src->last_in_chain; } } else { @@ -519,8 +523,26 @@ ngx_output_chain_copy_buf(ngx_output_cha #endif +#if (NGX_HAVE_FILE_AIO) + + if (ctx->aio_handler) { + n = ngx_file_aio_read(src->file, dst->pos, (size_t) size, + src->file_pos, ctx->pool); + if (n == NGX_AGAIN) { + ctx->aio_handler(ctx, src->file); + return NGX_AGAIN; + } + + } else { + n = ngx_read_file(src->file, dst->pos, (size_t) size, + src->file_pos); + } +#else + n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos); +#endif + #if (NGX_HAVE_ALIGNED_DIRECTIO) if (ctx->unaligned) { @@ -545,19 +567,11 @@ ngx_output_chain_copy_buf(ngx_output_cha return (ngx_int_t) n; } -#if (NGX_FILE_AIO_READ) - if (n == NGX_AGAIN) { - return (ngx_int_t) n; - } -#endif - if (n != size) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, ngx_read_file_n " read only %z of %O from \"%s\"", n, size, src->file->name.data); - if (n == 0) { - return NGX_ERROR; - } + return NGX_ERROR; } dst->last += n; @@ -577,6 +591,7 @@ ngx_output_chain_copy_buf(ngx_output_cha if (src->file_pos == src->file_last) { dst->flush = src->flush; dst->last_buf = src->last_buf; + dst->last_in_chain = src->last_in_chain; } } 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 @@ -25,6 +25,7 @@ ngx_create_pool(size_t size, ngx_log_t * p->d.last = (u_char *) p + sizeof(ngx_pool_t); p->d.end = (u_char *) p + size; p->d.next = NULL; + p->d.failed = 0; size = size - sizeof(ngx_pool_t); p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL; @@ -189,6 +190,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_ new->d.end = m + psize; new->d.next = NULL; + new->d.failed = 0; m += sizeof(ngx_pool_data_t); m = ngx_align_ptr(m, NGX_ALIGNMENT); @@ -197,7 +199,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_ current = pool->current; for (p = current; p->d.next; p = p->d.next) { - if ((size_t) (p->d.end - p->d.last) < NGX_ALIGNMENT) { + if (p->d.failed++ > 4) { current = p->d.next; } } @@ -214,6 +216,7 @@ static void * ngx_palloc_large(ngx_pool_t *pool, size_t size) { void *p; + ngx_uint_t n; ngx_pool_large_t *large; p = ngx_alloc(size, pool->log); @@ -221,6 +224,19 @@ ngx_palloc_large(ngx_pool_t *pool, size_ return NULL; } + n = 0; + + for (large = pool->large; large; large = large->next) { + if (large->alloc == NULL) { + large->alloc = p; + return p; + } + + if (n++ > 3) { + break; + } + } + large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); if (large == NULL) { ngx_free(p); 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 @@ -46,6 +46,7 @@ typedef struct { u_char *last; u_char *end; ngx_pool_t *next; + ngx_uint_t failed; } ngx_pool_data_t; diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -131,14 +131,14 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ r->event->handler = ngx_resolver_resend_handler; r->event->data = r; - r->event->log = cf->cycle->new_log; + r->event->log = &cf->cycle->new_log; r->ident = -1; r->resend_timeout = 5; r->expire = 30; r->valid = 300; - r->log = cf->cycle->new_log; + r->log = &cf->cycle->new_log; r->log_level = NGX_LOG_ALERT; if (addr) { @@ -152,7 +152,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ uc->sockaddr = addr->sockaddr; uc->socklen = addr->socklen; uc->server = addr->name; - uc->log = cf->cycle->new_log; + uc->log = &cf->cycle->new_log; } return r; @@ -1149,6 +1149,8 @@ ngx_resolver_process_a(ngx_resolver_t *r goto failed; } + ngx_resolver_free(r, name.data); + if (code == 0 && nan == 0) { code = 3; /* NXDOMAIN */ } @@ -1400,6 +1402,8 @@ failed: /* unlock name mutex */ + ngx_resolver_free(r, name.data); + return; } @@ -1595,7 +1599,6 @@ static ngx_resolver_node_t * ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash) { ngx_int_t rc; - size_t len; ngx_rbtree_node_t *node, *sentinel; ngx_resolver_node_t *rn; @@ -1619,9 +1622,7 @@ ngx_resolver_lookup_name(ngx_resolver_t do { rn = (ngx_resolver_node_t *) node; - len = (name->len > (size_t) rn->nlen) ? rn->nlen : name->len; - - rc = ngx_strncmp(name->data, rn->name, len); + rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen); if (rc == 0) { return rn; @@ -1675,7 +1676,6 @@ static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { - size_t len; ngx_rbtree_node_t **p; ngx_resolver_node_t *rn, *rn_temp; @@ -1694,10 +1694,8 @@ ngx_resolver_rbtree_insert_value(ngx_rbt rn = (ngx_resolver_node_t *) node; rn_temp = (ngx_resolver_node_t *) temp; - len = (rn->nlen > rn_temp->nlen) ? rn_temp->nlen : rn->nlen; - - p = (ngx_strncmp(rn->name, rn_temp->name, len) < 0) - ? &temp->left : &temp->right; + p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen) + < 0) ? &temp->left : &temp->right; } if (*p == sentinel) { 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 @@ -584,9 +584,9 @@ ngx_slab_free_locked(ngx_slab_pool_t *po ngx_slab_free_pages(pool, &pool->pages[n], size); - size <<= ngx_pagesize_shift; + ngx_slab_junk(p, size << ngx_pagesize_shift); - goto done; + return; } /* not reached */ diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -37,6 +37,9 @@ typedef struct { u_char *log_ctx; u_char zero; + + void *data; + void *addr; } ngx_slab_pool_t; 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 @@ -30,12 +30,15 @@ ngx_cpystrn(u_char *dst, u_char *src, si return dst; } - for ( /* void */ ; --n; dst++, src++) { + while (--n) { *dst = *src; if (*dst == '\0') { return dst; } + + dst++; + src++; } *dst = '\0'; @@ -87,7 +90,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t * * reserved: * %t ptrdiff_t - * %S null-teminated wchar string + * %S null-terminated wchar string * %C wchar */ @@ -99,7 +102,7 @@ ngx_sprintf(u_char *buf, const char *fmt va_list args; va_start(args, fmt); - p = ngx_vsnprintf(buf, /* STUB */ 65536, fmt, args); + p = ngx_vslprintf(buf, (void *) -1, fmt, args); va_end(args); return p; @@ -113,7 +116,21 @@ ngx_snprintf(u_char *buf, size_t max, co va_list args; va_start(args, fmt); - p = ngx_vsnprintf(buf, max, fmt, args); + p = ngx_vslprintf(buf, buf + max, fmt, args); + va_end(args); + + return p; +} + + +u_char * ngx_cdecl +ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...) +{ + u_char *p; + va_list args; + + va_start(args, fmt); + p = ngx_vslprintf(buf, last, fmt, args); va_end(args); return p; @@ -121,9 +138,9 @@ ngx_snprintf(u_char *buf, size_t max, co u_char * -ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args) +ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) { - u_char *p, zero, *last; + u_char *p, zero; int d; float f, scale; size_t len, slen; @@ -134,12 +151,6 @@ ngx_vsnprintf(u_char *buf, size_t max, c ngx_str_t *v; ngx_variable_value_t *vv; - if (max == 0) { - return buf; - } - - last = buf + max; - while (*fmt && buf < last) { /* @@ -557,8 +568,8 @@ ngx_strcasecmp(u_char *s1, u_char *s2) c1 = (ngx_uint_t) *s1++; c2 = (ngx_uint_t) *s2++; - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; if (c1 == c2) { @@ -583,8 +594,8 @@ ngx_strncasecmp(u_char *s1, u_char *s2, c1 = (ngx_uint_t) *s1++; c2 = (ngx_uint_t) *s2++; - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; if (c1 == c2) { @@ -672,7 +683,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si ngx_uint_t c1, c2; c2 = (ngx_uint_t) *s2++; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; do { do { @@ -682,7 +693,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si return NULL; } - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; } while (c1 != c2); @@ -692,6 +703,39 @@ ngx_strcasestrn(u_char *s1, char *s2, si } +/* + * ngx_strlcasestrn() is intended to search for static substring + * with known length in string until the argument last. The argument n + * must be length of the second substring - 1. + */ + +u_char * +ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n) +{ + ngx_uint_t c1, c2; + + c2 = (ngx_uint_t) *s2++; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + last -= n; + + do { + do { + if (s1 >= last) { + return NULL; + } + + c1 = (ngx_uint_t) *s1++; + + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + + } while (c1 != c2); + + } while (ngx_strncasecmp(s1, s2, n) != 0); + + return --s1; +} + + ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n) { @@ -776,6 +820,37 @@ ngx_memn2cmp(u_char *s1, u_char *s2, siz ngx_int_t +ngx_dns_strcmp(u_char *s1, u_char *s2) +{ + ngx_uint_t c1, c2; + + for ( ;; ) { + c1 = (ngx_uint_t) *s1++; + c2 = (ngx_uint_t) *s2++; + + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + + if (c1 == c2) { + + if (c1) { + continue; + } + + return 0; + } + + /* in ASCII '.' > '-', but we need '.' to be the lowest character */ + + c1 = (c1 == '.') ? ' ' : c1; + c2 = (c2 == '.') ? ' ' : c2; + + return c1 - c2; + } +} + + +ngx_int_t ngx_atoi(u_char *line, size_t n) { ngx_int_t value; @@ -1296,7 +1371,7 @@ ngx_escape_uri(u_char *dst, u_char *src, /* find the number of the characters to be escaped */ - n = 0; + n = 0; for (i = 0; i < size; i++) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { 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 @@ -140,7 +140,11 @@ u_char *ngx_cpystrn(u_char *dst, u_char u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src); u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...); u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...); -u_char *ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args); +u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt, + ...); +u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args); +#define ngx_vsnprintf(buf, max, fmt, args) \ + ngx_vslprintf(buf, buf + (max), fmt, args) ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2); ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n); @@ -149,10 +153,12 @@ u_char *ngx_strnstr(u_char *s1, char *s2 u_char *ngx_strstrn(u_char *s1, char *s2, size_t n); u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n); +u_char *ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n); ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2); +ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2); ngx_int_t ngx_atoi(u_char *line, size_t n); ssize_t ngx_atosz(u_char *line, size_t n); 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 @@ -7,11 +7,9 @@ #include #include #include -#include + -#if (NGX_HAVE_KQUEUE) -#include -#endif +extern ngx_event_module_t ngx_kqueue_module_ctx; static ngx_int_t ngx_aio_init(ngx_cycle_t *cycle, ngx_msec_t timer); @@ -73,7 +71,6 @@ ngx_module_t ngx_aio_module = { }; - #if (NGX_HAVE_KQUEUE) static ngx_int_t @@ -134,12 +131,14 @@ ngx_aio_del_connection(ngx_connection_t ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_cancel: %d", rc); if (rc == AIO_CANCELED) { - c->read->active = c->write->active = 0; + c->read->active = 0; + c->write->active = 0; return NGX_OK; } if (rc == AIO_ALLDONE) { - c->read->active = c->write->active = 0; + c->read->active = 0; + c->write->active = 0; ngx_log_error(NGX_LOG_ALERT, c->log, 0, "aio_cancel() returned AIO_ALLDONE"); return NGX_OK; diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -369,11 +369,7 @@ ngx_devpoll_process_events(ngx_cycle_t * dvp.dp_timeout = timer; events = ioctl(dp, DP_POLL, &dvp); - if (events == -1) { - err = ngx_errno; - } else { - err = 0; - } + err = (events == -1) ? ngx_errno : 0; if (flags & NGX_UPDATE_TIME) { ngx_time_update(0, 0); @@ -550,7 +546,7 @@ ngx_devpoll_create_conf(ngx_cycle_t *cyc dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t)); if (dpcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } dpcf->changes = NGX_CONF_UNSET; 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 @@ -43,10 +43,6 @@ struct epoll_event { epoll_data_t data; }; -int epoll_create(int size); -int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); -int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout); - int epoll_create(int size) { return -1; @@ -62,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_ev return -1; } +#if (NGX_HAVE_FILE_AIO) + +#define SYS_io_setup 245 +#define SYS_io_destroy 246 +#define SYS_io_getevents 247 +#define SYS_eventfd 323 + +typedef u_int aio_context_t; + +struct io_event { + uint64_t data; /* the data field from the iocb */ + uint64_t obj; /* what iocb this event came from */ + int64_t res; /* result code for this event */ + int64_t res2; /* secondary result */ +}; + + +int eventfd(u_int initval) +{ + return -1; +} + +#endif #endif @@ -82,6 +101,10 @@ static ngx_int_t ngx_epoll_del_connectio static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); +#if (NGX_HAVE_FILE_AIO) +static void ngx_epoll_eventfd_handler(ngx_event_t *ev); +#endif + static void *ngx_epoll_create_conf(ngx_cycle_t *cycle); static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); @@ -89,6 +112,15 @@ static int ep = -1; static struct epoll_event *event_list; static ngx_uint_t nevents; +#if (NGX_HAVE_FILE_AIO) + +int ngx_eventfd = -1; +aio_context_t ngx_aio_ctx = 0; + +static ngx_event_t ngx_eventfd_event; +static ngx_connection_t ngx_eventfd_conn; + +#endif static ngx_str_t epoll_name = ngx_string("epoll"); @@ -140,6 +172,42 @@ ngx_module_t ngx_epoll_module = { }; +#if (NGX_HAVE_FILE_AIO) + +/* + * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly + * as syscalls instead of libaio usage, because the library header file + * supports eventfd() since 0.3.107 version only. + * + * Also we do not use eventfd() in glibc, because glibc supports it + * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2() + * into single eventfd() function with different number of parameters. + */ + +static long +io_setup(u_int nr_reqs, aio_context_t *ctx) +{ + return syscall(SYS_io_setup, nr_reqs, ctx); +} + + +static int +io_destroy(aio_context_t ctx) +{ + return syscall(SYS_io_destroy, ctx); +} + + +static long +io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events, + struct timespec *tmo) +{ + return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo); +} + +#endif + + static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) { @@ -155,6 +223,55 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m "epoll_create() failed"); return NGX_ERROR; } + +#if (NGX_HAVE_FILE_AIO) + { + int n; + struct epoll_event ee; + + ngx_eventfd = syscall(SYS_eventfd, 0); + + if (ngx_eventfd == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "eventfd() failed"); + return NGX_ERROR; + } + + n = 1; + + if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "ioctl(eventfd, FIONBIO) failed"); + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "eventfd: %d", ngx_eventfd); + + n = io_setup(1024, &ngx_aio_ctx); + + if (n != 0) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, -n, "io_setup() failed"); + return NGX_ERROR; + } + + ngx_eventfd_event.data = &ngx_eventfd_conn; + ngx_eventfd_event.handler = ngx_epoll_eventfd_handler; + ngx_eventfd_event.log = cycle->log; + ngx_eventfd_event.active = 1; + ngx_eventfd_conn.fd = ngx_eventfd; + ngx_eventfd_conn.read = &ngx_eventfd_event; + ngx_eventfd_conn.log = cycle->log; + + ee.events = EPOLLIN|EPOLLET; + ee.data.ptr = &ngx_eventfd_conn; + + if (epoll_ctl(ep, EPOLL_CTL_ADD, ngx_eventfd, &ee) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed"); + return NGX_ERROR; + } + } +#endif } if (nevents < epcf->events) { @@ -197,6 +314,17 @@ ngx_epoll_done(ngx_cycle_t *cycle) ep = -1; +#if (NGX_HAVE_FILE_AIO) + + if (io_destroy(ngx_aio_ctx) != 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "io_destroy() failed"); + } + + ngx_aio_ctx = 0; + +#endif + ngx_free(event_list); event_list = NULL; @@ -401,11 +529,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy events = epoll_wait(ep, event_list, (int) nevents, timer); - if (events == -1) { - err = ngx_errno; - } else { - err = 0; - } + err = (events == -1) ? ngx_errno : 0; if (flags & NGX_UPDATE_TIME) { ngx_time_update(0, 0); @@ -545,6 +669,91 @@ ngx_epoll_process_events(ngx_cycle_t *cy } +#if (NGX_HAVE_FILE_AIO) + +static void +ngx_epoll_eventfd_handler(ngx_event_t *ev) +{ + int n; + long i, events; + uint64_t ready; + ngx_err_t err; + ngx_event_t *e; + ngx_event_aio_t *aio; + struct io_event event[64]; + struct timespec ts; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler"); + + n = read(ngx_eventfd, &ready, 8); + + err = ngx_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd: %d", n); + + if (n != 8) { + if (n == -1) { + if (err == NGX_EAGAIN) { + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, err, "read(eventfd) failed"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "read(eventfd) returned only %d bytes", n); + return; + } + + ts.tv_sec = 0; + ts.tv_nsec = 0; + + while (ready) { + + events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "io_getevents: %l", events); + + if (events > 0) { + ready -= events; + + for (i = 0; i < events; i++) { + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "io_event: %uXL %uXL %L %L", + event[i].data, event[i].obj, + event[i].res, event[i].res2); + + e = (ngx_event_t *) (uintptr_t) event[i].data; + + e->complete = 1; + e->active = 0; + e->ready = 1; + + aio = e->data; + aio->res = event[i].res; + + ngx_post_event(e, &ngx_posted_events); + } + + continue; + } + + if (events == 0) { + return; + } + + /* events < 0 */ + ngx_log_error(NGX_LOG_ALERT, ev->log, -events, "io_getevents() failed"); + return; + } +} + +#endif + + static void * ngx_epoll_create_conf(ngx_cycle_t *cycle) { @@ -552,7 +761,7 @@ ngx_epoll_create_conf(ngx_cycle_t *cycle epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t)); if (epcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } epcf->events = NGX_CONF_UNSET; 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 @@ -581,7 +581,7 @@ ngx_eventport_create_conf(ngx_cycle_t *c epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t)); if (epcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } epcf->events = NGX_CONF_UNSET; 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 @@ -7,7 +7,6 @@ #include #include #include -#include typedef struct { @@ -113,7 +112,6 @@ ngx_module_t ngx_kqueue_module = { }; - static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer) { @@ -537,11 +535,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp); - if (events == -1) { - err = ngx_errno; - } else { - err = 0; - } + err = (events == -1) ? ngx_errno : 0; if (flags & NGX_UPDATE_TIME) { ngx_time_update(0, 0); @@ -768,7 +762,7 @@ ngx_kqueue_create_conf(ngx_cycle_t *cycl kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t)); if (kcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } kcf->changes = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_kqueue_module.h b/src/event/modules/ngx_kqueue_module.h deleted file mode 100644 --- a/src/event/modules/ngx_kqueue_module.h +++ /dev/null @@ -1,16 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_KQUEUE_MODULE_H_INCLUDED_ -#define _NGX_KQUEUE_MODULE_H_INCLUDED_ - - -extern int ngx_kqueue; -extern ngx_module_t ngx_kqueue_module; -extern ngx_event_module_t ngx_kqueue_module_ctx; - - -#endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -260,11 +260,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc ready = poll(event_list, (u_int) nevents, (int) timer); - if (ready == -1) { - err = ngx_errno; - } else { - err = 0; - } + err = (ready == -1) ? ngx_errno : 0; if (flags & NGX_UPDATE_TIME) { ngx_time_update(0, 0); 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 @@ -691,7 +691,7 @@ ngx_rtsig_create_conf(ngx_cycle_t *cycle rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t)); if (rtscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } rtscf->signo = NGX_CONF_UNSET; 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 @@ -9,7 +9,6 @@ #include - static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer); static void ngx_select_done(ngx_cycle_t *cycle); static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, @@ -18,6 +17,7 @@ static ngx_int_t ngx_select_del_event(ng ngx_uint_t flags); static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); +static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle); static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf); @@ -26,13 +26,7 @@ static fd_set master_write_fd_se static fd_set work_read_fd_set; static fd_set work_write_fd_set; -#if (NGX_WIN32) -static ngx_uint_t max_read; -static ngx_uint_t max_write; -#else static ngx_int_t max_fd; -#endif - static ngx_uint_t nevents; static ngx_event_t **event_index; @@ -111,11 +105,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_ ngx_event_flags = NGX_USE_LEVEL_EVENT; -#if (NGX_WIN32) - max_read = max_write = 0; -#else max_fd = -1; -#endif return NGX_OK; } @@ -146,30 +136,17 @@ ngx_select_add_event(ngx_event_t *ev, ng return NGX_OK; } -#if (NGX_WIN32) - - if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE) - || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE)) + if ((event == NGX_READ_EVENT && ev->write) + || (event == NGX_WRITE_EVENT && !ev->write)) { - ngx_log_error(NGX_LOG_ERR, ev->log, 0, - "maximum number of descriptors " - "supported by select() is %d", FD_SETSIZE); + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "invalid select %s event fd:%d ev:%i", + ev->write ? "write" : "read", c->fd, event); return NGX_ERROR; } if (event == NGX_READ_EVENT) { FD_SET(c->fd, &master_read_fd_set); - max_read++; - - } else if (event == NGX_WRITE_EVENT) { - FD_SET(c->fd, &master_write_fd_set); - max_write++; - } - -#else - - if (event == NGX_READ_EVENT) { - FD_SET(c->fd, &master_read_fd_set); } else if (event == NGX_WRITE_EVENT) { FD_SET(c->fd, &master_write_fd_set); @@ -179,8 +156,6 @@ ngx_select_add_event(ngx_event_t *ev, ng max_fd = c->fd; } -#endif - ev->active = 1; event_index[nevents] = ev; @@ -194,6 +169,7 @@ ngx_select_add_event(ngx_event_t *ev, ng static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) { + ngx_event_t *e; ngx_connection_t *c; c = ev->data; @@ -207,19 +183,6 @@ ngx_select_del_event(ngx_event_t *ev, ng ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "select del event fd:%d ev:%i", c->fd, event); -#if (NGX_WIN32) - - if (event == NGX_READ_EVENT) { - FD_CLR(c->fd, &master_read_fd_set); - max_read--; - - } else if (event == NGX_WRITE_EVENT) { - FD_CLR(c->fd, &master_write_fd_set); - max_write--; - } - -#else - if (event == NGX_READ_EVENT) { FD_CLR(c->fd, &master_read_fd_set); @@ -231,11 +194,10 @@ ngx_select_del_event(ngx_event_t *ev, ng max_fd = -1; } -#endif - if (ev->index < --nevents) { - event_index[ev->index] = event_index[nevents]; - event_index[ev->index]->index = ev->index; + e = event_index[nevents]; + event_index[ev->index] = e; + e->index = ev->index; } ev->index = NGX_INVALID_INDEX; @@ -248,14 +210,12 @@ static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { - int ready, nready; - ngx_uint_t i, found; - ngx_err_t err; - ngx_event_t *ev, **queue; - ngx_connection_t *c; - struct timeval tv, *tp; - -#if !(NGX_WIN32) + int ready, nready; + ngx_err_t err; + ngx_uint_t i, found; + ngx_event_t *ev, **queue; + struct timeval tv, *tp; + ngx_connection_t *c; if (max_fd == -1) { for (i = 0; i < nevents; i++) { @@ -269,8 +229,6 @@ ngx_select_process_events(ngx_cycle_t *c "change max_fd: %d", max_fd); } -#endif - #if (NGX_DEBUG) if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { for (i = 0; i < nevents; i++) { @@ -280,10 +238,8 @@ ngx_select_process_events(ngx_cycle_t *c "select event: fd:%d wr:%d", c->fd, ev->write); } -#if !(NGX_WIN32) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "max_fd: %d", max_fd); -#endif } #endif @@ -302,31 +258,9 @@ ngx_select_process_events(ngx_cycle_t *c work_read_fd_set = master_read_fd_set; work_write_fd_set = master_write_fd_set; -#if 1 - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - /* - * (void *) disables "dereferencing type-punned - * pointer will break strict-aliasing rules - */ - "select read fd_set: %08Xd", - *(int *) (void *) &work_read_fd_set); -#endif - -#if (NGX_WIN32) - - ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); - -#else - ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp); -#endif - - if (ready == -1) { - err = ngx_socket_errno; - } else { - err = 0; - } + err = (ready == -1) ? ngx_errno : 0; if (flags & NGX_UPDATE_TIME) { ngx_time_update(0, 0); @@ -335,15 +269,6 @@ ngx_select_process_events(ngx_cycle_t *c ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select ready %d", ready); -#if (NGX_WIN32) - - if (err) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); - return NGX_ERROR; - } - -#else - if (err) { ngx_uint_t level; @@ -361,11 +286,14 @@ ngx_select_process_events(ngx_cycle_t *c } ngx_log_error(level, cycle->log, err, "select() failed"); + + if (err == EBADF) { + ngx_select_repair_fd_sets(cycle); + } + return NGX_ERROR; } -#endif - if (ready == 0) { if (timer != NGX_TIMER_INFINITE) { return NGX_OK; @@ -414,13 +342,64 @@ ngx_select_process_events(ngx_cycle_t *c ngx_mutex_unlock(ngx_posted_events_mutex); if (ready != nready) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "select ready != events: %d:%d", ready, nready); + + ngx_select_repair_fd_sets(cycle); } return NGX_OK; } +static void +ngx_select_repair_fd_sets(ngx_cycle_t *cycle) +{ + int n; + socklen_t len; + ngx_err_t err; + ngx_socket_t s; + + for (s = 0; s <= max_fd; s++) { + + if (FD_ISSET(s, &master_read_fd_set) == 0) { + continue; + } + + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in read fd_set", s); + + FD_CLR(s, &master_read_fd_set); + } + } + + for (s = 0; s <= max_fd; s++) { + + if (FD_ISSET(s, &master_write_fd_set) == 0) { + continue; + } + + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in write fd_set", s); + + FD_CLR(s, &master_write_fd_set); + } + } + + max_fd = -1; +} + + static char * ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) { @@ -434,8 +413,6 @@ ngx_select_init_conf(ngx_cycle_t *cycle, /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */ -#if !(NGX_WIN32) - if (cycle->connection_n > FD_SETSIZE) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "the maximum number of files " @@ -443,9 +420,7 @@ ngx_select_init_conf(ngx_cycle_t *cycle, return NGX_CONF_ERROR; } -#endif - -#if (NGX_THREADS) && !(NGX_WIN32) +#if (NGX_THREADS) ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "select() is not supported in the threaded mode"); diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_win32_select_module.c @@ -0,0 +1,399 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer); +static void ngx_select_done(ngx_cycle_t *cycle); +static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags); +static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle); +static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf); + + +static fd_set master_read_fd_set; +static fd_set master_write_fd_set; +static fd_set work_read_fd_set; +static fd_set work_write_fd_set; + +static ngx_uint_t max_read; +static ngx_uint_t max_write; +static ngx_uint_t nevents; + +static ngx_event_t **event_index; + + +static ngx_str_t select_name = ngx_string("select"); + +ngx_event_module_t ngx_select_module_ctx = { + &select_name, + NULL, /* create configuration */ + ngx_select_init_conf, /* init configuration */ + + { + ngx_select_add_event, /* add an event */ + ngx_select_del_event, /* delete an event */ + ngx_select_add_event, /* enable an event */ + ngx_select_del_event, /* disable an event */ + NULL, /* add an connection */ + NULL, /* delete an connection */ + NULL, /* process the changes */ + ngx_select_process_events, /* process the events */ + ngx_select_init, /* init the events */ + ngx_select_done /* done the events */ + } + +}; + +ngx_module_t ngx_select_module = { + NGX_MODULE_V1, + &ngx_select_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_EVENT_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer) +{ + ngx_event_t **index; + + if (event_index == NULL) { + FD_ZERO(&master_read_fd_set); + FD_ZERO(&master_write_fd_set); + nevents = 0; + } + + if (ngx_process == NGX_PROCESS_WORKER + || cycle->old_cycle == NULL + || cycle->old_cycle->connection_n < cycle->connection_n) + { + index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, + cycle->log); + if (index == NULL) { + return NGX_ERROR; + } + + if (event_index) { + ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents); + ngx_free(event_index); + } + + event_index = index; + } + + ngx_io = ngx_os_io; + + ngx_event_actions = ngx_select_module_ctx.actions; + + ngx_event_flags = NGX_USE_LEVEL_EVENT; + + max_read = 0; + max_write = 0; + + return NGX_OK; +} + + +static void +ngx_select_done(ngx_cycle_t *cycle) +{ + ngx_free(event_index); + + event_index = NULL; +} + + +static ngx_int_t +ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_connection_t *c; + + c = ev->data; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "select add event fd:%d ev:%i", c->fd, event); + + if (ev->index != NGX_INVALID_INDEX) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "select event fd:%d ev:%i is already set", c->fd, event); + return NGX_OK; + } + + if ((event == NGX_READ_EVENT && ev->write) + || (event == NGX_WRITE_EVENT && !ev->write)) + { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "invalid select %s event fd:%d ev:%i", + ev->write ? "write" : "read", c->fd, event); + return NGX_ERROR; + } + + if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE) + || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE)) + { + ngx_log_error(NGX_LOG_ERR, ev->log, 0, + "maximum number of descriptors " + "supported by select() is %d", FD_SETSIZE); + return NGX_ERROR; + } + + if (event == NGX_READ_EVENT) { + FD_SET(c->fd, &master_read_fd_set); + max_read++; + + } else if (event == NGX_WRITE_EVENT) { + FD_SET(c->fd, &master_write_fd_set); + max_write++; + } + + ev->active = 1; + + event_index[nevents] = ev; + ev->index = nevents; + nevents++; + + return NGX_OK; +} + + +static ngx_int_t +ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = ev->data; + + ev->active = 0; + + if (ev->index == NGX_INVALID_INDEX) { + return NGX_OK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "select del event fd:%d ev:%i", c->fd, event); + + if (event == NGX_READ_EVENT) { + FD_CLR(c->fd, &master_read_fd_set); + max_read--; + + } else if (event == NGX_WRITE_EVENT) { + FD_CLR(c->fd, &master_write_fd_set); + max_write--; + } + + if (ev->index < --nevents) { + e = event_index[nevents]; + event_index[ev->index] = e; + e->index = ev->index; + } + + ev->index = NGX_INVALID_INDEX; + + return NGX_OK; +} + + +static ngx_int_t +ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags) +{ + int ready, nready; + ngx_err_t err; + ngx_uint_t i, found; + ngx_event_t *ev, **queue; + struct timeval tv, *tp; + ngx_connection_t *c; + +#if (NGX_DEBUG) + if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { + for (i = 0; i < nevents; i++) { + ev = event_index[i]; + c = ev->data; + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select event: fd:%d wr:%d", c->fd, ev->write); + } + } +#endif + + if (timer == NGX_TIMER_INFINITE) { + tp = NULL; + + } else { + tv.tv_sec = (long) (timer / 1000); + tv.tv_usec = (long) ((timer % 1000) * 1000); + tp = &tv; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select timer: %M", timer); + + work_read_fd_set = master_read_fd_set; + work_write_fd_set = master_write_fd_set; + + if (max_read || max_write) { + ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); + + } else { + + /* + * Winsock select() requires that at least one descriptor set must be + * be non-null, and any non-null descriptor set must contain at least + * one handle to a socket. Otherwise select() returns WSAEINVAL. + */ + + ngx_msleep(timer); + + ready = 0; + } + + err = (ready == -1) ? ngx_socket_errno : 0; + + if (flags & NGX_UPDATE_TIME) { + ngx_time_update(0, 0); + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select ready %d", ready); + + if (err) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); + + if (err == WSAENOTSOCK) { + ngx_select_repair_fd_sets(cycle); + } + + return NGX_ERROR; + } + + if (ready == 0) { + if (timer != NGX_TIMER_INFINITE) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "select() returned no events without timeout"); + return NGX_ERROR; + } + + ngx_mutex_lock(ngx_posted_events_mutex); + + nready = 0; + + for (i = 0; i < nevents; i++) { + ev = event_index[i]; + c = ev->data; + found = 0; + + if (ev->write) { + if (FD_ISSET(c->fd, &work_write_fd_set)) { + found = 1; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select write %d", c->fd); + } + + } else { + if (FD_ISSET(c->fd, &work_read_fd_set)) { + found = 1; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select read %d", c->fd); + } + } + + if (found) { + ev->ready = 1; + + queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: + &ngx_posted_events); + ngx_locked_post_event(ev, queue); + + nready++; + } + } + + ngx_mutex_unlock(ngx_posted_events_mutex); + + if (ready != nready) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "select ready != events: %d:%d", ready, nready); + + ngx_select_repair_fd_sets(cycle); + } + + return NGX_OK; +} + + +static void +ngx_select_repair_fd_sets(ngx_cycle_t *cycle) +{ + int n; + u_int i; + socklen_t len; + ngx_err_t err; + ngx_socket_t s; + + for (i = 0; i < master_read_fd_set.fd_count; i++) { + + s = master_read_fd_set.fd_array[i]; + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in read fd_set", s); + + FD_CLR(s, &master_read_fd_set); + } + } + + for (i = 0; i < master_write_fd_set.fd_count; i++) { + + s = master_write_fd_set.fd_array[i]; + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in write fd_set", s); + + FD_CLR(s, &master_write_fd_set); + } + } +} + + +static char * +ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_event_conf_t *ecf; + + ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); + + if (ecf->use != ngx_select_module.ctx_index) { + return NGX_CONF_OK; + } + + return NGX_CONF_OK; +} 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 @@ -43,7 +43,7 @@ ngx_uint_t ngx_event_flags; ngx_event_actions_t ngx_event_actions; -ngx_atomic_t connection_counter = 1; +static ngx_atomic_t connection_counter = 1; ngx_atomic_t *ngx_connection_counter = &connection_counter; @@ -429,6 +429,7 @@ ngx_event_module_init(ngx_cycle_t *cycle u_char *shared; size_t size, cl; ngx_shm_t shm; + ngx_time_t *tp; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; @@ -442,7 +443,7 @@ ngx_event_module_init(ngx_cycle_t *cycle ecf = (*cf)[ngx_event_core_module.ctx_index]; - if (!ngx_test_config) { + if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "using the \"%s\" event method", ecf->name); } @@ -492,7 +493,8 @@ ngx_event_module_init(ngx_cycle_t *cycle cl = 128; size = cl /* ngx_accept_mutex */ - + cl; /* ngx_connection_counter */ + + cl /* ngx_connection_counter */ + + cl; /* ngx_temp_number */ #if (NGX_STAT_STUB) @@ -506,6 +508,8 @@ ngx_event_module_init(ngx_cycle_t *cycle #endif shm.size = size; + shm.name.len = sizeof("nginx_shared_zone"); + shm.name.data = (u_char *) "nginx_shared_zone"; shm.log = cycle->log; if (ngx_shm_alloc(&shm) != NGX_OK) { @@ -524,23 +528,29 @@ ngx_event_module_init(ngx_cycle_t *cycle ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl); -#if (NGX_STAT_STUB) - - ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * cl); - ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * cl); - ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * cl); - ngx_stat_active = (ngx_atomic_t *) (shared + 5 * cl); - ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * cl); - ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * cl); - -#endif - - *ngx_connection_counter = 1; + (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "counter: %p, %d", ngx_connection_counter, *ngx_connection_counter); + ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl); + + tp = ngx_timeofday(); + + ngx_random_number = (tp->msec << 16) + ngx_pid; + +#if (NGX_STAT_STUB) + + ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); + ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); + ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); + ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); + ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); + ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); + +#endif + return NGX_OK; } @@ -774,6 +784,10 @@ ngx_event_process_init(ngx_cycle_t *cycl rev->handler = ngx_event_acceptex; + if (ngx_use_accept_mutex) { + continue; + } + if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } @@ -790,6 +804,10 @@ ngx_event_process_init(ngx_cycle_t *cycl } else { rev->handler = ngx_event_accept; + if (ngx_use_accept_mutex) { + continue; + } + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } @@ -1103,7 +1121,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle ecf = ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t)); if (ecf == NULL) { - return NGX_CONF_ERROR; + return NULL; } ecf->connections = NGX_CONF_UNSET_UINT; @@ -1118,7 +1136,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle if (ngx_array_init(&ecf->debug_connection, cycle->pool, 4, sizeof(ngx_event_debug_t)) == NGX_ERROR) { - return NGX_CONF_ERROR; + return NULL; } #endif 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 @@ -189,6 +189,37 @@ struct ngx_event_s { }; +#if (NGX_HAVE_FILE_AIO) + +struct ngx_event_aio_s { + void *data; + ngx_event_handler_pt handler; + ngx_file_t *file; + + ngx_fd_t fd; + +#if (NGX_HAVE_EVENTFD) + int64_t res; +#if (NGX_TEST_BUILD_EPOLL) + ngx_err_t err; + size_t nbytes; +#endif +#else + ngx_err_t err; + size_t nbytes; +#endif + +#if (NGX_HAVE_AIO_SENDFILE) + off_t last_offset; +#endif + + ngx_aiocb_t aiocb; + ngx_event_t event; +}; + +#endif + + typedef struct { in_addr_t mask; in_addr_t addr; 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 @@ -57,8 +57,8 @@ ngx_event_accept(ngx_event_t *ev) return; } - ngx_log_error((err == NGX_ECONNABORTED) ? NGX_LOG_ERR: - NGX_LOG_ALERT, + ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ? + NGX_LOG_ERR : NGX_LOG_ALERT), ev->log, err, "accept() failed"); if (err == NGX_ECONNABORTED) { @@ -75,7 +75,7 @@ ngx_event_accept(ngx_event_t *ev) } #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_accepted, 1); + (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif ngx_accept_disabled = ngx_cycle->connection_n / 8 @@ -93,7 +93,7 @@ ngx_event_accept(ngx_event_t *ev) } #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_active, 1); + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif c->pool = ngx_create_pool(ls->pool_size, ev->log); @@ -188,7 +188,7 @@ ngx_event_accept(ngx_event_t *ev) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_handled, 1); + (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif #if (NGX_THREADS) @@ -379,7 +379,7 @@ ngx_close_accepted_connection(ngx_connec } #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_active, -1); + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif } 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 @@ -97,16 +97,12 @@ int ngx_ssl_session_cache_index; ngx_int_t ngx_ssl_init(ngx_log_t *log) { -#if OPENSSL_VERSION_NUMBER >= 0x00907000 OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); -#if (NGX_SSL_ENGINE) ENGINE_load_builtin_engines(); -#endif ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); @@ -169,9 +165,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG); -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); -#endif SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); @@ -267,6 +261,51 @@ ngx_ssl_client_certificate(ngx_conf_t *c } +ngx_int_t +ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl) +{ + X509_STORE *store; + X509_LOOKUP *lookup; + + if (crl->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) { + return NGX_ERROR; + } + + store = SSL_CTX_get_cert_store(ssl->ctx); + + if (store == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_get_cert_store() failed"); + return NGX_ERROR; + } + + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + + if (lookup == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_STORE_add_lookup() failed"); + return NGX_ERROR; + } + + if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_LOOKUP_load_file(\"%s\") failed", crl->data); + return NGX_ERROR; + } + + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + return NGX_OK; +} + + static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) { @@ -1201,9 +1240,7 @@ ngx_ssl_connection_error(ngx_connection_ if (err == NGX_ECONNRESET || err == NGX_EPIPE || err == NGX_ENOTCONN -#if !(NGX_CRIT_ETIMEDOUT) || err == NGX_ETIMEDOUT -#endif || err == NGX_ECONNREFUSED || err == NGX_ENETDOWN || err == NGX_ENETUNREACH @@ -1306,7 +1343,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ last = errstr + NGX_MAX_CONF_ERRSTR; va_start(args, fmt); - p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); + p = ngx_vslprintf(errstr, last - 1, fmt, args); va_end(args); p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); @@ -1387,7 +1424,7 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng } } - SSL_CTX_set_timeout(ssl->ctx, timeout); + SSL_CTX_set_timeout(ssl->ctx, (long) timeout); if (shm_zone) { shm_zone->init = ngx_ssl_session_cache_init; @@ -1421,6 +1458,11 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ return NGX_OK; } + if (shm_zone->shm.exists) { + shm_zone->data = data; + return NGX_OK; + } + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t)); @@ -1428,12 +1470,15 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ return NGX_ERROR; } + shpool->data = cache; + shm_zone->data = cache; + ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, ngx_ssl_session_rbtree_insert_value); ngx_queue_init(&cache->expire_queue); - len = sizeof(" in SSL session shared cache \"\"") + shm_zone->name.len; + len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len; shpool->log_ctx = ngx_slab_alloc(shpool, len); if (shpool->log_ctx == NULL) { @@ -1441,9 +1486,7 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ } ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z", - &shm_zone->name); - - shm_zone->data = cache; + &shm_zone->shm.name); return NGX_OK; } @@ -1968,7 +2011,7 @@ ngx_ssl_get_certificate(ngx_connection_t p = s->data; - for (i = 0; i < len; i++) { + for (i = 0; i < cert.len - 1; i++) { *p++ = cert.data[i]; if (cert.data[i] == LF) { *p++ = '\t'; @@ -2102,6 +2145,35 @@ ngx_ssl_get_serial_number(ngx_connection } +ngx_int_t +ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + X509 *cert; + + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { + s->len = sizeof("FAILED") - 1; + s->data = (u_char *) "FAILED"; + + return NGX_OK; + } + + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert) { + s->len = sizeof("SUCCESS") - 1; + s->data = (u_char *) "SUCCESS"; + + } else { + s->len = sizeof("NONE") - 1; + s->data = (u_char *) "NONE"; + } + + X509_free(cert); + + return NGX_OK; +} + + static void * ngx_openssl_create_conf(ngx_cycle_t *cycle) { @@ -2109,7 +2181,7 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t)); if (oscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -2125,7 +2197,6 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc static char * ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { -#if (NGX_SSL_ENGINE) ngx_openssl_conf_t *oscf = conf; ENGINE *engine; @@ -2160,23 +2231,11 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c ENGINE_free(engine); return NGX_CONF_OK; - -#else - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"ssl_engine\" directive is available only in " - "OpenSSL 0.9.7 and higher,"); - - return NGX_CONF_ERROR; - -#endif } static void ngx_openssl_exit(ngx_cycle_t *cycle) { -#if (NGX_SSL_ENGINE) ENGINE_cleanup(); -#endif } 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 @@ -13,12 +13,8 @@ #include #include - -#if OPENSSL_VERSION_NUMBER >= 0x00907000 #include #include -#define NGX_SSL_ENGINE 1 -#endif #define NGX_SSL_NAME "OpenSSL" @@ -100,6 +96,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t ngx_str_t *cert, ngx_str_t *key); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); +ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl); ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, @@ -131,6 +128,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_conn ngx_str_t *s); ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); 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 @@ -24,15 +24,22 @@ ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) { u_int flags; + ngx_int_t rc; ngx_event_t *rev, *wev; for ( ;; ) { if (do_write) { p->log->action = "sending to client"; - if (ngx_event_pipe_write_to_downstream(p) == NGX_ABORT) { + rc = ngx_event_pipe_write_to_downstream(p); + + if (rc == NGX_ABORT) { return NGX_ABORT; } + + if (rc == NGX_BUSY) { + return NGX_OK; + } } p->read = 0; @@ -397,7 +404,7 @@ ngx_event_pipe_read_upstream(ngx_event_p p->free_raw_bufs = p->free_raw_bufs->next; - if (p->free_bufs) { + if (p->free_bufs && p->buf_to_file == NULL) { for (cl = p->free_raw_bufs; cl; cl = cl->next) { if (cl->buf->shadow == NULL) { ngx_pfree(p->pool, cl->buf->start); @@ -422,7 +429,7 @@ ngx_event_pipe_write_to_downstream(ngx_e u_char *prev; size_t bsize; ngx_int_t rc; - ngx_uint_t flush, prev_last_shadow; + ngx_uint_t flush, flushed, prev_last_shadow; ngx_chain_t *out, **ll, *cl, file; ngx_connection_t *downstream; @@ -431,6 +438,8 @@ ngx_event_pipe_write_to_downstream(ngx_e ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream: %d", downstream->write->ready); + flushed = 0; + for ( ;; ) { if (p->downstream_error) { return ngx_event_pipe_drain_chains(p); @@ -454,10 +463,6 @@ ngx_event_pipe_write_to_downstream(ngx_e rc = p->output_filter(p->output_ctx, p->out); - if (downstream->destroyed) { - return NGX_ABORT; - } - if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); @@ -476,10 +481,6 @@ ngx_event_pipe_write_to_downstream(ngx_e rc = p->output_filter(p->output_ctx, p->in); - if (downstream->destroyed) { - return NGX_ABORT; - } - if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); @@ -618,16 +619,20 @@ ngx_event_pipe_write_to_downstream(ngx_e ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write: out:%p, f:%d", out, flush); - if (out == NULL && !flush) { - break; + if (out == NULL) { + + if (!flush) { + break; + } + + /* a workaround for AIO */ + if (flushed++ > 10) { + return NGX_BUSY; + } } rc = p->output_filter(p->output_ctx, out); - if (downstream->destroyed) { - return NGX_ABORT; - } - if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); 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 @@ -201,7 +201,7 @@ ngx_http_access_create_loc_conf(ngx_conf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } return conf; diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -45,7 +45,7 @@ static ngx_command_t ngx_http_addition_ offsetof(ngx_http_addition_conf_t, after_body), NULL }, - { ngx_string("addtion_types"), + { ngx_string("addition_types"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_http_types_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -212,7 +212,7 @@ ngx_http_addition_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -372,7 +372,7 @@ ngx_http_auth_basic_create_loc_conf(ngx_ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } return conf; 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 @@ -25,8 +25,11 @@ typedef struct { typedef struct { ngx_str_t name; size_t utf_len; - ngx_uint_t escape; - ngx_uint_t dir; + size_t escape; + + unsigned dir:1; + unsigned colon:1; + time_t mtime; off_t size; } ngx_http_autoindex_entry_t; @@ -142,7 +145,7 @@ ngx_http_autoindex_handler(ngx_http_requ ngx_int_t rc, size; ngx_str_t path; ngx_dir_t dir; - ngx_uint_t i, level; + ngx_uint_t i, level, utf8; ngx_pool_t *pool; ngx_time_t *tp; ngx_chain_t out; @@ -157,7 +160,6 @@ ngx_http_autoindex_handler(ngx_http_requ return NGX_DECLINED; } - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } @@ -250,6 +252,16 @@ ngx_http_autoindex_handler(ngx_http_requ filename = path.data; filename[path.len] = '/'; + if (r->headers_out.charset.len == 5 + && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) + == 0) + { + utf8 = 1; + + } else { + utf8 = 0; + } + for ( ;; ) { ngx_set_errno(0); @@ -333,12 +345,14 @@ ngx_http_autoindex_handler(ngx_http_requ entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, NGX_ESCAPE_HTML); - if (r->utf8) { + if (utf8) { entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); } else { entry->utf_len = len; } + entry->colon = (ngx_strchr(entry->name.data, ':') != NULL); + entry->dir = ngx_de_is_dir(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); @@ -364,7 +378,7 @@ ngx_http_autoindex_handler(ngx_http_requ + entry[i].name.len + entry[i].escape + 1 /* 1 is for "/" */ + sizeof("\">") - 1 - + entry[i].name.len - entry[i].utf_len + + entry[i].name.len - entry[i].utf_len + entry[i].colon * 2 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 + sizeof("") - 1 + sizeof(" 28-Sep-1970 12:00 ") - 1 @@ -397,6 +411,11 @@ ngx_http_autoindex_handler(ngx_http_requ for (i = 0; i < entries.nelts; i++) { b->last = ngx_cpymem(b->last, "last++ = '.'; + *b->last++ = '/'; + } + if (entry[i].escape) { ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len, NGX_ESCAPE_HTML); @@ -613,7 +632,7 @@ ngx_http_autoindex_create_loc_conf(ngx_c conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->enable = NGX_CONF_UNSET; 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 @@ -423,7 +423,7 @@ ngx_http_browser_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_browser_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -9,8 +9,9 @@ #include -#define NGX_HTTP_NO_CHARSET -2 -#define NGX_HTTP_CHARSET_VAR 0x10000 +#define NGX_HTTP_CHARSET_OFF -2 +#define NGX_HTTP_NO_CHARSET -3 +#define NGX_HTTP_CHARSET_VAR 0x10000 /* 1 byte length and up to 3 bytes for the UTF-8 encoding of the UCS-2 */ #define NGX_UTF_LEN 4 @@ -61,6 +62,7 @@ typedef struct { typedef struct { u_char *table; ngx_int_t charset; + ngx_str_t charset_name; ngx_chain_t *busy; ngx_chain_t *free_bufs; @@ -82,9 +84,16 @@ typedef struct { } ngx_http_charset_conf_ctx_t; -static ngx_int_t ngx_http_charset_get_charset(ngx_http_charset_t *charsets, - ngx_uint_t n, ngx_str_t *charset); -static ngx_int_t ngx_http_charset_set_charset(ngx_http_request_t *r, +static ngx_int_t ngx_http_destination_charset(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_main_request_charset(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_source_charset(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name); +static ngx_inline void ngx_http_set_charset(ngx_http_request_t *r, + ngx_str_t *charset); +static ngx_int_t ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset); static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table); static ngx_chain_t *ngx_http_charset_recode_from_utf8(ngx_pool_t *pool, @@ -207,206 +216,264 @@ static ngx_int_t ngx_http_charset_header_filter(ngx_http_request_t *r) { ngx_int_t charset, source_charset; - ngx_str_t *mc, *from, *to, s; - ngx_uint_t n; + ngx_str_t dst, src; ngx_http_charset_t *charsets; - ngx_http_charset_ctx_t *ctx; - ngx_http_variable_value_t *vv; - ngx_http_charset_loc_conf_t *lcf, *mlcf; ngx_http_charset_main_conf_t *mcf; - mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); - - charsets = mcf->charsets.elts; - n = mcf->charsets.nelts; - - /* destination charset */ - if (r == r->main) { - - if (r->headers_out.content_encoding - && r->headers_out.content_encoding->value.len) - { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.content_type.len == 0) { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.override_charset - && r->headers_out.override_charset->len) - { - charset = ngx_http_charset_get_charset(charsets, n, - r->headers_out.override_charset); - - if (charset == NGX_HTTP_NO_CHARSET) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unknown charset \"%V\" to override", - r->headers_out.override_charset); - - return ngx_http_next_header_filter(r); - } - - } else { - mlcf = ngx_http_get_module_loc_conf(r, - ngx_http_charset_filter_module); - charset = mlcf->charset; - - if (charset == NGX_HTTP_NO_CHARSET) { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.charset.len) { - if (mlcf->override_charset == 0) { - return ngx_http_next_header_filter(r); - } - - } else { - if (ngx_http_test_content_type(r, &mlcf->types) == NULL) { - return ngx_http_next_header_filter(r); - } - } - - if (charset >= NGX_HTTP_CHARSET_VAR) { - vv = ngx_http_get_indexed_variable(r, - charset - NGX_HTTP_CHARSET_VAR); - - if (vv == NULL || vv->not_found) { - return NGX_ERROR; - } - - s.len = vv->len; - s.data = vv->data; - - charset = ngx_http_charset_get_charset(charsets, n, &s); - } - } + charset = ngx_http_destination_charset(r, &dst); } else { - ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); - - if (ctx == NULL) { - - mc = &r->main->headers_out.charset; - - if (mc->len == 0) { - return ngx_http_next_header_filter(r); - } + charset = ngx_http_main_request_charset(r, &dst); + } - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module); + if (charset == NGX_ERROR) { + return NGX_ERROR; + } - charset = ngx_http_charset_get_charset(charsets, n, mc); - - ctx->charset = charset; - - } else { - charset = ctx->charset; - } + if (charset == NGX_DECLINED) { + return ngx_http_next_header_filter(r); } - /* source charset */ - - if (r->headers_out.charset.len == 0) { - lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); - - source_charset = lcf->source_charset; - - if (source_charset >= NGX_HTTP_CHARSET_VAR) { - vv = ngx_http_get_indexed_variable(r, - source_charset - NGX_HTTP_CHARSET_VAR); - - if (vv == NULL || vv->not_found) { - return NGX_ERROR; - } + /* charset: charset index or NGX_HTTP_NO_CHARSET */ - s.len = vv->len; - s.data = vv->data; - - source_charset = ngx_http_charset_get_charset(charsets, n, &s); - } + source_charset = ngx_http_source_charset(r, &src); - if (charset != NGX_HTTP_NO_CHARSET) { - return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset, - source_charset); - } - - if (source_charset == NGX_CONF_UNSET) { - return ngx_http_next_header_filter(r); - } - - from = &charsets[source_charset].name; - to = &r->main->headers_out.charset; - - goto no_charset_map; + if (source_charset == NGX_ERROR) { + return NGX_ERROR; } - source_charset = ngx_http_charset_get_charset(charsets, n, - &r->headers_out.charset); + /* + * source_charset: charset index, NGX_HTTP_NO_CHARSET, + * or NGX_HTTP_CHARSET_OFF + */ + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "charset: \"%V\" > \"%V\"", &src, &dst); + + if (source_charset == NGX_HTTP_CHARSET_OFF) { + ngx_http_set_charset(r, &dst); + + return ngx_http_next_header_filter(r); + } if (charset == NGX_HTTP_NO_CHARSET || source_charset == NGX_HTTP_NO_CHARSET) { - if (charset != source_charset - || ngx_strcasecmp(r->main->headers_out.charset.data, - r->headers_out.charset.data) - != 0) + if (source_charset != charset + || ngx_strncasecmp(dst.data, src.data, dst.len) != 0) { - from = &r->headers_out.charset; - to = (charset == NGX_HTTP_NO_CHARSET) ? - &r->main->headers_out.charset: - &charsets[charset].name; - goto no_charset_map; } + ngx_http_set_charset(r, &dst); + return ngx_http_next_header_filter(r); } + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + charsets = mcf->charsets.elts; + if (source_charset != charset && (charsets[source_charset].tables == NULL || charsets[source_charset].tables[charset] == NULL)) { - from = &charsets[source_charset].name; - to = &charsets[charset].name; - goto no_charset_map; } r->headers_out.content_type.len = r->headers_out.content_type_len; - return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset, - source_charset); + ngx_http_set_charset(r, &dst); + + if (source_charset != charset) { + return ngx_http_charset_ctx(r, charsets, charset, source_charset); + } + + return ngx_http_next_header_filter(r); no_charset_map: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no \"charset_map\" between the charsets \"%V\" and \"%V\"", - from, to); + &src, &dst); return ngx_http_next_header_filter(r); } static ngx_int_t -ngx_http_charset_get_charset(ngx_http_charset_t *charsets, ngx_uint_t n, - ngx_str_t *charset) +ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_int_t charset; + ngx_http_charset_t *charsets; + ngx_http_variable_value_t *vv; + ngx_http_charset_loc_conf_t *mlcf; + ngx_http_charset_main_conf_t *mcf; + + if (!r->ignore_content_encoding + && r->headers_out.content_encoding + && r->headers_out.content_encoding->value.len) + { + return NGX_DECLINED; + } + + if (r->headers_out.content_type.len == 0) { + return NGX_DECLINED; + } + + if (r->headers_out.override_charset + && r->headers_out.override_charset->len) + { + *name = *r->headers_out.override_charset; + + charset = ngx_http_get_charset(r, name); + + if (charset != NGX_HTTP_NO_CHARSET) { + return charset; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown charset \"%V\" to override", name); + + return NGX_DECLINED; + } + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + charset = mlcf->charset; + + if (charset == NGX_HTTP_CHARSET_OFF) { + return NGX_DECLINED; + } + + if (r->headers_out.charset.len) { + if (mlcf->override_charset == 0) { + return NGX_DECLINED; + } + + } else { + if (ngx_http_test_content_type(r, &mlcf->types) == NULL) { + return NGX_DECLINED; + } + } + + if (charset < NGX_HTTP_CHARSET_VAR) { + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + charsets = mcf->charsets.elts; + *name = charsets[charset].name; + return charset; + } + + vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR); + + if (vv == NULL || vv->not_found) { + return NGX_ERROR; + } + + name->len = vv->len; + name->data = vv->data; + + return ngx_http_get_charset(r, name); +} + + +static ngx_int_t +ngx_http_main_request_charset(ngx_http_request_t *r, ngx_str_t *src) { - ngx_uint_t i; + ngx_int_t charset; + ngx_str_t *main_charset; + ngx_http_charset_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); + + if (ctx) { + *src = ctx->charset_name; + return ctx->charset; + } + + main_charset = &r->main->headers_out.charset; + + if (main_charset->len == 0) { + return NGX_DECLINED; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module); + + charset = ngx_http_get_charset(r, main_charset); + + ctx->charset = charset; + ctx->charset_name = *main_charset; + *src = *main_charset; + + return charset; +} + + +static ngx_int_t +ngx_http_source_charset(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_int_t charset; + ngx_http_charset_t *charsets; + ngx_http_variable_value_t *vv; + ngx_http_charset_loc_conf_t *lcf; + ngx_http_charset_main_conf_t *mcf; + + if (r->headers_out.charset.len) { + *name = r->headers_out.charset; + return ngx_http_get_charset(r, name); + } + + lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + + charset = lcf->source_charset; + + if (charset == NGX_HTTP_CHARSET_OFF) { + name->len = 0; + return charset; + } + + if (charset < NGX_HTTP_CHARSET_VAR) { + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + charsets = mcf->charsets.elts; + *name = charsets[charset].name; + return charset; + } + + vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR); + + if (vv == NULL || vv->not_found) { + return NGX_ERROR; + } + + name->len = vv->len; + name->data = vv->data; + + return ngx_http_get_charset(r, name); +} + + +static ngx_int_t +ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_uint_t i, n; + ngx_http_charset_t *charset; + ngx_http_charset_main_conf_t *mcf; + + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + + charset = mcf->charsets.elts; + n = mcf->charsets.nelts; for (i = 0; i < n; i++) { - if (charsets[i].name.len != charset->len) { + if (charset[i].name.len != name->len) { continue; } - if (ngx_strncasecmp(charsets[i].name.data, charset->data, charset->len) - == 0) - { + if (ngx_strncasecmp(charset[i].name.data, name->data, name->len) == 0) { return i; } } @@ -415,11 +482,12 @@ ngx_http_charset_get_charset(ngx_http_ch } -static ngx_int_t -ngx_http_charset_set_charset(ngx_http_request_t *r, - ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset) +static ngx_inline void +ngx_http_set_charset(ngx_http_request_t *r, ngx_str_t *charset) { - ngx_http_charset_ctx_t *ctx; + if (r != r->main) { + return; + } if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) @@ -430,16 +498,18 @@ ngx_http_charset_set_charset(ngx_http_re */ r->headers_out.charset.len = 0; - - return ngx_http_next_header_filter(r); + return; } - r->headers_out.charset = charsets[charset].name; - r->utf8 = charsets[charset].utf8; + r->headers_out.charset = *charset; +} + - if (source_charset == NGX_CONF_UNSET || source_charset == charset) { - return ngx_http_next_header_filter(r); - } +static ngx_int_t +ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets, + ngx_int_t charset, ngx_int_t source_charset) +{ + ngx_http_charset_ctx_t *ctx; ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); if (ctx == NULL) { @@ -450,6 +520,7 @@ ngx_http_charset_set_charset(ngx_http_re ctx->table = charsets[source_charset].tables[charset]; ctx->charset = charset; + ctx->charset_name = charsets[charset].name; ctx->length = charsets[charset].length; ctx->from_utf8 = charsets[source_charset].utf8; ctx->to_utf8 = charsets[charset].utf8; @@ -1337,7 +1408,7 @@ ngx_http_set_charset_slot(ngx_conf_t *cf if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, charset) && ngx_strcmp(value[1].data, "off") == 0) { - *cp = NGX_HTTP_NO_CHARSET; + *cp = NGX_HTTP_CHARSET_OFF; return NGX_CONF_OK; } @@ -1417,27 +1488,27 @@ ngx_http_charset_create_main_conf(ngx_co mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t)); if (mcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&mcf->tables, cf->pool, 1, sizeof(ngx_http_charset_tables_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&mcf->recodes, cf->pool, 2, sizeof(ngx_http_charset_recode_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return mcf; @@ -1451,7 +1522,7 @@ ngx_http_charset_create_loc_conf(ngx_con lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t)); if (lcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -1488,14 +1559,12 @@ ngx_http_charset_merge_loc_conf(ngx_conf } ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0); - ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET); + ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_CHARSET_OFF); + ngx_conf_merge_value(conf->source_charset, prev->source_charset, + NGX_HTTP_CHARSET_OFF); - if (conf->source_charset == NGX_CONF_UNSET) { - conf->source_charset = prev->source_charset; - } - - if (conf->charset == NGX_HTTP_NO_CHARSET - || conf->source_charset == NGX_CONF_UNSET + if (conf->charset == NGX_HTTP_CHARSET_OFF + || conf->source_charset == NGX_HTTP_CHARSET_OFF || conf->charset == conf->source_charset) { return NGX_CONF_OK; 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 @@ -53,8 +53,6 @@ static ngx_int_t ngx_http_dav_copy_dir_t ngx_str_t *path); static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); -static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, - u_char *to); static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt); static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, @@ -148,7 +146,6 @@ ngx_http_dav_handler(ngx_http_request_t ngx_int_t rc; ngx_http_dav_loc_conf_t *dlcf; - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } @@ -217,12 +214,14 @@ ngx_http_dav_put_handler(ngx_http_reques ngx_http_map_uri_to_path(r, &path, &root, 0); + path.len--; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http put filename: \"%s\"", path.data); temp = &r->request_body->temp_file->file.name; - if (ngx_file_info(path.data, &fi) == -1) { + if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { status = NGX_HTTP_CREATED; } else { @@ -250,7 +249,6 @@ ngx_http_dav_put_handler(ngx_http_reques ext.time = -1; ext.create_path = dlcf->create_full_put_path; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; if (r->headers_in.date) { @@ -327,7 +325,7 @@ ok: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete filename: \"%s\"", path.data); - if (ngx_file_info(path.data, &fi) == -1) { + if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND; @@ -521,6 +519,7 @@ ngx_http_dav_copy_move_handler(ngx_http_ ngx_uint_t overwrite, slash, dir; ngx_str_t path, uri; ngx_tree_ctx_t tree; + ngx_copy_file_t cf; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_ext_rename_file_t ext; @@ -679,7 +678,7 @@ overwrite_done: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy to: \"%s\"", copy.path.data); - if (ngx_file_info(copy.path.data, &fi) == -1) { + if (ngx_file_info(copy.path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { @@ -713,7 +712,7 @@ overwrite_done: dir = ngx_is_dir(&fi); } - if (ngx_file_info(path.data, &fi) == -1) { + if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_file_info_n, path.data); @@ -792,43 +791,24 @@ overwrite_done: ext.time = -1; ext.create_path = 1; ext.delete_file = 0; - ext.log_rename_error = 0; ext.log = r->connection->log; if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } - if (ext.rename_error != NGX_EXDEV) { - - if (ext.rename_error) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ext.rename_error, - ngx_rename_file_n " \"%s\" to \"%s\" failed", - path.data, copy.path.data); - } - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + return NGX_HTTP_INTERNAL_SERVER_ERROR; } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); - tree.size = ngx_file_size(&fi); - tree.mtime = ngx_file_mtime(&fi); - tree.access = dlcf->access; - tree.log = r->connection->log; + cf.size = ngx_file_size(&fi); + cf.buf_size = 0; + cf.access = dlcf->access; + cf.time = ngx_file_mtime(&fi); + cf.log = r->connection->log; - if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK) - { - if (r->method == NGX_HTTP_MOVE) { - rc = ngx_http_dav_delete_path(r, &path, 0); - - if (rc != NGX_OK) { - return rc; - } - } - + if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } } @@ -942,6 +922,7 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx { u_char *p, *file; size_t len; + ngx_copy_file_t cf; ngx_http_dav_copy_ctx_t *copy; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, @@ -962,7 +943,13 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy file to: \"%s\"", file); - (void) ngx_http_dav_copy_file(ctx, path->data, file); + cf.size = ctx->size; + cf.buf_size = 0; + cf.access = ctx->access; + cf.time = ctx->mtime; + cf.log = ctx->log; + + (void) ngx_copy_file(path->data, file, &cf); ngx_free(file); @@ -971,75 +958,6 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx static ngx_int_t -ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to) -{ - off_t size; - ssize_t n; - ngx_fd_t fd, cfd; - ngx_int_t rc; - u_char buf[NGX_HTTP_DAV_COPY_BLOCK]; - - fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); - - if (fd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, - from); - return NGX_ERROR; - } - - cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - ctx->access); - - rc = NGX_ERROR; - - if (cfd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to); - goto failed; - } - - for (size = ctx->size; size > 0; size -= n) { - - n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK); - - if (n == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_read_fd_n " \"%s\" failed", from); - goto failed; - } - - if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_write_fd_n " \"%s\" failed", to); - goto failed; - } - } - - if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", to); - goto failed; - } - - if (ngx_close_file(cfd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", to); - goto failed; - } - - rc = NGX_OK; - -failed: - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", from); - } - - return rc; -} - - -static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt) { ngx_table_elt_t *depth; @@ -1155,7 +1073,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -178,11 +178,21 @@ static ngx_conf_bitmask_t ngx_http_fast { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, { ngx_null_string, 0 } }; +static ngx_conf_bitmask_t ngx_http_fastcgi_ignore_headers_masks[] = { + { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT }, + { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES }, + { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES }, + { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL }, + { ngx_null_string, 0 } +}; + + ngx_module_t ngx_http_fastcgi_module; @@ -330,7 +340,7 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid), NULL }, - { ngx_string("proxy_cache_min_uses"), + { ngx_string("fastcgi_cache_min_uses"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -344,6 +354,13 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale), &ngx_http_fastcgi_next_upstream_masks }, + { ngx_string("fastcgi_cache_methods"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods), + &ngx_http_upstream_cache_method_mask }, + #endif { ngx_string("fastcgi_temp_path"), @@ -409,6 +426,13 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers), NULL }, + { ngx_string("fastcgi_ignore_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers), + &ngx_http_fastcgi_ignore_headers_masks }, + { ngx_string("fastcgi_catch_stderr"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_str_array_slot, @@ -519,20 +543,17 @@ ngx_http_fastcgi_handler(ngx_http_reques return NGX_HTTP_INTERNAL_SERVER_ERROR; } + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); if (f == NULL) { - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); - if (u == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->upstream = u; - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); if (flcf->fastcgi_lengths) { @@ -541,15 +562,11 @@ ngx_http_fastcgi_handler(ngx_http_reques } } + u = r->upstream; + u->schema.len = sizeof("fastcgi://") - 1; u->schema.data = (u_char *) "fastcgi://"; - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif - u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module; u->conf = &flcf->upstream; @@ -1048,9 +1065,10 @@ ngx_http_fastcgi_reinit_request(ngx_http static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) { - u_char *p, *start, *last, *part_start; + u_char *p, *msg, *start, *last, + *part_start, *part_end; size_t size; - ngx_str_t *status_line, line, *pattern; + ngx_str_t *status_line, *pattern; ngx_int_t rc, status; ngx_buf_t buf; ngx_uint_t i; @@ -1134,40 +1152,39 @@ ngx_http_fastcgi_process_header(ngx_http if (f->type == NGX_HTTP_FASTCGI_STDERR) { if (f->length) { - line.data = u->buffer.pos; + msg = u->buffer.pos; if (u->buffer.pos + f->length <= u->buffer.last) { - line.len = f->length; u->buffer.pos += f->length; f->length = 0; f->state = ngx_http_fastcgi_st_padding; } else { - line.len = u->buffer.last - u->buffer.pos; f->length -= u->buffer.last - u->buffer.pos; u->buffer.pos = u->buffer.last; } - while (line.data[line.len - 1] == LF - || line.data[line.len - 1] == CR - || line.data[line.len - 1] == '.' - || line.data[line.len - 1] == ' ') - { - line.len--; + for (p = u->buffer.pos - 1; msg < p; p--) { + if (*p != LF && *p != CR && *p != '.' && *p != ' ') { + break; + } } + p++; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "FastCGI sent in stderr: \"%V\"", &line); + "FastCGI sent in stderr: \"%*s\"", p - msg, msg); flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); if (flcf->catch_stderr) { pattern = flcf->catch_stderr->elts; - line.data[line.len - 1] = '\0'; - for (i = 0; i < flcf->catch_stderr->nelts; i++) { - if (ngx_strstr(line.data, pattern[i].data)) { + if (ngx_strnstr(msg, (char *) pattern[i].data, + p - msg) + != NULL) + { return NGX_HTTP_UPSTREAM_INVALID_HEADER; } } @@ -1220,6 +1237,7 @@ ngx_http_fastcgi_process_header(ngx_http for ( ;; ) { part_start = u->buffer.pos; + part_end = u->buffer.last; rc = ngx_http_parse_header_line(r, &u->buffer, 1); @@ -1420,7 +1438,11 @@ ngx_http_fastcgi_process_header(ngx_http part = ngx_array_push(f->split_parts); part->start = part_start; - part->end = u->buffer.last; + part->end = part_end; + + if (u->buffer.pos < u->buffer.last) { + continue; + } return NGX_AGAIN; } @@ -1430,9 +1452,9 @@ ngx_http_fastcgi_process_header(ngx_http static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { + u_char *m, *msg; ngx_int_t rc; ngx_buf_t *b, **prev; - ngx_str_t line; ngx_chain_t *cl; ngx_http_request_t *r; ngx_http_fastcgi_ctx_t *f; @@ -1516,30 +1538,27 @@ ngx_http_fastcgi_input_filter(ngx_event_ break; } - line.data = f->pos; + msg = f->pos; if (f->pos + f->length <= f->last) { - line.len = f->length; f->pos += f->length; f->length = 0; f->state = ngx_http_fastcgi_st_padding; } else { - line.len = f->last - f->pos; f->length -= f->last - f->pos; f->pos = f->last; } - while (line.data[line.len - 1] == LF - || line.data[line.len - 1] == CR - || line.data[line.len - 1] == '.' - || line.data[line.len - 1] == ' ') - { - line.len--; + for (m = f->pos - 1; msg < m; m--) { + if (*m != LF && *m != CR && *m != '.' && *m != ' ') { + break; + } } ngx_log_error(NGX_LOG_ERR, p->log, 0, - "FastCGI sent in stderr: \"%V\"", &line); + "FastCGI sent in stderr: \"%*s\"", + m + 1 - msg, msg); if (f->pos == f->last) { break; @@ -1810,15 +1829,17 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* * set by ngx_pcalloc(): * * conf->upstream.bufs.num = 0; + * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; - * conf->upstream.use_stale_cache = 0; + * conf->upstream.cache_use_stale = 0; + * conf->upstream.cache_methods = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.uri = { 0, NULL }; @@ -1886,7 +1907,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf if (conf->upstream.store != 0) { ngx_conf_merge_value(conf->upstream.store, - prev->upstream.store, 0); + prev->upstream.store, 0); if (conf->upstream.store_lengths == NULL) { conf->upstream.store_lengths = prev->upstream.store_lengths; @@ -2012,6 +2033,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf } + ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, + prev->upstream.ignore_headers, + NGX_CONF_BITMASK_SET); + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, prev->upstream.next_upstream, (NGX_CONF_BITMASK_SET @@ -2043,7 +2069,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"fastcgi_cache\" zone \"%V\" is unknown", - &shm_zone->name); + &shm_zone->shm.name); return NGX_CONF_ERROR; } @@ -2061,9 +2087,19 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf |NGX_HTTP_UPSTREAM_FT_OFF; } + if (conf->upstream.cache_methods == 0) { + conf->upstream.cache_methods = prev->upstream.cache_methods; + } + + conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; + ngx_conf_merge_ptr_value(conf->upstream.cache_valid, prev->upstream.cache_valid, NULL); + if (conf->cache_key.value.data == NULL) { + conf->cache_key = prev->cache_key; + } + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, @@ -2397,8 +2433,13 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_fastcgi_handler; + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + value = cf->args->elts; url = &value[1]; @@ -2434,10 +2475,6 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng return NGX_CONF_ERROR; } - if (clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - return NGX_CONF_OK; } @@ -2501,20 +2538,31 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, n ngx_str_t *value; ngx_http_script_compile_t sc; - if (flcf->upstream.store != NGX_CONF_UNSET || flcf->upstream.store_lengths) + if (flcf->upstream.store != NGX_CONF_UNSET + || flcf->upstream.store_lengths) { return "is duplicate"; } value = cf->args->elts; - if (ngx_strcmp(value[1].data, "on") == 0) { - flcf->upstream.store = 1; + if (ngx_strcmp(value[1].data, "off") == 0) { + flcf->upstream.store = 0; return NGX_CONF_OK; } - if (ngx_strcmp(value[1].data, "off") == 0) { - flcf->upstream.store = 0; +#if (NGX_HTTP_CACHE) + + if (flcf->upstream.cache != NGX_CONF_UNSET_PTR + && flcf->upstream.cache != NULL) + { + return "is incompatible with \"fastcgi_cache\""; + } + +#endif + + if (ngx_strcmp(value[1].data, "on") == 0) { + flcf->upstream.store = 1; return NGX_CONF_OK; } @@ -2559,6 +2607,10 @@ ngx_http_fastcgi_cache(ngx_conf_t *cf, n return NGX_CONF_OK; } + if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) { + return "is incompatible with \"fastcgi_store\""; + } + flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_fastcgi_module); if (flcf->upstream.cache == NULL) { 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 @@ -80,7 +80,6 @@ ngx_http_flv_handler(ngx_http_request_t return NGX_DECLINED; } - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } @@ -144,7 +143,7 @@ ngx_http_flv_handler(ngx_http_request_t if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + "%s \"%s\" failed", of.failed, path.data); } return rc; 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 @@ -35,6 +35,7 @@ typedef struct { ngx_radix_tree_t *tree; ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; + ngx_array_t *proxies; ngx_pool_t *pool; ngx_pool_t *temp_pool; } ngx_http_geo_conf_ctx_t; @@ -46,12 +47,16 @@ typedef struct { ngx_http_geo_high_ranges_t *high; } u; + ngx_array_t *proxies; + ngx_int_t index; } ngx_http_geo_ctx_t; static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx); +static in_addr_t ngx_http_geo_real_addr(ngx_http_request_t *r, + ngx_http_geo_ctx_t *ctx); static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, @@ -64,6 +69,10 @@ static char *ngx_http_geo_cidr(ngx_conf_ ngx_str_t *value); static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_http_geo_add_proxy(ngx_conf_t *cf, + ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr); +static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, + ngx_cidr_t *cidr); static ngx_command_t ngx_http_geo_commands[] = { @@ -168,6 +177,50 @@ ngx_http_geo_range_variable(ngx_http_req static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) { + u_char *p, *ip; + size_t len; + in_addr_t addr; + ngx_uint_t i, n; + ngx_in_cidr_t *proxies; + ngx_table_elt_t *xfwd; + + addr = ngx_http_geo_real_addr(r, ctx); + + xfwd = r->headers_in.x_forwarded_for; + + if (xfwd == NULL || ctx->proxies == NULL) { + return addr; + } + + proxies = ctx->proxies->elts; + n = ctx->proxies->nelts; + + for (i = 0; i < n; i++) { + if ((addr & proxies[i].mask) == proxies[i].addr) { + + len = xfwd->value.len; + ip = xfwd->value.data; + + for (p = ip + len - 1; p > ip; p--) { + if (*p == ' ' || *p == ',') { + p++; + len -= p - ip; + ip = p; + break; + } + } + + return ntohl(ngx_inet_addr(ip, len)); + } + } + + return addr; +} + + +static in_addr_t +ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) +{ struct sockaddr_in *sin; ngx_http_variable_value_t *v; @@ -259,6 +312,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c ctx.high = NULL; ctx.tree = NULL; + ctx.proxies = NULL; ctx.pool = cf->pool; save = *cf; @@ -271,6 +325,8 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c *cf = save; + geo->proxies = ctx.proxies; + if (ctx.high) { for (i = 0; i < 0x10000; i++) { @@ -341,6 +397,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command { char *rv; ngx_str_t *value, file; + ngx_cidr_t cidr; ngx_http_geo_conf_ctx_t *ctx; ctx = cf->ctx; @@ -394,6 +451,16 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command rv = ngx_conf_parse(cf, &file); goto done; + + } else if (ngx_strcmp(value[0].data, "proxy") == 0) { + + if (ngx_http_geo_cidr_value(cf, &value[1], &cidr) != NGX_OK) { + goto failed; + } + + rv = ngx_http_geo_add_proxy(cf, ctx, &cidr); + + goto done; } if (ctx->high) { @@ -803,33 +870,8 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht del = 0; } - if (ngx_strcmp(net->data, "255.255.255.255") == 0) { - cidr.u.in.addr = 0xffffffff; - cidr.u.in.mask = 0xffffffff; - - } else { - rc = ngx_ptocidr(net, &cidr); - - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid network \"%V\"", net); - return NGX_CONF_ERROR; - } - - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"geo\" supports IPv4 only"); - return NGX_CONF_ERROR; - } - - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", - net); - } - - cidr.u.in.addr = ntohl(cidr.u.in.addr); - cidr.u.in.mask = ntohl(cidr.u.in.mask); + if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) { + return NGX_CONF_ERROR; } if (del) { @@ -864,7 +906,7 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht /* rc == NGX_BUSY */ - old = (ngx_http_variable_value_t *) + old = (ngx_http_variable_value_t *) ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask); ngx_conf_log_error(NGX_LOG_WARN, cf, 0, @@ -927,3 +969,64 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_h return val; } + + +static char * +ngx_http_geo_add_proxy(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_cidr_t *cidr) +{ + ngx_in_cidr_t *c; + + if (ctx->proxies == NULL) { + ctx->proxies = ngx_array_create(ctx->pool, 4, sizeof(ngx_in_cidr_t)); + if (ctx->proxies == NULL) { + return NGX_CONF_ERROR; + } + } + + c = ngx_array_push(ctx->proxies); + if (c == NULL) { + return NGX_CONF_ERROR; + } + + c->addr = cidr->u.in.addr; + c->mask = cidr->u.in.mask; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) +{ + ngx_int_t rc; + + if (ngx_strcmp(net->data, "255.255.255.255") == 0) { + cidr->u.in.addr = 0xffffffff; + cidr->u.in.mask = 0xffffffff; + + return NGX_OK; + } + + rc = ngx_ptocidr(net, cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net); + return NGX_ERROR; + } + + if (cidr->family != AF_INET) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"geo\" supports IPv4 only"); + return NGX_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", net); + } + + cidr->u.in.addr = ntohl(cidr->u.in.addr); + cidr->u.in.mask = ntohl(cidr->u.in.mask); + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_geoip_module.c @@ -0,0 +1,376 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + +#include +#include + + +typedef struct { + GeoIP *country; + GeoIP *city; +} ngx_http_geoip_conf_t; + + +typedef struct { + ngx_str_t *name; + uintptr_t data; +} ngx_http_geoip_var_t; + + +typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr); + +static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf); +static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); +static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void ngx_http_geoip_cleanup(void *data); + + +static ngx_command_t ngx_http_geoip_commands[] = { + + { ngx_string("geoip_country"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_geoip_country, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip_city"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_geoip_city, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_geoip_module_ctx = { + ngx_http_geoip_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_http_geoip_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_geoip_module = { + NGX_MODULE_V1, + &ngx_http_geoip_module_ctx, /* module context */ + ngx_http_geoip_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_variable_t ngx_http_geoip_vars[] = { + + { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable, + (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 }, + + { ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable, + (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 }, + + { ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable, + (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 }, + + { ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, country_code), 0, 0 }, + + { ngx_string("geoip_city_country_code3"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, country_code3), 0, 0 }, + + { ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, country_name), 0, 0 }, + + { ngx_string("geoip_region"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, region), 0, 0 }, + + { ngx_string("geoip_city"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, city), 0, 0 }, + + { ngx_string("geoip_postal_code"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, postal_code), 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static ngx_int_t +ngx_http_geoip_country_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_geoip_variable_handler_pt handler = + (ngx_http_geoip_variable_handler_pt) data; + + u_long addr; + const char *val; + struct sockaddr_in *sin; + ngx_http_geoip_conf_t *gcf; + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + + if (gcf->country == NULL) { + goto not_found; + } + + if (r->connection->sockaddr->sa_family != AF_INET) { + goto not_found; + } + + sin = (struct sockaddr_in *) r->connection->sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + val = handler(gcf->country, addr); + + if (val == NULL) { + goto not_found; + } + + v->len = ngx_strlen(val); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) val; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip_city_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_long addr; + char *val; + size_t len; + GeoIPRecord *gr; + struct sockaddr_in *sin; + ngx_http_geoip_conf_t *gcf; + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + + if (gcf->city == NULL) { + goto not_found; + } + + if (r->connection->sockaddr->sa_family != AF_INET) { + goto not_found; + } + + sin = (struct sockaddr_in *) r->connection->sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + gr = GeoIP_record_by_ipnum(gcf->city, addr); + + if (gr == NULL) { + goto not_found; + } + + val = *(char **) ((char *) gr + data); + + if (val == NULL) { + goto no_value; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(r->pool, len); + + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; + +no_value: + + GeoIPRecord_delete(gr); + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_geoip_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static void * +ngx_http_geoip_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_http_geoip_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t)); + if (conf == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_http_geoip_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->country) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->country == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIO_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + switch (gcf->country->databaseType) { + + case GEOIP_COUNTRY_EDITION: + case GEOIP_PROXY_EDITION: + case GEOIP_NETSPEED_EDITION: + + return NGX_CONF_OK; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->country->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * +ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->city) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->city == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIO_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + switch (gcf->city->databaseType) { + + case GEOIP_CITY_EDITION_REV0: + case GEOIP_CITY_EDITION_REV1: + + return NGX_CONF_OK; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP City database \"%V\" type:%d", + &value[1], gcf->city->databaseType); + return NGX_CONF_ERROR; + } +} + + +static void +ngx_http_geoip_cleanup(void *data) +{ + ngx_http_geoip_conf_t *gcf = data; + + if (gcf->country) { + GeoIP_delete(gcf->country); + } + + if (gcf->city) { + GeoIP_delete(gcf->city); + } +} 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 @@ -1069,7 +1069,7 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -89,14 +89,19 @@ ngx_http_gzip_static_handler(ngx_http_re return NGX_DECLINED; } - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); - if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) { + if (!gzcf->enable) { + return NGX_DECLINED; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) { return NGX_DECLINED; } @@ -117,8 +122,6 @@ ngx_http_gzip_static_handler(ngx_http_re ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.directio = clcf->directio; @@ -139,6 +142,7 @@ ngx_http_gzip_static_handler(ngx_http_re case NGX_ENOTDIR: case NGX_ENAMETOOLONG: + r->gzip = 0; return NGX_DECLINED; case NGX_EACCES: @@ -153,7 +157,7 @@ ngx_http_gzip_static_handler(ngx_http_re } ngx_log_error(level, log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + "%s \"%s\" failed", of.failed, path.data); return NGX_DECLINED; } @@ -206,6 +210,7 @@ ngx_http_gzip_static_handler(ngx_http_re h->value.data = (u_char *) "gzip"; r->headers_out.content_encoding = h; + r->ignore_content_encoding = 1; /* we need to allocate all before the header would be sent */ @@ -251,7 +256,7 @@ ngx_http_gzip_static_create_conf(ngx_con conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->enable = NGX_CONF_UNSET; 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 @@ -421,7 +421,7 @@ ngx_http_headers_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -0,0 +1,1222 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + +#include + + +#define NGX_HTTP_IMAGE_OFF 0 +#define NGX_HTTP_IMAGE_TEST 1 +#define NGX_HTTP_IMAGE_SIZE 2 +#define NGX_HTTP_IMAGE_RESIZE 3 +#define NGX_HTTP_IMAGE_CROP 4 + + +#define NGX_HTTP_IMAGE_START 0 +#define NGX_HTTP_IMAGE_READ 1 +#define NGX_HTTP_IMAGE_PROCESS 2 +#define NGX_HTTP_IMAGE_PASS 3 +#define NGX_HTTP_IMAGE_DONE 4 + + +#define NGX_HTTP_IMAGE_NONE 0 +#define NGX_HTTP_IMAGE_JPEG 1 +#define NGX_HTTP_IMAGE_GIF 2 +#define NGX_HTTP_IMAGE_PNG 3 + + +#define NGX_HTTP_IMAGE_BUFFERED 0x08 + + +typedef struct { + ngx_uint_t filter; + ngx_uint_t width; + ngx_uint_t height; + ngx_int_t jpeg_quality; + + ngx_flag_t transparency; + + ngx_http_complex_value_t *wcv; + ngx_http_complex_value_t *hcv; + + size_t buffer_size; +} ngx_http_image_filter_conf_t; + + +typedef struct { + u_char *image; + u_char *last; + + size_t length; + + ngx_uint_t width; + ngx_uint_t height; + + ngx_uint_t max_width; + ngx_uint_t max_height; + + ngx_uint_t phase; + ngx_uint_t type; +} ngx_http_image_filter_ctx_t; + + +static ngx_int_t ngx_http_image_send(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_uint_t ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in); +static ngx_int_t ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in); +static ngx_buf_t *ngx_http_image_process(ngx_http_request_t *r); +static ngx_buf_t *ngx_http_image_json(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static ngx_buf_t *ngx_http_image_asis(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static void ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b); +static ngx_int_t ngx_http_image_size(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); + +static ngx_buf_t *ngx_http_image_resize(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static gdImagePtr ngx_http_image_source(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static gdImagePtr ngx_http_image_new(ngx_http_request_t *r, int w, int h, + int colors); +static u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, + gdImagePtr img, int *size); +static void ngx_http_image_cleanup(void *data); +static ngx_uint_t ngx_http_image_filter_get_value(ngx_http_request_t *r, + ngx_http_complex_value_t *cv, ngx_uint_t v); +static ngx_uint_t ngx_http_image_filter_value(ngx_str_t *value); + + +static void *ngx_http_image_filter_create_conf(ngx_conf_t *cf); +static char *ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_image_filter_commands[] = { + + { ngx_string("image_filter"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13, + ngx_http_image_filter, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("image_filter_jpeg_quality"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_image_filter_conf_t, jpeg_quality), + NULL }, + + { ngx_string("image_filter_transparency"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_image_filter_conf_t, transparency), + NULL }, + + { ngx_string("image_filter_buffer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_image_filter_conf_t, buffer_size), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_image_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_image_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_image_filter_create_conf, /* create location configuration */ + ngx_http_image_filter_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_image_filter_module = { + NGX_MODULE_V1, + &ngx_http_image_filter_module_ctx, /* module context */ + ngx_http_image_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_str_t ngx_http_image_types[] = { + ngx_string("image/jpeg"), + ngx_string("image/gif"), + ngx_string("image/png") +}; + + +static ngx_int_t +ngx_http_image_header_filter(ngx_http_request_t *r) +{ + off_t len; + ngx_http_image_filter_ctx_t *ctx; + ngx_http_image_filter_conf_t *conf; + + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + if (ctx) { + ngx_http_set_ctx(r, NULL, ngx_http_image_filter_module); + return ngx_http_next_header_filter(r); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if (conf->filter == NGX_HTTP_IMAGE_OFF) { + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.content_type.len + >= sizeof("multipart/x-mixed-replace") - 1 + && ngx_strncasecmp(r->headers_out.content_type.data, + (u_char *) "multipart/x-mixed-replace", + sizeof("multipart/x-mixed-replace") - 1) + == 0) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "image filter: multipart/x-mixed-replace response"); + + return NGX_ERROR; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_image_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_image_filter_module); + + len = r->headers_out.content_length_n; + + if (len != -1 && len > (off_t) conf->buffer_size) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "image filter: too big response: %O", len); + + return NGX_ERROR; + } + + if (len == -1) { + ctx->length = conf->buffer_size; + + } else { + ctx->length = (size_t) len; + } + + if (r->headers_out.refresh) { + r->headers_out.refresh->hash = 0; + } + + r->main_filter_need_in_memory = 1; + r->allow_ranges = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_image_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_str_t *ct; + ngx_chain_t out; + ngx_http_image_filter_ctx_t *ctx; + ngx_http_image_filter_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "image filter"); + + if (in == NULL) { + return ngx_http_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + switch (ctx->phase) { + + case NGX_HTTP_IMAGE_START: + + ctx->type = ngx_http_image_test(r, in); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if (ctx->type == NGX_HTTP_IMAGE_NONE) { + + if (conf->filter == NGX_HTTP_IMAGE_SIZE) { + out.buf = ngx_http_image_json(r, NULL); + + if (out.buf) { + out.next = NULL; + ctx->phase = NGX_HTTP_IMAGE_DONE; + + return ngx_http_image_send(r, ctx, &out); + } + } + + return ngx_http_filter_finalize_request(r, + &ngx_http_image_filter_module, + NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); + } + + /* override content type */ + + ct = &ngx_http_image_types[ctx->type - 1]; + r->headers_out.content_type_len = ct->len; + r->headers_out.content_type = *ct; + r->headers_out.content_type_lowcase = NULL; + + if (conf->filter == NGX_HTTP_IMAGE_TEST) { + ctx->phase = NGX_HTTP_IMAGE_PASS; + + return ngx_http_image_send(r, ctx, in); + } + + ctx->phase = NGX_HTTP_IMAGE_READ; + + /* fall through */ + + case NGX_HTTP_IMAGE_READ: + + rc = ngx_http_image_read(r, in); + + if (rc == NGX_AGAIN) { + return NGX_OK; + } + + if (rc == NGX_ERROR) { + return ngx_http_filter_finalize_request(r, + &ngx_http_image_filter_module, + NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); + } + + /* fall through */ + + case NGX_HTTP_IMAGE_PROCESS: + + out.buf = ngx_http_image_process(r); + + if (out.buf == NULL) { + return ngx_http_filter_finalize_request(r, + &ngx_http_image_filter_module, + NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); + } + + out.next = NULL; + ctx->phase = NGX_HTTP_IMAGE_PASS; + + return ngx_http_image_send(r, ctx, &out); + + case NGX_HTTP_IMAGE_PASS: + + return ngx_http_next_body_filter(r, in); + + default: /* NGX_HTTP_IMAGE_DONE */ + + rc = ngx_http_next_body_filter(r, NULL); + + /* NGX_ERROR resets any pending data */ + return (rc == NGX_OK) ? NGX_ERROR : rc; + } +} + + +static ngx_int_t +ngx_http_image_send(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx, + ngx_chain_t *in) +{ + ngx_int_t rc; + + rc = ngx_http_next_header_filter(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return NGX_ERROR; + } + + rc = ngx_http_next_body_filter(r, in); + + if (ctx->phase == NGX_HTTP_IMAGE_DONE) { + /* NGX_ERROR resets any pending data */ + return (rc == NGX_OK) ? NGX_ERROR : rc; + } + + return rc; +} + + +static ngx_uint_t +ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in) +{ + u_char *p; + + p = in->buf->pos; + + if (in->buf->last - p < 16) { + return NGX_HTTP_IMAGE_NONE; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image filter: \"%c%c\"", p[0], p[1]); + + if (p[0] == 0xff && p[1] == 0xd8) { + + /* JPEG */ + + return NGX_HTTP_IMAGE_JPEG; + + } else if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F' && p[3] == '8' + && p[5] == 'a') + { + if (p[4] == '9' || p[4] == '7') { + /* GIF */ + return NGX_HTTP_IMAGE_GIF; + } + + } else if (p[0] == 0x89 && p[1] == 'P' && p[2] == 'N' && p[3] == 'G' + && p[4] == 0x0d && p[5] == 0x0a && p[6] == 0x1a && p[7] == 0x0a) + { + /* PNG */ + + return NGX_HTTP_IMAGE_PNG; + } + + return NGX_HTTP_IMAGE_NONE; +} + + +static ngx_int_t +ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in) +{ + u_char *p; + size_t size, rest; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_http_image_filter_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + if (ctx->image == NULL) { + ctx->image = ngx_palloc(r->pool, ctx->length); + if (ctx->image == NULL) { + return NGX_ERROR; + } + + ctx->last = ctx->image; + } + + p = ctx->last; + + for (cl = in; cl; cl = cl->next) { + + b = cl->buf; + size = b->last - b->pos; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image buf: %uz", size); + + rest = ctx->image + ctx->length - p; + size = (rest < size) ? rest : size; + + p = ngx_cpymem(p, b->pos, size); + b->pos += size; + + if (b->last_buf) { + ctx->last = p; + return NGX_OK; + } + } + + ctx->last = p; + r->connection->buffered |= NGX_HTTP_IMAGE_BUFFERED; + + return NGX_AGAIN; +} + + +static ngx_buf_t * +ngx_http_image_process(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_image_filter_ctx_t *ctx; + ngx_http_image_filter_conf_t *conf; + + r->connection->buffered &= ~NGX_HTTP_IMAGE_BUFFERED; + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + rc = ngx_http_image_size(r, ctx); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if (conf->filter == NGX_HTTP_IMAGE_SIZE) { + return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL); + } + + ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width); + if (ctx->max_width == 0) { + return NULL; + } + + ctx->max_height = ngx_http_image_filter_get_value(r, conf->hcv, + conf->height); + if (ctx->max_height == 0) { + return NULL; + } + + if (rc == NGX_OK + && ctx->width <= ctx->max_width + && ctx->height <= ctx->max_height) + { + return ngx_http_image_asis(r, ctx); + } + + return ngx_http_image_resize(r, ctx); +} + + +static ngx_buf_t * +ngx_http_image_json(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + size_t len; + ngx_buf_t *b; + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NULL; + } + + b->memory = 1; + b->last_buf = 1; + + ngx_http_clean_header(r); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_type.len = sizeof("text/plain") - 1; + r->headers_out.content_type.data = (u_char *) "text/plain"; + r->headers_out.content_type_lowcase = NULL; + + if (ctx == NULL) { + b->pos = (u_char *) "{}" CRLF; + b->last = b->pos + sizeof("{}" CRLF) - 1; + + ngx_http_image_length(r, b); + + return b; + } + + len = sizeof("{ \"img\" : " + "{ \"width\": , \"height\": , \"type\": \"jpeg\" } }" CRLF) - 1 + + 2 * NGX_SIZE_T_LEN; + + b->pos = ngx_pnalloc(r->pool, len); + if (b->pos == NULL) { + return NULL; + } + + b->last = ngx_sprintf(b->pos, + "{ \"img\" : " + "{ \"width\": %uz," + " \"height\": %uz," + " \"type\": \"%s\" } }" CRLF, + ctx->width, ctx->height, + ngx_http_image_types[ctx->type - 1].data + 6); + + ngx_http_image_length(r, b); + + return b; +} + + +static ngx_buf_t * +ngx_http_image_asis(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + ngx_buf_t *b; + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NULL; + } + + b->pos = ctx->image; + b->last = ctx->last; + b->memory = 1; + b->last_buf = 1; + + ngx_http_image_length(r, b); + + return b; +} + + +static void +ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b) +{ + r->headers_out.content_length_n = b->last - b->pos; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + } + + r->headers_out.content_length = NULL; +} + + +static ngx_int_t +ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + u_char *p, *last; + ngx_uint_t width, height; + + p = ctx->image; + + switch (ctx->type) { + + case NGX_HTTP_IMAGE_JPEG: + + p += 2; + last = ctx->image + ctx->length - 10; + + while (p < last) { + + if (p[0] == 0xff && p[1] != 0xff) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "JPEG: %02xd %02xd", *p, *(p + 1)); + + p++; + + if (*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3 + || *p == 0xc9 || *p == 0xca || *p == 0xcb) + { + goto found; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "JPEG: %02xd %02xd", p[1], p[2]); + + p += p[1] * 256 + p[2]; + + continue; + } + + p++; + } + + return NGX_DECLINED; + + found: + + width = p[6] * 256 + p[7]; + height = p[4] * 256 + p[5]; + + break; + + case NGX_HTTP_IMAGE_GIF: + + if (ctx->length < 10) { + return NGX_DECLINED; + } + + width = p[7] * 256 + p[6]; + height = p[9] * 256 + p[8]; + + break; + + case NGX_HTTP_IMAGE_PNG: + + if (ctx->length < 24) { + return NGX_DECLINED; + } + + width = p[18] * 256 + p[19]; + height = p[22] * 256 + p[23]; + + break; + + default: + + return NGX_DECLINED; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image size: %d x %d", width, height); + + ctx->width = width; + ctx->height = height; + + return NGX_OK; +} + + +static ngx_buf_t * +ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + int sx, sy, dx, dy, ox, oy, size, + colors, palette, transparent, + red, green, blue; + u_char *out; + ngx_buf_t *b; + ngx_uint_t resize; + gdImagePtr src, dst; + ngx_pool_cleanup_t *cln; + ngx_http_image_filter_conf_t *conf; + + src = ngx_http_image_source(r, ctx); + + if (src == NULL) { + return NULL; + } + + sx = gdImageSX(src); + sy = gdImageSY(src); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if ((ngx_uint_t) sx <= ctx->max_width + && (ngx_uint_t) sy <= ctx->max_height) + { + gdImageDestroy(src); + return ngx_http_image_asis(r, ctx); + } + + colors = gdImageColorsTotal(src); + + if (colors && conf->transparency) { + transparent = gdImageGetTransparent(src); + + if (transparent != -1) { + palette = colors; + red = gdImageRed(src, transparent); + green = gdImageGreen(src, transparent); + blue = gdImageBlue(src, transparent); + + goto transparent; + } + } + + palette = 0; + transparent = -1; + red = 0; + green = 0; + blue = 0; + +transparent: + + gdImageColorTransparent(src, -1); + + dx = sx; + dy = sy; + + if (conf->filter == NGX_HTTP_IMAGE_RESIZE) { + + if ((ngx_uint_t) dx > ctx->max_width) { + dy = dy * ctx->max_width / dx; + dy = dy ? dy : 1; + dx = ctx->max_width; + } + + if ((ngx_uint_t) dy > ctx->max_height) { + dx = dx * ctx->max_height / dy; + dx = dx ? dx : 1; + dy = ctx->max_height; + } + + resize = 1; + + } else { /* NGX_HTTP_IMAGE_CROP */ + + resize = 0; + + if ((ngx_uint_t) (dx * 100 / dy) + < ctx->max_width * 100 / ctx->max_height) + { + if ((ngx_uint_t) dx > ctx->max_width) { + dy = dy * ctx->max_width / dx; + dy = dy ? dy : 1; + dx = ctx->max_width; + resize = 1; + } + + } else { + if ((ngx_uint_t) dy > ctx->max_height) { + dx = dx * ctx->max_height / dy; + dx = dx ? dx : 1; + dy = ctx->max_height; + resize = 1; + } + } + } + + if (resize) { + dst = ngx_http_image_new(r, dx, dy, palette); + if (dst == NULL) { + gdImageDestroy(src); + return NULL; + } + + if (colors == 0) { + gdImageSaveAlpha(dst, 1); + gdImageAlphaBlending(dst, 0); + } + + gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy); + + if (colors) { + gdImageTrueColorToPalette(dst, 1, 256); + } + + gdImageDestroy(src); + + } else { + dst = src; + } + + if (conf->filter == NGX_HTTP_IMAGE_CROP) { + + src = dst; + + if ((ngx_uint_t) dx > ctx->max_width) { + ox = dx - ctx->max_width; + + } else { + ox = 0; + } + + if ((ngx_uint_t) dy > ctx->max_height) { + oy = dy - ctx->max_height; + + } else { + oy = 0; + } + + if (ox || oy) { + + dst = ngx_http_image_new(r, dx - ox, dy - oy, colors); + + if (dst == NULL) { + gdImageDestroy(src); + return NULL; + } + + ox /= 2; + oy /= 2; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image crop: %d x %d @ %d x %d", + dx, dy, ox, oy); + + if (colors == 0) { + gdImageSaveAlpha(dst, 1); + gdImageAlphaBlending(dst, 0); + } + + gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy); + + if (colors) { + gdImageTrueColorToPalette(dst, 1, 256); + } + + gdImageDestroy(src); + } + } + + if (transparent != -1 && colors) { + gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue)); + } + + out = ngx_http_image_out(r, ctx->type, dst, &size); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image: %d x %d %d", sx, sy, colors); + + gdImageDestroy(dst); + ngx_pfree(r->pool, ctx->image); + + if (out == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + gdFree(out); + return NULL; + } + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + gdFree(out); + return NULL; + } + + cln->handler = ngx_http_image_cleanup; + cln->data = out; + + b->pos = out; + b->last = out + size; + b->memory = 1; + b->last_buf = 1; + + ngx_http_image_length(r, b); + + return b; +} + + +static gdImagePtr +ngx_http_image_source(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + char *failed; + gdImagePtr img; + + img = NULL; + + switch (ctx->type) { + + case NGX_HTTP_IMAGE_JPEG: + img = gdImageCreateFromJpegPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromJpegPtr() failed"; + break; + + case NGX_HTTP_IMAGE_GIF: + img = gdImageCreateFromGifPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromGifPtr() failed"; + break; + + case NGX_HTTP_IMAGE_PNG: + img = gdImageCreateFromPngPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromPngPtr() failed"; + break; + + default: + failed = "unknown image type"; + break; + } + + if (img == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, failed); + } + + return img; +} + + +static gdImagePtr +ngx_http_image_new(ngx_http_request_t *r, int w, int h, int colors) +{ + gdImagePtr img; + + if (colors == 0) { + img = gdImageCreateTrueColor(w, h); + + if (img == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "gdImageCreateTrueColor() failed"); + return NULL; + } + + } else { + img = gdImageCreate(w, h); + + if (img == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "gdImageCreate() failed"); + return NULL; + } + } + + return img; +} + + +static u_char * +ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img, + int *size) +{ + char *failed; + u_char *out; + ngx_http_image_filter_conf_t *conf; + + out = NULL; + + switch (type) { + + case NGX_HTTP_IMAGE_JPEG: + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + out = gdImageJpegPtr(img, size, conf->jpeg_quality); + failed = "gdImageJpegPtr() failed"; + break; + + case NGX_HTTP_IMAGE_GIF: + out = gdImageGifPtr(img, size); + failed = "gdImageGifPtr() failed"; + break; + + case NGX_HTTP_IMAGE_PNG: + out = gdImagePngPtr(img, size); + failed = "gdImagePngPtr() failed"; + break; + + default: + failed = "unknown image type"; + break; + } + + if (out == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, failed); + } + + return out; +} + + +static void +ngx_http_image_cleanup(void *data) +{ + gdFree(data); +} + + +static ngx_uint_t +ngx_http_image_filter_get_value(ngx_http_request_t *r, + ngx_http_complex_value_t *cv, ngx_uint_t v) +{ + ngx_str_t val; + + if (cv == NULL) { + return v; + } + + if (ngx_http_complex_value(r, cv, &val) != NGX_OK) { + return 0; + } + + return ngx_http_image_filter_value(&val); +} + + +static ngx_uint_t +ngx_http_image_filter_value(ngx_str_t *value) +{ + ngx_int_t n; + + if (value->len == 1 && value->data[0] == '-') { + return (ngx_uint_t) -1; + } + + n = ngx_atoi(value->data, value->len); + + if (n > 0) { + return (ngx_uint_t) n; + } + + return 0; +} + + +static void * +ngx_http_image_filter_create_conf(ngx_conf_t *cf) +{ + ngx_http_image_filter_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_image_filter_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->filter = NGX_CONF_UNSET_UINT; + conf->jpeg_quality = NGX_CONF_UNSET; + conf->transparency = NGX_CONF_UNSET; + conf->buffer_size = NGX_CONF_UNSET_SIZE; + + return conf; +} + + +static char * +ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_image_filter_conf_t *prev = parent; + ngx_http_image_filter_conf_t *conf = child; + + if (conf->filter == NGX_CONF_UNSET_UINT) { + + if (prev->filter == NGX_CONF_UNSET_UINT) { + conf->filter = NGX_HTTP_IMAGE_OFF; + + } else { + conf->filter = prev->filter; + conf->width = prev->width; + conf->height = prev->height; + conf->wcv = prev->wcv; + conf->hcv = prev->hcv; + } + } + + /* 75 is libjpeg default quality */ + ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75); + + ngx_conf_merge_value(conf->transparency, prev->transparency, 1); + + ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, + 1 * 1024 * 1024); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_image_filter_conf_t *imcf = conf; + + ngx_str_t *value; + ngx_int_t n; + ngx_uint_t i; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + i = 1; + + if (cf->args->nelts == 2) { + if (ngx_strcmp(value[i].data, "off") == 0) { + imcf->filter = NGX_HTTP_IMAGE_OFF; + + } else if (ngx_strcmp(value[i].data, "test") == 0) { + imcf->filter = NGX_HTTP_IMAGE_TEST; + + } else if (ngx_strcmp(value[i].data, "size") == 0) { + imcf->filter = NGX_HTTP_IMAGE_SIZE; + + } else { + goto failed; + } + + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[i].data, "resize") == 0) { + imcf->filter = NGX_HTTP_IMAGE_RESIZE; + + } else if (ngx_strcmp(value[i].data, "crop") == 0) { + imcf->filter = NGX_HTTP_IMAGE_CROP; + + } else { + goto failed; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[++i]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths == NULL) { + n = ngx_http_image_filter_value(&value[i]); + + if (n == 0) { + goto failed; + } + + imcf->width = (ngx_uint_t) n; + + } else { + imcf->wcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (imcf->wcv == NULL) { + return NGX_CONF_ERROR; + } + + *imcf->wcv = cv; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[++i]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths == NULL) { + n = ngx_http_image_filter_value(&value[i]); + + if (n == 0) { + goto failed; + } + + imcf->height = (ngx_uint_t) n; + + } else { + imcf->hcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (imcf->hcv == NULL) { + return NGX_CONF_ERROR; + } + + *imcf->hcv = cv; + } + + return NGX_CONF_OK; + +failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", + &value[i]); + + return NGX_CONF_ERROR; +} + + +static ngx_int_t +ngx_http_image_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_image_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_image_body_filter; + + return NGX_OK; +} 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 @@ -83,13 +83,13 @@ ngx_module_t ngx_http_index_module = { /* - * Try to open the first index file before the test of the directory existence - * because the valid requests should be many more than invalid ones. - * If open() would fail, then stat() should be more quickly because some data - * is already cached in the kernel. - * Besides, Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR). - * Unix has ENOTDIR error, although it less helpfull - it points only - * that path contains the usual file in place of the directory. + * Try to open/test the first index file before the test of directory + * existence because valid requests should be much more than invalid ones. + * If the file open()/stat() would fail, then the directory stat() should + * be more quickly because some data is already cached in the kernel. + * Besides, Win32 may return ERROR_PATH_NOT_FOUND (NGX_ENOTDIR) at once. + * Unix has ENOTDIR error, however, it's less helpful than Win32's one: + * it only indicates that path contains an usual file in place of directory. */ static ngx_int_t @@ -116,7 +116,6 @@ ngx_http_index_handler(ngx_http_request_ return NGX_DECLINED; } - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } @@ -209,14 +208,15 @@ ngx_http_index_handler(ngx_http_request_ of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; + of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, + "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -240,8 +240,8 @@ ngx_http_index_handler(ngx_http_request_ continue; } - ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, + "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -292,6 +292,7 @@ ngx_http_index_test_dir(ngx_http_request ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.test_dir = 1; + of.test_only = 1; of.valid = clcf->open_file_cache_valid; of.errors = clcf->open_file_cache_errors; @@ -319,7 +320,7 @@ ngx_http_index_test_dir(ngx_http_request } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", dir.data); + "%s \"%s\" failed", of.failed, dir.data); } return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -365,7 +366,7 @@ ngx_http_index_create_loc_conf(ngx_conf_ conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->indices = NULL; diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -10,30 +10,39 @@ typedef struct { - u_char color; - u_char dummy; - u_short len; - ngx_queue_t queue; - ngx_msec_t last; - ngx_uint_t excess; /* integer value, 1 corresponds to 0.001 r/s */ - u_char data[1]; + u_char color; + u_char dummy; + u_short len; + ngx_queue_t queue; + ngx_msec_t last; + /* integer value, 1 corresponds to 0.001 r/s */ + ngx_uint_t excess; + u_char data[1]; } ngx_http_limit_req_node_t; typedef struct { - ngx_rbtree_t *rbtree; - ngx_queue_t *queue; - ngx_slab_pool_t *shpool; - ngx_uint_t rate; /* integer value, 1 corresponds to 0.001 r/s */ - ngx_int_t index; - ngx_str_t var; + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t queue; +} ngx_http_limit_req_shctx_t; + + +typedef struct { + ngx_http_limit_req_shctx_t *sh; + ngx_slab_pool_t *shpool; + /* integer value, 1 corresponds to 0.001 r/s */ + ngx_uint_t rate; + ngx_int_t index; + ngx_str_t var; } ngx_http_limit_req_ctx_t; typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_uint_t burst; /* integer value, 1 corresponds to 0.001 r/s */ - ngx_uint_t nodelay;/* unsigned nodelay:1 */ + ngx_shm_zone_t *shm_zone; + /* integer value, 1 corresponds to 0.001 r/s */ + ngx_uint_t burst; + ngx_uint_t nodelay;/* unsigned nodelay:1 */ } ngx_http_limit_req_conf_t; @@ -163,7 +172,7 @@ ngx_http_limit_req_handler(ngx_http_requ if (lr) { ngx_queue_remove(&lr->queue); - ngx_queue_insert_head(ctx->queue, &lr->queue); + ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); excess = lr->excess; @@ -172,14 +181,14 @@ ngx_http_limit_req_handler(ngx_http_requ } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); + "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); if (rc == NGX_BUSY) { ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "limiting requests, excess: %ui.%03ui by zone \"%V\"", - excess / 1000, excess % 1000, &lrcf->shm_zone->name); + excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); return NGX_HTTP_SERVICE_UNAVAILABLE; } @@ -193,7 +202,7 @@ ngx_http_limit_req_handler(ngx_http_requ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "delaying request, excess: %ui.%03ui, by zone \"%V\"", - excess / 1000, excess % 1000, &lrcf->shm_zone->name); + excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -239,9 +248,9 @@ ngx_http_limit_req_handler(ngx_http_requ lr->excess = 0; ngx_memcpy(lr->data, vv->data, len); - ngx_rbtree_insert(ctx->rbtree, node); + ngx_rbtree_insert(&ctx->sh->rbtree, node); - ngx_queue_insert_head(ctx->queue, &lr->queue); + ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); done: @@ -254,8 +263,23 @@ done: static void ngx_http_limit_req_delay(ngx_http_request_t *r) { + ngx_event_t *wev; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "limit_req delay"); + "limit_req delay"); + + wev = r->connection->write; + + if (!wev->timedout) { + + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + + return; + } + + wev->timedout = 0; if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -324,8 +348,8 @@ ngx_http_limit_req_lookup(ngx_http_limit ctx = lrcf->shm_zone->data; - node = ctx->rbtree->root; - sentinel = ctx->rbtree->sentinel; + node = ctx->sh->rbtree.root; + sentinel = ctx->sh->rbtree.sentinel; while (node != sentinel) { @@ -411,11 +435,11 @@ ngx_http_limit_req_expire(ngx_http_limit while (n < 3) { - if (ngx_queue_empty(ctx->queue)) { + if (ngx_queue_empty(&ctx->sh->queue)) { return; } - q = ngx_queue_last(ctx->queue); + q = ngx_queue_last(&ctx->sh->queue); lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); @@ -440,7 +464,7 @@ ngx_http_limit_req_expire(ngx_http_limit node = (ngx_rbtree_node_t *) ((u_char *) lr - offsetof(ngx_rbtree_node_t, color)); - ngx_rbtree_delete(ctx->rbtree, node); + ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); } @@ -453,7 +477,6 @@ ngx_http_limit_req_init_zone(ngx_shm_zon ngx_http_limit_req_ctx_t *octx = data; size_t len; - ngx_rbtree_node_t *sentinel; ngx_http_limit_req_ctx_t *ctx; ctx = shm_zone->data; @@ -463,12 +486,11 @@ ngx_http_limit_req_init_zone(ngx_shm_zon ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "limit_req \"%V\" uses the \"%V\" variable " "while previously it used the \"%V\" variable", - &shm_zone->name, &ctx->var, &octx->var); + &shm_zone->shm.name, &ctx->var, &octx->var); return NGX_ERROR; } - ctx->rbtree = octx->rbtree; - ctx->queue = octx->queue; + ctx->sh = octx->sh; ctx->shpool = octx->shpool; return NGX_OK; @@ -476,27 +498,25 @@ ngx_http_limit_req_init_zone(ngx_shm_zon ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - ctx->rbtree = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_t)); - if (ctx->rbtree == NULL) { - return NGX_ERROR; + if (shm_zone->shm.exists) { + ctx->sh = ctx->shpool->data; + + return NGX_OK; } - sentinel = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { + ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t)); + if (ctx->sh == NULL) { return NGX_ERROR; } - ngx_rbtree_init(ctx->rbtree, sentinel, + ctx->shpool->data = ctx->sh; + + ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, ngx_http_limit_req_rbtree_insert_value); - ctx->queue = ngx_slab_alloc(ctx->shpool, sizeof(ngx_queue_t)); - if (ctx->queue == NULL) { - return NGX_ERROR; - } + ngx_queue_init(&ctx->sh->queue); - ngx_queue_init(ctx->queue); - - len = sizeof(" in limit_req zone \"\"") + shm_zone->name.len; + len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len; ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); if (ctx->shpool->log_ctx == NULL) { @@ -504,7 +524,7 @@ ngx_http_limit_req_init_zone(ngx_shm_zon } ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", - &shm_zone->name); + &shm_zone->shm.name); return NGX_OK; } @@ -517,7 +537,7 @@ ngx_http_limit_req_create_conf(ngx_conf_ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -574,6 +594,8 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, p = (u_char *) ngx_strchr(name.data, ':'); if (p) { + *p = '\0'; + name.len = p - name.data; p++; @@ -744,7 +766,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c if (lrcf->shm_zone->data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unknown limit_req_zone \"%V\"", - &lrcf->shm_zone->name); + &lrcf->shm_zone->shm.name); return NGX_CONF_ERROR; } 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 @@ -191,7 +191,7 @@ ngx_http_limit_zone_handler(ngx_http_req ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "limiting connections by zone \"%V\"", - &lzcf->shm_zone->name); + &lzcf->shm_zone->shm.name); return NGX_HTTP_SERVICE_UNAVAILABLE; } @@ -328,7 +328,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "limit_zone \"%V\" uses the \"%V\" variable " "while previously it used the \"%V\" variable", - &shm_zone->name, &ctx->var, &octx->var); + &shm_zone->shm.name, &ctx->var, &octx->var); return NGX_ERROR; } @@ -339,11 +339,19 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + if (shm_zone->shm.exists) { + ctx->rbtree = shpool->data; + + return NGX_OK; + } + ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); if (ctx->rbtree == NULL) { return NGX_ERROR; } + shpool->data = ctx->rbtree; + sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); if (sentinel == NULL) { return NGX_ERROR; @@ -352,14 +360,15 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo ngx_rbtree_init(ctx->rbtree, sentinel, ngx_http_limit_zone_rbtree_insert_value); - len = sizeof(" in limit_zone \"\"") + shm_zone->name.len; + len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len; shpool->log_ctx = ngx_slab_alloc(shpool, len); if (shpool->log_ctx == NULL) { return NGX_ERROR; } - ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", &shm_zone->name); + ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", + &shm_zone->shm.name); return NGX_OK; } @@ -372,7 +381,7 @@ ngx_http_limit_zone_create_conf(ngx_conf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -385,6 +385,8 @@ ngx_http_log_script_write(ngx_http_reque of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; + of.test_dir = 1; + of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; @@ -439,7 +441,7 @@ ngx_http_log_script_write(ngx_http_reque != NGX_OK) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", log.data); + "%s \"%s\" failed", of.failed, log.data); /* simulate successfull logging */ return len; } @@ -674,7 +676,7 @@ ngx_http_log_escape(u_char *dst, u_char /* find the number of the characters to be escaped */ - n = 0; + n = 0; for (i = 0; i < size; i++) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { @@ -712,18 +714,18 @@ ngx_http_log_create_main_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } fmt = ngx_array_push(&conf->formats); if (fmt == NULL) { - return NGX_CONF_ERROR; + return NULL; } fmt->name.len = sizeof("combined") - 1; @@ -733,7 +735,7 @@ ngx_http_log_create_main_conf(ngx_conf_t fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t)); if (fmt->ops == NULL) { - return NGX_CONF_ERROR; + return NULL; } return conf; @@ -747,7 +749,7 @@ ngx_http_log_create_loc_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->open_file_cache = NGX_CONF_UNSET_PTR; @@ -835,7 +837,13 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx if (ngx_strcmp(value[1].data, "off") == 0) { llcf->off = 1; - return NGX_CONF_OK; + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; } if (llcf->logs == NULL) { 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 @@ -160,7 +160,7 @@ ngx_http_map_create_conf(ngx_conf_t *cf) mcf = ngx_palloc(cf->pool, sizeof(ngx_http_map_conf_t)); if (mcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } mcf->hash_max_size = NGX_CONF_UNSET_UINT; @@ -337,7 +337,7 @@ ngx_http_map_cmp_dns_wildcards(const voi first = (ngx_hash_key_t *) one; second = (ngx_hash_key_t *) two; - return ngx_strcmp(first->key.data, second->key.data); + return ngx_dns_strcmp(first->key.data, second->key.data); } 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 @@ -176,23 +176,18 @@ ngx_http_memcached_handler(ngx_http_requ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); - - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); - if (u == NULL) { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + u = r->upstream; + u->schema.len = sizeof("memcached://") - 1; u->schema.data = (u_char *) "memcached://"; - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif + u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; - u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); u->conf = &mlcf->upstream; @@ -202,8 +197,6 @@ ngx_http_memcached_handler(ngx_http_requ u->abort_request = ngx_http_memcached_abort_request; u->finalize_request = ngx_http_memcached_finalize_request; - r->upstream = u; - ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -218,6 +211,8 @@ ngx_http_memcached_handler(ngx_http_requ u->input_filter = ngx_http_memcached_filter; u->input_filter_ctx = ctx; + r->main->count++; + ngx_http_upstream_init(r); return NGX_DONE; @@ -513,7 +508,7 @@ ngx_http_memcached_create_loc_conf(ngx_c conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -47,8 +47,8 @@ ngx_module_t ngx_http_not_modified_filt static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static -ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r) +static ngx_int_t +ngx_http_not_modified_header_filter(ngx_http_request_t *r) { time_t ims; ngx_http_core_loc_conf_t *clcf; @@ -92,8 +92,8 @@ ngx_int_t ngx_http_not_modified_header_f } -static -ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf) +static ngx_int_t +ngx_http_not_modified_filter_init(ngx_conf_t *cf) { ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_not_modified_header_filter; 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 @@ -64,6 +64,10 @@ typedef struct { ngx_str_t location; ngx_str_t url; +#if (NGX_HTTP_CACHE) + ngx_http_complex_value_t cache_key; +#endif + ngx_http_proxy_vars_t vars; ngx_flag_t redirect; @@ -132,6 +136,8 @@ static char *ngx_http_proxy_store(ngx_co #if (NGX_HTTP_CACHE) static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); #endif static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -161,11 +167,21 @@ static ngx_conf_bitmask_t ngx_http_prox { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 }, { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, { ngx_null_string, 0 } }; +static ngx_conf_bitmask_t ngx_http_proxy_ignore_headers_masks[] = { + { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT }, + { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES }, + { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES }, + { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL }, + { ngx_null_string, 0 } +}; + + ngx_module_t ngx_http_proxy_module; @@ -327,6 +343,13 @@ static ngx_command_t ngx_http_proxy_com 0, NULL }, + { ngx_string("proxy_cache_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_http_proxy_cache_key, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, @@ -355,6 +378,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale), &ngx_http_proxy_next_upstream_masks }, + { ngx_string("proxy_cache_methods"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods), + &ngx_http_upstream_cache_method_mask }, + #endif { ngx_string("proxy_temp_path"), @@ -413,6 +443,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers), NULL }, + { ngx_string("proxy_ignore_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers), + &ngx_http_proxy_ignore_headers_masks }, + #if (NGX_HTTP_SSL) { ngx_string("proxy_ssl_session_reuse"), @@ -484,6 +521,40 @@ static ngx_str_t ngx_http_proxy_hide_he }; +#if (NGX_HTTP_CACHE) + +static ngx_keyval_t ngx_http_proxy_cache_headers[] = { + { ngx_string("Host"), ngx_string("$proxy_host") }, + { ngx_string("Connection"), ngx_string("close") }, + { ngx_string("Keep-Alive"), ngx_string("") }, + { ngx_string("Expect"), ngx_string("") }, + { ngx_string("If-Modified-Since"), ngx_string("") }, + { ngx_string("If-Unmodified-Since"), ngx_string("") }, + { ngx_string("If-Match-None"), ngx_string("") }, + { ngx_string("If-Match"), ngx_string("") }, + { ngx_string("Range"), ngx_string("") }, + { ngx_string("If-Range"), ngx_string("") }, + { ngx_null_string, ngx_null_string } +}; + + +static ngx_str_t ngx_http_proxy_hide_cache_headers[] = { + ngx_string("Date"), + ngx_string("Server"), + ngx_string("X-Pad"), + ngx_string("X-Accel-Expires"), + ngx_string("X-Accel-Redirect"), + ngx_string("X-Accel-Limit-Rate"), + ngx_string("X-Accel-Buffering"), + ngx_string("X-Accel-Charset"), + ngx_string("Set-Cookie"), + ngx_string("P3P"), + ngx_null_string +}; + +#endif + + static ngx_http_variable_t ngx_http_proxy_vars[] = { { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0, @@ -519,13 +590,10 @@ ngx_http_proxy_handler(ngx_http_request_ ngx_http_proxy_ctx_t *ctx; ngx_http_proxy_loc_conf_t *plcf; - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); - if (u == NULL) { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->upstream = u; - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -535,6 +603,8 @@ ngx_http_proxy_handler(ngx_http_request_ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + u = r->upstream; + if (plcf->proxy_lengths == 0) { ctx->vars = plcf->vars; u->schema = plcf->vars.schema; @@ -548,12 +618,6 @@ ngx_http_proxy_handler(ngx_http_request_ } } - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif - u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; u->conf = &plcf->upstream; @@ -715,6 +779,15 @@ ngx_http_proxy_create_key(ngx_http_reque return NGX_ERROR; } + if (plcf->cache_key.value.len) { + + if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; + } + *key = ctx->vars.key_start; key = ngx_array_push(&r->cache->keys); @@ -1804,15 +1877,17 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* * set by ngx_pcalloc(): * * conf->upstream.bufs.num = 0; + * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; - * conf->upstream.use_stale_cache = 0; + * conf->upstream.cache_use_stale = 0; + * conf->upstream.cache_methods = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.uri = { 0, NULL }; @@ -1884,6 +1959,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_http_proxy_loc_conf_t *conf = child; size_t size; + ngx_str_t *h; ngx_keyval_t *s; ngx_hash_init_t hash; ngx_http_proxy_redirect_t *pr; @@ -1891,7 +1967,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t if (conf->upstream.store != 0) { ngx_conf_merge_value(conf->upstream.store, - prev->upstream.store, 0); + prev->upstream.store, 0); if (conf->upstream.store_lengths == NULL) { conf->upstream.store_lengths = prev->upstream.store_lengths; @@ -2015,6 +2091,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } + ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, + prev->upstream.ignore_headers, + NGX_CONF_BITMASK_SET); + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, prev->upstream.next_upstream, (NGX_CONF_BITMASK_SET @@ -2047,7 +2128,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_cache\" zone \"%V\" is unknown", - &shm_zone->name); + &shm_zone->shm.name); return NGX_CONF_ERROR; } @@ -2060,6 +2141,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t (NGX_CONF_BITMASK_SET |NGX_HTTP_UPSTREAM_FT_OFF)); + if (conf->upstream.cache_methods == 0) { + conf->upstream.cache_methods = prev->upstream.cache_methods; + } + + conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; + if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) { conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET |NGX_HTTP_UPSTREAM_FT_OFF; @@ -2068,6 +2155,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_conf_merge_ptr_value(conf->upstream.cache_valid, prev->upstream.cache_valid, NULL); + if (conf->cache_key.value.data == NULL) { + conf->cache_key = prev->cache_key; + } + #endif if (conf->method.len == 0) { @@ -2131,6 +2222,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t conf->proxy_values = prev->proxy_values; } +#if (NGX_HTTP_SSL) + if (conf->upstream.ssl == NULL) { + conf->upstream.ssl = prev->upstream.ssl; + } +#endif + ngx_conf_merge_uint_value(conf->headers_hash_max_size, prev->headers_hash_max_size, 512); @@ -2144,9 +2241,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t hash.bucket_size = conf->headers_hash_bucket_size; hash.name = "proxy_headers_hash"; +#if (NGX_HTTP_CACHE) + + h = conf->upstream.cache ? ngx_http_proxy_hide_cache_headers: + ngx_http_proxy_hide_headers; +#else + + h = ngx_http_proxy_hide_headers; + +#endif + if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, - &prev->upstream, - ngx_http_proxy_hide_headers, &hash) + &prev->upstream, h, &hash) != NGX_OK) { return NGX_CONF_ERROR; @@ -2229,7 +2335,12 @@ ngx_http_proxy_merge_headers(ngx_conf_t conf->headers_source = prev->headers_source; } - if (conf->headers_set_hash.buckets) { + if (conf->headers_set_hash.buckets +#if (NGX_HTTP_CACHE) + && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) +#endif + ) + { return NGX_OK; } @@ -2260,7 +2371,17 @@ ngx_http_proxy_merge_headers(ngx_conf_t src = conf->headers_source->elts; - for (h = ngx_http_proxy_headers; h->key.len; h++) { +#if (NGX_HTTP_CACHE) + + h = conf->upstream.cache ? ngx_http_proxy_cache_headers: + ngx_http_proxy_headers; +#else + + h = ngx_http_proxy_headers; + +#endif + + while (h->key.len) { for (i = 0; i < conf->headers_source->nelts; i++) { if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { @@ -2279,7 +2400,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t next: - continue; + h++; } @@ -2464,6 +2585,12 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_proxy_handler; + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + value = cf->args->elts; url = &value[1]; @@ -2492,8 +2619,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ } #endif - clcf->handler = ngx_http_proxy_handler; - return NGX_CONF_OK; } @@ -2540,8 +2665,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ ngx_http_proxy_set_vars(&u, &plcf->vars); - clcf->handler = ngx_http_proxy_handler; - plcf->location = clcf->name; if (clcf->named @@ -2565,10 +2688,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ plcf->url = *url; - if (clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - return NGX_CONF_OK; } @@ -2589,10 +2708,26 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, value = cf->args->elts; - if (ngx_strcmp(value[1].data, "off") == 0) { - plcf->redirect = 0; - plcf->redirects = NULL; - return NGX_CONF_OK; + if (cf->args->nelts == 2) { + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->redirect = 0; + plcf->redirects = NULL; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "false") == 0) { + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, + "invalid parameter \"false\", use \"off\" instead"); + plcf->redirect = 0; + plcf->redirects = NULL; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "default") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } } if (plcf->redirects == NULL) { @@ -2608,7 +2743,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, return NGX_CONF_ERROR; } - if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) { + if (ngx_strcmp(value[1].data, "default") == 0) { if (plcf->url.data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_rewrite_location default\" must go " @@ -2671,20 +2806,31 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx ngx_str_t *value; ngx_http_script_compile_t sc; - if (plcf->upstream.store != NGX_CONF_UNSET || plcf->upstream.store_lengths) + if (plcf->upstream.store != NGX_CONF_UNSET + || plcf->upstream.store_lengths) { return "is duplicate"; } value = cf->args->elts; - if (ngx_strcmp(value[1].data, "on") == 0) { - plcf->upstream.store = 1; + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->upstream.store = 0; return NGX_CONF_OK; } - if (ngx_strcmp(value[1].data, "off") == 0) { - plcf->upstream.store = 0; +#if (NGX_HTTP_CACHE) + + if (plcf->upstream.cache != NGX_CONF_UNSET_PTR + && plcf->upstream.cache != NULL) + { + return "is incompatible with \"proxy_cache\""; + } + +#endif + + if (ngx_strcmp(value[1].data, "on") == 0) { + plcf->upstream.store = 1; return NGX_CONF_OK; } @@ -2729,6 +2875,10 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx return NGX_CONF_OK; } + if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) { + return "is incompatible with \"proxy_store\""; + } + plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_proxy_module); if (plcf->upstream.cache == NULL) { @@ -2738,6 +2888,34 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx return NGX_CONF_OK; } + +static char * +ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + if (plcf->cache_key.value.len) { + return "is duplicate"; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &plcf->cache_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + #endif diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c --- a/src/http/modules/ngx_http_random_index_module.c +++ b/src/http/modules/ngx_http_random_index_module.c @@ -86,7 +86,6 @@ ngx_http_random_index_handler(ngx_http_r return NGX_DECLINED; } - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } @@ -281,7 +280,7 @@ ngx_http_random_index_create_loc_conf(ng conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->enable = NGX_CONF_UNSET; 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 @@ -456,6 +456,8 @@ ngx_http_range_multipart_header(ngx_http return NGX_ERROR; } + r->headers_out.content_type_lowcase = NULL; + /* "Content-Type: multipart/byteranges; boundary=0123456789" */ r->headers_out.content_type.len = @@ -464,6 +466,7 @@ ngx_http_range_multipart_header(ngx_http boundary) - r->headers_out.content_type.data; + r->headers_out.content_type_len = r->headers_out.content_type.len; /* the size of the last boundary CRLF "--0123456789--" CRLF */ 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 @@ -360,7 +360,7 @@ ngx_http_realip_create_loc_conf(ngx_conf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -221,7 +221,7 @@ ngx_http_referer_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } #if (NGX_PCRE) @@ -506,6 +506,11 @@ ngx_http_add_regex_referer(ngx_conf_t *c ngx_regex_elt_t *re; u_char errstr[NGX_MAX_CONF_ERRSTR]; + if (name->len == 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name); + return NGX_CONF_ERROR; + } + if (rlcf->regex == NGX_CONF_UNSET_PTR) { rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t)); if (rlcf->regex == NULL) { @@ -562,5 +567,5 @@ ngx_http_cmp_referer_wildcards(const voi first = (ngx_hash_key_t *) one; second = (ngx_hash_key_t *) two; - return ngx_strcmp(first->key.data, second->key.data); + return ngx_dns_strcmp(first->key.data, second->key.data); } 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 @@ -220,7 +220,7 @@ ngx_http_rewrite_create_loc_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->stack_size = NGX_CONF_UNSET_UINT; @@ -568,7 +568,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t)); if (if_code == NULL) { - return NULL; + return NGX_CONF_ERROR; } if_code->code = ngx_http_script_if_code; diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -152,7 +152,7 @@ ngx_http_secure_link_create_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -360,6 +360,7 @@ ngx_http_ssi_header_filter(ngx_http_requ if (r == r->main) { ngx_http_clear_content_length(r); ngx_http_clear_last_modified(r); + ngx_http_clear_accept_ranges(r); } return ngx_http_next_header_filter(r); @@ -2689,14 +2690,14 @@ ngx_http_ssi_create_main_conf(ngx_conf_t smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_main_conf_t)); if (smcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } smcf->commands.pool = cf->pool; smcf->commands.temp_pool = cf->temp_pool; if (ngx_hash_keys_array_init(&smcf->commands, NGX_HASH_SMALL) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return smcf; @@ -2736,7 +2737,7 @@ ngx_http_ssi_create_loc_conf(ngx_conf_t slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_loc_conf_t)); if (slcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -31,15 +31,6 @@ static char *ngx_http_ssl_enable(ngx_con static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -static char ngx_http_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; - -#endif - static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, @@ -52,7 +43,7 @@ static ngx_conf_bitmask_t ngx_http_ssl_ static ngx_conf_enum_t ngx_http_ssl_verify[] = { { ngx_string("off"), 0 }, { ngx_string("on"), 1 }, - { ngx_string("ask"), 2 }, + { ngx_string("optional"), 2 }, { ngx_null_string, 0 } }; @@ -124,14 +115,10 @@ static ngx_command_t ngx_http_ssl_comma { ngx_string("ssl_prefer_server_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE ngx_conf_set_flag_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers), NULL }, -#else - ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 }, -#endif { ngx_string("ssl_session_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12, @@ -147,6 +134,13 @@ static ngx_command_t ngx_http_ssl_comma offsetof(ngx_http_ssl_srv_conf_t, session_timeout), NULL }, + { ngx_string("ssl_crl"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, crl), + NULL }, + ngx_null_command }; @@ -206,6 +200,9 @@ static ngx_http_variable_t ngx_http_ssl { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -302,7 +299,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)); if (sscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -313,6 +310,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t * sscf->certificate_key = { 0, NULL }; * sscf->dhparam = { 0, NULL }; * sscf->client_certificate = { 0, NULL }; + * sscf->crl = { 0, NULL }; * sscf->ciphers.len = 0; * sscf->ciphers.data = NULL; * sscf->shm_zone = NULL; @@ -320,8 +318,8 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; - sscf->verify = NGX_CONF_UNSET; - sscf->verify_depth = NGX_CONF_UNSET; + sscf->verify = NGX_CONF_UNSET_UINT; + sscf->verify_depth = NGX_CONF_UNSET_UINT; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; @@ -359,6 +357,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, ""); + ngx_conf_merge_str_value(conf->crl, prev->crl, ""); ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); @@ -407,9 +406,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_http_ssl_servername) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_tlsext_servername_callback() failed"); - return NGX_CONF_ERROR; + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "nginx was build with SNI support, however, now it is linked " + "dynamically to an OpenSSL library which has no tlsext support, " + "therefore SNI is not available"); } #endif @@ -453,16 +453,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * { return NGX_CONF_ERROR; } + + if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) { + return NGX_CONF_ERROR; + } } -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (conf->prefer_server_ciphers) { SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#endif - /* a temporary 512-bit RSA key is required for export versions of MSIE */ if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { return NGX_CONF_ERROR; @@ -564,6 +564,7 @@ ngx_http_ssl_session_cache(ngx_conf_t *c for (j = sizeof("shared:") - 1; j < value[i].len; j++) { if (value[i].data[j] == ':') { + value[i].data[j] = '\0'; break; } @@ -619,18 +620,3 @@ invalid: return NGX_CONF_ERROR; } - - -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char * -ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" directive is available only in %s,", - &cmd->name, cmd->post); - - return NGX_CONF_ERROR; -} - -#endif 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 @@ -33,6 +33,7 @@ typedef struct { ngx_str_t certificate_key; ngx_str_t dhparam; ngx_str_t client_certificate; + ngx_str_t crl; ngx_str_t ciphers; 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 @@ -66,7 +66,6 @@ ngx_http_static_handler(ngx_http_request return NGX_DECLINED; } - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; } @@ -129,7 +128,7 @@ ngx_http_static_handler(ngx_http_request if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + "%s \"%s\" failed", of.failed, path.data); } return rc; 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 @@ -638,7 +638,7 @@ ngx_http_sub_create_conf(ngx_conf_t *cf) slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t)); if (slcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -390,12 +390,13 @@ ngx_http_userid_set_uid(ngx_http_request } else { if (conf->service == NGX_CONF_UNSET) { - if (ngx_http_server_addr(r, NULL) != NGX_OK) { + + c = r->connection; + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { return NGX_ERROR; } - c = r->connection; - switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) @@ -569,7 +570,7 @@ ngx_http_userid_create_conf(ngx_conf_t * conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -64,7 +64,6 @@ typedef struct { static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); -static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r); static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); @@ -195,7 +194,7 @@ ngx_module_t ngx_http_xslt_filter_modul NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ - ngx_http_xslt_filter_exit, /* exit process */ + ngx_http_xslt_filter_exit, /* exit process */ ngx_http_xslt_filter_exit, /* exit master */ NGX_MODULE_V1_PADDING }; @@ -248,6 +247,7 @@ ngx_http_xslt_header_filter(ngx_http_req static ngx_int_t ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { + int wellFormed; ngx_chain_t *cl; ngx_http_xslt_filter_ctx_t *ctx; @@ -281,7 +281,7 @@ ngx_http_xslt_body_filter(ngx_http_reque return ngx_http_xslt_send(r, ctx, NULL); } - if (cl->buf->last_buf) { + if (cl->buf->last_buf || cl->buf->last_in_chain) { ctx->doc = ctx->ctxt->myDoc; @@ -289,9 +289,11 @@ ngx_http_xslt_body_filter(ngx_http_reque ctx->doc->extSubset = NULL; #endif + wellFormed = ctx->ctxt->wellFormed; + xmlFreeParserCtxt(ctx->ctxt); - if (ctx->ctxt->wellFormed) { + if (wellFormed) { return ngx_http_xslt_send(r, ctx, ngx_http_xslt_apply_stylesheet(r, ctx)); } @@ -320,14 +322,15 @@ ngx_http_xslt_send(ngx_http_request_t *r ctx->done = 1; if (b == NULL) { - return ngx_http_xslt_filter_internal_error(r); + return ngx_http_filter_finalize_request(r, NULL, + NGX_HTTP_INTERNAL_SERVER_ERROR); } cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { ngx_free(b->pos); - return ngx_http_special_response_handler(r, + return ngx_http_filter_finalize_request(r, NULL, NGX_HTTP_INTERNAL_SERVER_ERROR); } @@ -360,22 +363,6 @@ ngx_http_xslt_send(ngx_http_request_t *r static ngx_int_t -ngx_http_xslt_filter_internal_error(ngx_http_request_t *r) -{ - ngx_int_t rc; - - /* clear the modules contexts */ - ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); - - rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - - /* NGX_ERROR resets any pending data */ - - return (rc == NGX_OK) ? NGX_ERROR : rc; -} - - -static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b) { @@ -417,7 +404,7 @@ ngx_http_xslt_add_chunk(ngx_http_request sax->endElementNs = ngx_http_xslt_sax_end_element; sax->characters = ngx_http_xslt_sax_characters; - sax->ignorableWhitespace = ngx_http_xslt_sax_characters; + sax->ignorableWhitespace = ngx_http_xslt_sax_characters; sax->cdataBlock = ngx_http_xslt_sax_cdata_block; sax->getEntity = ngx_http_xslt_sax_get_entity; sax->resolveEntity = ngx_http_xslt_sax_resolve_entity; @@ -443,8 +430,8 @@ ngx_http_xslt_add_chunk(ngx_http_request ctx->request = r; } - err = xmlParseChunk(ctx->ctxt, (char *) b->pos, - (int) (b->last - b->pos), b->last_buf); + err = xmlParseChunk(ctx->ctxt, (char *) b->pos, (int) (b->last - b->pos), + (b->last_buf) || (b->last_in_chain)); if (err == 0) { b->pos = b->last; @@ -733,7 +720,7 @@ ngx_http_xslt_sax_error(void *data, cons while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ } ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, - "libxml2 error: \"%*s\"", n, buf); + "libxml2 error: \"%*s\"", n + 1, buf); } @@ -828,7 +815,6 @@ ngx_http_xslt_apply_stylesheet(ngx_http_ b->pos = buf; b->last = buf + len; b->memory = 1; - b->last_buf = 1; if (encoding) { r->headers_out.charset.len = ngx_strlen(encoding); @@ -839,6 +825,8 @@ ngx_http_xslt_apply_stylesheet(ngx_http_ return b; } + b->last_buf = 1; + if (type) { len = ngx_strlen(type); @@ -853,6 +841,8 @@ ngx_http_xslt_apply_stylesheet(ngx_http_ r->headers_out.content_type.data = (u_char *) "text/html"; } + r->headers_out.content_type_lowcase = NULL; + return b; } @@ -1182,7 +1172,7 @@ ngx_http_xslt_filter_create_main_conf(ng conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&conf->dtd_files, cf->pool, 1, @@ -1210,7 +1200,7 @@ ngx_http_xslt_filter_create_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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.7.47'; +our $VERSION = '0.8.16'; 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 @@ -607,7 +607,7 @@ sendfile(r, filename, offset = -1, bytes ngx_http_request_t *r; char *filename; - int offset; + off_t offset; size_t bytes; ngx_str_t path; ngx_buf_t *b; @@ -662,7 +662,7 @@ sendfile(r, filename, offset = -1, bytes } ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", filename); + "%s \"%s\" failed", of.failed, filename); XSRETURN_EMPTY; } 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 @@ -154,10 +154,14 @@ static ngx_http_ssi_command_t ngx_http_ #endif -static ngx_str_t ngx_null_name = ngx_null_string; +static ngx_str_t ngx_null_name = ngx_null_string; + +static HV *nginx_stash; +#if (NGX_HAVE_PERL_MULTIPLICITY) +static ngx_uint_t ngx_perl_term; +#endif -static HV *nginx_stash; static void ngx_http_perl_xs_init(pTHX) @@ -171,11 +175,12 @@ ngx_http_perl_xs_init(pTHX) static ngx_int_t ngx_http_perl_handler(ngx_http_request_t *r) { - /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_HTTP_NOT_FOUND; } + r->main->count++; + ngx_http_perl_handle_request(r); return NGX_DONE; @@ -229,7 +234,11 @@ ngx_http_perl_handle_request(ngx_http_re } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "perl handler done: %i", rc); + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); return; } @@ -237,9 +246,6 @@ ngx_http_perl_handle_request(ngx_http_re rc = NGX_OK; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "perl handler done: %i", rc); - if (ctx->redirect_uri.len) { uri = ctx->redirect_uri; args = ctx->redirect_args; @@ -252,11 +258,13 @@ ngx_http_perl_handle_request(ngx_http_re ctx->redirect_uri.len = 0; if (ctx->done || ctx->next) { + ngx_http_finalize_request(r, NGX_DONE); return; } if (uri.len) { ngx_http_internal_redirect(r, &uri, &args); + ngx_http_finalize_request(r, NGX_DONE); return; } @@ -683,15 +691,6 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt SPAGAIN; - if (c->destroyed) { - PUTBACK; - - FREETMPS; - LEAVE; - - return NGX_DONE; - } - if (n) { if (rv == NULL) { status = POPi; @@ -762,7 +761,10 @@ ngx_http_perl_eval_anon_sub(pTHX_ ngx_st } } - if (ngx_strncmp(p, "sub ", 4) == 0 || ngx_strncmp(p, "use ", 4) == 0) { + if (ngx_strncmp(p, "sub ", 4) == 0 + || ngx_strncmp(p, "sub{", 4) == 0 + || ngx_strncmp(p, "use ", 4) == 0) + { *sv = eval_pv((char *) p, FALSE); /* eval_pv() does not set ERRSV on failure */ @@ -781,7 +783,7 @@ ngx_http_perl_create_main_conf(ngx_conf_ pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t)); if (pmcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *)) @@ -821,6 +823,12 @@ ngx_http_perl_cleanup_perl(void *data) (void) perl_destruct(perl); perl_free(perl); + + if (ngx_perl_term) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "perl term"); + + PERL_SYS_TERM(); + } } #endif @@ -860,7 +868,7 @@ ngx_http_perl_create_loc_conf(ngx_conf_t plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t)); if (plcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -1041,15 +1049,13 @@ ngx_http_perl_init_worker(ngx_cycle_t *c pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module); - { - - dTHXa(pmcf->perl); - PERL_SET_CONTEXT(pmcf->perl); + if (pmcf) { + dTHXa(pmcf->perl); + PERL_SET_CONTEXT(pmcf->perl); - /* set worker's $$ */ + /* set worker's $$ */ - sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid); - + sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid); } return NGX_OK; @@ -1059,16 +1065,24 @@ ngx_http_perl_init_worker(ngx_cycle_t *c static void ngx_http_perl_exit(ngx_cycle_t *cycle) { +#if (NGX_HAVE_PERL_MULTIPLICITY) + + ngx_perl_term = 1; + +#else ngx_http_perl_main_conf_t *pmcf; pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module); - { + if (pmcf && nginx_stash) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term"); - dTHXa(pmcf->perl); - PERL_SET_CONTEXT(pmcf->perl); + (void) perl_destruct(pmcf->perl); - PERL_SYS_TERM(); + perl_free(pmcf->perl); + PERL_SYS_TERM(); } + +#endif } 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 @@ -18,7 +18,7 @@ static ngx_int_t ngx_http_init_phase_han ngx_http_core_main_conf_t *cmcf); static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf, - ngx_array_t *servers, ngx_array_t *in_ports); + ngx_array_t *servers, ngx_array_t *ports); static ngx_int_t ngx_http_add_ports(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_array_t *ports, ngx_http_listen_t *listen); @@ -122,7 +122,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma char *rv; ngx_uint_t mi, m, s; ngx_conf_t pcf; - ngx_array_t in_ports; + ngx_array_t ports; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; @@ -367,14 +367,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * to find quickly the server core module configuration at run-time */ - if (ngx_http_init_server_lists(cf, &cmcf->servers, &in_ports) != NGX_OK) { + if (ngx_http_init_server_lists(cf, &cmcf->servers, &ports) != NGX_OK) { return NGX_CONF_ERROR; } /* optimize the lists of ports, addresses and server names */ - if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) { + if (ngx_http_optimize_servers(cf, cmcf, &ports) != NGX_OK) { return NGX_CONF_ERROR; } @@ -1180,12 +1180,12 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h continue; } - /* a port is already in the in_port list */ + /* a port is already in the port list */ return ngx_http_add_addresses(cf, cscf, &port[i], listen); } - /* add a port to the in_port list */ + /* add a port to the port list */ port = ngx_array_push(ports); if (port == NULL) { @@ -1279,7 +1279,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n /* * add the server address, the server names and the server core module - * configurations to the port (in_port) + * configurations to the port list */ static ngx_int_t @@ -1373,10 +1373,10 @@ static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports) { - ngx_uint_t s, p, a; - ngx_http_conf_port_t *port; - ngx_http_conf_addr_t *addr; - ngx_http_server_name_t *name; + ngx_uint_t s, p, a; + ngx_http_conf_port_t *port; + ngx_http_conf_addr_t *addr; + ngx_http_server_name_t *name; port = ports->elts; for (p = 0; p < ports->nelts; p++) { @@ -1425,13 +1425,13 @@ static ngx_int_t ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr) { - ngx_int_t rc; - ngx_uint_t s; - ngx_hash_init_t hash; - ngx_http_server_name_t *name; - ngx_hash_keys_arrays_t ha; + ngx_int_t rc; + ngx_uint_t s; + ngx_hash_init_t hash; + ngx_hash_keys_arrays_t ha; + ngx_http_server_name_t *name; #if (NGX_PCRE) - ngx_uint_t regex, i; + ngx_uint_t regex, i; regex = 0; #endif @@ -1601,7 +1601,7 @@ ngx_http_cmp_dns_wildcards(const void *o first = (ngx_hash_key_t *) one; second = (ngx_hash_key_t *) two; - return ngx_strcmp(first->key.data, second->key.data); + return ngx_dns_strcmp(first->key.data, second->key.data); } @@ -1688,54 +1688,14 @@ static ngx_listening_t * ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) { ngx_listening_t *ls; - struct sockaddr *sa; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - u_char text[NGX_SOCKADDR_STRLEN]; - ls = ngx_array_push(&cf->cycle->listening); + ls = ngx_create_listening(cf, addr->sockaddr, addr->socklen); if (ls == NULL) { return NULL; } - ngx_memzero(ls, sizeof(ngx_listening_t)); - - sa = ngx_palloc(cf->pool, addr->socklen); - if (sa == NULL) { - return NULL; - } - - ngx_memcpy(sa, addr->sockaddr, addr->socklen); - - ls->sockaddr = sa; - ls->socklen = addr->socklen; - - ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); - - ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len); - if (ls->addr_text.data == NULL) { - return NULL; - } - - ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len); - - ls->fd = (ngx_socket_t) -1; - ls->type = SOCK_STREAM; - - switch (ls->sockaddr->sa_family) { -#if (NGX_HAVE_INET6) - case AF_INET6: - ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; - break; -#endif - case AF_INET: - ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; - break; - default: - ls->addr_text_max_len = NGX_SOCKADDR_STRLEN; - break; - } - ls->addr_ntop = 1; ls->handler = ngx_http_init_connection; @@ -1746,7 +1706,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; - ls->log = *clcf->err_log; + ls->logp = clcf->error_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; @@ -1825,7 +1785,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h return NGX_ERROR; } - addrs[i].conf.core_srv_conf->virtual_names = vn; + addrs[i].conf.virtual_names = vn; vn->names.hash = addr[i].hash; vn->names.wc_head = addr[i].wc_head; @@ -1882,7 +1842,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_ return NGX_ERROR; } - addrs6[i].conf.core_srv_conf->virtual_names = vn; + addrs6[i].conf.virtual_names = vn; vn->names.hash = addr[i].hash; vn->names.wc_head = addr[i].wc_head; 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 @@ -84,13 +84,17 @@ ngx_int_t ngx_http_find_server_conf(ngx_ void ngx_http_update_location_config(ngx_http_request_t *r); void ngx_http_handler(ngx_http_request_t *r); void ngx_http_run_posted_requests(ngx_connection_t *c); -ngx_int_t ngx_http_post_request(ngx_http_request_t *r); +ngx_int_t ngx_http_post_request(ngx_http_request_t *r, + ngx_http_posted_request_t *pr); void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc); void ngx_http_empty_handler(ngx_event_t *wev); void ngx_http_request_empty_handler(ngx_http_request_t *r); +#define ngx_http_ephemeral(r) (ngx_http_ephemeral_t *) (&r->uri_start) + + #define NGX_HTTP_LAST 1 #define NGX_HTTP_FLUSH 2 @@ -103,6 +107,9 @@ ngx_int_t ngx_http_read_client_request_b ngx_int_t ngx_http_send_header(ngx_http_request_t *r); ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error); +ngx_int_t ngx_http_filter_finalize_request(ngx_http_request_t *r, + ngx_module_t *m, ngx_int_t error); +void ngx_http_clean_header(ngx_http_request_t *r); time_t ngx_http_parse_time(u_char *value, size_t len); diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -13,11 +13,12 @@ #include -/**/ -#define NGX_HTTP_CACHE_STALE 1 -#define NGX_HTTP_CACHE_AGED 2 -#define NGX_HTTP_CACHE_THE_SAME 3 -/**/ +#define NGX_HTTP_CACHE_MISS 1 +#define NGX_HTTP_CACHE_EXPIRED 2 +#define NGX_HTTP_CACHE_STALE 3 +#define NGX_HTTP_CACHE_UPDATING 4 +#define NGX_HTTP_CACHE_HIT 5 +#define NGX_HTTP_CACHE_SCARCE 6 #define NGX_HTTP_CACHE_KEY_LEN 16 @@ -28,8 +29,6 @@ typedef struct { } ngx_http_cache_valid_t; -/* ngx_http_file_cache_node_t takes exactly 64 bytes on FreeBSD/i386 */ - typedef struct { ngx_rbtree_node_t node; ngx_queue_t queue; @@ -41,8 +40,9 @@ typedef struct { unsigned uses:10; unsigned valid_msec:10; unsigned error:10; - /* 7 unused bits */ unsigned exists:1; + unsigned updating:1; + /* 12 unused bits */ ngx_file_uniq_t uniq; time_t expire; @@ -68,7 +68,6 @@ struct ngx_http_cache_s { off_t length; ngx_uint_t min_uses; - ngx_uint_t uses; ngx_uint_t error; ngx_uint_t valid_msec; @@ -94,16 +93,22 @@ typedef struct { } ngx_http_file_cache_header_t; +typedef struct { + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t queue; + ngx_atomic_t cold; + ngx_atomic_t loading; + off_t size; +} ngx_http_file_cache_sh_t; + + struct ngx_http_file_cache_s { - ngx_rbtree_t *rbtree; - ngx_queue_t *queue; + ngx_http_file_cache_sh_t *sh; ngx_slab_pool_t *shpool; ngx_path_t *path; - ngx_atomic_t *cold; - off_t *size; - off_t max_size; size_t bsize; @@ -124,11 +129,12 @@ ngx_int_t ngx_http_cache_send(ngx_http_r void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf); time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status); - char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +extern ngx_str_t ngx_http_cache_status[]; + #endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */ diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -69,8 +69,10 @@ typedef struct { ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index] #define ngx_http_cycle_get_module_main_conf(cycle, module) \ - ((ngx_http_conf_ctx_t *) \ - cycle->conf_ctx[ngx_http_module.index])->main_conf[module.ctx_index] + (cycle->conf_ctx[ngx_http_module.index] ? \ + ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]) \ + ->main_conf[module.ctx_index]: \ + NULL) #endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */ 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 @@ -14,6 +14,15 @@ typedef struct { } ngx_http_copy_filter_conf_t; +#if (NGX_HAVE_FILE_AIO) +static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, + ngx_file_t *file); +static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); +#if (NGX_HAVE_AIO_SENDFILE) +static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); +#endif +#endif + static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf); static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -73,18 +82,17 @@ ngx_http_copy_filter(ngx_http_request_t ngx_int_t rc; ngx_connection_t *c; ngx_output_chain_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; ngx_http_copy_filter_conf_t *conf; c = r->connection; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "copy filter: \"%V?%V\"", &r->uri, &r->args); + "http copy filter: \"%V?%V\"", &r->uri, &r->args); ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { - conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); - ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -92,11 +100,16 @@ ngx_http_copy_filter(ngx_http_request_t ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); + conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ctx->sendfile = c->sendfile; ctx->need_in_memory = r->main_filter_need_in_memory || r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; + ctx->alignment = clcf->directio_alignment; + ctx->pool = r->pool; ctx->bufs = conf->bufs; ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; @@ -104,27 +117,139 @@ ngx_http_copy_filter(ngx_http_request_t ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter; ctx->filter_ctx = r; +#if (NGX_HAVE_FILE_AIO) + if (clcf->aio) { + ctx->aio_handler = ngx_http_copy_aio_handler; +#if (NGX_HAVE_AIO_SENDFILE) + c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE); +#endif + } +#endif + r->request_output = 1; } - rc = ngx_output_chain(ctx, in); +#if (NGX_HAVE_FILE_AIO) + ctx->aio = r->aio; +#endif - if (!c->destroyed) { + for ( ;; ) { + rc = ngx_output_chain(ctx, in); if (ctx->in == NULL) { r->buffered &= ~NGX_HTTP_COPY_BUFFERED; + } else { r->buffered |= NGX_HTTP_COPY_BUFFERED; } - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); + +#if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE) + + if (c->busy_sendfile) { + ssize_t n; + off_t offset; + ngx_file_t *file; + ngx_http_ephemeral_t *e; + + file = c->busy_sendfile->file; + offset = c->busy_sendfile->file_pos; + + if (file->aio) { + c->aio_sendfile = (offset != file->aio->last_offset); + file->aio->last_offset = offset; + + if (c->aio_sendfile == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile(%V) returned busy again", + &file->name); + } + } + + c->busy_sendfile = NULL; + e = (ngx_http_ephemeral_t *) &r->uri_start; + + n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool); + + if (n > 0) { + in = NULL; + continue; + } + + rc = n; + + if (file->aio) { + file->aio->data = r; + file->aio->handler = ngx_http_copy_aio_sendfile_event_handler; + + r->main->blocked++; + r->aio = 1; + } + } +#endif + + return rc; } +} - return rc; + +#if (NGX_HAVE_FILE_AIO) + +static void +ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) +{ + ngx_http_request_t *r; + + r = ctx->filter_ctx; + + file->aio->data = r; + file->aio->handler = ngx_http_copy_aio_event_handler; + + r->main->blocked++; + r->aio = 1; } +static void +ngx_http_copy_aio_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + ngx_http_request_t *r; + + aio = ev->data; + r = aio->data; + + r->main->blocked--; + r->aio = 0; + + r->connection->write->handler(r->connection->write); +} + + +#if (NGX_HAVE_AIO_SENDFILE) + +static void +ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + ngx_http_request_t *r; + + aio = ev->data; + r = aio->data; + + r->main->blocked--; + r->aio = 0; + ev->complete = 0; + + r->connection->write->handler(r->connection->write); +} + +#endif +#endif + + static void * ngx_http_copy_filter_create_conf(ngx_conf_t *cf) { 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 @@ -104,6 +104,20 @@ static ngx_conf_enum_t ngx_http_core_re }; +#if (NGX_HAVE_FILE_AIO) + +static ngx_conf_enum_t ngx_http_core_aio[] = { + { ngx_string("off"), NGX_HTTP_AIO_OFF }, + { ngx_string("on"), NGX_HTTP_AIO_ON }, +#if (NGX_HAVE_AIO_SENDFILE) + { ngx_string("sendfile"), NGX_HTTP_AIO_SENDFILE }, +#endif + { ngx_null_string, 0 } +}; + +#endif + + static ngx_conf_enum_t ngx_http_core_satisfy[] = { { ngx_string("all"), NGX_HTTP_SATISFY_ALL }, { ngx_string("any"), NGX_HTTP_SATISFY_ANY }, @@ -355,12 +369,19 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("client_body_in_file_only"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, client_body_in_file_only), &ngx_http_core_request_body_in_file }, + { ngx_string("client_body_in_single_buffer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, client_body_in_single_buffer), + NULL }, + { ngx_string("sendfile"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -376,6 +397,17 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk), NULL }, +#if (NGX_HAVE_FILE_AIO) + + { ngx_string("aio"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, aio), + &ngx_http_core_aio }, + +#endif + { ngx_string("directio"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_core_directio, @@ -383,6 +415,13 @@ static ngx_command_t ngx_http_core_comm 0, NULL }, + { ngx_string("directio_alignment"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_off_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, directio_alignment), + NULL }, + { ngx_string("tcp_nopush"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -426,6 +465,14 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, limit_rate), NULL }, + { ngx_string("limit_rate_after"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, limit_rate_after), + NULL }, + { ngx_string("keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, ngx_http_core_keepalive, @@ -433,6 +480,13 @@ static ngx_command_t ngx_http_core_comm 0, NULL }, + { ngx_string("keepalive_requests"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, keepalive_requests), + NULL }, + { ngx_string("satisfy"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, @@ -691,7 +745,7 @@ ngx_module_t ngx_http_core_module = { }; -static ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " }; +ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " }; void @@ -863,6 +917,7 @@ ngx_http_core_find_config_phase(ngx_http "client intended to send too large body: %O bytes", r->headers_in.content_length_n); + (void) ngx_http_discard_request_body(r); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; } @@ -939,6 +994,7 @@ ngx_http_core_post_rewrite_phase(ngx_htt "rewrite or internal redirection cycle " "while processing \"%V\"", &r->uri); + r->main->count++; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } @@ -1144,6 +1200,11 @@ ngx_http_core_try_files_phase(ngx_http_r if (tf->lengths == NULL && tf->name.len == 0) { + if (tf->code) { + ngx_http_finalize_request(r, tf->code); + return NGX_OK; + } + path.len -= root; path.data += root; @@ -1156,6 +1217,7 @@ ngx_http_core_try_files_phase(ngx_http_r (void) ngx_http_internal_redirect(r, &path, &args); } + ngx_http_finalize_request(r, NGX_DONE); return NGX_OK; } @@ -1164,6 +1226,7 @@ ngx_http_core_try_files_phase(ngx_http_r of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; + of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; @@ -1172,7 +1235,7 @@ ngx_http_core_try_files_phase(ngx_http_r { if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + "%s \"%s\" failed", of.failed, path.data); } continue; @@ -1200,10 +1263,7 @@ ngx_http_core_try_files_phase(ngx_http_r ngx_memcpy(p, name, path.len); } - if (ngx_http_set_exten(r) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } + ngx_http_set_exten(r); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "try file uri: \"%V\"", &r->uri); @@ -1235,10 +1295,6 @@ ngx_http_core_content_phase(ngx_http_req rc = ph->handler(r); - if (rc == NGX_DONE) { - return NGX_OK; - } - if (rc != NGX_DECLINED) { ngx_http_finalize_request(r, rc); return NGX_OK; @@ -1286,10 +1342,10 @@ ngx_http_update_location_config(ngx_http } if (r == r->main) { - r->connection->log->file = clcf->err_log->file; + r->connection->log->file = clcf->error_log->file; if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->err_log->log_level; + r->connection->log->log_level = clcf->error_log->log_level; } } @@ -1311,8 +1367,15 @@ ngx_http_update_location_config(ngx_http r->request_body_file_log_level = NGX_LOG_WARN; } - if (r->keepalive && clcf->keepalive_timeout == 0) { - r->keepalive = 0; + r->request_body_in_single_buf = clcf->client_body_in_single_buffer; + + if (r->keepalive) { + if (clcf->keepalive_timeout == 0) { + r->keepalive = 0; + + } else if (r->connection->requests >= clcf->keepalive_requests) { + r->keepalive = 0; + } } if (!clcf->tcp_nopush) { @@ -1515,38 +1578,38 @@ ngx_http_core_find_static_location(ngx_h void * ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash) { - u_char c, *p; - ngx_uint_t i, hash; + u_char c, *lowcase; + size_t len; + ngx_uint_t i, hash; if (r->headers_out.content_type.len == 0) { return NULL; } + len = r->headers_out.content_type_len; + if (r->headers_out.content_type_lowcase == NULL) { - p = ngx_pnalloc(r->pool, r->headers_out.content_type_len); - - if (p == NULL) { + lowcase = ngx_pnalloc(r->pool, len); + if (lowcase == NULL) { return NULL; } - r->headers_out.content_type_lowcase = p; + r->headers_out.content_type_lowcase = lowcase; hash = 0; - for (i = 0; i < r->headers_out.content_type_len; i++) { + for (i = 0; i < len; i++) { c = ngx_tolower(r->headers_out.content_type.data[i]); hash = ngx_hash(hash, c); - *p++ = c; + lowcase[i] = c; } r->headers_out.content_type_hash = hash; } - return ngx_hash_find(types_hash, - r->headers_out.content_type_hash, - r->headers_out.content_type_lowcase, - r->headers_out.content_type_len); + return ngx_hash_find(types_hash, r->headers_out.content_type_hash, + r->headers_out.content_type_lowcase, len); } @@ -1606,7 +1669,7 @@ ngx_http_set_content_type(ngx_http_reque } -ngx_int_t +void ngx_http_set_exten(ngx_http_request_t *r) { ngx_int_t i; @@ -1620,14 +1683,14 @@ ngx_http_set_exten(ngx_http_request_t *r r->exten.len = r->uri.len - i - 1; r->exten.data = &r->uri.data[i + 1]; - break; + return; } else if (r->uri.data[i] == '/') { - break; + return; } } - return NGX_OK; + return; } @@ -1646,16 +1709,19 @@ ngx_http_send_header(ngx_http_request_t ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) { - ngx_int_t rc; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_int_t rc; + ngx_connection_t *c; + + c = r->connection; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http output filter \"%V?%V\"", &r->uri, &r->args); rc = ngx_http_top_body_filter(r, in); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ - r->connection->error = 1; + c->error = 1; } return rc; @@ -1805,68 +1871,6 @@ ngx_http_auth_basic_user(ngx_http_reques } -ngx_int_t -ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s) -{ - socklen_t len; - ngx_uint_t addr; - ngx_connection_t *c; - u_char sa[NGX_SOCKADDRLEN]; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - ngx_uint_t i; - struct sockaddr_in6 *sin6; -#endif - - c = r->connection; - - switch (c->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - - for (addr = 0, i = 0; addr == 0 && i < 16; i++) { - addr |= sin6->sin6_addr.s6_addr[i]; - } - - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->local_sockaddr; - addr = sin->sin_addr.s_addr; - break; - } - - if (addr == 0) { - - len = NGX_SOCKADDRLEN; - - if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) { - ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); - return NGX_ERROR; - } - - c->local_sockaddr = ngx_palloc(r->connection->pool, len); - if (c->local_sockaddr == NULL) { - return NGX_ERROR; - } - - c->local_socklen = len; - ngx_memcpy(c->local_sockaddr, &sa, len); - } - - if (s == NULL) { - return NGX_OK; - } - - s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, 0); - - return NGX_OK; -} - - #if (NGX_HTTP_GZIP) ngx_int_t @@ -2106,9 +2110,7 @@ ngx_http_subrequest(ngx_http_request_t * sr->method_name = ngx_http_core_get_method; sr->http_protocol = r->http_protocol; - if (ngx_http_set_exten(sr) != NGX_OK) { - return NGX_ERROR; - } + ngx_http_set_exten(sr); sr->main = r->main; sr->parent = r; @@ -2150,10 +2152,11 @@ ngx_http_subrequest(ngx_http_request_t * sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; r->main->subrequests++; + r->main->count++; *psr = sr; - return ngx_http_post_request(sr); + return ngx_http_post_request(sr, NULL); } @@ -2170,6 +2173,7 @@ ngx_http_internal_redirect(ngx_http_requ "rewrite or internal redirection cycle " "while internal redirect to \"%V\"", uri); + r->main->count++; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_DONE; } @@ -2187,10 +2191,7 @@ ngx_http_internal_redirect(ngx_http_requ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "internal redirect: \"%V?%V\"", uri, &r->args); - if (ngx_http_set_exten(r) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_DONE; - } + ngx_http_set_exten(r); /* clear the modules contexts */ ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); @@ -2205,6 +2206,7 @@ ngx_http_internal_redirect(ngx_http_requ #endif r->internal = 1; + r->main->count++; ngx_http_handler(r); @@ -2219,6 +2221,8 @@ ngx_http_named_location(ngx_http_request ngx_http_core_loc_conf_t **clcfp; ngx_http_core_main_conf_t *cmcf; + r->main->count++; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); if (cscf->named_locations) { @@ -2593,6 +2597,10 @@ ngx_http_core_regex_location(ngx_conf_t err.len = NGX_MAX_CONF_ERRSTR; err.data = errstr; +#if (NGX_HAVE_CASELESS_FILESYSTEM) + caseless = 1; +#endif + clcf->regex = ngx_regex_compile(regex, caseless ? NGX_REGEX_CASELESS: 0, cf->pool, &err); @@ -2722,14 +2730,14 @@ ngx_http_core_create_main_conf(ngx_conf_ cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)); if (cmcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cmcf->servers, cf->pool, 4, sizeof(ngx_http_core_srv_conf_t *)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT; @@ -2781,7 +2789,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)); if (cscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -2794,14 +2802,14 @@ ngx_http_core_create_srv_conf(ngx_conf_t sizeof(ngx_http_listen_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } cscf->connection_pool_size = NGX_CONF_UNSET_SIZE; @@ -2912,7 +2920,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)); if (lcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -2923,7 +2931,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t * lcf->post_action = { 0, NULL }; * lcf->types = NULL; * lcf->default_type = { 0, NULL }; - * lcf->err_log = NULL; + * lcf->error_log = NULL; * lcf->error_pages = NULL; * lcf->try_files = NULL; * lcf->client_body_path = NULL; @@ -2939,19 +2947,26 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->client_body_timeout = NGX_CONF_UNSET_MSEC; lcf->satisfy = NGX_CONF_UNSET_UINT; lcf->if_modified_since = NGX_CONF_UNSET_UINT; + lcf->client_body_in_file_only = NGX_CONF_UNSET_UINT; + lcf->client_body_in_single_buffer = NGX_CONF_UNSET; lcf->internal = NGX_CONF_UNSET; - lcf->client_body_in_file_only = NGX_CONF_UNSET; lcf->sendfile = NGX_CONF_UNSET; lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; +#if (NGX_HAVE_FILE_AIO) + lcf->aio = NGX_CONF_UNSET; +#endif lcf->directio = NGX_CONF_UNSET; + lcf->directio_alignment = NGX_CONF_UNSET; lcf->tcp_nopush = NGX_CONF_UNSET; lcf->tcp_nodelay = NGX_CONF_UNSET; lcf->send_timeout = NGX_CONF_UNSET_MSEC; lcf->send_lowat = NGX_CONF_UNSET_SIZE; lcf->postpone_output = NGX_CONF_UNSET_SIZE; lcf->limit_rate = NGX_CONF_UNSET_SIZE; + lcf->limit_rate_after = NGX_CONF_UNSET_SIZE; lcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; lcf->keepalive_header = NGX_CONF_UNSET; + lcf->keepalive_requests = NGX_CONF_UNSET_UINT; lcf->lingering_time = NGX_CONF_UNSET_MSEC; lcf->lingering_timeout = NGX_CONF_UNSET_MSEC; lcf->resolver_timeout = NGX_CONF_UNSET_MSEC; @@ -3103,11 +3118,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t } } - if (conf->err_log == NULL) { - if (prev->err_log) { - conf->err_log = prev->err_log; + if (conf->error_log == NULL) { + if (prev->error_log) { + conf->error_log = prev->error_log; } else { - conf->err_log = cf->cycle->new_log; + conf->error_log = &cf->cycle->new_log; } } @@ -3130,14 +3145,21 @@ ngx_http_core_merge_loc_conf(ngx_conf_t NGX_HTTP_SATISFY_ALL); ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since, NGX_HTTP_IMS_EXACT); + ngx_conf_merge_uint_value(conf->client_body_in_file_only, + prev->client_body_in_file_only, 0); + ngx_conf_merge_value(conf->client_body_in_single_buffer, + prev->client_body_in_single_buffer, 0); ngx_conf_merge_value(conf->internal, prev->internal, 0); - ngx_conf_merge_value(conf->client_body_in_file_only, - prev->client_body_in_file_only, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, prev->sendfile_max_chunk, 0); +#if (NGX_HAVE_FILE_AIO) + ngx_conf_merge_value(conf->aio, prev->aio, 0); +#endif ngx_conf_merge_off_value(conf->directio, prev->directio, NGX_MAX_OFF_T_VALUE); + ngx_conf_merge_off_value(conf->directio_alignment, prev->directio_alignment, + 512); ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1); @@ -3146,10 +3168,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); + ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, + 0); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, prev->keepalive_header, 0); + ngx_conf_merge_uint_value(conf->keepalive_requests, + prev->keepalive_requests, 100); ngx_conf_merge_msec_value(conf->lingering_time, prev->lingering_time, 30000); ngx_conf_merge_msec_value(conf->lingering_timeout, @@ -3525,6 +3551,12 @@ ngx_http_core_server_name(ngx_conf_t *cf ngx_str_t err; u_char errstr[NGX_MAX_CONF_ERRSTR]; + if (value[i].len == 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "empty regex in server name \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + err.len = NGX_MAX_CONF_ERRSTR; err.data = errstr; @@ -3875,7 +3907,7 @@ ngx_http_core_error_page(ngx_conf_t *cf, args.len = 0; args.data = NULL; - if (cv.lengths == NULL) { + if (cv.lengths == NULL && uri.data[0] == '/') { p = (u_char *) ngx_strchr(uri.data, '?'); if (p) { @@ -3939,6 +3971,7 @@ ngx_http_core_try_files(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf = conf; ngx_str_t *value; + ngx_int_t code; ngx_uint_t i, n; ngx_http_try_file_t *tf; ngx_http_script_compile_t sc; @@ -3994,6 +4027,20 @@ ngx_http_core_try_files(ngx_conf_t *cf, } } + if (tf[i - 1].name.data[0] == '=') { + + code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); + + if (code == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid code \"%*s\"", + tf[i - 1].name.len - 1, tf[i - 1].name.data); + return NGX_CONF_ERROR; + } + + tf[i].code = code; + } + return NGX_CONF_OK; } @@ -4081,12 +4128,25 @@ ngx_http_core_error_log(ngx_conf_t *cf, { ngx_http_core_loc_conf_t *lcf = conf; - lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args); - if (lcf->err_log == NULL) { + ngx_str_t *value; + + if (lcf->error_log) { + return "is duplicate"; + } + + value = cf->args->elts; + + lcf->error_log = ngx_log_create(cf->cycle, &value[1]); + if (lcf->error_log == NULL) { return NGX_CONF_ERROR; } - return ngx_set_error_log_levels(cf, lcf->err_log); + if (cf->args->nelts == 2) { + lcf->error_log->log_level = NGX_LOG_ERR; + return NGX_CONF_OK; + } + + return ngx_log_set_levels(cf, lcf->error_log); } 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 @@ -24,6 +24,11 @@ #define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 +#define NGX_HTTP_AIO_OFF 0 +#define NGX_HTTP_AIO_ON 1 +#define NGX_HTTP_AIO_SENDFILE 2 + + #define NGX_HTTP_SATISFY_ALL 0 #define NGX_HTTP_SATISFY_ANY 1 @@ -153,8 +158,6 @@ typedef struct { /* server ctx */ ngx_http_conf_ctx_t *ctx; - ngx_http_virtual_names_t *virtual_names; - ngx_str_t server_name; size_t connection_pool_size; @@ -180,6 +183,8 @@ typedef struct { /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *core_srv_conf; + ngx_http_virtual_names_t *virtual_names; + #if (NGX_HTTP_SSL) ngx_uint_t ssl; /* unsigned ssl:1; */ #endif @@ -267,7 +272,9 @@ typedef struct { ngx_array_t *lengths; ngx_array_t *values; ngx_str_t name; - ngx_uint_t test_dir; /* unsigned test_dir:1; */ + + unsigned code:10; + unsigned test_dir:1; } ngx_http_try_file_t; @@ -317,11 +324,13 @@ struct ngx_http_core_loc_conf_s { off_t client_max_body_size; /* client_max_body_size */ off_t directio; /* directio */ + off_t directio_alignment; /* directio_alignment */ size_t client_body_buffer_size; /* client_body_buffer_size */ size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ size_t limit_rate; /* limit_rate */ + size_t limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ ngx_msec_t client_body_timeout; /* client_body_timeout */ @@ -335,12 +344,18 @@ struct ngx_http_core_loc_conf_s { time_t keepalive_header; /* keepalive_timeout */ + ngx_uint_t keepalive_requests; /* keepalive_requests */ ngx_uint_t satisfy; /* satisfy */ ngx_uint_t if_modified_since; /* if_modified_since */ + ngx_uint_t client_body_in_file_only; /* client_body_in_file_only */ + ngx_flag_t client_body_in_single_buffer; + /* client_body_in_singe_buffer */ ngx_flag_t internal; /* internal */ - ngx_flag_t client_body_in_file_only; /* client_body_in_file_only */ ngx_flag_t sendfile; /* sendfile */ +#if (NGX_HAVE_FILE_AIO) + ngx_flag_t aio; /* aio */ +#endif ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ @@ -375,7 +390,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t open_file_cache_errors; ngx_flag_t open_file_cache_events; - ngx_log_t *err_log; + ngx_log_t *error_log; ngx_uint_t types_hash_max_size; ngx_uint_t types_hash_bucket_size; @@ -432,11 +447,10 @@ ngx_int_t ngx_http_core_content_phase(ng void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash); ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); -ngx_int_t ngx_http_set_exten(ngx_http_request_t *r); +void ngx_http_set_exten(ngx_http_request_t *r); u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name, size_t *root_length, size_t reserved); ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r); -ngx_int_t ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s); #if (NGX_HTTP_GZIP) ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); #endif @@ -466,6 +480,8 @@ extern ngx_module_t ngx_http_core_modul extern ngx_uint_t ngx_http_max_module; +extern ngx_str_t ngx_http_core_get_method; + #define ngx_http_clear_content_length(r) \ \ diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -10,6 +10,11 @@ #include +static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, + ngx_http_cache_t *c); +#if (NGX_HAVE_FILE_AIO) +static void ngx_http_cache_aio_event_handler(ngx_event_t *ev); +#endif static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c); static ngx_http_file_cache_node_t * @@ -35,6 +40,15 @@ static ngx_int_t ngx_http_file_cache_del ngx_str_t *path); +ngx_str_t ngx_http_cache_status[] = { + ngx_string("MISS"), + ngx_string("EXPIRED"), + ngx_string("STALE"), + ngx_string("UPDATING"), + ngx_string("HIT") +}; + + static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' }; @@ -44,7 +58,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_http_file_cache_t *ocache = data; size_t len; - ngx_rbtree_node_t *sentinel; + ngx_uint_t n; ngx_http_file_cache_t *cache; cache = shm_zone->data; @@ -54,65 +68,65 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "cache \"%V\" uses the \"%V\" cache path " "while previously it used the \"%V\" cache path", - &shm_zone->name, &cache->path->name, + &shm_zone->shm.name, &cache->path->name, &ocache->path->name); return NGX_ERROR; } - cache->rbtree = ocache->rbtree; - cache->queue = ocache->queue; + for (n = 0; n < 3; n++) { + if (cache->path->level[n] != ocache->path->level[n]) { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "cache \"%V\" had previously different levels", + &shm_zone->shm.name); + return NGX_ERROR; + } + } + + cache->sh = ocache->sh; + cache->shpool = ocache->shpool; - cache->cold = ocache->cold; - cache->size = ocache->size; cache->bsize = ocache->bsize; cache->max_size /= cache->bsize; + if (!cache->sh->cold || cache->sh->loading) { + cache->path->loader = NULL; + } + return NGX_OK; } cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - cache->rbtree = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_t)); - if (cache->rbtree == NULL) { - return NGX_ERROR; + if (shm_zone->shm.exists) { + cache->sh = cache->shpool->data; + cache->bsize = ngx_fs_bsize(cache->path->name.data); + + return NGX_OK; } - sentinel = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { + cache->sh = ngx_slab_alloc(cache->shpool, sizeof(ngx_http_file_cache_sh_t)); + if (cache->sh == NULL) { return NGX_ERROR; } - ngx_rbtree_init(cache->rbtree, sentinel, + cache->shpool->data = cache->sh; + + ngx_rbtree_init(&cache->sh->rbtree, &cache->sh->sentinel, ngx_http_file_cache_rbtree_insert_value); - cache->queue = ngx_slab_alloc(cache->shpool, sizeof(ngx_queue_t)); - if (cache->queue == NULL) { - return NGX_ERROR; - } - - ngx_queue_init(cache->queue); + ngx_queue_init(&cache->sh->queue); - cache->cold = ngx_slab_alloc(cache->shpool, sizeof(ngx_atomic_t)); - if (cache->cold == NULL) { - return NGX_ERROR; - } - - *cache->cold = 1; - - cache->size = ngx_slab_alloc(cache->shpool, sizeof(off_t)); - if (cache->size == NULL) { - return NGX_ERROR; - } - - *cache->size = 0; + cache->sh->cold = 1; + cache->sh->loading = 0; + cache->sh->size = 0; cache->bsize = ngx_fs_bsize(cache->path->name.data); cache->max_size /= cache->bsize; - len = sizeof(" in cache keys zone \"\"") + shm_zone->name.len; + len = sizeof(" in cache keys zone \"\"") + shm_zone->shm.name.len; cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len); if (cache->shpool->log_ctx == NULL) { @@ -120,7 +134,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t } ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z", - &shm_zone->name); + &shm_zone->shm.name); return NGX_OK; } @@ -164,20 +178,22 @@ ngx_http_file_cache_create_key(ngx_http_ ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { - u_char *p; - time_t now; - ssize_t n; - ngx_int_t rc, rv; - ngx_uint_t cold, test; - ngx_path_t *path; - ngx_http_cache_t *c; - ngx_pool_cleanup_t *cln; - ngx_open_file_info_t of; - ngx_http_file_cache_t *cache; - ngx_http_core_loc_conf_t *clcf; - ngx_http_file_cache_header_t *h; + u_char *p; + ngx_int_t rc, rv; + ngx_uint_t cold, test; + ngx_path_t *path; + ngx_http_cache_t *c; + ngx_pool_cleanup_t *cln; + ngx_open_file_info_t of; + ngx_http_file_cache_t *cache; + ngx_http_core_loc_conf_t *clcf; c = r->cache; + + if (c->buf) { + return ngx_http_file_cache_read(r, c); + } + cache = c->file_cache; cln = ngx_pool_cleanup_add(r->pool, 0); @@ -187,9 +203,8 @@ ngx_http_file_cache_open(ngx_http_reques rc = ngx_http_file_cache_exists(cache, c); - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http file cache exists: %i u:%ui e:%d", - rc, c->uses, c->exists); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache exists: %i e:%d", rc, c->exists); if (rc == NGX_ERROR) { return rc; @@ -199,10 +214,10 @@ ngx_http_file_cache_open(ngx_http_reques cln->data = c; if (rc == NGX_AGAIN) { - return rc; + return NGX_HTTP_CACHE_SCARCE; } - cold = *cache->cold; + cold = cache->sh->cold; if (rc == NGX_OK) { @@ -219,11 +234,11 @@ ngx_http_file_cache_open(ngx_http_reques if (c->min_uses > 1) { if (!cold) { - return NGX_AGAIN; + return NGX_HTTP_CACHE_SCARCE; } test = 1; - rv = NGX_AGAIN; + rv = NGX_HTTP_CACHE_SCARCE; } else { c->temp_file = 1; @@ -291,14 +306,58 @@ ngx_http_file_cache_open(ngx_http_reques c->file.fd = of.fd; c->file.log = r->connection->log; + c->uniq = of.uniq; + c->length = of.size; c->buf = ngx_create_temp_buf(r->pool, c->body_start); if (c->buf == NULL) { return NGX_ERROR; } + return ngx_http_file_cache_read(r, c); +} + + +static ngx_int_t +ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + time_t now; + ssize_t n; + ngx_int_t rc; + ngx_http_file_cache_t *cache; + ngx_http_file_cache_header_t *h; + + c = r->cache; + +#if (NGX_HAVE_FILE_AIO) + { + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->aio) { + n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); + + if (n == NGX_AGAIN) { + c->file.aio->data = r; + c->file.aio->handler = ngx_http_cache_aio_event_handler; + + r->main->blocked++; + r->aio = 1; + + return NGX_AGAIN; + } + + } else { + n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); + } + } +#else + n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); +#endif + if (n == NGX_ERROR) { return n; } @@ -323,12 +382,13 @@ ngx_http_file_cache_open(ngx_http_reques c->last_modified = h->last_modified; c->date = h->date; c->valid_msec = h->valid_msec; - c->length = of.size; c->body_start = h->body_start; r->cached = 1; - if (cold) { + cache = c->file_cache; + + if (cache->sh->cold) { ngx_shmtx_lock(&cache->shpool->mutex); @@ -336,8 +396,9 @@ ngx_http_file_cache_open(ngx_http_reques c->node->uses = 1; c->node->body_start = c->body_start; c->node->exists = 1; + c->node->uniq = c->uniq; - *cache->size += (c->length + cache->bsize - 1) / cache->bsize; + cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize; } ngx_shmtx_unlock(&cache->shpool->mutex); @@ -347,20 +408,50 @@ ngx_http_file_cache_open(ngx_http_reques if (c->valid_sec < now) { - c->uses = c->min_uses; + ngx_shmtx_lock(&cache->shpool->mutex); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http file cache expired: %T %T", c->valid_sec, now); + if (c->node->updating) { + rc = NGX_HTTP_CACHE_UPDATING; - return NGX_HTTP_CACHE_STALE; + } else { + c->node->updating = 1; + rc = NGX_HTTP_CACHE_STALE; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache expired: %i %T %T", + rc, c->valid_sec, now); + + return rc; } - /* TODO: NGX_HTTP_CACHE_AGED */ - return NGX_OK; } +#if (NGX_HAVE_FILE_AIO) + + +static void +ngx_http_cache_aio_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + ngx_http_request_t *r; + + aio = ev->data; + r = aio->data; + + r->main->blocked--; + r->aio = 0; + + r->connection->write->handler(r->connection->write); +} + +#endif + + static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) { @@ -417,7 +508,7 @@ ngx_http_file_cache_exists(ngx_http_file if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); - ngx_http_file_cache_forced_expire(cache); + (void) ngx_http_file_cache_forced_expire(cache); ngx_shmtx_lock(&cache->shpool->mutex); @@ -434,7 +525,7 @@ ngx_http_file_cache_exists(ngx_http_file ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); - ngx_rbtree_insert(cache->rbtree, &fcn->node); + ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); renew: @@ -454,10 +545,9 @@ done: fcn->expire = ngx_time() + cache->inactive; - ngx_queue_insert_head(cache->queue, &fcn->queue); + ngx_queue_insert_head(&cache->sh->queue, &fcn->queue); c->uniq = fcn->uniq; - c->uses = fcn->uses; c->error = fcn->error; c->node = fcn; @@ -479,8 +569,8 @@ ngx_http_file_cache_lookup(ngx_http_file ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t)); - node = cache->rbtree->root; - sentinel = cache->rbtree->sentinel; + node = cache->sh->rbtree.root; + sentinel = cache->sh->rbtree.sentinel; while (node != sentinel) { @@ -633,7 +723,6 @@ ngx_http_file_cache_update(ngx_http_requ ext.time = -1; ext.create_path = 1; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext); @@ -663,12 +752,14 @@ ngx_http_file_cache_update(ngx_http_requ c->node->length = c->length; - *cache->size += size; + cache->sh->size += size; if (rc == NGX_OK) { c->node->exists = 1; } + c->node->updating = 0; + ngx_shmtx_unlock(&cache->shpool->mutex); } @@ -676,6 +767,7 @@ ngx_http_file_cache_update(ngx_http_requ ngx_int_t ngx_http_cache_send(ngx_http_request_t *r) { + off_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; @@ -704,10 +796,15 @@ ngx_http_cache_send(ngx_http_request_t * return rc; } + size = c->length - c->body_start; + if (size == 0) { + return rc; + } + b->file_pos = c->body_start; b->file_last = c->length; - b->in_file = (c->length - c->body_start) ? 1: 0; + b->in_file = size ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; @@ -751,6 +848,8 @@ ngx_http_file_cache_free(ngx_http_reques c->node->error = c->error; } + c->node->updating = 0; + ngx_shmtx_unlock(&cache->shpool->mutex); if (c->temp_file) { @@ -818,18 +917,18 @@ ngx_http_file_cache_forced_expire(ngx_ht name = ngx_alloc(len + 1, ngx_cycle->log); if (name == NULL) { - return 60; + return 10; } ngx_memcpy(name, path->name.data, path->name.len); - wait = 60; + wait = 10; tries = 0; ngx_shmtx_lock(&cache->shpool->mutex); - for (q = ngx_queue_last(cache->queue); - q != ngx_queue_sentinel(cache->queue); + for (q = ngx_queue_last(&cache->sh->queue); + q != ngx_queue_sentinel(&cache->sh->queue); q = ngx_queue_prev(q)) { fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); @@ -853,7 +952,7 @@ ngx_http_file_cache_forced_expire(ngx_ht if (!fcn->exists) { ngx_queue_remove(q); - ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); break; @@ -891,7 +990,7 @@ ngx_http_file_cache_expire(ngx_http_file name = ngx_alloc(len + 1, ngx_cycle->log); if (name == NULL) { - return 60; + return 10; } ngx_memcpy(name, path->name.data, path->name.len); @@ -902,19 +1001,19 @@ ngx_http_file_cache_expire(ngx_http_file for ( ;; ) { - if (ngx_queue_empty(cache->queue)) { - wait = 60; + if (ngx_queue_empty(&cache->sh->queue)) { + wait = 10; break; } - q = ngx_queue_last(cache->queue); + q = ngx_queue_last(&cache->sh->queue); fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); wait = fcn->expire - now; if (wait > 0) { - wait = wait > 60 ? 60 : wait; + wait = wait > 10 ? 10 : wait; break; } @@ -939,7 +1038,7 @@ ngx_http_file_cache_expire(ngx_http_file */ ngx_queue_remove(q); - ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ignore long locked inactive cache entry %*s, count:%d", @@ -951,7 +1050,7 @@ ngx_http_file_cache_expire(ngx_http_file if (!fcn->exists) { ngx_queue_remove(q); - ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); continue; @@ -979,7 +1078,7 @@ ngx_http_file_cache_delete(ngx_http_file fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); - *cache->size -= (fcn->length + cache->bsize - 1) / cache->bsize; + cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize; path = cache->path; @@ -993,7 +1092,7 @@ ngx_http_file_cache_delete(ngx_http_file ngx_queue_remove(q); - ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); @@ -1020,39 +1119,8 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; - time_t next; - ngx_tree_ctx_t tree; - - if (*cache->cold) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http file cache manager update"); - - tree.init_handler = NULL; - tree.file_handler = ngx_http_file_cache_manage_file; - tree.pre_tree_handler = ngx_http_file_cache_noop; - tree.post_tree_handler = ngx_http_file_cache_noop; - tree.spec_handler = ngx_http_file_cache_delete_file; - tree.data = cache; - tree.alloc = 0; - tree.log = ngx_cycle->log; - - cache->last = ngx_current_msec; - cache->files = 0; - - if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { - return 60; - } - - *cache->cold = 0; - - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "http file cache: %V %.3fM, bsize: %uz", - &cache->path->name, - ((double) *cache->size * cache->bsize) / (1024 * 1024), - cache->bsize); - } + off_t size; + time_t next; next = ngx_http_file_cache_expire(cache); @@ -1062,7 +1130,7 @@ ngx_http_file_cache_manager(void *data) for ( ;; ) { ngx_shmtx_lock(&cache->shpool->mutex); - size = *cache->size; + size = cache->sh->size; ngx_shmtx_unlock(&cache->shpool->mutex); @@ -1082,6 +1150,52 @@ ngx_http_file_cache_manager(void *data) } +static void +ngx_http_file_cache_loader(void *data) +{ + ngx_http_file_cache_t *cache = data; + + ngx_tree_ctx_t tree; + + if (!cache->sh->cold || cache->sh->loading) { + return; + } + + if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache loader"); + + tree.init_handler = NULL; + tree.file_handler = ngx_http_file_cache_manage_file; + tree.pre_tree_handler = ngx_http_file_cache_noop; + tree.post_tree_handler = ngx_http_file_cache_noop; + tree.spec_handler = ngx_http_file_cache_delete_file; + tree.data = cache; + tree.alloc = 0; + tree.log = ngx_cycle->log; + + cache->last = ngx_current_msec; + cache->files = 0; + + if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { + cache->sh->loading = 0; + return; + } + + cache->sh->cold = 0; + cache->sh->loading = 0; + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "http file cache: %V %.3fM, bsize: %uz", + &cache->path->name, + ((double) cache->sh->size * cache->bsize) / (1024 * 1024), + cache->bsize); +} + + static ngx_int_t ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) { @@ -1245,7 +1359,7 @@ ngx_http_file_cache_add(ngx_http_file_ca ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); - ngx_rbtree_insert(cache->rbtree, &fcn->node); + ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); fcn->uses = 1; fcn->count = 0; @@ -1257,7 +1371,7 @@ ngx_http_file_cache_add(ngx_http_file_ca fcn->body_start = c->body_start; fcn->length = c->length; - *cache->size += (c->length + cache->bsize - 1) / cache->bsize; + cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize; } else { ngx_queue_remove(&fcn->queue); @@ -1265,7 +1379,7 @@ ngx_http_file_cache_add(ngx_http_file_ca fcn->expire = ngx_time() + cache->inactive; - ngx_queue_insert_head(cache->queue, &fcn->queue); + ngx_queue_insert_head(&cache->sh->queue, &fcn->queue); ngx_shmtx_unlock(&cache->shpool->mutex); @@ -1357,13 +1471,12 @@ ngx_http_file_cache_set_slot(ngx_conf_t if (ngx_strncmp(value[i].data, "levels=", 7) == 0) { - n = 0; p = value[i].data + 7; last = value[i].data + value[i].len; - while (p < last) { + for (n = 0; n < 3 && p < last; n++) { - if (*p > '0' && *p < '6') { + if (*p > '0' && *p < '3') { cache->path->level[n] = *p++ - '0'; cache->path->len += cache->path->level[n] + 1; @@ -1372,20 +1485,11 @@ ngx_http_file_cache_set_slot(ngx_conf_t break; } - if (*p++ == ':') { - - if (n > 2) { - goto invalid_levels; - } - - if (cache->path->level[n] == 0) { - goto invalid_levels; - } - - n++; - + if (*p++ == ':' && n < 2 && p != last) { continue; } + + goto invalid_levels; } goto invalid_levels; @@ -1409,6 +1513,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t p = (u_char *) ngx_strchr(name.data, ':'); if (p) { + *p = '\0'; + name.len = p - name.data; p++; @@ -1470,6 +1576,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t } cache->path->manager = ngx_http_file_cache_manager; + cache->path->loader = ngx_http_file_cache_loader; cache->path->data = cache; if (ngx_add_path(cf, &cache->path) != NGX_OK) { 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 @@ -61,7 +61,8 @@ static ngx_str_t ngx_http_status_lines[] /* ngx_null_string, */ /* "207 Multi-Status" */ -#define NGX_HTTP_LEVEL_200 7 +#define NGX_HTTP_LAST_LEVEL_200 207 +#define NGX_HTTP_LEVEL_200 (NGX_HTTP_LAST_LEVEL_200 - 200) /* ngx_null_string, */ /* "300 Multiple Choices" */ @@ -74,7 +75,8 @@ static ngx_str_t ngx_http_status_lines[] /* ngx_null_string, */ /* "306 unused" */ /* ngx_null_string, */ /* "307 Temporary Redirect" */ -#define NGX_HTTP_LEVEL_300 4 +#define NGX_HTTP_LAST_LEVEL_300 305 +#define NGX_HTTP_LEVEL_300 (NGX_HTTP_LAST_LEVEL_300 - 301) ngx_string("400 Bad Request"), ngx_string("401 Unauthorized"), @@ -106,7 +108,8 @@ static ngx_str_t ngx_http_status_lines[] /* ngx_null_string, */ /* "423 Locked" */ /* ngx_null_string, */ /* "424 Failed Dependency" */ -#define NGX_HTTP_LEVEL_400 17 +#define NGX_HTTP_LAST_LEVEL_400 417 +#define NGX_HTTP_LEVEL_400 (NGX_HTTP_LAST_LEVEL_400 - 400) ngx_string("500 Internal Server Error"), ngx_string("501 Method Not Implemented"), @@ -120,6 +123,9 @@ static ngx_str_t ngx_http_status_lines[] /* ngx_null_string, */ /* "508 unused" */ /* ngx_null_string, */ /* "509 unused" */ /* ngx_null_string, */ /* "510 Not Extended" */ + +#define NGX_HTTP_LAST_LEVEL_500 508 + }; @@ -153,12 +159,13 @@ ngx_http_header_filter(ngx_http_request_ { u_char *p; size_t len; - ngx_str_t host; + ngx_str_t host, *status_line; ngx_buf_t *b; ngx_uint_t status, i, port; ngx_chain_t out; ngx_list_part_t *part; ngx_table_elt_t *header; + ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; struct sockaddr_in *sin; @@ -199,17 +206,21 @@ ngx_http_header_filter(ngx_http_request_ if (r->headers_out.status_line.len) { len += r->headers_out.status_line.len; + status_line = &r->headers_out.status_line; #if (NGX_SUPPRESS_WARN) - status = NGX_INVALID_ARRAY_INDEX; + status = 0; #endif } else { - if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY) { + status = r->headers_out.status; + + if (status >= NGX_HTTP_OK + && status < NGX_HTTP_LAST_LEVEL_200) + { /* 2XX */ - status = r->headers_out.status - NGX_HTTP_OK; - if (r->headers_out.status == NGX_HTTP_NO_CONTENT) { + if (status == NGX_HTTP_NO_CONTENT) { r->header_only = 1; r->headers_out.content_type.len = 0; r->headers_out.content_type.data = NULL; @@ -219,30 +230,50 @@ ngx_http_header_filter(ngx_http_request_ r->headers_out.content_length_n = -1; } - } else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST) { + status -= NGX_HTTP_OK; + status_line = &ngx_http_status_lines[status]; + len += ngx_http_status_lines[status].len; + + } else if (status >= NGX_HTTP_MOVED_PERMANENTLY + && status < NGX_HTTP_LAST_LEVEL_300) + { /* 3XX */ - status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY - + NGX_HTTP_LEVEL_200; - if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + if (status == NGX_HTTP_NOT_MODIFIED) { r->header_only = 1; } - } else if (r->headers_out.status < NGX_HTTP_INTERNAL_SERVER_ERROR) { + status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200; + status_line = &ngx_http_status_lines[status]; + len += ngx_http_status_lines[status].len; + + } else if (status >= NGX_HTTP_BAD_REQUEST + && status < NGX_HTTP_LAST_LEVEL_400) + { /* 4XX */ - status = r->headers_out.status - NGX_HTTP_BAD_REQUEST - + NGX_HTTP_LEVEL_200 - + NGX_HTTP_LEVEL_300; + status = status - NGX_HTTP_BAD_REQUEST + + NGX_HTTP_LEVEL_200 + + NGX_HTTP_LEVEL_300; + + status_line = &ngx_http_status_lines[status]; + len += ngx_http_status_lines[status].len; + + } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR + && status < NGX_HTTP_LAST_LEVEL_500) + { + /* 5XX */ + status = status - NGX_HTTP_INTERNAL_SERVER_ERROR + + NGX_HTTP_LEVEL_200 + + NGX_HTTP_LEVEL_300 + + NGX_HTTP_LEVEL_400; + + status_line = &ngx_http_status_lines[status]; + len += ngx_http_status_lines[status].len; } else { - /* 5XX */ - status = r->headers_out.status - NGX_HTTP_INTERNAL_SERVER_ERROR - + NGX_HTTP_LEVEL_200 - + NGX_HTTP_LEVEL_300 - + NGX_HTTP_LEVEL_400; + len += NGX_INT_T_LEN; + status_line = NULL; } - - len += ngx_http_status_lines[status].len; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -279,6 +310,8 @@ ngx_http_header_filter(ngx_http_request_ len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } + c = r->connection; + if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') @@ -296,21 +329,21 @@ ngx_http_header_filter(ngx_http_request_ host.len = NGX_SOCKADDR_STRLEN; host.data = addr; - if (ngx_http_server_addr(r, &host) != NGX_OK) { + if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { return NGX_ERROR; } } - switch (r->connection->local_sockaddr->sa_family) { + switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: - sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif default: /* AF_INET */ - sin = (struct sockaddr_in *) r->connection->local_sockaddr; + sin = (struct sockaddr_in *) c->local_sockaddr; port = ntohs(sin->sin_port); break; } @@ -322,11 +355,14 @@ ngx_http_header_filter(ngx_http_request_ if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) - if (r->connection->ssl) + if (c->ssl) port = (port == 443) ? 0 : port; else #endif port = (port == 80) ? 0 : port; + + } else { + port = 0; } if (port) { @@ -400,13 +436,11 @@ ngx_http_header_filter(ngx_http_request_ b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); /* status line */ - if (r->headers_out.status_line.len) { - b->last = ngx_copy(b->last, r->headers_out.status_line.data, - r->headers_out.status_line.len); + if (status_line) { + b->last = ngx_copy(b->last, status_line->data, status_line->len); } else { - b->last = ngx_copy(b->last, ngx_http_status_lines[status].data, - ngx_http_status_lines[status].len); + b->last = ngx_sprintf(b->last, "%ui", status); } *b->last++ = CR; *b->last++ = LF; @@ -480,7 +514,7 @@ ngx_http_header_filter(ngx_http_request_ sizeof("Location: http") - 1); #if (NGX_HTTP_SSL) - if (r->connection->ssl) { + if (c->ssl) { *b->last++ ='s'; } #endif @@ -557,8 +591,8 @@ ngx_http_header_filter(ngx_http_request_ *b->last++ = CR; *b->last++ = LF; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "%*s\n", (size_t) (b->last - b->pos), b->pos); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "%*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; 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 @@ -143,7 +143,7 @@ ngx_http_parse_request_line(ngx_http_req break; } - if (ch < 'A' || ch > 'Z') { + if ((ch < 'A' || ch > 'Z') && ch != '_') { return NGX_HTTP_PARSE_INVALID_METHOD; } @@ -257,7 +257,7 @@ ngx_http_parse_request_line(ngx_http_req break; } - if (ch < 'A' || ch > 'Z') { + if ((ch < 'A' || ch > 'Z') && ch != '_') { return NGX_HTTP_PARSE_INVALID_METHOD; } @@ -739,6 +739,7 @@ ngx_http_parse_header_line(ngx_http_requ /* first char */ case sw_start: + r->header_name_start = p; r->invalid_header = 0; switch (ch) { @@ -751,7 +752,6 @@ ngx_http_parse_header_line(ngx_http_requ goto header_done; default: state = sw_name; - r->header_name_start = p; c = lowcase[ch]; @@ -950,9 +950,6 @@ ngx_http_parse_complex_uri(ngx_http_requ sw_slash, sw_dot, sw_dot_dot, -#if (NGX_WIN32) - sw_dot_dot_dot, -#endif sw_quoted, sw_quoted_second } state, quoted_state; @@ -1137,65 +1134,15 @@ ngx_http_parse_complex_uri(ngx_http_requ #endif case '/': state = sw_slash; - u -= 4; - if (u < r->uri.data) { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - while (*(u - 1) != '/') { - u--; - } - break; - case '%': - quoted_state = state; - state = sw_quoted; - break; - case '?': - r->args_start = p; - goto args; - case '#': - goto done; -#if (NGX_WIN32) - case '.': - state = sw_dot_dot_dot; - *u++ = ch; - break; -#endif - case '+': - r->plus_in_uri = 1; - default: - state = sw_usual; - *u++ = ch; - break; - } - - ch = *p++; - break; - -#if (NGX_WIN32) - case sw_dot_dot_dot: - - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { - state = sw_usual; - *u++ = ch; - ch = *p++; - break; - } - - switch(ch) { - case '\\': - case '/': - state = sw_slash; u -= 5; - if (u < r->uri.data) { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - while (*u != '/') { - u--; - } - if (u < r->uri.data) { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - while (*(u - 1) != '/') { + for ( ;; ) { + if (u < r->uri.data) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + if (*u == '/') { + u++; + break; + } u--; } break; @@ -1218,7 +1165,6 @@ ngx_http_parse_complex_uri(ngx_http_requ ch = *p++; break; -#endif case sw_quoted: r->quoted_uri = 1; @@ -1337,12 +1283,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque goto unsafe; } - if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/' -#if (NGX_WIN32) - || p[2] == '\\' -#endif - )) - { + if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) { goto unsafe; } @@ -1367,35 +1308,13 @@ ngx_http_parse_unsafe_uri(ngx_http_reque continue; } - if ((ch == '/' -#if (NGX_WIN32) - || ch == '\\' -#endif - ) && len > 2) - { + if (ngx_path_separator(ch) && len > 2) { + /* detect "/../" */ - if (p[0] == '.' && p[1] == '.' && p[2] == '/') { + if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) { goto unsafe; } - -#if (NGX_WIN32) - - if (p[2] == '\\') { - goto unsafe; - } - - if (len > 3) { - - /* detect "/.../" */ - - if (p[0] == '.' && p[1] == '.' && p[2] == '.' - && (p[3] == '/' || p[3] == '\\')) - { - goto unsafe; - } - } -#endif } } @@ -1486,20 +1405,20 @@ ngx_http_parse_multi_header_lines(ngx_ar ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value) { - u_char *p; + u_char *p, *last; if (r->args.len == 0) { return NGX_DECLINED; } - for (p = r->args.data; *p && *p != ' '; p++) { + p = r->args.data; + last = p + r->args.len; - /* - * although r->args.data is not null-terminated by itself, - * however, there is null in the end of request line - */ + for ( /* void */ ; p < last; p++) { - p = ngx_strcasestrn(p, (char *) name, len - 1); + /* we need '=' after name, so drop one char from last */ + + p = ngx_strlcasestrn(p, last - 1, name, len - 1); if (p == NULL) { return NGX_DECLINED; @@ -1509,7 +1428,7 @@ ngx_http_arg(ngx_http_request_t *r, u_ch value->data = p + len + 1; - p = (u_char *) ngx_strchr(p, '&'); + p = ngx_strlchr(p, last, '&'); if (p == NULL) { p = r->args.data + r->args.len; 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 @@ -102,7 +102,7 @@ ngx_http_postpone_filter(ngx_http_reques c->data = pr->request; - return ngx_http_post_request(pr->request); + return ngx_http_post_request(pr->request, NULL); } if (pr->out == NULL) { 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 @@ -36,6 +36,9 @@ static ngx_int_t ngx_http_find_virtual_s u_char *host, size_t len); static void ngx_http_request_handler(ngx_event_t *ev); +static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc); +static void ngx_http_terminate_handler(ngx_http_request_t *r); +static void ngx_http_finalize_connection(ngx_http_request_t *r); static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); static void ngx_http_writer(ngx_http_request_t *r); static void ngx_http_request_finalizer(ngx_http_request_t *r); @@ -46,7 +49,7 @@ static void ngx_http_set_lingering_close static void ngx_http_lingering_close_handler(ngx_event_t *ev); static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); -static void ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error); +static void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t error); static void ngx_http_log_request(ngx_http_request_t *r); static void ngx_http_close_connection(ngx_connection_t *c); @@ -129,7 +132,7 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), ngx_http_process_header_line }, -#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP) +#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO) { ngx_string("X-Forwarded-For"), offsetof(ngx_http_headers_in_t, x_forwarded_for), ngx_http_process_header_line }, @@ -198,7 +201,7 @@ ngx_http_init_connection(ngx_connection_ c->write->handler = ngx_http_empty_handler; #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, 1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif if (rev->ready) { @@ -217,7 +220,7 @@ ngx_http_init_connection(ngx_connection_ if (ngx_handle_read_event(rev, 0) != NGX_OK) { #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, -1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); #endif ngx_http_close_connection(c); return; @@ -247,7 +250,7 @@ ngx_http_init_request(ngx_event_t *rev) #endif #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, -1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); #endif c = rev->data; @@ -259,6 +262,8 @@ ngx_http_init_request(ngx_event_t *rev) return; } + c->requests++; + hc = c->data; if (hc == NULL) { @@ -310,7 +315,7 @@ ngx_http_init_request(ngx_event_t *rev) * is required to determine a server address */ - if (ngx_http_server_addr(r, NULL) != NGX_OK) { + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { ngx_http_close_connection(c); return; } @@ -321,7 +326,7 @@ ngx_http_init_request(ngx_event_t *rev) case AF_INET6: sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - addr6 = (ngx_http_in6_addr_t *) port->addrs; + addr6 = port->addrs; /* the last address is "*" */ @@ -360,7 +365,7 @@ ngx_http_init_request(ngx_event_t *rev) #if (NGX_HAVE_INET6) case AF_INET6: - addr6 = (ngx_http_in6_addr_t *) port->addrs; + addr6 = port->addrs; addr_conf = &addr6[0].conf; break; #endif @@ -372,6 +377,8 @@ ngx_http_init_request(ngx_event_t *rev) } } + r->virtual_names = addr_conf->virtual_names; + /* the default server configuration for the address:port */ cscf = addr_conf->core_srv_conf; @@ -380,6 +387,7 @@ ngx_http_init_request(ngx_event_t *rev) r->loc_conf = cscf->ctx->loc_conf; rev->handler = ngx_http_process_request_line; + r->read_event_handler = ngx_http_block_reading; #if (NGX_HTTP_SSL) @@ -418,9 +426,9 @@ ngx_http_init_request(ngx_event_t *rev) #endif clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - c->log->file = clcf->err_log->file; + c->log->file = clcf->error_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - c->log->log_level = clcf->err_log->log_level; + c->log->log_level = clcf->error_log->log_level; } if (c->buffer == NULL) { @@ -447,13 +455,15 @@ ngx_http_init_request(ngx_event_t *rev) sizeof(ngx_table_elt_t)) != NGX_OK) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_destroy_pool(r->pool); + ngx_http_close_connection(c); return; } r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_destroy_pool(r->pool); + ngx_http_close_connection(c); return; } @@ -462,7 +472,8 @@ ngx_http_init_request(ngx_event_t *rev) r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t)); if (r->variables == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_destroy_pool(r->pool); + ngx_http_close_connection(c); return; } @@ -470,6 +481,7 @@ ngx_http_init_request(ngx_event_t *rev) c->destroyed = 0; r->main = r; + r->count = 1; tp = ngx_timeofday(); r->start_sec = tp->sec; @@ -493,9 +505,9 @@ ngx_http_init_request(ngx_event_t *rev) r->log_handler = ngx_http_log_error_handler; #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, 1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); r->stat_reading = 1; - ngx_atomic_fetch_add(ngx_stat_requests, 1); + (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); #endif rev->handler(rev); @@ -697,7 +709,6 @@ ngx_http_process_request_line(ngx_event_ r->request_line.len = r->request_end - r->request_start; r->request_line.data = r->request_start; - *r->request_end = '\0'; if (r->args_start) { @@ -760,6 +771,22 @@ ngx_http_process_request_line(ngx_event_ r->args.data = r->args_start; } +#if (NGX_WIN32) + { + u_char *p; + + p = r->uri.data + r->uri.len - 1; + + if (*p == '.') { + + while (--p > r->uri.data && *p == '.') { /* void */ } + + r->uri.len = p + 1 - r->uri.data; + + ngx_http_set_exten(r); + } + } +#endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); @@ -866,9 +893,10 @@ ngx_http_process_request_line(ngx_event_ static void ngx_http_process_request_headers(ngx_event_t *rev) { + u_char *p; + size_t len; ssize_t n; ngx_int_t rc, rv; - ngx_str_t header; ngx_table_elt_t *h; ngx_connection_t *c; ngx_http_header_t *hh; @@ -908,19 +936,17 @@ ngx_http_process_request_headers(ngx_eve } if (rv == NGX_DECLINED) { - header.len = r->header_in->end - r->header_name_start; - header.data = r->header_name_start; - - if (header.len > NGX_MAX_ERROR_STR - 300) { - header.len = NGX_MAX_ERROR_STR - 300; - header.data[header.len++] = '.'; - header.data[header.len++] = '.'; - header.data[header.len++] = '.'; + len = r->header_in->end - r->header_name_start; + p = r->header_name_start; + + if (len > NGX_MAX_ERROR_STR - 300) { + len = NGX_MAX_ERROR_STR - 300; + p[len++] = '.'; p[len++] = '.'; p[len++] = '.'; } ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent too long header line: \"%V\"", - &header); + "client sent too long header line: \"%*s\"", + len, r->header_name_start); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } @@ -942,12 +968,10 @@ ngx_http_process_request_headers(ngx_eve /* there was error while a header line parsing */ - header.len = r->header_end - r->header_name_start; - header.data = r->header_name_start; - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line: \"%V\"", - &header); + "client sent invalid header line: \"%*s\"", + r->header_end - r->header_name_start, + r->header_name_start); continue; } @@ -1027,11 +1051,10 @@ ngx_http_process_request_headers(ngx_eve /* rc == NGX_HTTP_PARSE_INVALID_HEADER: "\r" is not followed by "\n" */ - header.len = r->header_end - r->header_name_start; - header.data = r->header_name_start; ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line: \"%V\\r...\"", - &header); + "client sent invalid header line: \"%*s\\r...\"", + r->header_end - r->header_name_start, + r->header_name_start); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } @@ -1359,8 +1382,13 @@ ngx_http_process_user_agent(ngx_http_req r->headers_in.msie4 = 1; /* fall through */ case '5': + r->headers_in.msie6 = 1; + break; case '6': - r->headers_in.msie6 = 1; + if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { + r->headers_in.msie6 = 1; + } + break; } } @@ -1502,7 +1530,7 @@ ngx_http_process_request(ngx_http_reques sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->verify == 1) { + if (sscf->verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { @@ -1517,20 +1545,22 @@ ngx_http_process_request(ngx_http_reques return; } - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, + if (sscf->verify == 1) { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, (SSL_get0_session(c->ssl->connection))); - ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); - return; + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); + return; + } + + X509_free(cert); } - - X509_free(cert); } } @@ -1541,9 +1571,9 @@ ngx_http_process_request(ngx_http_reques } #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, -1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); r->stat_reading = 0; - ngx_atomic_fetch_add(ngx_stat_writing, 1); + (void) ngx_atomic_fetch_add(ngx_stat_writing, 1); r->stat_writing = 1; #endif @@ -1586,15 +1616,9 @@ ngx_http_validate_host(u_char *host, siz continue; } - if (ch == '/' || ch == '\0') { + if (ngx_path_separator(ch) || ch == '\0') { return -1; } - -#if (NGX_WIN32) - if (ch == '\\') { - return -1; - } -#endif } if (dot) { @@ -1610,15 +1634,11 @@ ngx_http_find_virtual_server(ngx_http_re { u_char *server; ngx_uint_t hash; - ngx_http_virtual_names_t *vn; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; u_char buf[32]; - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - vn = cscf->virtual_names; - - if (vn == NULL) { + if (r->virtual_names == NULL) { return NGX_DECLINED; } @@ -1634,7 +1654,7 @@ ngx_http_find_virtual_server(ngx_http_re hash = ngx_hash_strlow(server, host, len); - cscf = ngx_hash_find_combined(&vn->names, hash, server, len); + cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len); if (cscf) { goto found; @@ -1642,7 +1662,7 @@ ngx_http_find_virtual_server(ngx_http_re #if (NGX_PCRE) - if (vn->nregex) { + if (r->virtual_names->nregex) { size_t ncaptures; ngx_int_t n; ngx_uint_t i; @@ -1654,9 +1674,9 @@ ngx_http_find_virtual_server(ngx_http_re ncaptures = 0; - sn = vn->regex; - - for (i = 0; i < vn->nregex; i++) { + sn = r->virtual_names->regex; + + for (i = 0; i < r->virtual_names->nregex; i++) { if (sn[i].captures && r->captures == NULL) { @@ -1713,10 +1733,10 @@ found: r->loc_conf = cscf->ctx->loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - r->connection->log->file = clcf->err_log->file; + r->connection->log->file = clcf->error_log->file; if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->err_log->log_level; + r->connection->log->log_level = clcf->error_log->log_level; } return NGX_OK; @@ -1786,13 +1806,15 @@ ngx_http_run_posted_requests(ngx_connect ngx_int_t -ngx_http_post_request(ngx_http_request_t *r) +ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr) { - ngx_http_posted_request_t *pr, **p; - - pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); + ngx_http_posted_request_t **p; + if (pr == NULL) { - return NGX_ERROR; + pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } } pr->request = r; @@ -1813,16 +1835,21 @@ ngx_http_finalize_request(ngx_http_reque ngx_http_request_t *pr; ngx_http_core_loc_conf_t *clcf; + c = r->connection; + + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http finalize request: %d, \"%V?%V\" a:%d, c:%d", + rc, &r->uri, &r->args, r == c->data, r->main->count); + if (rc == NGX_DONE) { - /* the request pool may be already destroyed */ + ngx_http_finalize_connection(r); return; } - c = r->connection; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http finalize request: %d, \"%V?%V\" %d", - rc, &r->uri, &r->args, r == c->data); + if (rc == NGX_OK && r->filter_finalize) { + c->error = 1; + return; + } if (rc == NGX_DECLINED) { r->content_handler = NULL; @@ -1840,15 +1867,15 @@ ngx_http_finalize_request(ngx_http_reque || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST || c->error) { - if (rc > 0 && r->headers_out.status == 0) { - r->headers_out.status = rc; - } - if (ngx_http_post_action(r) == NGX_OK) { return; } - ngx_http_close_request(r, 0); + if (r->main->blocked) { + r->write_event_handler = ngx_http_request_finalizer; + } + + ngx_http_terminate_request(r, rc); return; } @@ -1857,7 +1884,7 @@ ngx_http_finalize_request(ngx_http_reque || rc == NGX_HTTP_NO_CONTENT) { if (rc == NGX_HTTP_CLOSE) { - ngx_http_close_request(r, rc); + ngx_http_terminate_request(r, rc); return; } @@ -1883,7 +1910,7 @@ ngx_http_finalize_request(ngx_http_reque if (r->buffered || r->postponed) { if (ngx_http_set_write_handler(r) != NGX_OK) { - ngx_http_close_request(r->main, 0); + ngx_http_terminate_request(r, 0); } return; @@ -1901,6 +1928,8 @@ ngx_http_finalize_request(ngx_http_reque if (r == c->data) { + r->main->count--; + if (!r->logged) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -1934,8 +1963,9 @@ ngx_http_finalize_request(ngx_http_reque } } - if (ngx_http_post_request(pr) != NGX_OK) { - ngx_http_close_request(r->main, 0); + if (ngx_http_post_request(pr, NULL) != NGX_OK) { + r->main->count++; + ngx_http_terminate_request(r, 0); return; } @@ -1946,10 +1976,10 @@ ngx_http_finalize_request(ngx_http_reque return; } - if (r->buffered || c->buffered || r->postponed) { + if (r->buffered || c->buffered || r->postponed || r->blocked) { if (ngx_http_set_write_handler(r) != NGX_OK) { - ngx_http_close_request(r, 0); + ngx_http_terminate_request(r, 0); } return; @@ -1981,11 +2011,77 @@ ngx_http_finalize_request(ngx_http_reque ngx_del_timer(c->write); } - if (c->destroyed) { + if (c->read->eof) { + ngx_http_close_request(r, 0); return; } - if (c->read->eof) { + ngx_http_finalize_connection(r); +} + + +static void +ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc) +{ + ngx_http_cleanup_t *cln; + ngx_http_request_t *mr; + ngx_http_ephemeral_t *e; + + mr = r->main; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http terminate request count:%d", mr->count); + + cln = mr->cleanup; + mr->cleanup = NULL; + + while (cln) { + if (cln->handler) { + cln->handler(cln->data); + } + + cln = cln->next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http terminate cleanup count:%d blk:%d", + mr->count, mr->blocked); + + if (mr->write_event_handler) { + + if (mr->blocked) { + return; + } + + e = ngx_http_ephemeral(mr); + mr->posted_requests = NULL; + mr->write_event_handler = ngx_http_terminate_handler; + (void) ngx_http_post_request(mr, &e->terminal_posted_request); + return; + } + + ngx_http_close_request(mr, rc); +} + + +static void +ngx_http_terminate_handler(ngx_http_request_t *r) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http terminate handler count:%d", r->count); + + r->count = 1; + + ngx_http_close_request(r, 0); +} + + +static void +ngx_http_finalize_connection(ngx_http_request_t *r) +{ + ngx_http_core_loc_conf_t *clcf; + + if (r->main->count != 1) { ngx_http_close_request(r, 0); return; } @@ -2080,7 +2176,7 @@ ngx_http_writer(ngx_http_request_t *r) } } else { - if (wev->delayed) { + if (wev->delayed || r->aio) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer delayed"); @@ -2094,14 +2190,15 @@ ngx_http_writer(ngx_http_request_t *r) rc = ngx_http_output_filter(r, NULL); - if (c->destroyed) { - return; - } - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http writer output filter: %d, \"%V?%V\"", rc, &r->uri, &r->args); + if (rc == NGX_ERROR) { + ngx_http_finalize_request(r, rc); + return; + } + if (r->buffered || r->postponed || (r == r->main && c->buffered)) { if (!wev->ready && !wev->delayed) { @@ -2294,7 +2391,7 @@ ngx_http_set_keepalive(ngx_http_request_ } } - ngx_http_request_done(r, 0); + ngx_http_free_request(r, 0); c->data = hc; @@ -2313,7 +2410,7 @@ ngx_http_set_keepalive(ngx_http_request_ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request"); #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, 1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif hc->pipeline = 1; @@ -2543,7 +2640,7 @@ ngx_http_keepalive_handler(ngx_event_t * b->last += n; #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_reading, 1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif c->log->handler = ngx_http_log_error; @@ -2688,7 +2785,14 @@ ngx_http_send_special(ngx_http_request_t } if (flags & NGX_HTTP_LAST) { - b->last_buf = 1; + + if (r == r->main && !r->post_action) { + b->last_buf = 1; + + } else { + b->sync = 1; + b->last_in_chain = 1; + } } if (flags & NGX_HTTP_FLUSH) { @@ -2716,6 +2820,8 @@ ngx_http_post_action(ngx_http_request_t ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "post action: \"%V\"", &clcf->post_action); + r->main->count--; + r->http_version = NGX_HTTP_VERSION_9; r->header_only = 1; r->post_action = 1; @@ -2734,19 +2840,33 @@ ngx_http_post_action(ngx_http_request_t static void -ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error) +ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_connection_t *c; + r = r->main; c = r->connection; - ngx_http_request_done(r->main, error); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http request count:%d blk:%d", r->count, r->blocked); + + if (r->count == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero"); + } + + r->count--; + + if (r->count || r->blocked) { + return; + } + + ngx_http_free_request(r, rc); ngx_http_close_connection(c); } static void -ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error) +ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_log_t *log; struct linger linger; @@ -2772,17 +2892,17 @@ ngx_http_request_done(ngx_http_request_t #if (NGX_STAT_STUB) if (r->stat_reading) { - ngx_atomic_fetch_add(ngx_stat_reading, -1); + (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); } if (r->stat_writing) { - ngx_atomic_fetch_add(ngx_stat_writing, -1); + (void) ngx_atomic_fetch_add(ngx_stat_writing, -1); } #endif - if (error && r->headers_out.status == 0) { - r->headers_out.status = error; + if (rc > 0 && (r->headers_out.status == 0 || r->connection->sent == 0)) { + r->headers_out.status = rc; } log->action = "logging request"; @@ -2857,7 +2977,7 @@ ngx_http_close_connection(ngx_connection #endif #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_active, -1); + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif c->destroyed = 1; 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 @@ -184,7 +184,7 @@ typedef struct { ngx_table_elt_t *keep_alive; -#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP) +#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO) ngx_table_elt_t *x_forwarded_for; #endif @@ -387,6 +387,8 @@ struct ngx_http_request_s { ngx_http_post_subrequest_t *post_subrequest; ngx_http_posted_request_t *posted_requests; + ngx_http_virtual_names_t *virtual_names; + ngx_int_t phase_handler; ngx_http_handler_pt content_handler; ngx_uint_t access_code; @@ -414,6 +416,12 @@ struct ngx_http_request_s { ngx_http_cleanup_t *cleanup; + unsigned subrequests:8; + unsigned count:8; + unsigned blocked:8; + + unsigned aio:1; + unsigned http_state:4; /* URI with "/." and on Win32 with "//" */ @@ -476,6 +484,8 @@ struct ngx_http_request_s { unsigned discard_body:1; unsigned internal:1; unsigned error_page:1; + unsigned ignore_content_encoding:1; + unsigned filter_finalize:1; unsigned post_action:1; unsigned request_complete:1; unsigned request_output:1; @@ -484,7 +494,6 @@ struct ngx_http_request_s { unsigned root_tested:1; unsigned done:1; unsigned logged:1; - unsigned utf8:1; unsigned buffered:4; @@ -498,11 +507,24 @@ struct ngx_http_request_s { unsigned stat_writing:1; #endif - unsigned subrequests:8; - /* used to parse HTTP headers */ ngx_uint_t state; + + ngx_uint_t header_hash; + ngx_uint_t lowcase_index; + u_char lowcase_header[NGX_HTTP_LC_HEADER_LEN]; + + u_char *header_name_start; + u_char *header_name_end; + u_char *header_start; + u_char *header_end; + + /* + * a memory that can be reused after parsing a request line + * via ngx_http_ephemeral_t + */ + u_char *uri_start; u_char *uri_end; u_char *uri_ext; @@ -516,18 +538,18 @@ struct ngx_http_request_s { u_char *host_end; u_char *port_start; u_char *port_end; - u_char *header_name_start; - u_char *header_name_end; - u_char *header_start; - u_char *header_end; unsigned http_minor:16; unsigned http_major:16; +}; - ngx_uint_t header_hash; - ngx_uint_t lowcase_index; - u_char lowcase_header[NGX_HTTP_LC_HEADER_LEN]; -}; + +typedef struct { + ngx_http_posted_request_t terminal_posted_request; +#if (NGX_HAVE_AIO_SENDFILE) + u_char aio_preload; +#endif +} ngx_http_ephemeral_t; extern ngx_http_header_t ngx_http_headers_in[]; 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 @@ -37,6 +37,8 @@ ngx_http_read_client_request_body(ngx_ht ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + r->main->count++; + if (r->request_body || r->discard_body) { post_handler(r); return NGX_OK; @@ -475,6 +477,7 @@ ngx_http_discard_request_body(ngx_http_r return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->count++; (void) ngx_http_read_discarded_request_body(r); return NGX_OK; 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 @@ -561,7 +561,7 @@ ngx_http_script_add_code(ngx_array_t *co new = ngx_array_push_n(codes, size); if (new == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (code) { @@ -1074,11 +1074,7 @@ ngx_http_script_regex_end_code(ngx_http_ return; } - if (ngx_http_set_exten(r) != NGX_OK) { - e->ip = ngx_http_script_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } + ngx_http_set_exten(r); } e->ip += sizeof(ngx_http_script_regex_end_code_t); @@ -1213,7 +1209,7 @@ ngx_http_script_add_full_name_code(ngx_h } code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code; - code->prefix = sc->conf_prefix; + code->conf_prefix = sc->conf_prefix; code = ngx_http_script_add_code(*sc->values, sizeof(ngx_http_script_full_name_code_t), @@ -1223,7 +1219,7 @@ ngx_http_script_add_full_name_code(ngx_h } code->code = ngx_http_script_full_name_code; - code->prefix = sc->conf_prefix; + code->conf_prefix = sc->conf_prefix; return NGX_OK; } @@ -1238,7 +1234,8 @@ ngx_http_script_full_name_len_code(ngx_h e->ip += sizeof(ngx_http_script_full_name_code_t); - return code->prefix ? sizeof(NGX_CONF_PREFIX) : ngx_cycle->root.len; + return code->conf_prefix ? ngx_cycle->conf_prefix.len: + ngx_cycle->prefix.len; } @@ -1254,7 +1251,7 @@ ngx_http_script_full_name_code(ngx_http_ value.data = e->buf.data; value.len = e->pos - e->buf.data; - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->prefix) + if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix) != NGX_OK) { e->ip = ngx_http_script_exit; @@ -1413,6 +1410,7 @@ ngx_http_script_file_code(ngx_http_scrip of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; + of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; @@ -1421,7 +1419,7 @@ ngx_http_script_file_code(ngx_http_scrip { if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_file_info_n " \"%s\" failed", value->data); + "%s \"%s\" failed", of.failed, value->data); } switch (code->op) { 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 @@ -153,7 +153,7 @@ typedef struct { typedef struct { ngx_http_script_code_pt code; - uintptr_t prefix; + uintptr_t conf_prefix; } ngx_http_script_full_name_code_t; 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 @@ -275,14 +275,16 @@ static ngx_str_t ngx_http_error_pages[] ngx_null_string, /* 201, 204 */ -#define NGX_HTTP_LEVEL_200 1 +#define NGX_HTTP_LAST_LEVEL_200 202 +#define NGX_HTTP_LEVEL_200 (NGX_HTTP_LAST_LEVEL_200 - 201) /* ngx_null_string, */ /* 300 */ ngx_string(ngx_http_error_301_page), ngx_string(ngx_http_error_302_page), ngx_null_string, /* 303 */ -#define NGX_HTTP_LEVEL_300 3 +#define NGX_HTTP_LAST_LEVEL_300 304 +#define NGX_HTTP_LEVEL_300 (NGX_HTTP_LAST_LEVEL_300 - 301) ngx_string(ngx_http_error_400_page), ngx_string(ngx_http_error_401_page), @@ -302,7 +304,8 @@ static ngx_str_t ngx_http_error_pages[] ngx_string(ngx_http_error_415_page), ngx_string(ngx_http_error_416_page), -#define NGX_HTTP_LEVEL_400 17 +#define NGX_HTTP_LAST_LEVEL_400 417 +#define NGX_HTTP_LEVEL_400 (NGX_HTTP_LAST_LEVEL_400 - 400) ngx_string(ngx_http_error_495_page), /* 495, https certificate error */ ngx_string(ngx_http_error_496_page), /* 496, https no certificate */ @@ -318,6 +321,9 @@ static ngx_str_t ngx_http_error_pages[] ngx_null_string, /* 505 */ ngx_null_string, /* 506 */ ngx_string(ngx_http_error_507_page) + +#define NGX_HTTP_LAST_LEVEL_500 508 + }; @@ -402,16 +408,22 @@ ngx_http_special_response_handler(ngx_ht /* 204 */ err = 0; - } else if (error < NGX_HTTP_BAD_REQUEST) { + } else if (error >= NGX_HTTP_MOVED_PERMANENTLY + && error < NGX_HTTP_LAST_LEVEL_300) + { /* 3XX */ err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200; - } else if (error < NGX_HTTP_OWN_CODES) { + } else if (error >= NGX_HTTP_BAD_REQUEST + && error < NGX_HTTP_LAST_LEVEL_400) + { /* 4XX */ err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200 + NGX_HTTP_LEVEL_300; - } else { + } else if (error >= NGX_HTTP_OWN_CODES + && error < NGX_HTTP_LAST_LEVEL_500) + { /* 49X, 5XX */ err = error - NGX_HTTP_OWN_CODES + NGX_HTTP_LEVEL_200 + NGX_HTTP_LEVEL_300 @@ -423,12 +435,72 @@ ngx_http_special_response_handler(ngx_ht r->err_status = NGX_HTTP_BAD_REQUEST; break; } + + } else { + /* unknown code, zero body */ + err = 0; } return ngx_http_send_special_response(r, clcf, err); } +ngx_int_t +ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m, + ngx_int_t error) +{ + void *ctx; + ngx_int_t rc; + + ngx_http_clean_header(r); + + ctx = NULL; + + if (m) { + ctx = r->ctx[m->ctx_index]; + } + + /* clear the modules contexts */ + ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); + + if (m) { + r->ctx[m->ctx_index] = ctx; + } + + r->filter_finalize = 1; + + rc = ngx_http_special_response_handler(r, error); + + /* NGX_ERROR resets any pending data */ + + switch (rc) { + + case NGX_OK: + case NGX_DONE: + return NGX_ERROR; + + default: + return rc; + } +} + + +void +ngx_http_clean_header(ngx_http_request_t *r) +{ + ngx_memzero(&r->headers_out.status, + sizeof(ngx_http_headers_out_t) + - offsetof(ngx_http_headers_out_t, status)); + + r->headers_out.headers.part.nelts = 0; + r->headers_out.headers.part.next = NULL; + r->headers_out.headers.last = &r->headers_out.headers.part; + + r->headers_out.content_length_n = -1; + r->headers_out.last_modified_time = -1; +} + + static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) { @@ -451,14 +523,14 @@ ngx_http_send_error_page(ngx_http_reques return NGX_ERROR; } - if (err_page->value.lengths) { - ngx_http_split_args(r, &uri, &args); + if (uri.data[0] == '/') { - } else { - args = err_page->args; - } + if (err_page->value.lengths) { + ngx_http_split_args(r, &uri, &args); - if (uri.data[0] == '/') { + } else { + args = err_page->args; + } if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; @@ -538,6 +610,7 @@ ngx_http_send_special_response(ngx_http_ r->headers_out.content_type_len = sizeof("text/html") - 1; r->headers_out.content_type.len = sizeof("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; + r->headers_out.content_type_lowcase = NULL; } else { r->headers_out.content_length_n = -1; @@ -640,6 +713,7 @@ ngx_http_send_refresh(ngx_http_request_t r->headers_out.content_type_len = sizeof("text/html") - 1; r->headers_out.content_type.len = sizeof("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; + r->headers_out.content_type_lowcase = NULL; r->headers_out.location->hash = 0; r->headers_out.location = NULL; 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 @@ -14,8 +14,11 @@ static ngx_int_t ngx_http_upstream_cache ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u); +static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); #endif +static void ngx_http_upstream_init_request(ngx_http_request_t *r); static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx); static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r); static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); @@ -70,10 +73,14 @@ static void ngx_http_upstream_finalize_r static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t - ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_http_upstream_process_cache_control(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r, @@ -155,6 +162,12 @@ ngx_http_upstream_header_t ngx_http_ups offsetof(ngx_http_upstream_headers_in_t, last_modified), ngx_http_upstream_copy_last_modified, 0, 0 }, + { ngx_string("ETag"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, etag), + ngx_http_upstream_copy_header_line, + offsetof(ngx_http_headers_out_t, etag), 0 }, + { ngx_string("Server"), ngx_http_upstream_process_header_line, offsetof(ngx_http_upstream_headers_in_t, server), @@ -184,14 +197,12 @@ ngx_http_upstream_header_t ngx_http_ups ngx_http_upstream_copy_header_line, 0, 1 }, { ngx_string("Cache-Control"), - ngx_http_upstream_process_multi_header_lines, - offsetof(ngx_http_upstream_headers_in_t, cache_control), + ngx_http_upstream_process_cache_control, 0, ngx_http_upstream_copy_multi_header_lines, offsetof(ngx_http_headers_out_t, cache_control), 1 }, { ngx_string("Expires"), - ngx_http_upstream_process_header_line, - offsetof(ngx_http_upstream_headers_in_t, expires), + ngx_http_upstream_process_expires, 0, ngx_http_upstream_copy_header_line, offsetof(ngx_http_headers_out_t, expires), 1 }, @@ -214,26 +225,25 @@ ngx_http_upstream_header_t ngx_http_ups ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Expires"), - ngx_http_upstream_process_header_line, - offsetof(ngx_http_upstream_headers_in_t, x_accel_expires), + ngx_http_upstream_process_accel_expires, 0, ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Redirect"), ngx_http_upstream_process_header_line, offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect), - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Limit-Rate"), ngx_http_upstream_process_limit_rate, 0, - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Buffering"), ngx_http_upstream_process_buffering, 0, - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Charset"), ngx_http_upstream_process_charset, 0, - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, #if (NGX_HTTP_GZIP) { ngx_string("Content-Encoding"), @@ -315,6 +325,14 @@ static ngx_http_variable_t ngx_http_ups ngx_http_upstream_response_length_variable, 0, NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 }, +#if (NGX_HTTP_CACHE) + + { ngx_string("upstream_cache_status"), NULL, + ngx_http_upstream_cache_status, 0, + NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + +#endif + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -328,18 +346,53 @@ static ngx_http_upstream_next_t ngx_htt { 0, 0 } }; + +ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[] = { + { ngx_string("GET"), NGX_HTTP_GET}, + { ngx_string("HEAD"), NGX_HTTP_HEAD }, + { ngx_string("POST"), NGX_HTTP_POST }, + { ngx_null_string, 0 } +}; + + +ngx_int_t +ngx_http_upstream_create(ngx_http_request_t *r) +{ + ngx_http_upstream_t *u; + + u = r->upstream; + + if (u && u->cleanup) { + r->main->count++; + ngx_http_upstream_cleanup(r); + *u->cleanup = NULL; + } + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); + if (u == NULL) { + return NGX_ERROR; + } + + r->upstream = u; + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + +#if (NGX_HTTP_CACHE) + r->cache = NULL; +#endif + + return NGX_OK; +} + + void ngx_http_upstream_init(ngx_http_request_t *r) { - ngx_str_t *host; - ngx_uint_t i; - ngx_connection_t *c; - ngx_resolver_ctx_t *ctx, temp; - ngx_http_cleanup_t *cln; - ngx_http_upstream_t *u; - ngx_http_core_loc_conf_t *clcf; - ngx_http_upstream_srv_conf_t *uscf, **uscfp; - ngx_http_upstream_main_conf_t *umcf; + ngx_connection_t *c; c = r->connection; @@ -350,13 +403,6 @@ ngx_http_upstream_init(ngx_http_request_ ngx_del_timer(c->read); } - u = r->upstream; - - if (!r->post_action && !u->conf->ignore_client_abort) { - r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; - r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; - } - if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { if (!c->write->active) { @@ -369,10 +415,28 @@ ngx_http_upstream_init(ngx_http_request_ } } - if (r->request_body) { - u->request_bufs = r->request_body->bufs; + ngx_http_upstream_init_request(r); +} + + +static void +ngx_http_upstream_init_request(ngx_http_request_t *r) +{ + ngx_str_t *host; + ngx_uint_t i; + ngx_resolver_ctx_t *ctx, temp; + ngx_http_cleanup_t *cln; + ngx_http_upstream_t *u; + ngx_http_core_loc_conf_t *clcf; + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + if (r->aio) { + return; } + u = r->upstream; + #if (NGX_HTTP_CACHE) if (u->conf->cache) { @@ -380,6 +444,13 @@ ngx_http_upstream_init(ngx_http_request_ rc = ngx_http_upstream_cache(r, u); + if (rc == NGX_BUSY) { + r->write_event_handler = ngx_http_upstream_init_request; + return; + } + + r->write_event_handler = ngx_http_request_empty_handler; + if (rc == NGX_DONE) { return; } @@ -392,6 +463,17 @@ ngx_http_upstream_init(ngx_http_request_ #endif + u->store = (u->conf->store || u->conf->store_lengths); + + if (!u->store && !r->post_action && !u->conf->ignore_client_abort) { + r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; + r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; + } + + if (r->request_body) { + u->request_bufs = r->request_body->bufs; + } + if (u->create_request(r) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -399,6 +481,7 @@ ngx_http_upstream_init(ngx_http_request_ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + u->output.alignment = clcf->directio_alignment; u->output.pool = r->pool; u->output.bufs.num = 1; u->output.bufs.size = clcf->client_body_buffer_size; @@ -438,8 +521,6 @@ ngx_http_upstream_init(ngx_http_request_ cln->data = r; u->cleanup = &cln->handler; - u->store = (u->conf->store || u->conf->store_lengths); - if (u->resolved == NULL) { uscf = u->conf->upstream; @@ -488,7 +569,7 @@ ngx_http_upstream_init(ngx_http_request_ } if (ctx == NGX_NO_RESOLVER) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no resolver defined to resolve %V", host); ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY); @@ -531,38 +612,73 @@ ngx_http_upstream_cache(ngx_http_request ngx_int_t rc; ngx_http_cache_t *c; - c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); + c = r->cache; + if (c == NULL) { - return NGX_ERROR; - } - - if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) { - return NGX_ERROR; + + if (!(r->method & u->conf->cache_methods)) { + return NGX_DECLINED; + } + + if (r->method & NGX_HTTP_HEAD) { + u->method = ngx_http_core_get_method; + } + + c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); + if (c == NULL) { + return NGX_ERROR; + } + + if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) { + return NGX_ERROR; + } + + r->cache = c; + c->file.log = r->connection->log; + + if (u->create_key(r) != NGX_OK) { + return NGX_ERROR; + } + + /* TODO: add keys */ + + ngx_http_file_cache_create_key(r); + + u->cacheable = 1; + + c->min_uses = u->conf->cache_min_uses; + c->body_start = u->conf->buffer_size; + c->file_cache = u->conf->cache->data; + + u->cache_status = NGX_HTTP_CACHE_MISS; } - r->cache = c; - c->file.log = r->connection->log; - - if (u->create_key(r) != NGX_OK) { - return NGX_ERROR; - } - - /* TODO: add keys */ - - ngx_http_file_cache_create_key(r); - - u->cacheable = 1; - - c->min_uses = r->upstream->conf->cache_min_uses; - c->body_start = r->upstream->conf->buffer_size; - c->file_cache = u->conf->cache->data; - rc = ngx_http_file_cache_open(r); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http upstream cache: %i u:%ui", rc, c->uses); - - if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream cache: %i", rc); + + switch (rc) { + + case NGX_HTTP_CACHE_UPDATING: + + if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) { + u->cache_status = rc; + rc = NGX_OK; + + } else { + rc = NGX_HTTP_CACHE_STALE; + } + + break; + + case NGX_OK: + u->cache_status = NGX_HTTP_CACHE_HIT; + } + + switch (rc) { + + case NGX_OK: rc = ngx_http_upstream_cache_send(r, u); @@ -570,16 +686,17 @@ ngx_http_upstream_cache(ngx_http_request return rc; } - } else if (rc == NGX_ERROR) { - - return NGX_ERROR; - - } else if (rc == NGX_HTTP_CACHE_STALE) { - - u->stale_cache = 1; + break; + + case NGX_HTTP_CACHE_STALE: + + c->valid_sec = 0; u->buffer.start = NULL; - - } else if (rc == NGX_DECLINED) { + u->cache_status = NGX_HTTP_CACHE_EXPIRED; + + break; + + case NGX_DECLINED: if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) { u->buffer.start = NULL; @@ -589,14 +706,28 @@ ngx_http_upstream_cache(ngx_http_request u->buffer.last = u->buffer.pos; } - } else if (rc == NGX_AGAIN) { + break; + + case NGX_HTTP_CACHE_SCARCE: u->cacheable = 0; - } else { + break; + + case NGX_AGAIN: + + return NGX_BUSY; + + case NGX_ERROR: + + return NGX_ERROR; + + default: /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */ + u->cache_status = NGX_HTTP_CACHE_HIT; + return rc; } @@ -612,6 +743,7 @@ ngx_http_upstream_cache_send(ngx_http_re ngx_int_t rc; ngx_http_cache_t *c; + r->cached = 1; c = r->cache; /* TODO: cache stack */ @@ -758,6 +890,7 @@ ngx_http_upstream_check_broken_connectio int n; char buf[1]; ngx_err_t err; + ngx_int_t event; ngx_connection_t *c; ngx_http_upstream_t *u; @@ -769,8 +902,22 @@ ngx_http_upstream_check_broken_connectio u = r->upstream; if (c->error) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_CLIENT_CLOSED_REQUEST); + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { + + event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT; + + if (ngx_del_event(ev, event, 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + + if (!u->cacheable) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + } + return; } @@ -793,7 +940,7 @@ ngx_http_upstream_check_broken_connectio ev->error = 1; } - if (!u->cacheable && !u->store && u->peer.connection) { + if (!u->cacheable && u->peer.connection) { ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, "kevent() reported that client closed prematurely " "connection, so upstream connection is closed too"); @@ -824,17 +971,15 @@ ngx_http_upstream_check_broken_connectio ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err, "http upstream recv(): %d", n); - /* - * we do not need to disable the write event because - * that event has NGX_USE_CLEAR_EVENT type - */ - if (ev->write && (n >= 0 || err == NGX_EAGAIN)) { return; } if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { - if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { + + event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT; + + if (ngx_del_event(ev, event, 0) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -859,7 +1004,7 @@ ngx_http_upstream_check_broken_connectio ev->eof = 1; c->error = 1; - if (!u->cacheable && !u->store && u->peer.connection) { + if (!u->cacheable && u->peer.connection) { ngx_log_error(NGX_LOG_INFO, ev->log, err, "client closed prematurely connection, " "so upstream connection is closed too"); @@ -949,7 +1094,9 @@ ngx_http_upstream_connect(ngx_http_reque u->output.sendfile = c->sendfile; c->pool = r->pool; - c->read->log = c->write->log = c->log = r->connection->log; + c->log = r->connection->log; + c->read->log = c->log; + c->write->log = c->log; /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ @@ -1463,10 +1610,6 @@ ngx_http_upstream_test_next(ngx_http_req ngx_uint_t status; ngx_http_upstream_next_t *un; - if (!(u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_STATUS)) { - return NGX_DECLINED; - } - status = u->headers_in.status_n; for (un = ngx_http_upstream_next_errors; un->status; un++) { @@ -1482,12 +1625,19 @@ ngx_http_upstream_test_next(ngx_http_req #if (NGX_HTTP_CACHE) - if (u->peer.tries == 0 - && u->stale_cache + if (u->cache_status == NGX_HTTP_CACHE_EXPIRED && (u->conf->cache_use_stale & un->mask)) { - ngx_http_upstream_finalize_request(r, u, - ngx_http_upstream_cache_send(r, u)); + ngx_int_t rc; + + rc = u->reinit_request(r); + + if (rc == NGX_OK) { + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); + } + + ngx_http_upstream_finalize_request(r, u, rc); return NGX_OK; } @@ -1530,8 +1680,9 @@ ngx_http_upstream_intercept_errors(ngx_h if (err_page[i].status == status) { - if (status == NGX_HTTP_UNAUTHORIZED) { - + if (status == NGX_HTTP_UNAUTHORIZED + && u->headers_in.www_authenticate) + { h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { @@ -1611,8 +1762,9 @@ ngx_http_upstream_process_headers(ngx_ht umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); - if (u->headers_in.x_accel_redirect) { - + if (u->headers_in.x_accel_redirect + && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT)) + { ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); part = &u->headers_in.headers.part; @@ -1663,6 +1815,7 @@ ngx_http_upstream_process_headers(ngx_ht r->valid_unparsed_uri = 0; ngx_http_internal_redirect(r, uri, &args); + ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } @@ -1815,11 +1968,32 @@ ngx_http_upstream_send_response(ngx_http rc = ngx_http_send_header(r); - if (rc == NGX_ERROR || rc > NGX_OK || r->post_action || r->header_only) { + if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) { ngx_http_upstream_finalize_request(r, u, rc); return; } + c = r->connection; + + if (r->header_only) { + + if (u->cacheable || u->store) { + + if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + } + + r->read_event_handler = ngx_http_request_empty_handler; + r->write_event_handler = ngx_http_request_empty_handler; + c->error = 1; + + } else { + ngx_http_upstream_finalize_request(r, u, rc); + return; + } + } + u->header_sent = 1; if (r->request_body && r->request_body->temp_file) { @@ -1827,8 +2001,6 @@ ngx_http_upstream_send_response(ngx_http r->request_body->temp_file->file.fd = NGX_INVALID_FILE; } - c = r->connection; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (!u->buffering) { @@ -1910,14 +2082,19 @@ ngx_http_upstream_send_response(ngx_http if (u->cacheable) { time_t now, valid; - valid = ngx_http_file_cache_valid(u->conf->cache_valid, - u->headers_in.status_n); + now = ngx_time(); + + valid = r->cache->valid_sec; + + if (valid == 0) { + valid = ngx_http_file_cache_valid(u->conf->cache_valid, + u->headers_in.status_n); + if (valid) { + r->cache->valid_sec = now + valid; + } + } + if (valid) { - - now = ngx_time(); - - r->cache->valid_sec = now + valid; - r->cache->last_modified = r->headers_out.last_modified_time; r->cache->date = now; r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start); @@ -1931,9 +2108,17 @@ ngx_http_upstream_send_response(ngx_http } else { u->cacheable = 0; + r->headers_out.last_modified_time = -1; } } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http cacheable: %d", u->cacheable); + + if (u->cacheable == 0 && r->cache) { + ngx_http_file_cache_free(r, u->pipe->temp_file); + } + #endif p = u->pipe; @@ -2115,10 +2300,6 @@ ngx_http_upstream_process_non_buffered_r if (u->out_bufs || u->busy_bufs) { rc = ngx_http_output_filter(r, u->out_bufs); - if (downstream->destroyed) { - return; - } - if (rc == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, 0); return; @@ -2291,11 +2472,6 @@ ngx_http_upstream_process_downstream(ngx } if (ngx_event_pipe(p, wev->write) == NGX_ABORT) { - - if (c->destroyed) { - return; - } - ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -2321,11 +2497,6 @@ ngx_http_upstream_process_downstream(ngx } if (ngx_event_pipe(p, 1) == NGX_ABORT) { - - if (c->destroyed) { - return; - } - ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -2353,14 +2524,7 @@ ngx_http_upstream_process_upstream(ngx_h ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); } else { - c = r->connection; - if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) { - - if (c->destroyed) { - return; - } - ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -2448,7 +2612,7 @@ ngx_http_upstream_process_request(ngx_ht ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream downstream error"); - if (!u->cacheable && u->peer.connection) { + if (!u->cacheable && !u->store && u->peer.connection) { ngx_http_upstream_finalize_request(r, u, 0); } } @@ -2496,7 +2660,6 @@ ngx_http_upstream_store(ngx_http_request ext.time = -1; ext.create_path = 1; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; if (u->headers_in.last_modified) { @@ -2523,6 +2686,8 @@ ngx_http_upstream_store(ngx_http_request } } + path.len--; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "upstream stores \"%s\" to \"%s\"", tf->file.name.data, path.data); @@ -2608,10 +2773,19 @@ ngx_http_upstream_next(ngx_http_request_ #if (NGX_HTTP_CACHE) - if (u->stale_cache && (u->conf->cache_use_stale & ft_type)) { - - ngx_http_upstream_finalize_request(r, u, - ngx_http_upstream_cache_send(r, u)); + if (u->cache_status == NGX_HTTP_CACHE_EXPIRED + && (u->conf->cache_use_stale & ft_type)) + { + ngx_int_t rc; + + rc = u->reinit_request(r); + + if (rc == NGX_OK) { + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); + } + + ngx_http_upstream_finalize_request(r, u, rc); return; } #endif @@ -2735,7 +2909,7 @@ ngx_http_upstream_finalize_request(ngx_h #if (NGX_HTTP_CACHE) - if (r->cache) { + if (u->cacheable && r->cache) { time_t valid; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -2757,7 +2931,8 @@ ngx_http_upstream_finalize_request(ngx_h #endif - if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) + if (u->header_sent + && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) { rc = 0; } @@ -2768,7 +2943,7 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; - if (rc == 0 && r == r->main && !r->post_action) { + if (rc == 0) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); } @@ -2793,13 +2968,23 @@ ngx_http_upstream_process_header_line(ng static ngx_int_t -ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, +ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_process_cache_control(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_array_t *pa; - ngx_table_elt_t **ph; - - pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset); + ngx_array_t *pa; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; + + u = r->upstream; + pa = &u->headers_in.cache_control; if (pa->elts == NULL) { if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) @@ -2815,14 +3000,159 @@ ngx_http_upstream_process_multi_header_l *ph = h; +#if (NGX_HTTP_CACHE) + { + u_char *p, *last; + ngx_int_t n; + + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) { + return NGX_OK; + } + + if (r->cache == NULL) { + return NGX_OK; + } + + if (r->cache->valid_sec != 0) { + return NGX_OK; + } + + last = h->value.data + h->value.len; + + if (ngx_strlcasestrn(h->value.data, last, (u_char *) "no-cache", 8 - 1) + != NULL) + { + u->cacheable = 0; + return NGX_OK; + } + + p = ngx_strlcasestrn(h->value.data, last, (u_char *) "max-age=", 8 - 1); + + if (p == NULL) { + return NGX_OK; + } + + n = 0; + + for (p += 8; p < last; p++) { + if (*p == ';' || *p == ' ') { + break; + } + + if (*p >= '0' && *p <= '9') { + n = n * 10 + *p - '0'; + continue; + } + + u->cacheable = 0; + return NGX_OK; + } + + if (n == 0) { + u->cacheable = 0; + return NGX_OK; + } + + r->cache->valid_sec = ngx_time() + n; + } +#endif + return NGX_OK; } static ngx_int_t -ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, +ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { + ngx_http_upstream_t *u; + + u = r->upstream; + u->headers_in.expires = h; + +#if (NGX_HTTP_CACHE) + { + time_t expires; + + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) { + return NGX_OK; + } + + if (r->cache == NULL) { + return NGX_OK; + } + + if (r->cache->valid_sec != 0) { + return NGX_OK; + } + + expires = ngx_http_parse_time(h->value.data, h->value.len); + + if (expires == NGX_ERROR || expires < ngx_time()) { + u->cacheable = 0; + return NGX_OK; + } + + r->cache->valid_sec = expires; + } +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_http_upstream_t *u; + + u = r->upstream; + u->headers_in.x_accel_expires = h; + +#if (NGX_HTTP_CACHE) + { + u_char *p; + size_t len; + ngx_int_t n; + + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) { + return NGX_OK; + } + + if (r->cache == NULL) { + return NGX_OK; + } + + len = h->value.len; + p = h->value.data; + + if (p[0] != '@') { + n = ngx_atoi(p, len); + + switch (n) { + case 0: + u->cacheable = 0; + case NGX_ERROR: + return NGX_OK; + + default: + r->cache->valid_sec = ngx_time() + n; + return NGX_OK; + } + } + + p++; + len--; + + n = ngx_atoi(p, len); + + if (n != NGX_ERROR) { + r->cache->valid_sec = n; + } + } +#endif + return NGX_OK; } @@ -2949,6 +3279,7 @@ ngx_http_upstream_copy_content_type(ngx_ r->headers_out.content_type_len = h->value.len; r->headers_out.content_type = h->value; + r->headers_out.content_type_lowcase = NULL; for (p = h->value.data; *p; p++) { @@ -3025,10 +3356,11 @@ ngx_http_upstream_copy_last_modified(ngx *ho = *h; + r->headers_out.last_modified = ho; + #if (NGX_HTTP_CACHE) - if (r->cached) { - r->headers_out.last_modified = ho; + if (r->upstream->cacheable) { r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data, h->value.len); } @@ -3152,6 +3484,8 @@ ngx_http_upstream_copy_allow_ranges(ngx_ *ho = *h; + r->headers_out.accept_ranges = ho; + return NGX_OK; } @@ -3478,6 +3812,33 @@ ngx_http_upstream_header_variable(ngx_ht } +#if (NGX_HTTP_CACHE) + +ngx_int_t +ngx_http_upstream_cache_status(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t n; + + if (r->upstream == NULL || r->upstream->cache_status == 0) { + v->not_found = 1; + return NGX_OK; + } + + n = r->upstream->cache_status - 1; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = ngx_http_cache_status[n].len; + v->data = ngx_http_cache_status[n].data; + + return NGX_OK; +} + +#endif + + static char * ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { @@ -3850,7 +4211,12 @@ ngx_http_upstream_hide_headers_hash(ngx_ { conf->hide_headers_hash = prev->hide_headers_hash; - if (conf->hide_headers_hash.buckets) { + if (conf->hide_headers_hash.buckets +#if (NGX_HTTP_CACHE) + && ((conf->cache == NULL) == (prev->cache == NULL)) +#endif + ) + { return NGX_OK; } @@ -3956,7 +4322,7 @@ ngx_http_upstream_create_main_conf(ngx_c sizeof(ngx_http_upstream_srv_conf_t *)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return umcf; 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 @@ -24,8 +24,9 @@ #define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040 #define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080 #define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000100 -#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000200 -#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000400 +#define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000200 +#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000400 +#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000800 #define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000 #define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000 @@ -38,6 +39,12 @@ #define NGX_HTTP_UPSTREAM_INVALID_HEADER 40 +#define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT 0x00000002 +#define NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES 0x00000004 +#define NGX_HTTP_UPSTREAM_IGN_EXPIRES 0x00000008 +#define NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL 0x00000010 + + typedef struct { ngx_msec_t bl_time; ngx_uint_t bl_state; @@ -128,6 +135,7 @@ typedef struct { ngx_bufs_t bufs; + ngx_uint_t ignore_headers; ngx_uint_t next_upstream; ngx_uint_t store_access; ngx_flag_t buffering; @@ -149,6 +157,7 @@ typedef struct { ngx_uint_t cache_min_uses; ngx_uint_t cache_use_stale; + ngx_uint_t cache_methods; ngx_array_t *cache_valid; #endif @@ -162,7 +171,7 @@ typedef struct { #if (NGX_HTTP_SSL) ngx_ssl_t *ssl; - ngx_flag_t ssl_session_reuse; + ngx_flag_t ssl_session_reuse; #endif } ngx_http_upstream_conf_t; @@ -289,7 +298,7 @@ struct ngx_http_upstream_s { unsigned accel:1; unsigned ssl:1; #if (NGX_HTTP_CACHE) - unsigned stale_cache:1; + unsigned cache_status:3; #endif unsigned buffering:1; @@ -308,6 +317,7 @@ typedef struct { ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r); void ngx_http_upstream_init(ngx_http_request_t *r); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); @@ -320,7 +330,9 @@ ngx_int_t ngx_http_upstream_hide_headers uscf->srv_conf[module.ctx_index] -extern ngx_module_t ngx_http_upstream_module; +extern ngx_module_t ngx_http_upstream_module; +extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[]; + #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ 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 @@ -25,6 +25,8 @@ static ngx_int_t ngx_http_variable_unkno ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r, @@ -62,6 +64,8 @@ static ngx_int_t ngx_http_variable_body_ ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_body(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -162,8 +166,7 @@ static ngx_http_variable_t ngx_http_cor offsetof(ngx_http_request_t, uri), NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_string("request"), NULL, ngx_http_variable_request, - offsetof(ngx_http_request_t, request_line), 0, 0 }, + { ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 }, { ngx_string("document_root"), NULL, ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -202,6 +205,10 @@ static ngx_http_variable_t ngx_http_cor ngx_http_variable_request_completion, 0, 0, 0 }, + { ngx_string("request_body"), NULL, + ngx_http_variable_request_body, + 0, 0, 0 }, + { ngx_string("request_body_file"), NULL, ngx_http_variable_request_body_file, 0, 0, 0 }, @@ -745,6 +752,42 @@ ngx_http_variable_unknown_header(ngx_htt static ngx_int_t +ngx_http_variable_request_line(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p, *s; + + s = r->request_line.data; + + if (s == NULL) { + s = r->request_start; + + if (s == NULL) { + v->not_found = 1; + return NGX_OK; + } + + for (p = s; p < r->header_in->last; p++) { + if (*p == CR || *p == LF) { + break; + } + } + + r->request_line.len = p - s; + r->request_line.data = s; + } + + v->len = r->request_line.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = s; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { @@ -932,7 +975,7 @@ ngx_http_variable_server_addr(ngx_http_r s.len = NGX_SOCKADDR_STRLEN; s.data = addr; - if (ngx_http_server_addr(r, &s) != NGX_OK) { + if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) { return NGX_ERROR; } @@ -968,7 +1011,7 @@ ngx_http_variable_server_port(ngx_http_r v->no_cacheable = 0; v->not_found = 0; - if (ngx_http_server_addr(r, NULL) != NGX_OK) { + if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) { return NGX_ERROR; } @@ -1478,6 +1521,59 @@ ngx_http_variable_request_completion(ngx static ngx_int_t +ngx_http_variable_request_body(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_buf_t *buf, *next; + ngx_chain_t *cl; + + if (r->request_body == NULL + || r->request_body->bufs == NULL + || r->request_body->temp_file) + { + v->not_found = 1; + + return NGX_OK; + } + + cl = r->request_body->bufs; + buf = cl->buf; + + if (cl->next == NULL) { + v->len = buf->last - buf->pos; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = buf->pos; + + return NGX_OK; + } + + next = cl->next->buf; + len = (buf->last - buf->pos) + (next->last - next->pos); + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + p = ngx_cpymem(p, buf->pos, buf->last - buf->pos); + ngx_memcpy(p, next->pos, next->last - next->pos); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { 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 @@ -46,7 +46,7 @@ ngx_module_t ngx_http_write_filter_modu ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { - off_t size, sent, limit; + off_t size, sent, nsent, limit; ngx_uint_t last, flush; ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; @@ -210,7 +210,8 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - limit = r->limit_rate * (ngx_time() - r->start_sec + 1) - c->sent; + limit = r->limit_rate * (ngx_time() - r->start_sec + 1) + - (c->sent - clcf->limit_rate_after); if (limit <= 0) { c->write->delayed = 1; @@ -245,7 +246,23 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1); + + nsent = c->sent; + + if (clcf->limit_rate_after) { + + sent -= clcf->limit_rate_after; + if (sent < 0) { + sent = 0; + } + + nsent -= clcf->limit_rate_after; + if (nsent < 0) { + nsent = 0; + } + } + + delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1); if (delay > 0) { c->write->delayed = 1; 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,16 @@ static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two); +static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, + ngx_mail_listen_t *listen); +static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports); +static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, + ngx_mail_conf_addr_t *addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, + ngx_mail_conf_addr_t *addr); +#endif +static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two); ngx_uint_t ngx_mail_max_module; @@ -64,18 +73,12 @@ static char * ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - u_char *text; - size_t len; - ngx_uint_t i, a, l, m, mi, s, p, last, bind_all, done; + ngx_uint_t i, m, mi, s; ngx_conf_t pcf; - ngx_array_t in_ports; - ngx_listening_t *ls; - ngx_mail_listen_t *imls; + ngx_array_t ports; + ngx_mail_listen_t *listen; ngx_mail_module_t *module; - ngx_mail_in_port_t *imip; ngx_mail_conf_ctx_t *ctx; - ngx_mail_conf_in_port_t *in_port; - ngx_mail_conf_in_addr_t *in_addr; ngx_mail_core_srv_conf_t **cscfp; ngx_mail_core_main_conf_t *cmcf; @@ -216,178 +219,196 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma *cf = pcf; - if (ngx_array_init(&in_ports, cf->temp_pool, 4, - sizeof(ngx_mail_conf_in_port_t)) + if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t)) != NGX_OK) { return NGX_CONF_ERROR; } - imls = cmcf->listen.elts; - - for (l = 0; l < cmcf->listen.nelts; l++) { - - /* AF_INET only */ + listen = cmcf->listen.elts; - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { - if (in_port[p].port == imls[l].port) { - in_port = &in_port[p]; - goto found; - } - } - - in_port = ngx_array_push(&in_ports); - if (in_port == NULL) { - return NGX_CONF_ERROR; - } - - in_port->port = imls[l].port; - - if (ngx_array_init(&in_port->addrs, cf->temp_pool, 2, - sizeof(ngx_mail_conf_in_addr_t)) - != NGX_OK) - { + for (i = 0; i < cmcf->listen.nelts; i++) { + if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) { return NGX_CONF_ERROR; } + } - found: + return ngx_mail_optimize_servers(cf, &ports); +} + + +static ngx_int_t +ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, + ngx_mail_listen_t *listen) +{ + in_port_t p; + ngx_uint_t i; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_mail_conf_port_t *port; + ngx_mail_conf_addr_t *addr; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + sa = (struct sockaddr *) &listen->sockaddr; - in_addr = ngx_array_push(&in_port->addrs); - if (in_addr == NULL) { - return NGX_CONF_ERROR; + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + p = sin6->sin6_port; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + p = sin->sin_port; + break; + } + + port = ports->elts; + for (i = 0; i < ports->nelts; i++) { + if (p == port[i].port && sa->sa_family == port[i].family) { + + /* a port is already in the port list */ + + port = &port[i]; + goto found; } - - in_addr->addr = imls[l].addr; - in_addr->ctx = imls[l].ctx; - in_addr->bind = imls[l].bind; -#if (NGX_MAIL_SSL) - in_addr->ssl = imls[l].ssl; -#endif } - /* optimize the lists of ports and addresses */ + /* add a port to the port list */ + + port = ngx_array_push(ports); + if (port == NULL) { + return NGX_ERROR; + } + + port->family = sa->sa_family; + port->port = p; - /* AF_INET only */ + if (ngx_array_init(&port->addrs, cf->temp_pool, 2, + sizeof(ngx_mail_conf_addr_t)) + != NGX_OK) + { + return NGX_ERROR; + } + +found: + + addr = ngx_array_push(&port->addrs); + if (addr == NULL) { + return NGX_ERROR; + } - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { + addr->sockaddr = (struct sockaddr *) &listen->sockaddr; + addr->socklen = listen->socklen; + addr->ctx = listen->ctx; + addr->bind = listen->bind; + addr->wildcard = listen->wildcard; +#if (NGX_MAIL_SSL) + addr->ssl = listen->ssl; +#endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + addr->ipv6only = listen->ipv6only; +#endif + + return NGX_OK; +} + - ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, - sizeof(ngx_mail_conf_in_addr_t), ngx_mail_cmp_conf_in_addrs); +static char * +ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) +{ + ngx_uint_t i, p, last, bind_wildcard; + ngx_listening_t *ls; + ngx_mail_port_t *mport; + ngx_mail_conf_port_t *port; + ngx_mail_conf_addr_t *addr; - in_addr = in_port[p].addrs.elts; - last = in_port[p].addrs.nelts; + port = ports->elts; + for (p = 0; p < ports->nelts; p++) { + + ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, + sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs); + + addr = port[p].addrs.elts; + last = port[p].addrs.nelts; /* * if there is the binding to the "*:port" then we need to bind() * to the "*:port" only and ignore the other bindings */ - if (in_addr[last - 1].addr == INADDR_ANY) { - in_addr[last - 1].bind = 1; - bind_all = 0; + if (addr[last - 1].wildcard) { + addr[last - 1].bind = 1; + bind_wildcard = 1; } else { - bind_all = 1; + bind_wildcard = 0; } - for (a = 0; a < last; /* void */ ) { + i = 0; - if (!bind_all && !in_addr[a].bind) { - a++; + while (i < last) { + + if (bind_wildcard && !addr[i].bind) { + i++; continue; } - ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, - in_port[p].port); + ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); if (ls == NULL) { return NGX_CONF_ERROR; } - ls->backlog = NGX_LISTEN_BACKLOG; - ls->rcvbuf = -1; - ls->sndbuf = -1; - ls->addr_ntop = 1; ls->handler = ngx_mail_init_connection; ls->pool_size = 256; - /* STUB */ - ls->log = *cf->cycle->new_log; + /* TODO: error_log directive */ + ls->logp = &cf->cycle->new_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; - /**/ - imip = ngx_palloc(cf->pool, sizeof(ngx_mail_in_port_t)); - if (imip == NULL) { +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + ls->ipv6only = addr[i].ipv6only; +#endif + + mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t)); + if (mport == NULL) { return NGX_CONF_ERROR; } - ls->servers = imip; - - in_addr = in_port[p].addrs.elts; + ls->servers = mport; - if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { - imip->naddrs = 1; - done = 0; - - } else if (in_port[p].addrs.nelts > 1 - && in_addr[last - 1].addr == INADDR_ANY) - { - imip->naddrs = last; - done = 1; + if (i == last - 1) { + mport->naddrs = last; } else { - imip->naddrs = 1; - done = 0; + mport->naddrs = 1; + i = 0; } -#if 0 - ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - "%ui: %V %d %ui %ui", - a, &ls->addr_text, in_addr[a].bind, - imip->naddrs, last); -#endif - - imip->addrs = ngx_pcalloc(cf->pool, - imip->naddrs * sizeof(ngx_mail_in_addr_t)); - if (imip->addrs == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 0; i < imip->naddrs; i++) { - imip->addrs[i].addr = in_addr[i].addr; - imip->addrs[i].ctx = in_addr[i].ctx; - - text = ngx_pnalloc(cf->pool, - NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1); - if (text == NULL) { + switch (ls->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } - - len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text, - NGX_INET_ADDRSTRLEN); - - len = ngx_sprintf(text + len, ":%d", in_port[p].port) - text; - - imip->addrs[i].addr_text.len = len; - imip->addrs[i].addr_text.data = text; - -#if (NGX_MAIL_SSL) - imip->addrs[i].ssl = in_addr[i].ssl; + break; #endif - } - - if (done) { + default: /* AF_INET */ + if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) { + return NGX_CONF_ERROR; + } break; } - in_addr++; - in_port[p].addrs.elts = in_addr; + addr++; last--; - - a = 0; } } @@ -396,15 +417,111 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma static ngx_int_t -ngx_mail_cmp_conf_in_addrs(const void *one, const void *two) +ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, + ngx_mail_conf_addr_t *addr) { - ngx_mail_conf_in_addr_t *first, *second; + u_char *p; + size_t len; + ngx_uint_t i; + ngx_mail_in_addr_t *addrs; + struct sockaddr_in *sin; + u_char buf[NGX_SOCKADDR_STRLEN]; + + mport->addrs = ngx_pcalloc(cf->pool, + mport->naddrs * sizeof(ngx_mail_in_addr_t)); + if (mport->addrs == NULL) { + return NGX_ERROR; + } + + addrs = mport->addrs; + + for (i = 0; i < mport->naddrs; i++) { + + sin = (struct sockaddr_in *) addr[i].sockaddr; + addrs[i].addr = sin->sin_addr.s_addr; + + addrs[i].conf.ctx = addr[i].ctx; +#if (NGX_MAIL_SSL) + addrs[i].conf.ssl = addr[i].ssl; +#endif + + len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1); + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, buf, len); + + addrs[i].conf.addr_text.len = len; + addrs[i].conf.addr_text.data = p; + } + + return NGX_OK; +} + + +#if (NGX_HAVE_INET6) - first = (ngx_mail_conf_in_addr_t *) one; - second = (ngx_mail_conf_in_addr_t *) two; +static ngx_int_t +ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, + ngx_mail_conf_addr_t *addr) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_mail_in6_addr_t *addrs6; + struct sockaddr_in6 *sin6; + u_char buf[NGX_SOCKADDR_STRLEN]; + + mport->addrs = ngx_pcalloc(cf->pool, + mport->naddrs * sizeof(ngx_mail_in6_addr_t)); + if (mport->addrs == NULL) { + return NGX_ERROR; + } + + addrs6 = mport->addrs; + + for (i = 0; i < mport->naddrs; i++) { + + sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + addrs6[i].addr6 = sin6->sin6_addr; + + addrs6[i].conf.ctx = addr[i].ctx; +#if (NGX_MAIL_SSL) + addrs6[i].conf.ssl = addr[i].ssl; +#endif - if (first->addr == INADDR_ANY) { - /* the INADDR_ANY must be the last resort, shift it to the end */ + len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1); + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, buf, len); + + addrs6[i].conf.addr_text.len = len; + addrs6[i].conf.addr_text.data = p; + } + + return NGX_OK; +} + +#endif + + +static ngx_int_t +ngx_mail_cmp_conf_addrs(const void *one, const void *two) +{ + ngx_mail_conf_addr_t *first, *second; + + first = (ngx_mail_conf_addr_t *) one; + second = (ngx_mail_conf_addr_t *) two; + + if (first->wildcard) { + /* a wildcard must be the last resort, shift it to the end */ return 1; } 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 @@ -26,50 +26,76 @@ typedef struct { typedef struct { - in_addr_t addr; - in_port_t port; - int family; + u_char sockaddr[NGX_SOCKADDRLEN]; + socklen_t socklen; /* server ctx */ ngx_mail_conf_ctx_t *ctx; unsigned bind:1; + unsigned wildcard:1; #if (NGX_MAIL_SSL) unsigned ssl:1; #endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif } ngx_mail_listen_t; typedef struct { - in_addr_t addr; ngx_mail_conf_ctx_t *ctx; ngx_str_t addr_text; #if (NGX_MAIL_SSL) ngx_uint_t ssl; /* unsigned ssl:1; */ #endif +} ngx_mail_addr_conf_t; + +typedef struct { + in_addr_t addr; + ngx_mail_addr_conf_t conf; } ngx_mail_in_addr_t; +#if (NGX_HAVE_INET6) + typedef struct { - ngx_mail_in_addr_t *addrs; /* array of ngx_mail_in_addr_t */ - ngx_uint_t naddrs; -} ngx_mail_in_port_t; + struct in6_addr addr6; + ngx_mail_addr_conf_t conf; +} ngx_mail_in6_addr_t; + +#endif typedef struct { + /* ngx_mail_in_addr_t or ngx_mail_in6_addr_t */ + void *addrs; + ngx_uint_t naddrs; +} ngx_mail_port_t; + + +typedef struct { + int family; in_port_t port; - ngx_array_t addrs; /* array of ngx_mail_conf_in_addr_t */ -} ngx_mail_conf_in_port_t; + ngx_array_t addrs; /* array of ngx_mail_conf_addr_t */ +} ngx_mail_conf_port_t; typedef struct { - in_addr_t addr; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_mail_conf_ctx_t *ctx; + unsigned bind:1; + unsigned wildcard:1; #if (NGX_MAIL_SSL) unsigned ssl:1; #endif -} ngx_mail_conf_in_addr_t; +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif +} ngx_mail_conf_addr_t; typedef struct { 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 @@ -139,6 +139,7 @@ ngx_module_t ngx_mail_auth_http_module static ngx_str_t ngx_mail_auth_http_method[] = { ngx_string("plain"), ngx_string("plain"), + ngx_string("plain"), ngx_string("apop"), ngx_string("cram-md5"), ngx_string("none") @@ -770,6 +771,8 @@ ngx_mail_auth_http_process_headers(ngx_m return; } + /* AF_INET only */ + sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in)); if (sin == NULL) { ngx_destroy_pool(ctx->pool); @@ -1299,7 +1302,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_ ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t)); if (ahcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } ahcf->timeout = NGX_CONF_UNSET_MSEC; 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 @@ -120,20 +120,20 @@ ngx_mail_core_create_main_conf(ngx_conf_ cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t)); if (cmcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cmcf->servers, cf->pool, 4, sizeof(ngx_mail_core_srv_conf_t *)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return cmcf; @@ -274,19 +274,24 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx } -/* AF_INET only */ - static char * ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_mail_core_srv_conf_t *cscf = conf; + size_t len, off; + in_port_t port; ngx_str_t *value; ngx_url_t u; ngx_uint_t i, m; - ngx_mail_listen_t *imls; + struct sockaddr *sa; + ngx_mail_listen_t *ls; ngx_mail_module_t *module; + struct sockaddr_in *sin; ngx_mail_core_main_conf_t *cmcf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif value = cf->args->elts; @@ -305,18 +310,42 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - if (u.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "listen supports IPv4 only"); - return NGX_CONF_ERROR; - } - cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module); - imls = cmcf->listen.elts; + ls = cmcf->listen.elts; for (i = 0; i < cmcf->listen.nelts; i++) { - if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) { + sa = (struct sockaddr *) ls[i].sockaddr; + + if (sa->sa_family != u.family) { + continue; + } + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + off = offsetof(struct sockaddr_in6, sin6_addr); + len = 16; + sin6 = (struct sockaddr_in6 *) sa; + port = sin6->sin6_port; + break; +#endif + + default: /* AF_INET */ + off = offsetof(struct sockaddr_in, sin_addr); + len = 4; + sin = (struct sockaddr_in *) sa; + port = sin->sin_port; + break; + } + + if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) { + continue; + } + + if (port != u.port) { continue; } @@ -325,17 +354,18 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - imls = ngx_array_push(&cmcf->listen); - if (imls == NULL) { + ls = ngx_array_push(&cmcf->listen); + if (ls == NULL) { return NGX_CONF_ERROR; } - ngx_memzero(imls, sizeof(ngx_mail_listen_t)); + ngx_memzero(ls, sizeof(ngx_mail_listen_t)); + + ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); - imls->addr = u.addr.in_addr; - imls->port = u.port; - imls->family = u.family; - imls->ctx = cf->ctx; + ls->socklen = u.socklen; + ls->wildcard = u.wildcard; + ls->ctx = cf->ctx; for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_MAIL_MODULE) { @@ -359,13 +389,54 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx for (i = 2; i < cf->args->nelts; i++) { if (ngx_strcmp(value[i].data, "bind") == 0) { - imls->bind = 1; + ls->bind = 1; continue; } + if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + struct sockaddr *sa; + u_char buf[NGX_SOCKADDR_STRLEN]; + + sa = (struct sockaddr *) ls->sockaddr; + + if (sa->sa_family == AF_INET6) { + + if (ngx_strcmp(&value[i].data[10], "n") == 0) { + ls->ipv6only = 1; + + } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { + ls->ipv6only = 2; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid ipv6only flags \"%s\"", + &value[i].data[9]); + return NGX_CONF_ERROR; + } + + ls->bind = 1; + + } else { + len = ngx_sock_ntop(sa, buf, NGX_SOCKADDR_STRLEN, 1); + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ipv6only is not supported " + "on addr \"%*s\", ignored", len, buf); + } + + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bind ipv6only is not supported " + "on this platform"); + return NGX_CONF_ERROR; +#endif + } + if (ngx_strcmp(value[i].data, "ssl") == 0) { #if (NGX_MAIL_SSL) - imls->ssl = 1; + ls->ssl = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 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 @@ -21,25 +21,27 @@ static void ngx_mail_ssl_handshake_handl void ngx_mail_init_connection(ngx_connection_t *c) { - in_addr_t in_addr; - socklen_t len; - ngx_uint_t i; - struct sockaddr_in sin; - ngx_mail_log_ctx_t *ctx; - ngx_mail_in_port_t *imip; - ngx_mail_in_addr_t *imia; - ngx_mail_session_t *s; + ngx_uint_t i; + ngx_mail_port_t *port; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_mail_log_ctx_t *ctx; + ngx_mail_in_addr_t *addr; + ngx_mail_session_t *s; + ngx_mail_addr_conf_t *addr_conf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; + ngx_mail_in6_addr_t *addr6; +#endif + /* find the server configuration for the address:port */ /* AF_INET only */ - imip = c->listening->servers; - imia = imip->addrs; + port = c->listening->servers; - i = 0; - - if (imip->naddrs > 1) { + if (port->naddrs > 1) { /* * There are several addresses on this port and one of them @@ -49,45 +51,79 @@ ngx_mail_init_connection(ngx_connection_ * AcceptEx() already gave this address. */ -#if (NGX_WIN32) - if (c->local_sockaddr) { - in_addr = - ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + + sa = c->local_sockaddr; + + switch (sa->sa_family) { - } else -#endif - { - len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { - ngx_connection_error(c, ngx_socket_errno, - "getsockname() failed"); - ngx_mail_close_connection(c); - return; +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + + addr6 = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { + break; + } } - in_addr = sin.sin_addr.s_addr; + addr_conf = &addr6[i].conf; + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + + addr = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (addr[i].addr == sin->sin_addr.s_addr) { + break; + } + } + + addr_conf = &addr[i].conf; + + break; } - /* the last address is "*" */ + } else { + switch (c->local_sockaddr->sa_family) { - for ( /* void */ ; i < imip->naddrs - 1; i++) { - if (in_addr == imia[i].addr) { - break; - } +#if (NGX_HAVE_INET6) + case AF_INET6: + addr6 = port->addrs; + addr_conf = &addr6[0].conf; + break; +#endif + + default: /* AF_INET */ + addr = port->addrs; + addr_conf = &addr[0].conf; + break; } } - s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t)); if (s == NULL) { ngx_mail_close_connection(c); return; } - s->main_conf = imia[i].ctx->main_conf; - s->srv_conf = imia[i].ctx->srv_conf; + s->main_conf = addr_conf->ctx->main_conf; + s->srv_conf = addr_conf->ctx->srv_conf; - s->addr_text = &imia[i].addr_text; + s->addr_text = &addr_conf->addr_text; c->data = s; s->connection = c; @@ -124,7 +160,7 @@ ngx_mail_init_connection(ngx_connection_ return; } - if (imia[i].ssl) { + if (addr_conf->ssl) { c->log->action = "SSL handshaking"; @@ -680,7 +716,7 @@ ngx_mail_close_connection(ngx_connection #endif #if (NGX_STAT_STUB) - ngx_atomic_fetch_add(ngx_stat_active, -1); + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif c->destroyed = 1; 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 @@ -1066,7 +1066,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *c pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t)); if (pcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } pcf->enable = NGX_CONF_UNSET; 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 @@ -66,6 +66,12 @@ ngx_mail_smtp_init_session(ngx_mail_sess return; } + if (c->sockaddr->sa_family != AF_INET) { + s->host = smtp_tempunavail; + ngx_mail_smtp_greeting(s, c); + return; + } + c->log->action = "in resolving client address"; ctx = ngx_resolve_start(cscf->resolver, NULL); 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 @@ -22,15 +22,6 @@ static char *ngx_mail_ssl_starttls(ngx_c static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char *ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -static char ngx_mail_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; - -#endif - static ngx_conf_enum_t ngx_http_starttls_state[] = { { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, @@ -102,14 +93,10 @@ static ngx_command_t ngx_mail_ssl_comma { ngx_string("ssl_prefer_server_ciphers"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE ngx_conf_set_flag_slot, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers), NULL }, -#else - ngx_mail_ssl_nosupported, 0, 0, ngx_mail_ssl_openssl097 }, -#endif { ngx_string("ssl_session_cache"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, @@ -166,7 +153,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t)); if (scf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -182,7 +169,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) */ scf->enable = NGX_CONF_UNSET; - scf->starttls = NGX_CONF_UNSET; + scf->starttls = NGX_CONF_UNSET_UINT; scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->builtin_session_cache = NGX_CONF_UNSET; scf->session_timeout = NGX_CONF_UNSET; @@ -297,14 +284,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, } } -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (conf->prefer_server_ciphers) { SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#endif - if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { return NGX_CONF_ERROR; } @@ -492,18 +475,3 @@ invalid: return NGX_CONF_ERROR; } - - -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char * -ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" directive is available only in %s,", - &cmd->name, cmd->post); - - return NGX_CONF_ERROR; -} - -#endif diff --git a/src/os/unix/ngx_aio.h b/src/os/unix/ngx_aio.h deleted file mode 100644 --- a/src/os/unix/ngx_aio.h +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_AIO_H_INCLUDED_ -#define _NGX_AIO_H_INCLUDED_ - - -#include - - -ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size); -ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl); -ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size); -ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, - off_t limit); - - -#endif /* _NGX_AIO_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_aio_read.c b/src/os/unix/ngx_aio_read.c --- a/src/os/unix/ngx_aio_read.c +++ b/src/os/unix/ngx_aio_read.c @@ -7,20 +7,10 @@ #include #include #include -#include - -#if (NGX_HAVE_KQUEUE) -#include -#endif -/* - * the ready data requires 3 syscalls: - * aio_write(), aio_error(), aio_return() - * the non-ready data requires 4 (kqueue) or 5 syscalls: - * aio_write(), aio_error(), notifiction, aio_error(), aio_return() - * timeout, aio_cancel(), aio_error() - */ +extern int ngx_kqueue; + ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size) diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c --- a/src/os/unix/ngx_aio_read_chain.c +++ b/src/os/unix/ngx_aio_read_chain.c @@ -7,7 +7,6 @@ #include #include #include -#include ssize_t diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c --- a/src/os/unix/ngx_aio_write.c +++ b/src/os/unix/ngx_aio_write.c @@ -7,20 +7,10 @@ #include #include #include -#include - -#if (NGX_HAVE_KQUEUE) -#include -#endif -/* - * the ready data requires 3 syscalls: - * aio_write(), aio_error(), aio_return() - * the non-ready data requires 4 (kqueue) or 5 syscalls: - * aio_write(), aio_error(), notifiction, aio_error(), aio_return() - * timeout, aio_cancel(), aio_error() - */ +extern int ngx_kqueue; + ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size) diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c --- a/src/os/unix/ngx_aio_write_chain.c +++ b/src/os/unix/ngx_aio_write_chain.c @@ -7,7 +7,6 @@ #include #include #include -#include ngx_chain_t * diff --git a/src/os/unix/ngx_darwin_sendfile_chain.c b/src/os/unix/ngx_darwin_sendfile_chain.c --- a/src/os/unix/ngx_darwin_sendfile_chain.c +++ b/src/os/unix/ngx_darwin_sendfile_chain.c @@ -42,7 +42,7 @@ ngx_darwin_sendfile_chain(ngx_connection u_char *prev; off_t size, send, prev_send, aligned, sent, fprev; off_t header_size, file_size; - ngx_uint_t eintr, eagain, complete; + ngx_uint_t eintr, complete; ngx_err_t err; ngx_buf_t *file; ngx_array_t header, trailer; @@ -75,7 +75,6 @@ ngx_darwin_sendfile_chain(ngx_connection } send = 0; - eagain = 0; header.elts = headers; header.size = sizeof(struct iovec); @@ -238,22 +237,22 @@ ngx_darwin_sendfile_chain(ngx_connection if (rc == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; + switch (err) { + case NGX_EAGAIN: + break; - } else { - eagain = 1; - } + case NGX_EINTR: + eintr = 1; + break; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, - "sendfile() sent only %O bytes", sent); - - } else { + default: wev->error = 1; (void) ngx_connection_error(c, err, "sendfile() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() sent only %O bytes", sent); } if (rc == 0 && sent == 0) { @@ -284,19 +283,22 @@ ngx_darwin_sendfile_chain(ngx_connection if (rc == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; - } + switch (err) { + case NGX_EAGAIN: + break; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + case NGX_EINTR: + eintr = 1; + break; - } else { + default: wev->error = 1; ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); } sent = rc > 0 ? rc : 0; 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 @@ -16,6 +16,7 @@ typedef int ngx_err_t; #define NGX_EPERM EPERM #define NGX_ENOENT ENOENT +#define NGX_ENOPATH ENOENT #define NGX_ESRCH ESRCH #define NGX_EINTR EINTR #define NGX_ECHILD ECHILD diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_file_aio_read.c @@ -0,0 +1,214 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +/* + * FreeBSD file AIO features and quirks: + * + * if an asked data are already in VM cache, then aio_error() returns 0, + * and the data are already copied in buffer; + * + * aio_read() preread in VM cache as minimum 16K (probably BKVASIZE); + * the first AIO preload may be up to 128K; + * + * aio_read/aio_error() may return EINPROGRESS for just written data; + * + * kqueue EVFILT_AIO filter is level triggered only: an event repeats + * until aio_return() will be called; + * + * aio_cancel() can not cancel file AIO: it returns AIO_NOTCANCELED always. + */ + + +extern int ngx_kqueue; + + +static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, + ngx_event_t *ev); +static void ngx_file_aio_event_handler(ngx_event_t *ev); + + +ssize_t +ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, + ngx_pool_t *pool) +{ + int n; + ngx_event_t *ev; + ngx_event_aio_t *aio; + static ngx_uint_t enosys = 0; + + if (enosys) { + return ngx_read_file(file, buf, size, offset); + } + + aio = file->aio; + + if (aio == NULL) { + aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); + if (aio == NULL) { + return NGX_ERROR; + } + + aio->file = file; + aio->fd = file->fd; + aio->event.data = aio; + aio->event.ready = 1; + aio->event.log = file->log; +#if (NGX_HAVE_AIO_SENDFILE) + aio->last_offset = -1; +#endif + file->aio = aio; + } + + ev = &aio->event; + + if (!ev->ready) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "second aio post for \"%V\"", &file->name); + return NGX_AGAIN; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio complete:%d @%O:%z %V", + ev->complete, offset, size, &file->name); + + if (ev->complete) { + ev->complete = 0; + ngx_set_errno(aio->err); + + if (aio->err == 0) { + return aio->nbytes; + } + + return NGX_ERROR; + } + + ngx_memzero(&aio->aiocb, sizeof(struct aiocb)); + + aio->aiocb.aio_fildes = file->fd; + aio->aiocb.aio_offset = offset; + aio->aiocb.aio_buf = buf; + aio->aiocb.aio_nbytes = size; +#if (NGX_HAVE_KQUEUE) + aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; + aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; + aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; +#endif + ev->handler = ngx_file_aio_event_handler; + + n = aio_read(&aio->aiocb); + + if (n == -1) { + n = ngx_errno; + + if (n == NGX_EAGAIN) { + return ngx_read_file(file, buf, size, offset); + } + + ngx_log_error(NGX_LOG_CRIT, file->log, n, + "aio_read(\"%V\") failed", &file->name); + + if (n == NGX_ENOSYS) { + enosys = 1; + return ngx_read_file(file, buf, size, offset); + } + + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio_read: fd:%d %d", file->fd, n); + + ev->active = 1; + ev->ready = 0; + ev->complete = 0; + + return ngx_file_aio_result(aio->file, aio, ev); +} + + +static ssize_t +ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev) +{ + int n; + ngx_err_t err; + + n = aio_error(&aio->aiocb); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio_error: fd:%d %d", file->fd, n); + + if (n == -1) { + err = ngx_errno; + aio->err = err; + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + "aio_error(\"%V\") failed", &file->name); + return NGX_ERROR; + } + + if (n != 0) { + if (n == NGX_EINPROGRESS) { + if (ev->ready) { + ev->ready = 0; + ngx_log_error(NGX_LOG_ALERT, file->log, n, + "aio_read(\"%V\") still in progress", + &file->name); + } + + return NGX_AGAIN; + } + + aio->err = n; + ev->ready = 0; + + ngx_log_error(NGX_LOG_CRIT, file->log, n, + "aio_read(\"%V\") failed", &file->name); + return NGX_ERROR; + } + + n = aio_return(&aio->aiocb); + + if (n == -1) { + err = ngx_errno; + aio->err = err; + ev->ready = 0; + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + "aio_return(\"%V\") failed", &file->name); + return NGX_ERROR; + } + + aio->err = 0; + aio->nbytes = n; + ev->ready = 1; + ev->active = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio_return: fd:%d %d", file->fd, n); + + return n; +} + + +static void +ngx_file_aio_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + + aio = ev->data; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0, + "aio event handler fd:%d %V", aio->fd, &aio->file->name); + + if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) { + aio->handler(ev); + } +} 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 @@ -18,13 +18,13 @@ typedef ino_t ngx_fil typedef struct { - DIR *dir; - struct dirent *de; - struct stat info; + DIR *dir; + struct dirent *de; + struct stat info; - unsigned type:8; - unsigned valid_info:1; - unsigned valid_type:1; + unsigned type:8; + unsigned valid_info:1; + unsigned valid_type:1; } ngx_dir_t; @@ -63,7 +63,7 @@ typedef struct { #define NGX_FILE_RDWR O_RDWR #define NGX_FILE_CREATE_OR_OPEN O_CREAT #define NGX_FILE_OPEN 0 -#define NGX_FILE_TRUNCATE O_TRUNC +#define NGX_FILE_TRUNCATE O_CREAT|O_TRUNC #define NGX_FILE_APPEND O_WRONLY|O_APPEND #define NGX_FILE_DEFAULT_ACCESS 0644 @@ -113,6 +113,10 @@ ngx_write_fd(ngx_fd_t fd, void *buf, siz #define ngx_write_fd_n "write()" + +#define ngx_write_console ngx_write_fd + + #define ngx_linefeed(p) *p++ = LF; #define NGX_LINEFEED_SIZE 1 @@ -158,8 +162,10 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_realpath(p, r) realpath((char *) p, (char *) r) #define ngx_realpath_n "realpath()" -#define ngx_getcwd(buf, size) (getcwd(buf, size) != NULL) +#define ngx_getcwd(buf, size) (getcwd((char *) buf, size) != NULL) #define ngx_getcwd_n "getcwd()" +#define ngx_path_separator(c) ((c) == '/') + #define NGX_MAX_PATH PATH_MAX #define NGX_DIR_MASK_LEN 0 @@ -273,8 +279,20 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #endif - size_t ngx_fs_bsize(u_char *name); +#define ngx_stderr STDERR_FILENO +#define ngx_set_stderr(fd) dup2(fd, STDERR_FILENO) +#define ngx_set_stderr_n "dup2(STDERR_FILENO)" + + +#if (NGX_HAVE_FILE_AIO) + +ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, + off_t offset, ngx_pool_t *pool); + +#endif + + #endif /* _NGX_FILES_H_INCLUDED_ */ 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 @@ -73,13 +73,14 @@ #endif -#if (NGX_HAVE_AIO) -#include +#if (NGX_HAVE_KQUEUE) +#include #endif -#if (NGX_HAVE_KQUEUE) -#include +#if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO) +#include +typedef struct aiocb ngx_aiocb_t; #endif diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -40,7 +40,7 @@ ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc; + int rc, flags; u_char *prev; off_t size, send, prev_send, aligned, sent, fprev; size_t header_size, file_size; @@ -78,6 +78,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio send = 0; eagain = 0; + flags = 0; header.elts = headers; header.size = sizeof(struct iovec); @@ -261,36 +262,46 @@ ngx_freebsd_sendfile_chain(ngx_connectio sent = 0; +#if (NGX_HAVE_AIO_SENDFILE) + flags = c->aio_sendfile ? SF_NODISKIO : 0; +#endif + rc = sendfile(file->file->fd, c->fd, file->file_pos, - file_size + header_size, &hdtr, &sent, 0); + file_size + header_size, &hdtr, &sent, flags); if (rc == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; + switch (err) { + case NGX_EAGAIN: + eagain = 1; + break; - } else { - eagain = 1; - } + case NGX_EINTR: + eintr = 1; + break; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, - "sendfile() sent only %O bytes", sent); +#if (NGX_HAVE_AIO_SENDFILE) + case NGX_EBUSY: + c->busy_sendfile = file; + break; +#endif - } else { + default: wev->error = 1; (void) ngx_connection_error(c, err, "sendfile() failed"); return NGX_CHAIN_ERROR; } - } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() sent only %O bytes", sent); /* * sendfile() in FreeBSD 3.x-4.x may return value >= 0 * on success, although only 0 is documented */ - if (rc >= 0 && sent == 0) { + } else if (rc >= 0 && sent == 0) { /* * if rc is OK and sent equal to zero, then someone @@ -299,8 +310,8 @@ ngx_freebsd_sendfile_chain(ngx_connectio */ ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "sendfile() reported that \"%s\" was truncated", - file->file->name.data); + "sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); return NGX_CHAIN_ERROR; } @@ -318,19 +329,22 @@ ngx_freebsd_sendfile_chain(ngx_connectio if (rc == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; - } + switch (err) { + case NGX_EAGAIN: + break; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + case NGX_EINTR: + eintr = 1; + break; - } else { + default: wev->error = 1; ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); } sent = rc > 0 ? rc : 0; @@ -379,6 +393,12 @@ ngx_freebsd_sendfile_chain(ngx_connectio break; } +#if (NGX_HAVE_AIO_SENDFILE) + if (c->busy_sendfile) { + return cl; + } +#endif + if (eagain) { /* diff --git a/src/os/unix/ngx_linux_aio_read.c b/src/os/unix/ngx_linux_aio_read.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_linux_aio_read.c @@ -0,0 +1,131 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +extern int ngx_eventfd; +extern aio_context_t ngx_aio_ctx; + + +static void ngx_file_aio_event_handler(ngx_event_t *ev); + + +static long +io_submit(aio_context_t ctx, long n, struct iocb **paiocb) +{ + return syscall(SYS_io_submit, ctx, n, paiocb); +} + + +ssize_t +ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, + ngx_pool_t *pool) +{ + long n; + struct iocb *piocb[1]; + ngx_event_t *ev; + ngx_event_aio_t *aio; + static ngx_uint_t enosys = 0; + + if (enosys) { + return ngx_read_file(file, buf, size, offset); + } + + aio = file->aio; + + if (aio == NULL) { + aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); + if (aio == NULL) { + return NGX_ERROR; + } + + aio->file = file; + aio->fd = file->fd; + aio->event.data = aio; + aio->event.ready = 1; + aio->event.log = file->log; + file->aio = aio; + } + + ev = &aio->event; + + if (!ev->ready) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "second aio post for \"%V\"", &file->name); + return NGX_AGAIN; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio complete:%d @%O:%z %V", + ev->complete, offset, size, &file->name); + + if (ev->complete) { + ev->active = 0; + ev->complete = 0; + + if (aio->res >= 0) { + ngx_set_errno(0); + return aio->res; + } + + ngx_set_errno(-aio->res); + return NGX_ERROR; + } + + ngx_memzero(&aio->aiocb, sizeof(struct iocb)); + + aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev; + aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD; + aio->aiocb.aio_fildes = file->fd; + aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf; + aio->aiocb.aio_nbytes = size; + aio->aiocb.aio_offset = offset; + aio->aiocb.aio_flags = IOCB_FLAG_RESFD; + aio->aiocb.aio_resfd = ngx_eventfd; + + ev->handler = ngx_file_aio_event_handler; + + piocb[0] = &aio->aiocb; + + n = io_submit(ngx_aio_ctx, 1, piocb); + + if (n == 1) { + return NGX_AGAIN; + } + + n = -n; + + if (n == NGX_EAGAIN) { + return ngx_read_file(file, buf, size, offset); + } + + ngx_log_error(NGX_LOG_CRIT, file->log, n, + "io_submit(\"%V\") failed", &file->name); + + if (n == NGX_ENOSYS) { + enosys = 1; + return ngx_read_file(file, buf, size, offset); + } + + return NGX_ERROR; +} + + +static void +ngx_file_aio_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + + aio = ev->data; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0, + "aio event handler fd:%d %V", aio->fd, &aio->file->name); + + aio->handler(ev); +} 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 @@ -81,6 +81,13 @@ extern ssize_t sendfile(int s, int fd, i #endif +#if (NGX_HAVE_FILE_AIO) +#include +#include +typedef struct iocb ngx_aiocb_t; +#endif + + #define NGX_LISTEN_BACKLOG 511 @@ -95,11 +102,6 @@ extern ssize_t sendfile(int s, int fd, i #endif -#ifndef NGX_HAVE_GNU_CRYPT_R -#define NGX_HAVE_GNU_CRYPT_R 1 -#endif - - #ifndef NGX_HAVE_INHERITED_NONBLOCK #define NGX_HAVE_INHERITED_NONBLOCK 0 #endif diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -263,19 +263,22 @@ ngx_linux_sendfile_chain(ngx_connection_ if (rc == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; - } + switch (err) { + case NGX_EAGAIN: + break; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "sendfile() is not ready"); + case NGX_EINTR: + eintr = 1; + break; - } else { + default: wev->error = 1; ngx_connection_error(c, err, "sendfile() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() is not ready"); } sent = rc > 0 ? rc : 0; @@ -290,19 +293,22 @@ ngx_linux_sendfile_chain(ngx_connection_ if (rc == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; - } + switch (err) { + case NGX_EAGAIN: + break; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + case NGX_EINTR: + eintr = 1; + break; - } else { + default: wev->error = 1; ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); } sent = rc > 0 ? rc : 0; 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 @@ -37,6 +37,7 @@ void ngx_os_status(ngx_log_t *log); ngx_int_t ngx_os_specific_init(ngx_log_t *log); void ngx_os_specific_status(ngx_log_t *log); ngx_int_t ngx_daemon(ngx_log_t *log); +ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid); ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); @@ -46,6 +47,14 @@ ssize_t ngx_unix_send(ngx_connection_t * ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); +#if (NGX_HAVE_AIO) +ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl); +ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size); +ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +#endif + extern ngx_os_io_t ngx_os_io; extern ngx_int_t ngx_ncpu; @@ -53,7 +62,6 @@ extern ngx_int_t ngx_max_sockets; extern ngx_uint_t ngx_inherited_nonblocking; extern ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; -#define ngx_stderr_fileno STDERR_FILENO #if (NGX_FREEBSD) #include 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 @@ -44,6 +44,9 @@ #include #include #include +#if (NGX_HAVE_SYS_PARAM_H) +#include /* statfs() */ +#endif #if (NGX_HAVE_SYS_MOUNT_H) #include /* statfs() */ #endif @@ -109,6 +112,12 @@ #endif +#if (NGX_HAVE_FILE_AIO) +#include +typedef struct aiocb ngx_aiocb_t; +#endif + + #define NGX_LISTEN_BACKLOG 511 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 @@ -13,6 +13,7 @@ typedef struct { int signo; char *signame; + char *name; void (*handler)(int signo); } ngx_signal_t; @@ -36,39 +37,47 @@ ngx_process_t ngx_processes[NGX_MAX_P ngx_signal_t signals[] = { { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), + "reload", ngx_signal_handler }, { ngx_signal_value(NGX_REOPEN_SIGNAL), "SIG" ngx_value(NGX_REOPEN_SIGNAL), + "reopen", ngx_signal_handler }, { ngx_signal_value(NGX_NOACCEPT_SIGNAL), "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), + "", ngx_signal_handler }, { ngx_signal_value(NGX_TERMINATE_SIGNAL), "SIG" ngx_value(NGX_TERMINATE_SIGNAL), + "stop", ngx_signal_handler }, { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), + "quit", ngx_signal_handler }, { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), + "", ngx_signal_handler }, - { SIGALRM, "SIGALRM", ngx_signal_handler }, + { SIGALRM, "SIGALRM", "", ngx_signal_handler }, - { SIGINT, "SIGINT", ngx_signal_handler }, + { SIGINT, "SIGINT", "", ngx_signal_handler }, - { SIGIO, "SIGIO", ngx_signal_handler }, + { SIGIO, "SIGIO", "", ngx_signal_handler }, - { SIGCHLD, "SIGCHLD", ngx_signal_handler }, + { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, + + { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN }, - { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN }, + { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN }, - { 0, NULL, NULL } + { 0, NULL, "", NULL } }; @@ -207,21 +216,33 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng switch (respawn) { + case NGX_PROCESS_NORESPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_SPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + case NGX_PROCESS_RESPAWN: ngx_processes[s].respawn = 1; - ngx_processes[s].just_respawn = 0; + ngx_processes[s].just_spawn = 0; ngx_processes[s].detached = 0; break; case NGX_PROCESS_JUST_RESPAWN: ngx_processes[s].respawn = 1; - ngx_processes[s].just_respawn = 1; + ngx_processes[s].just_spawn = 1; ngx_processes[s].detached = 0; break; case NGX_PROCESS_DETACHED: ngx_processes[s].respawn = 0; - ngx_processes[s].just_respawn = 0; + ngx_processes[s].just_spawn = 0; ngx_processes[s].detached = 1; break; } @@ -352,6 +373,7 @@ ngx_signal_handler(int signo) break; case SIGALRM: + ngx_sigalrm = 1; break; case SIGIO: @@ -540,3 +562,23 @@ ngx_debug_point(void) ngx_abort(); } } + + +ngx_int_t +ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid) +{ + ngx_signal_t *sig; + + for (sig = signals; sig->signo != 0; sig++) { + if (ngx_strcmp(name, sig->name) == 0) { + if (kill(pid, sig->signo) != -1) { + return 0; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "kill(%P, %d) failed", pid, sig->signo); + } + } + + return 1; +} diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -27,7 +27,7 @@ typedef struct { char *name; unsigned respawn:1; - unsigned just_respawn:1; + unsigned just_spawn:1; unsigned detached:1; unsigned exiting:1; unsigned exited:1; @@ -45,9 +45,10 @@ typedef struct { #define NGX_MAX_PROCESSES 1024 #define NGX_PROCESS_NORESPAWN -1 -#define NGX_PROCESS_RESPAWN -2 -#define NGX_PROCESS_JUST_RESPAWN -3 -#define NGX_PROCESS_DETACHED -4 +#define NGX_PROCESS_JUST_SPAWN -2 +#define NGX_PROCESS_RESPAWN -3 +#define NGX_PROCESS_JUST_RESPAWN -4 +#define NGX_PROCESS_DETACHED -5 #define ngx_getpid getpid 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 @@ -12,7 +12,9 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type); -static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, + ngx_uint_t respawn); +static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle); static void ngx_master_process_exit(ngx_cycle_t *cycle); @@ -26,6 +28,7 @@ static ngx_thread_value_t ngx_worker_thr #endif static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_cache_manager_process_handler(ngx_event_t *ev); +static void ngx_cache_loader_process_handler(ngx_event_t *ev); ngx_uint_t ngx_process; @@ -34,6 +37,7 @@ ngx_uint_t ngx_threaded; sig_atomic_t ngx_reap; sig_atomic_t ngx_sigio; +sig_atomic_t ngx_sigalrm; sig_atomic_t ngx_terminate; sig_atomic_t ngx_quit; sig_atomic_t ngx_debug_quit; @@ -61,6 +65,15 @@ u_long cpu_affinity; static u_char master_process[] = "master process"; +static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = { + ngx_cache_manager_process_handler, "cache manager process", 0 +}; + +static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = { + ngx_cache_loader_process_handler, "cache loader process", 60000 +}; + + static ngx_cycle_t ngx_exit_cycle; static ngx_log_t ngx_exit_log; static ngx_open_file_t ngx_exit_log_file; @@ -122,7 +135,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; @@ -130,10 +143,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy for ( ;; ) { if (delay) { - delay *= 2; + if (ngx_sigalrm) { + delay *= 2; + ngx_sigalrm = 0; + } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "temination cycle: %d", delay); + "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; @@ -203,7 +219,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; @@ -222,7 +238,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN); + ngx_start_cache_manager_processes(cycle, 1); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); @@ -232,7 +248,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); live = 1; } @@ -265,8 +281,6 @@ ngx_single_process_cycle(ngx_cycle_t *cy { ngx_uint_t i; - ngx_init_temp_number(); - for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { @@ -317,7 +331,7 @@ ngx_single_process_cycle(ngx_cycle_t *cy static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { - ngx_int_t i, s; + ngx_int_t i; ngx_channel_t ch; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); @@ -335,58 +349,70 @@ ngx_start_worker_processes(ngx_cycle_t * ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; - for (s = 0; s < ngx_last_process; s++) { - - if (s == ngx_process_slot - || ngx_processes[s].pid == -1 - || ngx_processes[s].channel[0] == -1) - { - continue; - } - - ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, - s, ngx_processes[s].pid, - ngx_processes[s].channel[0]); - - /* TODO: NGX_AGAIN */ - - ngx_write_channel(ngx_processes[s].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); - } + ngx_pass_open_channel(cycle, &ch); } } static void -ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type) +ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) { - ngx_int_t i; - ngx_uint_t n; + ngx_uint_t i, manager, loader; ngx_path_t **path; ngx_channel_t ch; + manager = 0; + loader = 0; + path = ngx_cycle->pathes.elts; - for (n = 0; n < ngx_cycle->pathes.nelts; n++) { - if (path[n]->manager) { - goto start; + for (i = 0; i < ngx_cycle->pathes.nelts; i++) { + + if (path[i]->manager) { + manager = 1; + } + + if (path[i]->loader) { + loader = 1; } } - return; + if (manager == 0) { + return; + } -start: + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_manager_ctx, "cache manager process", + respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN); ch.command = NGX_CMD_OPEN_CHANNEL; - - ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, NULL, - "cache manager process", type); - ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; + ngx_pass_open_channel(cycle, &ch); + + if (loader == 0) { + return; + } + + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_loader_ctx, "cache loader process", + respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN); + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); +} + + +static void +ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) +{ + ngx_int_t i; + for (i = 0; i < ngx_last_process; i++) { if (i == ngx_process_slot @@ -398,14 +424,14 @@ start: ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, + ch->slot, ch->pid, ch->fd, i, ngx_processes[i].pid, ngx_processes[i].channel[0]); /* TODO: NGX_AGAIN */ ngx_write_channel(ngx_processes[i].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); + ch, sizeof(ngx_channel_t), cycle->log); } } @@ -456,14 +482,14 @@ ngx_signal_worker_processes(ngx_cycle_t ngx_processes[i].exited, ngx_processes[i].detached, ngx_processes[i].respawn, - ngx_processes[i].just_respawn); + ngx_processes[i].just_spawn); if (ngx_processes[i].detached || ngx_processes[i].pid == -1) { continue; } - if (ngx_processes[i].just_respawn) { - ngx_processes[i].just_respawn = 0; + if (ngx_processes[i].just_spawn) { + ngx_processes[i].just_spawn = 0; continue; } @@ -492,8 +518,7 @@ ngx_signal_worker_processes(ngx_cycle_t if (kill(ngx_processes[i].pid, signo) == -1) { err = ngx_errno; ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - "kill(%P, %d) failed", - ngx_processes[i].pid, signo); + "kill(%P, %d) failed", ngx_processes[i].pid, signo); if (err == NGX_ESRCH) { ngx_processes[i].exited = 1; @@ -533,7 +558,7 @@ ngx_reap_children(ngx_cycle_t *cycle) ngx_processes[i].exited, ngx_processes[i].detached, ngx_processes[i].respawn, - ngx_processes[i].just_respawn); + ngx_processes[i].just_spawn); if (ngx_processes[i].pid == -1) { continue; @@ -590,26 +615,7 @@ ngx_reap_children(ngx_cycle_t *cycle) ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; - for (n = 0; n < ngx_last_process; n++) { - - if (n == ngx_process_slot - || ngx_processes[n].pid == -1 - || ngx_processes[n].channel[0] == -1) - { - continue; - } - - ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, - n, ngx_processes[n].pid, - ngx_processes[n].channel[0]); - - /* TODO: NGX_AGAIN */ - - ngx_write_channel(ngx_processes[n].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); - } + ngx_pass_open_channel(cycle, &ch); live = 1; @@ -925,8 +931,6 @@ ngx_worker_process_init(ngx_cycle_t *cyc "sigprocmask() failed"); } - ngx_init_temp_number(); - /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point @@ -1012,13 +1016,14 @@ ngx_worker_process_exit(ngx_cycle_t *cyc && !c[i].read->resolver) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in connection %ui%s", - c[i].fd, i, ngx_debug_quit ? ", aborting" : ""); - ngx_debug_point(); + "open socket #%d left in connection %ui", + c[i].fd, i); + ngx_debug_quit = 1; } } if (ngx_debug_quit) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting"); ngx_debug_point(); } } @@ -1265,6 +1270,8 @@ ngx_worker_thread_cycle(void *data) static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { + ngx_cache_manager_ctx_t *ctx = data; + void *ident[4]; ngx_event_t ev; @@ -1275,16 +1282,16 @@ ngx_cache_manager_process_cycle(ngx_cycl ngx_close_listening_sockets(cycle); ngx_memzero(&ev, sizeof(ngx_event_t)); - ev.handler = ngx_cache_manager_process_handler; + ev.handler = ctx->handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; - ngx_setproctitle("cache manager process"); + ngx_setproctitle(ctx->name); - ngx_add_timer(&ev, 0); + ngx_add_timer(&ev, ctx->delay); for ( ;; ) { @@ -1331,3 +1338,29 @@ ngx_cache_manager_process_handler(ngx_ev ngx_add_timer(ev, next * 1000); } + + +static void +ngx_cache_loader_process_handler(ngx_event_t *ev) +{ + ngx_uint_t i; + ngx_path_t **path; + ngx_cycle_t *cycle; + + cycle = (ngx_cycle_t *) ngx_cycle; + + path = cycle->pathes.elts; + for (i = 0; i < cycle->pathes.nelts; i++) { + + if (ngx_terminate || ngx_quit) { + break; + } + + if (path[i]->loader) { + path[i]->loader(path[i]->data); + ngx_time_update(0, 0); + } + } + + exit(0); +} diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h --- a/src/os/unix/ngx_process_cycle.h +++ b/src/os/unix/ngx_process_cycle.h @@ -19,9 +19,17 @@ #define NGX_CMD_REOPEN 5 -#define NGX_PROCESS_SINGLE 0 -#define NGX_PROCESS_MASTER 1 -#define NGX_PROCESS_WORKER 2 +#define NGX_PROCESS_SINGLE 0 +#define NGX_PROCESS_MASTER 1 +#define NGX_PROCESS_WORKER 2 +#define NGX_PROCESS_SIGNALLER 3 + + +typedef struct { + ngx_event_handler_pt handler; + char *name; + ngx_msec_t delay; +} ngx_cache_manager_ctx_t; void ngx_master_process_cycle(ngx_cycle_t *cycle); @@ -38,6 +46,7 @@ extern ngx_uint_t ngx_exiting; extern sig_atomic_t ngx_reap; extern sig_atomic_t ngx_sigio; +extern sig_atomic_t ngx_sigalrm; extern sig_atomic_t ngx_quit; extern sig_atomic_t ngx_debug_quit; extern sig_atomic_t ngx_terminate; 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 @@ -40,6 +40,8 @@ ngx_unix_send(ngx_connection_t *c, u_cha wev->ready = 0; } + c->sent += n; + return n; } diff --git a/src/os/unix/ngx_shmem.h b/src/os/unix/ngx_shmem.h --- a/src/os/unix/ngx_shmem.h +++ b/src/os/unix/ngx_shmem.h @@ -15,7 +15,9 @@ typedef struct { u_char *addr; size_t size; + ngx_str_t name; ngx_log_t *log; + ngx_uint_t exists; /* unsigned exists:1; */ } ngx_shm_t; diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -62,16 +62,6 @@ #endif -#if (NGX_HAVE_SENDFILE) -#include -#endif - - -#if (NGX_HAVE_AIO) -#include -#endif - - #if (NGX_HAVE_DEVPOLL) #include #include @@ -83,6 +73,11 @@ #endif +#if (NGX_HAVE_SENDFILE) +#include +#endif + + #define NGX_LISTEN_BACKLOG 511 diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c --- a/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -168,19 +168,22 @@ ngx_solaris_sendfilev_chain(ngx_connecti if (n == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; - } + switch (err) { + case NGX_EAGAIN: + break; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, - "sendfilev() sent only %uz bytes", sent); + case NGX_EINTR: + eintr = 1; + break; - } else { + default: wev->error = 1; ngx_connection_error(c, err, "sendfilev() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfilev() sent only %uz bytes", sent); } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, diff --git a/src/os/unix/ngx_sunpro_x86.il b/src/os/unix/ngx_sunpro_x86.il --- a/src/os/unix/ngx_sunpro_x86.il +++ b/src/os/unix/ngx_sunpro_x86.il @@ -5,7 +5,7 @@ / ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, / ngx_atomic_uint_t old, ngx_atomic_uint_t set); / -/ the arguments are passed on the stack (%esp), 4(%esp), 8(%esp) +/ the arguments are passed on stack (%esp), 4(%esp), 8(%esp) .inline ngx_atomic_cmp_set,0 movl (%esp), %ecx @@ -21,7 +21,7 @@ / ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, / ngx_atomic_int_t add); / -/ the arguments are passed on the stack (%esp), 4(%esp) +/ the arguments are passed on stack (%esp), 4(%esp) .inline ngx_atomic_fetch_add,0 movl (%esp), %ecx @@ -32,7 +32,12 @@ / ngx_cpu_pause() +/ +/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware +/ capability added by linker because Solaris/i386 does not know about it: +/ +/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] .inline ngx_cpu_pause,0 - pause + rep; nop .end diff --git a/src/os/unix/ngx_sunpro_x86.map b/src/os/unix/ngx_sunpro_x86.map deleted file mode 100644 --- a/src/os/unix/ngx_sunpro_x86.map +++ /dev/null @@ -1,2 +0,0 @@ -# disable { PAUSE ] hwcap for Sun Studio 11 -hwcap_1 = OVERRIDE; diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -110,19 +110,22 @@ ngx_writev_chain(ngx_connection_t *c, ng if (n == -1) { err = ngx_errno; - if (err == NGX_EAGAIN || err == NGX_EINTR) { - if (err == NGX_EINTR) { - eintr = 1; - } + switch (err) { + case NGX_EAGAIN: + break; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + case NGX_EINTR: + eintr = 1; + break; - } else { + default: wev->error = 1; (void) ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); } sent = n > 0 ? n : 0;