# HG changeset patch # User Maxim Dounin # Date 1268332037 -10800 # Node ID f3a9e57d2e179caeb8ec67e729ffec113b4f9dc3 # Parent 5f4de8cf0d9d664a3f71fa99c288763830200477# Parent dd7104f21940d9026698b6db4a52622f49745caa Merge with current. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -262,3 +262,22 @@ d41628eb4d0a5a82c915b2684a4299f32b0ded22 1bc8c12d80ecec4f7f88c35359585ca5139248e3 NGINX_0_8_13 80f7156c296569546cf57fa286749d84e0cc8b9d NGINX_0_8_14 0161f31978175e258b8bb4989262b2ccb5fa9207 NGINX_0_8_15 +005a70f9573bc6bcf760786cb0573a62f1e570f3 NGINX_0_8_16 +4c5d2c627a6c0ad577b5e930782128fc7b082599 NGINX_0_8_17 +f7ec98e3caeb844c9401027b092837eee63dccab NGINX_0_8_18 +a52c99698e7f7001336116600d8bb40bdfdc59e0 NGINX_0_8_19 +0dc162a5f3e89e9d967f4aa30b2add942d895083 NGINX_0_8_20 +1dcf6adad48485e10aec666e0774634c318a9d76 NGINX_0_8_21 +c04fa65fe604240cbf3b29f4dddfc7683514fa5a NGINX_0_8_22 +2b9e388c61f18f47f2a26639c1bdf836db7ef41e NGINX_0_8_23 +40c366b3535c1c7c93baedb2ee910c1de0180e62 NGINX_0_8_24 +e19e5f54287869c93f4dc51035231772e5dca61c NGINX_0_8_25 +ab7d265273edb2eb721cb032870c23ffeda0ce60 NGINX_0_8_26 +697030d79811b68a1541986a16d39b8a9bd705c9 NGINX_0_8_27 +43e02819c5cf4e5124486eed8a338cfc2e868f18 NGINX_0_8_28 +5c576ea5dbd969cb73e9c6672723eeb11ddda2ac NGINX_0_8_29 +25255878df91eae733aead855caa35aaf8275671 NGINX_0_8_30 +2da4537168f879f528f09d0e0ce80abe68adf05e NGINX_0_8_31 +daf4847b43ff5f01a6cd52111fc8d747e2db0d72 NGINX_0_8_32 +7fa8dc2315bd08cb5329d94763ea7475d8c4d46d NGINX_0_8_33 +da3c99095432591583f4fde189906f6b860002f7 NGINX_0_8_34 diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,383 @@ +Changes with nginx 0.8.34 03 Mar 2010 + + *) Bugfix: nginx did not support all ciphers and digests used in client + certificates. + Thanks to Innocenty Enikeew. + + *) Bugfix: nginx cached incorrectly FastCGI responses if there was + large stderr output before response. + + *) Bugfix: nginx did not support HTTPS referrers. + + *) Bugfix: nginx/Windows might not find file if path in configuration + was given in other character case; the bug had appeared in 0.8.34. + + *) Bugfix: the $date_local variable has an incorrect value, if the "%s" + format was used. + Thanks to Maxim Dounin. + + *) Bugfix: if ssl_session_cache was not set or was set to "none", then + during client certificate verify the error "session id context + uninitialized" might occur; the bug had appeared in 0.7.1. + + *) Bugfix: a geo range returned default value if the range included two + or more /16 networks and did not begin at /16 network boundary. + + *) Bugfix: a block used in a "stub" parameter of an "include" SSI + directive was output with "text/plain" MIME type. + + *) Bugfix: $r->sleep() did not work; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.33 01 Feb 2010 + + *) Security: now nginx/Windows ignores trailing spaces in URI. + Thanks to Dan Crowley, Core Security Technologies. + + *) Security: now nginx/Windows ignores short files names. + Thanks to Dan Crowley, Core Security Technologies. + + *) Change: now keepalive connections after POST requests are not + disabled for MSIE 7.0+. + Thanks to Adam Lounds. + + *) Workaround: now keepalive connections are disabled for Safari. + Thanks to Joshua Sierles. + + *) Bugfix: if a proxied or FastCGI request was internally redirected to + another proxied or FastCGI location, then $upstream_response_time + variable may have abnormally large value; the bug had appeared in + 0.8.7. + + *) Bugfix: a segmentation fault might occur in a worker process, while + discarding a request body; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.32 11 Jan 2010 + + *) Bugfix: UTF-8 encoding usage in the ngx_http_autoindex_module. + Thanks to Maxim Dounin. + + *) Bugfix: regular expression named captures worked for two names only. + Thanks to Maxim Dounin. + + *) Bugfix: now the "localhost" name is used in the "Host" request + header line, if an unix domain socket is defined in the "auth_http" + directive. + Thanks to Maxim Dounin. + + *) Bugfix: nginx did not support chunked transfer encoding for 201 + responses. + Thanks to Julian Reich. + + *) Bugfix: if the "expires modified" set date in the past, then a + negative number was set in the "Cache-Control" response header line. + Thanks to Alex Kapranoff. + + +Changes with nginx 0.8.31 23 Dec 2009 + + *) Feature: now the "error_page" directive may redirect the 301 and 302 + responses. + + *) Feature: the $geoip_city_continent_code, $geoip_latitude, and + $geoip_longitude variables. + Thanks to Arvind Sundararajan. + + *) Feature: now the ngx_http_image_filter_module deletes always EXIF + and other application specific data if the data consume more than 5% + of a JPEG file. + + *) Bugfix: nginx closed a connection if a cached response had an empty + body. + Thanks to Piotr Sikora. + + *) Bugfix: nginx might not be built by gcc 4.x if the -O2 or higher + optimization option was used. + Thanks to Maxim Dounin and Denis F. Latypoff. + + *) Bugfix: regular expressions in location were always tested in + case-sensitive mode; the bug had appeared in 0.8.25. + + *) Bugfix: nginx cached a 304 response if there was the "If-None-Match" + header line in a proxied request. + Thanks to Tim Dettrick and David Kostal. + + *) Bugfix: nginx/Windows tried to delete a temporary file twice if the + file should replace an already existent file. + + +Changes with nginx 0.8.30 15 Dec 2009 + + *) Change: now the default buffer size of the + "large_client_header_buffers" directive is 8K. + Thanks to Andrew Cholakian. + + *) Feature: the conf/fastcgi.conf for simple FastCGI configurations. + + *) Bugfix: nginx/Windows tried to rename a temporary file twice if the + file should replace an already existent file. + + *) Bugfix: of "double free or corruption" error issued if host could + not be resolved; the bug had appeared in 0.8.22. + Thanks to Konstantin Svist. + + *) Bugfix: in libatomic usage on some platforms. + Thanks to W-Mark Kubacki. + + +Changes with nginx 0.8.29 30 Nov 2009 + + *) Change: now the "009" status code is written to an access log for + proxied HTTP/0.9 responses. + + *) Feature: the "addition_types", "charset_types", "gzip_types", + "ssi_types", "sub_filter_types", and "xslt_types" directives support + an "*" parameter. + + *) Feature: GCC 4.1+ built-in atomic operations usage. + Thanks to W-Mark Kubacki. + + *) Feature: the --with-libatomic[=DIR] option in the configure. + Thanks to W-Mark Kubacki. + + *) Bugfix: listen unix domain socket had limited access rights. + + *) Bugfix: cached HTTP/0.9 responses were handled incorrectly. + + *) Bugfix: regular expression named captures given by "?P<...>" did not + work in a "server_name" directive. + Thanks to Maxim Dounin. + + +Changes with nginx 0.8.28 23 Nov 2009 + + *) Bugfix: nginx could not be built with the --without-pcre parameter; + the bug had appeared in 0.8.25. + + +Changes with nginx 0.8.27 17 Nov 2009 + + *) Bugfix: regular expressions did not work in nginx/Windows; the bug + had appeared in 0.8.25. + + +Changes with nginx 0.8.26 16 Nov 2009 + + *) Bugfix: in captures usage in "rewrite" directive; the bug had + appeared in 0.8.25. + + *) Bugfix: nginx could not be built without the --with-debug option; + the bug had appeared in 0.8.25. + + +Changes with nginx 0.8.25 16 Nov 2009 + + *) Change: now no message is written in an error log if a variable is + not found by $r->variable() method. + + *) Feature: the ngx_http_degradation_module. + + *) Feature: regular expression named captures. + + *) Feature: now URI part is not required a "proxy_pass" directive if + variables are used. + + *) Feature: now the "msie_padding" directive works for Chrome too. + + *) Bugfix: a segmentation fault occurred in a worker process on low + memory condition; the bug had appeared in 0.8.18. + + *) Bugfix: nginx sent gzipped responses to clients those do not support + gzip, if "gzip_static on" and "gzip_vary off"; the bug had appeared + in 0.8.16. + + +Changes with nginx 0.8.24 11 Nov 2009 + + *) Bugfix: nginx always added "Content-Encoding: gzip" response header + line in 304 responses sent by ngx_http_gzip_static_module. + + *) Bugfix: nginx could not be built without the --with-debug option; + the bug had appeared in 0.8.23. + + *) Bugfix: the "unix:" parameter of the "set_real_ip_from" directive + inherited incorrectly from previous level. + + *) Bugfix: in resolving empty name. + + +Changes with nginx 0.8.23 11 Nov 2009 + + *) Security: now SSL/TLS renegotiation is disabled. + Thanks to Maxim Dounin. + + *) Bugfix: listen unix domain socket did not inherit while online + upgrade. + + *) Bugfix: the "unix:" parameter of the "set_real_ip_from" directive + did not without yet another directive with any IP address. + + *) Bugfix: segmentation fault and infinite looping in resolver. + + *) Bugfix: in resolver. + Thanks to Artem Bokhan. + + +Changes with nginx 0.8.22 03 Nov 2009 + + *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" + directives. + + *) Feature: the "access" and the "deny" directives support IPv6. + + *) Feature: the "set_real_ip_from" directive supports IPv6 addresses in + request headers. + + *) Feature: the "unix:" parameter of the "set_real_ip_from" directive. + + *) Bugfix: nginx did not delete unix domain socket after configuration + testing. + + *) Bugfix: nginx deleted unix domain socket while online upgrade. + + *) Bugfix: the "!-x" operator did not work. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault might occur in a worker process, if + limit_rate was used in HTTPS server. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault might occur in a worker process while + $limit_rate logging. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault might occur in a worker process, if + there was no "listen" directive in "server" block; the bug had + appeared in 0.8.21. + + +Changes with nginx 0.8.21 26 Oct 2009 + + *) Feature: now the "-V" switch shows TLS SNI support. + + *) Feature: the "listen" directive of the HTTP module supports unix + domain sockets. + Thanks to Hongli Lai. + + *) Feature: the "default_server" parameter of the "listen" directive. + + *) Feature: now a "default" parameter is not required to set listen + socket options. + + *) Bugfix: nginx did not support dates in 2038 year on 32-bit platforms; + + *) Bugfix: socket leak; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.20 14 Oct 2009 + + *) Change: now default SSL ciphers are "HIGH:!ADH:!MD5". + + *) Bugfix: the ngx_http_autoindex_module did not show the trailing + slash in links to a directory; the bug had appeared in 0.7.15. + + *) Bugfix: nginx did not close a log file set by the --error-log-path + configuration option; the bug had appeared in 0.7.53. + + *) Bugfix: nginx did not treat a comma as separator in the + "Cache-Control" backend response header line. + + *) Bugfix: nginx/Windows might not create temporary file, a cache file, + or "proxy/fastcgi_store"d file if a worker had no enough access + rights for top level directories. + + *) Bugfix: the "Set-Cookie" and "P3P" FastCGI response header lines + were not hidden while caching if no "fastcgi_hide_header" directives + were used with any parameters. + + *) Bugfix: nginx counted incorrectly disk cache size. + + +Changes with nginx 0.8.19 06 Oct 2009 + + *) Change: now SSLv2 protocol is disabled by default. + + *) Change: now default SSL ciphers are "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM". + + *) Bugfix: a "limit_req" directive did not work; the bug had appeared + in 0.8.18. + + +Changes with nginx 0.8.18 06 Oct 2009 + + *) Feature: the "read_ahead" directive. + + *) Feature: now several "perl_modules" directives may be used. + + *) Feature: the "limit_req_log_level" and "limit_conn_log_level" + directives. + + *) Bugfix: now "limit_req" directive conforms to the leaky bucket + algorithm. + Thanks to Maxim Dounin. + + *) Bugfix: nginx did not work on Linux/sparc. + Thanks to Marcus Ramberg. + + *) Bugfix: nginx sent '\0' in a "Location" response header line on + MKCOL request. + Thanks to Xie Zhenye. + + *) Bugfix: zero status code was logged instead of 499 status code; the + bug had appeared in 0.8.11. + + *) Bugfix: socket leak; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.17 28 Sep 2009 + + *) Security: now "/../" are disabled in "Destination" request header + line. + + *) Change: now $host variable value is always low case. + + *) Feature: the $ssl_session_id variable. + + *) Bugfix: socket leak; the bug had appeared in 0.8.11. + + +Changes with nginx 0.8.16 22 Sep 2009 + + *) Feature: the "image_filter_transparency" directive. + + *) 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 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,394 @@ +Изменения в nginx 0.8.34 03.03.2010 + + *) Исправление: nginx не поддерживал все шифры, используемые в + клиентских сертификатах. + Спасибо Иннокентию Еникееву. + + *) Исправление: nginx неправильно кэшировал FastCGI-ответы, если перед + ответом было много вывода в stderr. + + *) Исправление: nginx не поддерживал HTTPS-рефереры. + + *) Исправление: nginx/Windows мог не находить файлы, если путь в + конфигурации был задан в другом регистре; ошибка появилась в 0.8.34. + + *) Исправление: переменная $date_local выдавала неверное время, если + использовался формат "%s". + Спасибо Максиму Дунину. + + *) Исправление: если ssl_session_cache не был установлен или установлен + в none, то при проверке клиентского сертификаты могла происходить + ошибка "session id context uninitialized"; ошибка появилась в 0.7.1. + + *) Исправление: geo-диапазон возвращал значение по умолчанию, если + диапазон включал в себя одну и более сетей размером /16 и не + начинался на границе сети размером /16. + + *) Исправление: блок, используемый в параметре stub в SSI-директиве + include, выводился с MIME-типом "text/plain". + + *) Исправление: $r->sleep() не работал; ошибка появилась в 0.8.11. + + +Изменения в nginx 0.8.33 01.02.2010 + + *) Безопасность: теперь nginx/Windows игнорирует пробелы в конце URI. + Спасибо Dan Crowley, Core Security Technologies. + + *) Безопасность: теперь nginx/Windows игнорирует короткие имена файлов. + Спасибо Dan Crowley, Core Security Technologies. + + *) Изменение: теперь keepalive соединения после запросов POST не + запрещаются для MSIE 7.0+. + Спасибо Adam Lounds. + + *) Изменение: теперь keepalive соединения запрещены для Safari. + Спасибо Joshua Sierles. + + *) Исправление: если проксированный или FastCGI запрос внутренне + перенаправлялся в другой проксированный или FastCGI location, то + переменная $upstream_response_time могла иметь ненормально большое + значение; ошибка появилась в 0.8.7. + + *) Исправление: в рабочем процессе мог произойти segmentation fault при + отбрасывания тела запроса; ошибка появилась в 0.8.11. + + +Изменения в nginx 0.8.32 11.01.2010 + + *) Исправление: ошибки при использовании кодировки UTF-8 в + ngx_http_autoindex_module. + Спасибо Максиму Дунину. + + *) Исправление: именованные выделения в регулярных выражениях работали + только для двух переменных. + Спасибо Максиму Дунину. + + *) Исправление: теперь в строке заголовка запроса "Host" используется + имя "localhost", если в директиве auth_http указан unix domain + сокет. + Спасибо Максиму Дунину. + + *) Исправление: nginx не поддерживал передачу chunk'ами для 201-ых + ответов. + Спасибо Julian Reich. + + *) Исправление: если директива "expires modified" выставляла дату в + прошлом, то в строке заголовка ответа "Cache-Control" выдавалось + отрицательное число. + Спасибо Алексею Капранову. + + +Изменения в nginx 0.8.31 23.12.2009 + + *) Добавление: теперь директива error_page может перенаправлять ответы + со статусом 301 и 302. + + *) Добавление: переменные $geoip_city_continent_code, $geoip_latitude и + $geoip_longitude. + Спасибо Arvind Sundararajan. + + *) Добавление: модуль ngx_http_image_filter_module теперь всегда + удаляет EXIF и другие данные, если они занимают больше 5% в + JPEG-файле. + + *) Исправление: nginx закрывал соединение при запросе закэшированного + ответа с пустым телом. + Спасибо Piotr Sikora. + + *) Исправление: nginx мог не собираться gcc 4.x при использовании + оптимизации -O2 и выше. + Спасибо Максиму Дунину и Денису Латыпову. + + *) Исправление: регулярные выражения в location всегда тестировались с + учётом регистра; ошибка появилась в 0.8.25. + + *) Исправление: nginx кэшировал 304 ответ, если в заголовке + проксируемого запроса была строка "If-None-Match". + Спасибо Tim Dettrick и David Kostal. + + *) Исправление: nginx/Windows пытался дважды удалить временный файл при + перезаписи уже существующего файла. + + +Изменения в nginx 0.8.30 15.12.2009 + + *) Изменение: теперь по умолчанию размер буфера директивы + large_client_header_buffers равен 8K. + Спасибо Andrew Cholakian. + + *) Добавление: файл conf/fastcgi.conf для простых конфигураций FastCGI. + + *) Исправление: nginx/Windows пытался дважды переименовать временный + файл при перезаписи уже существующего файла. + + *) Исправление: ошибки double free or corruption, возникающей, если имя + хоста не было найдено; ошибка появилась в 0.8.22. + Спасибо Константину Свисту. + + *) Исправление: в использовании libatomic на некоторых платформах. + Спасибо W-Mark Kubacki. + + +Изменения в nginx 0.8.29 30.11.2009 + + *) Изменение: теперь для проксируемых ответов HTTP/0.9 в лог пишется + код ответа "009". + + *) Добавление: директивы addition_types, charset_types, gzip_types, + ssi_types, sub_filter_types и xslt_types поддерживают параметр "*". + + *) Добавление: использование встроенных атомарных операций GCC 4.1+. + Спасибо W-Mark Kubacki. + + *) Добавление: параметр --with-libatomic[=DIR] в configure. + Спасибо W-Mark Kubacki. + + *) Исправление: listen unix domain сокет имели ограниченные права + доступа. + + *) Исправление: закэшированные ответы ответов HTTP/0.9 неправильно + обрабатывались. + + *) Исправление: именованные выделения в регулярных выражениях, заданные + как "?P<...>", не работали в директиве server_name. + Спасибо Максиму Дунину. + + +Изменения в nginx 0.8.28 23.11.2009 + + *) Исправление: nginx не собирался с параметром --without-pcre; ошибка + появилась в 0.8.25. + + +Изменения в nginx 0.8.27 17.11.2009 + + *) Исправление: регулярные выражения не работали в nginx/Windows; + ошибка появилась в 0.8.25. + + +Изменения в nginx 0.8.26 16.11.2009 + + *) Исправление: ошибки при использовании выделений в директиве rewrite; + ошибка появилась в 0.8.25. + + *) Исправление: nginx не собирался без параметра --with-debug; ошибка + появилась в 0.8.25. + + +Изменения в nginx 0.8.25 16.11.2009 + + *) Изменение: теперь в лог ошибок не пишется сообщение, если переменная + не найдена с помощью метода $r->variable(). + + *) Добавление: модуль ngx_http_degradation_module. + + *) Добавление: именованные выделения в регулярных выражениях. + + *) Добавление: теперь при использовании переменных в директиве + proxy_pass не требуется задавать URI. + + *) Добавление: теперь директива msie_padding работает и для Chrome. + + *) Исправление: в рабочем процессе происходил segmentation fault при + недостатке памяти; ошибка появилась в 0.8.18. + + *) Исправление: nginx передавал сжатые ответы клиентам, не + поддерживающим сжатие, при настройках gzip_static on и gzip_vary + off; ошибка появилась в 0.8.16. + + +Изменения в nginx 0.8.24 11.11.2009 + + *) Исправление: nginx всегда добавлял строку "Content-Encoding: gzip" в + заголовок 304-ых ответов модуля ngx_http_gzip_static_module. + + *) Исправление: nginx не собирался без параметра --with-debug; ошибка + появилась в 0.8.23. + + *) Исправление: параметр "unix:" в директиве set_real_ip_from + неправильно наследовался с предыдущего уровня. + + *) Исправление: в resolver'е при определении пустого имени. + + +Изменения в nginx 0.8.23 11.11.2009 + + *) Безопасность: теперь SSL/TLS renegotiation запрещён. + Спасибо Максиму Дунину. + + *) Исправление: listen unix domain сокет не наследовались во время + обновления без перерыва. + + *) Исправление: параметр "unix:" в директиве set_real_ip_from не + работал без ещё одной директивы с любым IP-адресом. + + *) Исправление: segmentation fault и зацикливания в resolver'е. + + *) Исправление: в resolver'е. + Спасибо Артёму Бохану. + + +Изменения в nginx 0.8.22 03.11.2009 + + *) Добавление: директивы proxy_bind, fastcgi_bind и memcached_bind. + + *) Добавление: директивы access и deny поддерживают IPv6. + + *) Добавление: директива set_real_ip_from поддерживает IPv6 адреса в + заголовках запроса. + + *) Добавление: параметр "unix:" в директиве set_real_ip_from. + + *) Исправление: nginx не удалял unix domain сокет после тестирования + конфигурации. + + *) Исправление: nginx удалял unix domain сокет во время обновления без + перерыва. + + *) Исправление: оператор "!-x" не работал. + Спасибо Максиму Дунину. + + *) Исправление: в рабочем процессе мог произойти segmentation fault при + использовании limit_rate в HTTPS сервере. + Спасибо Максиму Дунину. + + *) Исправление: при записи в лог переменной $limit_rate в рабочем + процессе происходил segmentation fault. + Спасибо Максиму Дунину. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если внутри блока server не было директивы listen; ошибка появилась + в 0.8.21. + + +Изменения в nginx 0.8.21 26.10.2009 + + *) Добавление: теперь ключ -V показывает статус поддержки TLS SNI. + + *) Добавление: директива listen модуля HTTP поддерживает unix domain + сокеты. + Спасибо Hongli Lai. + + *) Добавление: параметр "default_server" в директиве listen. + + *) Добавление: теперь параметр "default" не обязателен для установки + параметров listen-сокета. + + *) Исправление: nginx не поддерживал даты в 2038 году на 32-битных + платформах; + + *) Исправление: утечки сокетов; ошибка появилась в 0.8.11. + + +Изменения в nginx 0.8.20 14.10.2009 + + *) Изменение: теперь по умолчанию используются следующие шифры SSL: + "HIGH:!ADH:!MD5". + + *) Исправление: модуль ngx_http_autoindex_module не показывал последний + слэш для линков на каталоги; ошибка появилась в 0.7.15. + + *) Исправление: nginx не закрывал лог, заданный параметром конфигурации + --error-log-path; ошибка появилась в 0.7.53. + + *) Исправление: nginx не считал запятую разделителем в строке + "Cache-Control" в строке заголовка бэкенда. + + *) Исправление: nginx/Windows мог не создать временный файл, файл в + кэше или файл с помощью директив proxy/fastcgi_store, если рабочий + процесс не имел достаточно прав для работы с каталогами верхнего + уровня. + + *) Исправление: строки "Set-Cookie" и "P3P" в заголовке ответа + FastCGI-сервера не скрывались при кэшировании, если не + использовались директивы fastcgi_hide_header с любыми параметрами. + + *) Исправление: nginx неверно считал размер кэша на диске. + + +Изменения в nginx 0.8.19 06.10.2009 + + *) Изменение: теперь протокол SSLv2 по умолчанию запрещён. + + *) Изменение: теперь по умолчанию используются следующие шифры SSL: + "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM". + + *) Исправление: директива limit_req не работала; ошибка появилась в + 0.8.18. + + +Изменения в nginx 0.8.18 06.10.2009 + + *) Добавление: директива read_ahead. + + *) Добавление: теперь можно использовать несколько директив + perl_modules. + + *) Добавление: директивы limit_req_log_level и limit_conn_log_level. + + *) Исправление: Теперь директива limit_req соответствует алгоритму + leaky bucket. + Спасибо Максиму Дунину. + + *) Исправление: nginx не работал на Linux/sparc. + Спасибо Marcus Ramberg. + + *) Исправление: nginx слал символ '\0' в строке "Location" в заголовке + в ответе на запрос MKCOL. + Спасибо Xie Zhenye. + + *) Исправление: вместо кода ответа 499 в лог записывался код 0; ошибка + появилась в 0.8.11. + + *) Исправление: утечки сокетов; ошибка появилась в 0.8.11. + + +Изменения в nginx 0.8.17 28.09.2009 + + *) Безопасность: теперь символы "/../" запрещены в строке "Destination" + в заголовке запроса. + + *) Изменение: теперь значение переменной $host всегда в нижнем регистре. + + *) Добавление: переменная $ssl_session_id. + + *) Исправление: утечки сокетов; ошибка появилась в 0.8.11. + + +Изменения в nginx 0.8.16 22.09.2009 + + *) Добавление: директива image_filter_transparency. + + *) Исправление: директива "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 *) Безопасность: при обработке специально созданного запроса в рабочем @@ -125,7 +515,7 @@ Спасибо Максиму Дунину. *) Исправление: в обработке строк "Last-Modified" и "Accept-Ranges" в - заголовке ответа бэкенда; ошибка появилась в 0.7.44 + заголовке ответа бэкенда; ошибка появилась в 0.7.44. Спасибо Максиму Дунину. *) Исправление: ошибки "[alert] zero size buf" при получении пустых diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 Igor Sysoev + * Copyright (C) 2002-2010 Igor Sysoev * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/auto/cc/conf b/auto/cc/conf --- a/auto/cc/conf +++ b/auto/cc/conf @@ -104,7 +104,7 @@ else fi CFLAGS="$CFLAGS $NGX_CC_OPT" - +NGX_TEST_LD_OPT="$NGX_LD_OPT" if [ "$NGX_PLATFORM" != win32 ]; then @@ -125,6 +125,24 @@ if [ "$NGX_PLATFORM" != win32 ]; then fi fi + + ngx_feature="gcc builtin atomic operations" + ngx_feature_name=NGX_HAVE_GCC_ATOMIC + ngx_feature_run=yes + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="long n = 0; + if (!__sync_bool_compare_and_swap(&n, 0, 1)) + return 1; + if (__sync_fetch_and_add(&n, 1) != 1) + return 1; + if (n != 2) + return 1; + __sync_synchronize();" + . auto/feature + + ngx_feature="gcc variadic macros" ngx_feature_name="NGX_HAVE_GCC_VARIADIC_MACROS" ngx_feature_run=yes diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -51,8 +51,6 @@ esac #NGX_GCC_OPT="-Os" NGX_GCC_OPT="-O" -CFLAGS="$CFLAGS $NGX_GCC_OPT" - #CFLAGS="$CFLAGS -fomit-frame-pointer" case $CPU in @@ -90,7 +88,6 @@ case $CPU in # build 32-bit UltraSparc binary CPU_OPT="-m32" CORE_LINK="$CORE_LINK -m32" - CC_AUX_FLAGS="$CC_AUX_FLAGS -m32" NGX_CPU_CACHE_LINE=64 ;; @@ -98,7 +95,6 @@ case $CPU in # build 64-bit UltraSparc binary CPU_OPT="-m64" CORE_LINK="$CORE_LINK -m64" - CC_AUX_FLAGS="$CC_AUX_FLAGS -m64" NGX_CPU_CACHE_LINE=64 ;; @@ -108,12 +104,12 @@ case $CPU in CPU_OPT="$CPU_OPT -falign-functions=32 -falign-labels=32" CPU_OPT="$CPU_OPT -falign-loops=32 -falign-jumps=32" CORE_LINK="$CORE_LINK -m64" - CC_AUX_FLAGS="$CC_AUX_FLAGS -m64" NGX_CPU_CACHE_LINE=128 ;; esac +CC_AUX_FLAGS="$CC_AUX_FLAGS $CPU_OPT" case "$NGX_GCC_VER" in 2.7*) diff --git a/auto/feature b/auto/feature --- a/auto/feature +++ b/auto/feature @@ -39,7 +39,7 @@ END ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \ - -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" + -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs" ngx_feature_inc_path= diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -101,6 +101,10 @@ install: $NGX_OBJS${ngx_dirsep}nginx${ng cp conf/fastcgi_params \ '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default' + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \ + || cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default' + test -f '\$(DESTDIR)$NGX_CONF_PATH' \ || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH' cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default' @@ -144,19 +148,4 @@ upgrade: test -f $NGX_PID_PATH.oldbin kill -QUIT \`cat $NGX_PID_PATH.oldbin\` - -upgrade1: - # upgrade 0.1.x to 0.2+ - - $NGX_SBIN_PATH -t - - cp $NGX_PID_PATH $NGX_PID_PATH.oldbin - - kill -USR2 \`cat $NGX_PID_PATH\` - sleep 1 - test -f $NGX_PID_PATH.oldbin - - cp $NGX_PID_PATH $NGX_PID_PATH.newbin - - kill -QUIT \`cat $NGX_PID_PATH.oldbin\` END diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -70,6 +70,11 @@ fi if [ $HTTP_GEOIP = YES ]; then . auto/lib/geoip/conf fi + if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then . auto/lib/google-perftools/conf fi + +if [ $NGX_LIBATOMIC != NO ]; then + . auto/lib/libatomic/conf +fi diff --git a/auto/lib/libatomic/conf b/auto/lib/libatomic/conf new file mode 100644 --- /dev/null +++ b/auto/lib/libatomic/conf @@ -0,0 +1,42 @@ + +# Copyright (C) Igor Sysoev + + +if [ $NGX_LIBATOMIC != YES ]; then + + have=NGX_HAVE_LIBATOMIC . auto/have + CORE_INCS="$CORE_INCS $NGX_LIBATOMIC/src" + LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/src/libatomic_ops.a" + CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/src/libatomic_ops.a" + +else + + ngx_feature="atomic_ops library" + ngx_feature_name=NGX_HAVE_LIBATOMIC + ngx_feature_run=yes + ngx_feature_incs="#define AO_REQUIRE_CAS + #include " + ngx_feature_path= + ngx_feature_libs="-latomic_ops" + ngx_feature_test="long n = 0; + if (!AO_compare_and_swap(&n, 0, 1)) + return 1; + if (AO_fetch_and_add(&n, 1) != 1) + return 1; + if (n != 2) + return 1; + AO_nop();" + . auto/feature + + if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + else + +cat << END + +$0: error: libatomic_ops library was not found. + +END + exit 1 + fi +fi diff --git a/auto/lib/libatomic/make b/auto/lib/libatomic/make new file mode 100644 --- /dev/null +++ b/auto/lib/libatomic/make @@ -0,0 +1,13 @@ + +# Copyright (C) Igor Sysoev + + + cat << END >> $NGX_MAKEFILE + +$NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile + cd $NGX_LIBATOMIC && make + +$NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE + cd $NGX_LIBATOMIC && ./configure + +END diff --git a/auto/lib/make b/auto/lib/make --- a/auto/lib/make +++ b/auto/lib/make @@ -22,6 +22,10 @@ if [ $ZLIB != NONE -a $ZLIB != NO -a $ZL . auto/lib/zlib/make fi +if [ $NGX_LIBATOMIC != NO -a $NGX_LIBATOMIC != YES ]; then + . auto/lib/libatomic/make +fi + if [ $USE_PERL = YES ]; then . auto/lib/perl/make fi diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -25,10 +25,10 @@ if [ $OPENSSL != NONE ]; then have=NGX_OPENSSL . auto/have have=NGX_SSL . auto/have - CORE_INCS="$CORE_INCS $OPENSSL/openssl/include" - CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h" - CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libssl.a" - CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libcrypto.a" + CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include" + CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h" + CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a" + CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a" CORE_LIBS="$CORE_LIBS $NGX_LIBDL" ;; esac diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -46,13 +46,13 @@ END esac case $OPENSSL in - /*) ngx_prefix="$OPENSSL/openssl" ;; - *) ngx_prefix="$PWD/$OPENSSL/openssl" ;; + /*) ngx_prefix="$OPENSSL/.openssl" ;; + *) ngx_prefix="$PWD/$OPENSSL/.openssl" ;; esac cat << END >> $NGX_MAKEFILE -$OPENSSL/openssl/include/openssl/ssl.h: $NGX_MAKEFILE +$OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE cd $OPENSSL \\ && \$(MAKE) clean \\ && ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\ diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -318,6 +318,11 @@ if [ $HTTP_SECURE_LINK = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_SECURE_LINK_SRCS" fi +if [ $HTTP_DEGRADATION = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_DEGRADATION_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_DEGRADATION_SRCS" +fi + if [ $HTTP_FLV = YES ]; then HTTP_MODULES="$HTTP_MODULES $HTTP_FLV_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -85,6 +85,7 @@ HTTP_LIMIT_REQ=YES HTTP_EMPTY_GIF=YES HTTP_BROWSER=YES HTTP_SECURE_LINK=NO +HTTP_DEGRADATION=NO HTTP_FLV=NO HTTP_GZIP_STATIC=NO HTTP_UPSTREAM_IP_HASH=YES @@ -131,6 +132,8 @@ USE_LIBGD=NO NGX_GOOGLE_PERFTOOLS=NO NGX_CPP_TEST=NO +NGX_LIBATOMIC=NO + NGX_CPU_CACHE_LINE= opt= @@ -194,6 +197,7 @@ do --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; --with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;; --with-http_secure_link_module) HTTP_SECURE_LINK=YES ;; + --with-http_degradation_module) HTTP_DEGRADATION=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; @@ -264,6 +268,9 @@ do --with-zlib-opt=*) ZLIB_OPT="$value" ;; --with-zlib-asm=*) ZLIB_ASM="$value" ;; + --with-libatomic) NGX_LIBATOMIC=YES ;; + --with-libatomic=*) NGX_LIBATOMIC="$value" ;; + --test-build-devpoll) NGX_TEST_BUILD_DEVPOLL=YES ;; --test-build-eventport) NGX_TEST_BUILD_EVENTPORT=YES ;; --test-build-epoll) NGX_TEST_BUILD_EPOLL=YES ;; @@ -322,6 +329,7 @@ cat << END --with-http_gzip_static_module enable ngx_http_gzip_static_module --with-http_random_index_module enable ngx_http_random_index_module --with-http_secure_link_module enable ngx_http_secure_link_module + --with-http_degradation_module enable ngx_http_degradation_module --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module @@ -397,6 +405,9 @@ cat << END for specified CPU, the valid values: pentium, pentiumpro + --with-libatomic force libatomic_ops library usage + --with-libatomic=DIR set path to libatomic_ops library sources + --with-openssl=DIR set path to OpenSSL library sources --with-openssl-opt=OPTIONS set additional options for OpenSSL building diff --git a/auto/os/features b/auto/os/features --- a/auto/os/features +++ b/auto/os/features @@ -172,6 +172,26 @@ if [ $ngx_found = no ]; then fi +ngx_feature="F_READAHEAD" +ngx_feature_name="NGX_HAVE_F_READAHEAD" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="fcntl(0, F_READAHEAD, 1);" +. auto/feature + + +ngx_feature="posix_fadvise()" +ngx_feature_name="NGX_HAVE_POSIX_FADVISE" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="posix_fadvise(0, 0, 0, POSIX_FADV_SEQUENTIAL);" +. auto/feature + + ngx_feature="O_DIRECT" ngx_feature_name="NGX_HAVE_O_DIRECT" ngx_feature_run=no diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -35,6 +35,12 @@ then fi +# posix_fadvise64() had been implemented in 2.5.60 + +if [ $version -lt 132412 ]; then + have=NGX_HAVE_POSIX_FADVISE . auto/nohave +fi + # epoll, EPOLLET version ngx_feature="epoll" diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -439,6 +439,10 @@ HTTP_SECURE_LINK_MODULE=ngx_http_secure_ HTTP_SECURE_LINK_SRCS=src/http/modules/ngx_http_secure_link_module.c +HTTP_DEGRADATION_MODULE=ngx_http_degradation_module +HTTP_DEGRADATION_SRCS=src/http/modules/ngx_http_degradation_module.c + + HTTP_FLV_MODULE=ngx_http_flv_module HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -71,6 +71,12 @@ case $ZLIB in *) echo " + using zlib library: $ZLIB" ;; esac +case $NGX_LIBATOMIC in + YES) echo " + using system libatomic_ops library" ;; + NO) ;; # not used + *) echo " + using libatomic_ops library: $NGX_LIBATOMIC" ;; +esac + echo diff --git a/conf/fastcgi.conf b/conf/fastcgi.conf new file mode 100644 --- /dev/null +++ b/conf/fastcgi.conf @@ -0,0 +1,24 @@ + +fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; +fastcgi_param QUERY_STRING $query_string; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_NAME $fastcgi_script_name; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $server_name; + +# PHP only, required if PHP was built with --enable-force-cgi-redirect +fastcgi_param REDIRECT_STATUS 200; diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -35,6 +35,7 @@ types { application/vnd.wap.xhtml+xml xhtml; application/vnd.google-earth.kml+xml kml; application/vnd.google-earth.kmz kmz; + application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; application/x-java-jnlp-file jnlp; diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -239,6 +239,13 @@ main(int argc, char *const *argv) #ifdef NGX_COMPILER ngx_log_stderr(0, "built by " NGX_COMPILER); #endif +#if (NGX_SSL) +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + ngx_log_stderr(0, "TLS SNI support enabled"); +#else + ngx_log_stderr(0, "TLS SNI support disabled"); +#endif +#endif ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE); } @@ -373,6 +380,13 @@ main(int argc, char *const *argv) } } + if (log->file->fd != ngx_stderr) { + if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_close_file_n " built-in log failed"); + } + } + ngx_use_stderr = 0; if (ngx_process == NGX_PROCESS_SINGLE) { 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 8015 -#define NGINX_VERSION "0.8.15" +#define nginx_version 8034 +#define NGINX_VERSION "0.8.34" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" 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 @@ -261,7 +261,7 @@ done: if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", - cf->conf_file->file.name.data); + filename->data); return NGX_CONF_ERROR; } @@ -1006,7 +1006,7 @@ ngx_conf_flush_files(ngx_cycle_t *cycle) void ngx_cdecl ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err, - char *fmt, ...) + const char *fmt, ...) { u_char errstr[NGX_MAX_CONF_ERRSTR], *p, *last; va_list args; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -322,7 +322,7 @@ ngx_int_t ngx_conf_full_name(ngx_cycle_t ngx_uint_t conf_prefix); ngx_open_file_t *ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name); void ngx_cdecl ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, - ngx_err_t err, char *fmt, ...); + ngx_err_t err, const char *fmt, ...); char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 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 @@ -15,6 +15,7 @@ ngx_os_io_t ngx_io; ngx_listening_t * ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) { + size_t len; ngx_listening_t *ls; struct sockaddr *sa; u_char text[NGX_SOCKADDR_STRLEN]; @@ -36,17 +37,8 @@ ngx_create_listening(ngx_conf_t *cf, voi ls->sockaddr = sa; ls->socklen = socklen; - ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); - - ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len); - if (ls->addr_text.data == NULL) { - return NULL; - } - - ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len); - - ls->fd = (ngx_socket_t) -1; - ls->type = SOCK_STREAM; + len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); + ls->addr_text.len = len; switch (ls->sockaddr->sa_family) { #if (NGX_HAVE_INET6) @@ -54,6 +46,12 @@ ngx_create_listening(ngx_conf_t *cf, voi ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN; + len++; + break; +#endif case AF_INET: ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; break; @@ -62,6 +60,16 @@ ngx_create_listening(ngx_conf_t *cf, voi break; } + ls->addr_text.data = ngx_pnalloc(cf->pool, len); + if (ls->addr_text.data == NULL) { + return NULL; + } + + ngx_memcpy(ls->addr_text.data, text, len); + + ls->fd = (ngx_socket_t) -1; + ls->type = SOCK_STREAM; + ls->backlog = NGX_LISTEN_BACKLOG; ls->rcvbuf = -1; ls->sndbuf = -1; @@ -109,11 +117,20 @@ ngx_set_inherited_sockets(ngx_cycle_t *c #if (NGX_HAVE_INET6) case AF_INET6: ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; + len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN; + len = NGX_UNIX_ADDRSTRLEN; break; #endif case AF_INET: ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; break; default: @@ -124,8 +141,6 @@ ngx_set_inherited_sockets(ngx_cycle_t *c continue; } - len = ls[i].addr_text_max_len + sizeof(":65535") - 1; - ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len); if (ls[i].addr_text.data == NULL) { return NGX_ERROR; @@ -357,6 +372,29 @@ ngx_open_listening_sockets(ngx_cycle_t * continue; } +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ls[i].sockaddr->sa_family == AF_UNIX) { + mode_t mode; + u_char *name; + + name = ls[i].addr_text.data + sizeof("unix:") - 1; + mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + + if (chmod((char *) name, mode) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "chmod() \"%s\" failed", name); + } + + if (ngx_test_config) { + if (ngx_delete_file(name) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_delete_file_n " %s failed", name); + } + } + } +#endif + if (listen(s, ls[i].backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %V, backlog %d failed", @@ -604,6 +642,22 @@ ngx_close_listening_sockets(ngx_cycle_t ngx_close_socket_n " %V failed", &ls[i].addr_text); } +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ls[i].sockaddr->sa_family == AF_UNIX + && ngx_process <= NGX_PROCESS_MASTER + && ngx_new_binary == 0) + { + u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; + + if (ngx_delete_file(name) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_delete_file_n " %s failed", name); + } + } + +#endif + ls[i].fd = (ngx_socket_t) -1; } } @@ -858,7 +912,6 @@ ngx_connection_local_sockaddr(ngx_connec return NGX_ERROR; } - c->local_socklen = len; ngx_memcpy(c->local_sockaddr, &sa, len); } @@ -917,12 +970,8 @@ ngx_connection_error(ngx_connection_t *c level = NGX_LOG_INFO; break; - case NGX_ERROR_ERR: + default: level = NGX_LOG_ERR; - break; - - default: - level = NGX_LOG_ALERT; } } else { 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 @@ -129,7 +129,6 @@ struct ngx_connection_s { #endif struct sockaddr *local_sockaddr; - socklen_t local_socklen; ngx_buf_t *buffer; 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 @@ -83,7 +83,9 @@ typedef void (*ngx_connection_handler_pt #define CRLF "\x0d\x0a" -#define ngx_abs(value) (((value) >= 0) ? (value) : - (value)) +#define ngx_abs(value) (((value) >= 0) ? (value) : - (value)) +#define ngx_max(val1, val2) ((val1 < val2) ? (val2) : (val1)) +#define ngx_min(val1, val2) ((val1 > val2) ? (val2) : (val1)) void ngx_cpuinfo(void); 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 @@ -204,7 +204,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } - ngx_memcpy(cycle->hostname.data, hostname, cycle->hostname.len); + ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len); for (i = 0; ngx_modules[i]; i++) { @@ -255,11 +255,13 @@ 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; } @@ -280,6 +282,7 @@ 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; } @@ -698,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. */ 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 @@ -183,7 +183,15 @@ ngx_create_full_path(u_char *dir, ngx_ui u_char *p, ch; ngx_err_t err; - for (p = dir + 1; *p; p++) { + err = 0; + +#if (NGX_WIN32) + p = dir + 3; +#else + p = dir + 1; +#endif + + for ( /* void */ ; *p; p++) { ch = *p; if (ch != '/') { @@ -194,7 +202,14 @@ ngx_create_full_path(u_char *dir, ngx_ui if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) { err = ngx_errno; - if (err != NGX_EEXIST) { + + switch (err) { + case NGX_EEXIST: + err = 0; + case NGX_EACCES: + break; + + default: return err; } } @@ -202,7 +217,7 @@ ngx_create_full_path(u_char *dir, ngx_ui *p = '/'; } - return 0; + return err; } @@ -576,16 +591,10 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ #if (NGX_WIN32) if (err == NGX_EEXIST) { - if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) { + err = ngx_win32_rename_file(src, to, ext->log); - if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { - return NGX_OK; - } - - err = ngx_errno; - - } else { - err = 0; + if (err == 0) { + return NGX_OK; } } diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -8,9 +8,6 @@ #include -#if (NGX_HAVE_INET6) -static size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len); -#endif static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u); @@ -59,6 +56,126 @@ ngx_inet_addr(u_char *text, size_t len) } +#if (NGX_HAVE_INET6) + +ngx_int_t +ngx_inet6_addr(u_char *p, size_t len, u_char *addr) +{ + u_char c, *zero, *digit, *s, *d; + size_t len4; + ngx_uint_t n, nibbles, word; + + if (len == 0) { + return NGX_ERROR; + } + + zero = NULL; + digit = NULL; + len4 = 0; + nibbles = 0; + word = 0; + n = 8; + + if (p[0] == ':') { + p++; + len--; + } + + for (/* void */; len; len--) { + c = *p++; + + if (c == ':') { + if (nibbles) { + digit = p; + len4 = len; + *addr++ = (u_char) (word >> 8); + *addr++ = (u_char) (word & 0xff); + + if (--n) { + nibbles = 0; + word = 0; + continue; + } + + } else { + if (zero == NULL) { + digit = p; + len4 = len; + zero = addr; + continue; + } + } + + return NGX_ERROR; + } + + if (c == '.' && nibbles) { + if (n < 2) { + return NGX_ERROR; + } + + word = ngx_inet_addr(digit, len4 - 1); + if (word == INADDR_NONE) { + return NGX_ERROR; + } + + word = ntohl(word); + *addr++ = (u_char) ((word >> 24) & 0xff); + *addr++ = (u_char) ((word >> 16) & 0xff); + n--; + break; + } + + if (++nibbles > 4) { + return NGX_ERROR; + } + + if (c >= '0' && c <= '9') { + word = word * 16 + (c - '0'); + continue; + } + + c |= 0x20; + + if (c >= 'a' && c <= 'f') { + word = word * 16 + (c - 'a') + 10; + continue; + } + + return NGX_ERROR; + } + + if (nibbles == 0 && zero == NULL) { + return NGX_ERROR; + } + + *addr++ = (u_char) (word >> 8); + *addr++ = (u_char) (word & 0xff); + + if (--n) { + if (zero) { + n *= 2; + s = addr - 1; + d = s + n; + while (s >= zero) { + *d-- = *s--; + } + ngx_memzero(zero, n); + return NGX_OK; + } + + } else { + if (zero == NULL) { + return NGX_OK; + } + } + + return NGX_ERROR; +} + +#endif + + size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) { @@ -68,6 +185,9 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha size_t n; struct sockaddr_in6 *sin6; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif switch (sa->sa_family) { @@ -98,7 +218,7 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha text[n++] = '['; } - n = ngx_inet6_ntop((u_char *) &sin6->sin6_addr, &text[n], len); + n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len); if (port) { n = ngx_sprintf(&text[1 + n], "]:%d", @@ -108,6 +228,17 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha return n; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + + case AF_UNIX: + saun = (struct sockaddr_un *) sa; + + /* we do not include trailing zero in address length */ + + return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1; + +#endif + default: return 0; } @@ -144,7 +275,7 @@ ngx_inet_ntop(int family, void *addr, u_ #if (NGX_HAVE_INET6) -static size_t +size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len) { u_char *dst; @@ -223,31 +354,47 @@ ngx_inet6_ntop(u_char *p, u_char *text, #endif -/* AF_INET only */ - ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr) { - u_char *addr, *mask, *last; - ngx_int_t shift; + u_char *addr, *mask, *last; + size_t len; + ngx_int_t shift; +#if (NGX_HAVE_INET6) + ngx_int_t rc; + ngx_uint_t s, i; +#endif addr = text->data; last = addr + text->len; mask = ngx_strlchr(addr, last, '/'); + len = (mask ? mask : last) - addr; - cidr->u.in.addr = ngx_inet_addr(addr, (mask ? mask : last) - addr); + cidr->u.in.addr = ngx_inet_addr(addr, len); + + if (cidr->u.in.addr != INADDR_NONE) { + cidr->family = AF_INET; + + if (mask == NULL) { + cidr->u.in.mask = 0xffffffff; + return NGX_OK; + } - if (cidr->u.in.addr == INADDR_NONE) { +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) { + cidr->family = AF_INET6; + + if (mask == NULL) { + ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16); + return NGX_OK; + } + +#endif + } else { return NGX_ERROR; } - if (mask == NULL) { - cidr->family = AF_INET; - cidr->u.in.mask = 0xffffffff; - return NGX_OK; - } - mask++; shift = ngx_atoi(mask, last - mask); @@ -255,30 +402,108 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t return NGX_ERROR; } - cidr->family = AF_INET; + switch (cidr->family) { - if (shift == 0) { +#if (NGX_HAVE_INET6) + case AF_INET6: + addr = cidr->u.in6.addr.s6_addr; + mask = cidr->u.in6.mask.s6_addr; + rc = NGX_OK; + + for (i = 0; i < 16; i++) { + + s = (shift > 8) ? 8 : shift; + shift -= s; + + mask[i] = (u_char) (0 - (1 << (8 - s))); - /* the x86 compilers use the shl instruction that shifts by modulo 32 */ + if (addr[i] != (addr[i] & mask[i])) { + rc = NGX_DONE; + addr[i] &= mask[i]; + } + } + + return rc; +#endif - cidr->u.in.mask = 0; + default: /* AF_INET */ + + if (shift) { + cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); - if (cidr->u.in.addr == 0) { + } else { + /* x86 compilers use a shl instruction that shifts by modulo 32 */ + cidr->u.in.mask = 0; + } + + if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { return NGX_OK; } + cidr->u.in.addr &= cidr->u.in.mask; + return NGX_DONE; } +} + + +ngx_int_t +ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) +{ + in_addr_t inaddr; + ngx_uint_t family; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr inaddr6; + struct sockaddr_in6 *sin6; + + /* + * prevent MSVC8 waring: + * potentially uninitialized local variable 'inaddr6' used + */ + ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr)); +#endif + + inaddr = ngx_inet_addr(text, len); + + if (inaddr != INADDR_NONE) { + family = AF_INET; + len = sizeof(struct sockaddr_in); + +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) { + family = AF_INET6; + len = sizeof(struct sockaddr_in6); + +#endif + } else { + return NGX_DECLINED; + } - cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); - - if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { - return NGX_OK; + addr->sockaddr = ngx_pcalloc(pool, len); + if (addr->sockaddr == NULL) { + return NGX_ERROR; } - cidr->u.in.addr &= cidr->u.in.mask; + addr->sockaddr->sa_family = (u_char) family; + addr->socklen = len; + + switch (family) { - return NGX_DONE; +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr->sockaddr; + ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr->sockaddr; + sin->sin_addr.s_addr = inaddr; + break; + } + + return NGX_OK; } @@ -351,7 +576,7 @@ ngx_parse_unix_domain_url(ngx_pool_t *po saun->sun_family = AF_UNIX; (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); - u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } @@ -509,22 +734,22 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx return NGX_OK; } - if (len++) { - - p = ngx_alloc(len, pool->log); - if (p == NULL) { - return NGX_ERROR; - } - - (void) ngx_cpystrn(p, host, len); - - sin->sin_addr.s_addr = inet_addr((const char *) p); + if (len) { + sin->sin_addr.s_addr = ngx_inet_addr(host, len); if (sin->sin_addr.s_addr == INADDR_NONE) { + p = ngx_alloc(++len, pool->log); + if (p == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(p, host, len); + h = gethostbyname((const char *) p); + ngx_free(p); + if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_free(p); u->err = "host not found"; return NGX_ERROR; } @@ -536,8 +761,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx u->wildcard = 1; } - ngx_free(p); - } else { sin->sin_addr.s_addr = INADDR_ANY; u->wildcard = 1; @@ -564,7 +787,6 @@ static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) { #if (NGX_HAVE_INET6) - int rc; u_char *p, *host, *port, *last, *uri; size_t len; ngx_int_t n; @@ -636,35 +858,10 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng return NGX_ERROR; } - u->host.len = len++; + u->host.len = len; u->host.data = host; - p = ngx_alloc(len, pool->log); - if (p == NULL) { - return NGX_ERROR; - } - - (void) ngx_cpystrn(p, host, len); - -#if (NGX_WIN32) - - rc = WSAStringToAddress((char *) p, AF_INET6, NULL, - (SOCKADDR *) sin6, &u->socklen); - rc = !rc; - - if (u->port) { - sin6->sin6_port = htons(u->port); - } - -#else - - rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr); - -#endif - - ngx_free(p); - - if (rc == 0) { + if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) { u->err = "invalid IPv6 address"; return NGX_ERROR; } @@ -707,20 +904,20 @@ ngx_inet_resolve_host(ngx_pool_t *pool, struct hostent *h; struct sockaddr_in *sin; - host = ngx_alloc(u->host.len + 1, pool->log); - if (host == NULL) { - return NGX_ERROR; - } - - (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); - /* AF_INET only */ port = htons(u->port); - in_addr = inet_addr((char *) host); + in_addr = ngx_inet_addr(u->host.data, u->host.len); if (in_addr == INADDR_NONE) { + host = ngx_alloc(u->host.len + 1, pool->log); + if (host == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + h = gethostbyname((char *) host); ngx_free(host); @@ -739,7 +936,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } @@ -775,11 +972,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, } else { - ngx_free(host); - /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } 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 @@ -12,21 +12,26 @@ #include -#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1) -#define NGX_INET6_ADDRSTRLEN \ - (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) - -#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1) - - /* - * TODO: autoconfigure NGX_SOCKADDRLEN as + * TODO: autoconfigure NGX_SOCKADDRLEN and NGX_SOCKADDR_STRLEN as * sizeof(struct sockaddr_storage) * sizeof(struct sockaddr_un) * sizeof(struct sockaddr_in6) * sizeof(struct sockaddr_in) */ +#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1) +#define NGX_INET6_ADDRSTRLEN \ + (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) +#define NGX_UNIX_ADDRSTRLEN \ + (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) + +#if (NGX_HAVE_UNIX_DOMAIN) +#define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN) +#else +#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1) +#endif + #if (NGX_HAVE_UNIX_DOMAIN) #define NGX_SOCKADDRLEN sizeof(struct sockaddr_un) #else @@ -65,7 +70,7 @@ typedef struct { struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t name; -} ngx_peer_addr_t; +} ngx_addr_t; typedef struct { @@ -89,7 +94,7 @@ typedef struct { socklen_t socklen; u_char sockaddr[NGX_SOCKADDRLEN]; - ngx_peer_addr_t *addrs; + ngx_addr_t *addrs; ngx_uint_t naddrs; char *err; @@ -97,13 +102,18 @@ typedef struct { in_addr_t ngx_inet_addr(u_char *text, size_t len); +#if (NGX_HAVE_INET6) +ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr); +size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len); +#endif size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr); +ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, + size_t len); ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u); - #endif /* _NGX_INET_H_INCLUDED_ */ 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 @@ -17,6 +17,9 @@ */ +#define NGX_MIN_READ_AHEAD (128 * 1024) + + static void ngx_open_file_cache_cleanup(void *data); static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log); @@ -524,8 +527,15 @@ ngx_open_and_stat_file(u_char *name, ngx } else { of->fd = fd; + if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { + if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_read_ahead_n " \"%s\" failed", name); + } + } + if (of->directio <= ngx_file_size(&fi)) { - if (ngx_directio_on(fd) == -1) { + if (ngx_directio_on(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%s\" failed", name); 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,6 +21,7 @@ typedef struct { time_t mtime; off_t size; off_t directio; + size_t read_ahead; ngx_err_t err; char *failed; 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 @@ -514,7 +514,7 @@ ngx_output_chain_copy_buf(ngx_output_cha #if (NGX_HAVE_ALIGNED_DIRECTIO) if (ctx->unaligned) { - if (ngx_directio_off(src->file->fd) == -1) { + if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, ngx_directio_off_n " \"%s\" failed", src->file->name.data); @@ -550,7 +550,7 @@ ngx_output_chain_copy_buf(ngx_output_cha err = ngx_errno; - if (ngx_directio_on(src->file->fd) == -1) { + if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, ngx_directio_on_n " \"%s\" failed", src->file->name.data); @@ -571,9 +571,7 @@ ngx_output_chain_copy_buf(ngx_output_cha 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; 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 @@ -17,7 +17,7 @@ ngx_create_pool(size_t size, ngx_log_t * { ngx_pool_t *p; - p = ngx_alloc(size, log); + p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log); if (p == NULL) { return NULL; } @@ -181,7 +181,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_ psize = (size_t) (pool->d.end - (u_char *) pool); - m = ngx_alloc(psize, pool->log); + m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log); if (m == NULL) { return NULL; } 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 @@ -19,8 +19,11 @@ #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1) #define NGX_DEFAULT_POOL_SIZE (16 * 1024) + +#define NGX_POOL_ALIGNMENT 16 #define NGX_MIN_POOL_SIZE \ - (sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)) + ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), \ + NGX_POOL_ALIGNMENT) typedef void (*ngx_pool_cleanup_pt)(void *data); diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -23,61 +23,116 @@ ngx_regex_init(void) } -ngx_regex_t * -ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, ngx_pool_t *pool, - ngx_str_t *err) +static ngx_inline void +ngx_regex_malloc_init(ngx_pool_t *pool) { - int erroff; - const char *errstr; - ngx_regex_t *re; #if (NGX_THREADS) ngx_core_tls_t *tls; -#if (NGX_SUPPRESS_WARN) - tls = NULL; -#endif - if (ngx_threaded) { tls = ngx_thread_get_tls(ngx_core_tls_key); tls->pool = pool; - } else { - ngx_pcre_pool = pool; + return; } -#else +#endif ngx_pcre_pool = pool; +} + + +static ngx_inline void +ngx_regex_malloc_done(void) +{ +#if (NGX_THREADS) + ngx_core_tls_t *tls; + + if (ngx_threaded) { + tls = ngx_thread_get_tls(ngx_core_tls_key); + tls->pool = NULL; + return; + } #endif - re = pcre_compile((const char *) pattern->data, (int) options, + ngx_pcre_pool = NULL; +} + + +ngx_int_t +ngx_regex_compile(ngx_regex_compile_t *rc) +{ + int n, erroff; + char *p; + const char *errstr; + ngx_regex_t *re; + + ngx_regex_malloc_init(rc->pool); + + re = pcre_compile((const char *) rc->pattern.data, (int) rc->options, &errstr, &erroff, NULL); + /* ensure that there is no current pool */ + ngx_regex_malloc_done(); + if (re == NULL) { - if ((size_t) erroff == pattern->len) { - ngx_snprintf(err->data, err->len - 1, - "pcre_compile() failed: %s in \"%s\"%Z", - errstr, pattern->data); + if ((size_t) erroff == rc->pattern.len) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre_compile() failed: %s in \"%V\"", + errstr, &rc->pattern) + - rc->err.data; + } else { - ngx_snprintf(err->data, err->len - 1, - "pcre_compile() failed: %s in \"%s\" at \"%s\"%Z", - errstr, pattern->data, pattern->data + erroff); + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre_compile() failed: %s in \"%V\" at \"%s\"", + errstr, &rc->pattern, rc->pattern.data + erroff) + - rc->err.data; } + + return NGX_ERROR; + } + + rc->regex = re; + + n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures); + if (n < 0) { + p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d"; + goto failed; + } + + if (rc->captures == 0) { + return NGX_OK; } - /* ensure that there is no current pool */ + n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures); + if (n < 0) { + p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d"; + goto failed; + } + + if (rc->named_captures == 0) { + return NGX_OK; + } -#if (NGX_THREADS) - if (ngx_threaded) { - tls->pool = NULL; - } else { - ngx_pcre_pool = NULL; + n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size); + if (n < 0) { + p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d"; + goto failed; } -#else - ngx_pcre_pool = NULL; -#endif + + n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names); + if (n < 0) { + p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d"; + goto failed; + } - return re; + return NGX_OK; + +failed: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) + - rc->err.data; + return NGX_OK; } @@ -99,22 +154,6 @@ ngx_regex_capture_count(ngx_regex_t *re) ngx_int_t -ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_int_t size) -{ - int rc; - - rc = pcre_exec(re, NULL, (const char *) s->data, s->len, 0, 0, - captures, size); - - if (rc == -1) { - return NGX_REGEX_NO_MATCHED; - } - - return rc; -} - - -ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) { ngx_int_t n; @@ -133,7 +172,7 @@ ngx_regex_exec_array(ngx_array_t *a, ngx if (n < 0) { ngx_log_error(NGX_LOG_ALERT, log, 0, - ngx_regex_exec_n " failed: %d on \"%V\" using \"%s\"", + ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"", n, s, re[i].name); return NGX_ERROR; } @@ -157,11 +196,15 @@ ngx_regex_malloc(size_t size) if (ngx_threaded) { tls = ngx_thread_get_tls(ngx_core_tls_key); pool = tls->pool; + } else { pool = ngx_pcre_pool; } + #else + pool = ngx_pcre_pool; + #endif if (pool) { diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -14,29 +14,42 @@ #include -#define NGX_REGEX_NO_MATCHED -1000 +#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ #define NGX_REGEX_CASELESS PCRE_CASELESS typedef pcre ngx_regex_t; + typedef struct { - ngx_regex_t *regex; - u_char *name; + ngx_str_t pattern; + ngx_pool_t *pool; + ngx_int_t options; + + ngx_regex_t *regex; + int captures; + int named_captures; + int name_size; + u_char *names; + ngx_str_t err; +} ngx_regex_compile_t; + + +typedef struct { + ngx_regex_t *regex; + u_char *name; } ngx_regex_elt_t; void ngx_regex_init(void); -ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, - ngx_pool_t *pool, ngx_str_t *err); -ngx_int_t ngx_regex_capture_count(ngx_regex_t *re); -ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, - ngx_int_t size); +ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc); + +#define ngx_regex_exec(re, s, captures, size) \ + pcre_exec(re, NULL, (const char *) (s)->data, (s)->len, 0, 0, \ + captures, size) +#define ngx_regex_exec_n "pcre_exec()" + ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); -#define ngx_regex_exec_n "pcre_exec()" -#define ngx_regex_capture_count_n "pcre_fullinfo()" - - #endif /* _NGX_REGEX_H_INCLUDED_ */ 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 @@ -87,12 +87,11 @@ static void *ngx_resolver_calloc(ngx_res static void ngx_resolver_free(ngx_resolver_t *r, void *p); static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); - - -/* STUB: ngx_peer_addr_t * */ +static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len); + ngx_resolver_t * -ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr) +ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr) { ngx_resolver_t *r; ngx_pool_cleanup_t *cln; @@ -152,7 +151,11 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ uc->sockaddr = addr->sockaddr; uc->socklen = addr->socklen; uc->server = addr->name; - uc->log = &cf->cycle->new_log; + + uc->log = cf->cycle->new_log; + uc->log.handler = ngx_resolver_log_error; + uc->log.data = uc; + uc->log.action = "resolving"; } return r; @@ -464,6 +467,7 @@ ngx_resolve_name_locked(ngx_resolver_t * ctx->next = rn->waiting; rn->waiting = ctx; + ctx->state = NGX_AGAIN; return NGX_AGAIN; } @@ -625,6 +629,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx ctx->next = rn->waiting; rn->waiting = ctx; + ctx->state = NGX_AGAIN; /* unlock addr mutex */ @@ -840,7 +845,7 @@ ngx_resolver_send_query(ngx_resolver_t * } if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, uc->log, 0, "send() incomplete"); + ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); return NGX_ERROR; } @@ -1149,6 +1154,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 +1407,8 @@ failed: /* unlock name mutex */ + ngx_resolver_free(r, name.data); + return; } @@ -1595,7 +1604,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 +1627,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 +1681,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 +1699,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) { @@ -1719,15 +1722,16 @@ static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) { u_char *p, *s; - size_t len; + size_t len, nlen; ngx_uint_t ident; ngx_resolver_qs_t *qs; ngx_resolver_query_t *query; - len = sizeof(ngx_resolver_query_t) - + 1 + ctx->name.len + 1 + sizeof(ngx_resolver_qs_t); - - p = ngx_resolver_calloc(ctx->resolver, len); + nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1; + + len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t); + + p = ngx_resolver_alloc(ctx->resolver, len); if (p == NULL) { return NGX_ERROR; } @@ -1754,7 +1758,7 @@ ngx_resolver_create_name_query(ngx_resol query->nns_hi = 0; query->nns_lo = 0; query->nar_hi = 0; query->nar_lo = 0; - p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1; + p += sizeof(ngx_resolver_query_t) + nlen; qs = (ngx_resolver_qs_t *) p; @@ -1808,7 +1812,7 @@ ngx_resolver_create_addr_query(ngx_resol + sizeof(".255.255.255.255.in-addr.arpa.") - 1 + sizeof(ngx_resolver_qs_t); - p = ngx_resolver_calloc(ctx->resolver, len); + p = ngx_resolver_alloc(ctx->resolver, len); if (p == NULL) { return NGX_ERROR; } @@ -1902,6 +1906,12 @@ done: return NGX_OK; } + if (len == -1) { + name->len = 0; + name->data = NULL; + return NGX_OK; + } + dst = ngx_resolver_alloc(r, len); if (dst == NULL) { return NGX_ERROR; @@ -2066,6 +2076,29 @@ ngx_resolver_strerror(ngx_int_t err) } +static u_char * +ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_udp_connection_t *uc; + + p = buf; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + } + + uc = log->data; + + if (uc) { + p = ngx_snprintf(p, len, ", resolver: %V", &uc->server); + } + + return p; +} + + ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc) { @@ -2077,19 +2110,19 @@ ngx_udp_connect(ngx_udp_connection_t *uc s = ngx_socket(AF_INET, SOCK_DGRAM, 0); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, uc->log, 0, "UDP socket %d", s); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s); if (s == -1) { - ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } - c = ngx_get_connection(s, uc->log); + c = ngx_get_connection(s, &uc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } @@ -2097,13 +2130,13 @@ ngx_udp_connect(ngx_udp_connection_t *uc } if (ngx_nonblocking(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); ngx_free_connection(c); if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -2113,8 +2146,8 @@ ngx_udp_connect(ngx_udp_connection_t *uc rev = c->read; wev = c->write; - rev->log = uc->log; - wev->log = uc->log; + rev->log = &uc->log; + wev->log = &uc->log; uc->connection = c; @@ -2131,7 +2164,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc #endif - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, uc->log, 0, + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); rc = connect(s, uc->sockaddr, uc->socklen); @@ -2139,8 +2172,8 @@ ngx_udp_connect(ngx_udp_connection_t *uc /* TODO: aio, iocp */ if (rc == -1) { - ngx_log_error(NGX_LOG_CRIT, uc->log, ngx_socket_errno, - "connect() to %V failed", &uc->server); + ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, + "connect() failed"); return NGX_ERROR; } diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -37,7 +37,7 @@ typedef struct { struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t server; - ngx_log_t *log; + ngx_log_t log; } ngx_udp_connection_t; @@ -135,7 +135,7 @@ struct ngx_resolver_ctx_s { }; -ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr); +ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr); ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp); ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx); 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 @@ -15,10 +15,11 @@ static u_char *ngx_sprintf_num(u_char *b void ngx_strlow(u_char *dst, u_char *src, size_t n) { - while (n--) { + while (n) { *dst = ngx_tolower(*src); dst++; src++; + n--; } } @@ -147,7 +148,7 @@ ngx_vslprintf(u_char *buf, u_char *last, int64_t i64; uint64_t ui64; ngx_msec_t ms; - ngx_uint_t width, sign, hex, max_width, frac_width, i; + ngx_uint_t width, sign, hex, max_width, frac_width, n; ngx_str_t *v; ngx_variable_value_t *vv; @@ -377,7 +378,7 @@ ngx_vslprintf(u_char *buf, u_char *last, scale = 1.0; - for (i = 0; i < frac_width; i++) { + for (n = frac_width; n; n--) { scale *= 10.0; } @@ -1238,10 +1239,8 @@ ngx_utf8_cpystrn(u_char *dst, u_char *sr break; } - len--; - while (src < next) { - *++dst = *++src; + *dst++ = *src++; len--; } } @@ -1255,7 +1254,7 @@ ngx_utf8_cpystrn(u_char *dst, u_char *sr uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) { - ngx_uint_t i, n; + ngx_uint_t n; uint32_t *escape; static u_char hex[] = "0123456789abcdef"; @@ -1373,17 +1372,18 @@ ngx_escape_uri(u_char *dst, u_char *src, n = 0; - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { n++; } src++; + size--; } return (uintptr_t) n; } - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { *dst++ = '%'; *dst++ = hex[*src >> 4]; @@ -1393,6 +1393,7 @@ ngx_escape_uri(u_char *dst, u_char *src, } else { *dst++ = *src++; } + size--; } return (uintptr_t) dst; @@ -1533,13 +1534,13 @@ uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size) { u_char ch; - ngx_uint_t i, len; + ngx_uint_t len; if (dst == NULL) { len = 0; - for (i = 0; i < size; i++) { + while (size) { switch (*src++) { case '<': @@ -1557,12 +1558,13 @@ ngx_escape_html(u_char *dst, u_char *src default: break; } + size--; } return (uintptr_t) len; } - for (i = 0; i < size; i++) { + while (size) { ch = *src++; switch (ch) { @@ -1584,6 +1586,7 @@ ngx_escape_html(u_char *dst, u_char *src *dst++ = ch; break; } + size--; } return (uintptr_t) dst; 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 @@ -72,7 +72,7 @@ ngx_poll_init(ngx_cycle_t *cycle, ngx_ms nevents = 0; } - if (ngx_process == NGX_PROCESS_WORKER + if (ngx_process >= NGX_PROCESS_WORKER || cycle->old_cycle == NULL || cycle->old_cycle->connection_n < cycle->connection_n) { 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 @@ -81,7 +81,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_ nevents = 0; } - if (ngx_process == NGX_PROCESS_WORKER + if (ngx_process >= NGX_PROCESS_WORKER || cycle->old_cycle == NULL || cycle->old_cycle->connection_n < cycle->connection_n) { diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c @@ -82,7 +82,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_ nevents = 0; } - if (ngx_process == NGX_PROCESS_WORKER + if (ngx_process >= NGX_PROCESS_WORKER || cycle->old_cycle == NULL || cycle->old_cycle->connection_n < cycle->connection_n) { 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 @@ -152,10 +152,20 @@ ngx_event_accept(ngx_event_t *ev) c->socklen = socklen; c->listening = ls; c->local_sockaddr = ls->sockaddr; - c->local_socklen = ls->socklen; c->unexpected_eof = 1; +#if (NGX_HAVE_UNIX_DOMAIN) + if (c->sockaddr->sa_family == AF_UNIX) { + c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; + c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; +#if (NGX_SOLARIS) + /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ + c->sendfile = 0; +#endif + } +#endif + rev = c->read; wev = c->write; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -54,15 +54,7 @@ ngx_event_connect_peer(ngx_peer_connecti { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); - - ngx_free_connection(c); - - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - - return NGX_ERROR; + goto failed; } } @@ -70,14 +62,16 @@ ngx_event_connect_peer(ngx_peer_connecti ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); - ngx_free_connection(c); + goto failed; + } - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); + if (pc->local) { + if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, + "bind(%V) failed", &pc->local->name); + + goto failed; } - - return NGX_ERROR; } c->recv = ngx_recv; @@ -107,27 +101,22 @@ ngx_event_connect_peer(ngx_peer_connecti pc->connection = c; - /* - * TODO: MT: - ngx_atomic_fetch_add() - * or protection by critical section or mutex - * - * TODO: MP: - allocated in a shared memory - * - ngx_atomic_fetch_add() - * or protection by critical section or mutex - */ - c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_THREADS) + + /* TODO: lock event when call completion handler */ + rev->lock = pc->lock; wev->lock = pc->lock; rev->own_lock = &c->lock; wev->own_lock = &c->lock; + #endif if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; + goto failed; } } @@ -199,7 +188,7 @@ ngx_event_connect_peer(ngx_peer_connecti if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); - return NGX_ERROR; + goto failed; } /* @@ -229,7 +218,7 @@ ngx_event_connect_peer(ngx_peer_connecti } if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } if (rc == -1) { @@ -237,7 +226,7 @@ ngx_event_connect_peer(ngx_peer_connecti /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } return NGX_AGAIN; @@ -248,6 +237,17 @@ ngx_event_connect_peer(ngx_peer_connecti wev->ready = 1; return NGX_OK; + +failed: + + ngx_free_connection(c); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; } diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -55,6 +55,8 @@ struct ngx_peer_connection_s { ngx_atomic_t *lock; #endif + ngx_addr_t *local; + int rcvbuf; ngx_log_t *log; @@ -70,5 +72,4 @@ ngx_int_t ngx_event_connect_peer(ngx_pee ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data); - #endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */ 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 @@ -15,6 +15,8 @@ typedef struct { static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); +static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, + int ret); static void ngx_ssl_handshake_handler(ngx_event_t *ev); static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); @@ -104,6 +106,8 @@ ngx_ssl_init(ngx_log_t *log) ENGINE_load_builtin_engines(); + OpenSSL_add_all_algorithms(); + ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (ngx_ssl_connection_index == -1) { @@ -175,6 +179,8 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_read_ahead(ssl->ctx, 1); + SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback); + return NGX_OK; } @@ -350,6 +356,22 @@ ngx_http_ssl_verify_callback(int ok, X50 } +static void +ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) +{ + ngx_connection_t *c; + + if (where & SSL_CB_HANDSHAKE_START) { + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + + if (c->ssl->handshaked) { + c->ssl->renegotiation = 1; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation"); + } + } +} + + ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl) { @@ -587,6 +609,11 @@ ngx_ssl_handshake(ngx_connection_t *c) c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; + /* initial handshake done, disable renegotiation (CVE-2009-3555) */ + if (c->ssl->connection->s3) { + c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; + } + return NGX_OK; } @@ -789,6 +816,21 @@ ngx_ssl_handle_recv(ngx_connection_t *c, int sslerr; ngx_err_t err; + if (c->ssl->renegotiation) { + /* + * disable renegotiation (CVE-2009-3555): + * OpenSSL (at least up to 0.9.8l) does not handle disabled + * renegotiation gracefully, so drop connection here + */ + + ngx_log_error(NGX_LOG_NOTICE, c->log, 0, "SSL renegotiation disabled"); + + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + + return NGX_ERROR; + } + if (n > 0) { if (c->ssl->saved_write_handler) { @@ -946,7 +988,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, for ( ;; ) { - while (in && buf->last < buf->end) { + while (in && buf->last < buf->end && send < limit) { if (in->buf->last_buf || in->buf->flush) { flush = 1; } @@ -973,8 +1015,8 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_memcpy(buf->last, in->buf->pos, size); buf->last += size; - in->buf->pos += size; + send += size; if (in->buf->pos == in->buf->last) { in = in->next; @@ -999,7 +1041,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, } buf->pos += n; - send += n; c->sent += n; if (n < size) { @@ -1269,10 +1310,15 @@ ngx_ssl_connection_error(ngx_connection_ /* handshake failures */ if (n == SSL_R_DIGEST_CHECK_FAILED /* 149 */ + || n == SSL_R_LENGTH_MISMATCH /* 159 */ || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ + || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ + || n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */ || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ + || n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */ + || n == SSL_R_UNKNOWN_PROTOCOL /* 252 */ || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */ || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */ || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ @@ -1384,6 +1430,8 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng return NGX_OK; } + SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len); + if (builtin_session_cache == NGX_SSL_NONE_SCACHE) { /* @@ -1415,8 +1463,6 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode); - SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len); - if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) { if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) { @@ -1588,7 +1634,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ hash = ngx_crc32_short(sess->session_id, sess->session_id_length); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "http ssl new session: %08XD:%d:%d", + "ssl new session: %08XD:%d:%d", hash, sess->session_id_length, len); sess_id->node.key = hash; @@ -1651,7 +1697,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ *copy = 0; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "http ssl get session: %08XD:%d", hash, len); + "ssl get session: %08XD:%d", hash, len); shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn), ngx_ssl_session_cache_index); @@ -1765,7 +1811,7 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx hash = ngx_crc32_short(id, len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, - "http ssl remove session: %08XD:%uz", hash, len); + "ssl remove session: %08XD:%uz", hash, len); shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; @@ -1929,6 +1975,40 @@ ngx_ssl_get_cipher_name(ngx_connection_t ngx_int_t +ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + int len; + u_char *p, *buf; + SSL_SESSION *sess; + + sess = SSL_get0_session(c->ssl->connection); + + len = i2d_SSL_SESSION(sess, NULL); + + buf = ngx_alloc(len, c->log); + if (buf == NULL) { + return NGX_ERROR; + } + + s->len = 2 * len; + s->data = ngx_pnalloc(pool, 2 * len); + if (s->data == NULL) { + ngx_free(buf); + return NGX_ERROR; + } + + p = buf; + i2d_SSL_SESSION(sess, &p); + + ngx_hex_dump(s->data, buf, len); + + ngx_free(buf); + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { size_t len; @@ -2237,5 +2317,6 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c static void ngx_openssl_exit(ngx_cycle_t *cycle) { + EVP_cleanup(); ENGINE_cleanup(); } 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 @@ -15,6 +15,7 @@ #include #include #include +#include #define NGX_SSL_NAME "OpenSSL" @@ -41,6 +42,7 @@ typedef struct { ngx_event_handler_pt saved_write_handler; unsigned handshaked:1; + unsigned renegotiation:1; unsigned buffer:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; @@ -118,6 +120,8 @@ ngx_int_t ngx_ssl_get_protocol(ngx_conne ngx_str_t *s); ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, 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 @@ -10,18 +10,37 @@ typedef struct { - in_addr_t mask; - in_addr_t addr; - ngx_uint_t deny; /* unsigned deny:1; */ + in_addr_t mask; + in_addr_t addr; + ngx_uint_t deny; /* unsigned deny:1; */ } ngx_http_access_rule_t; +#if (NGX_HAVE_INET6) typedef struct { - ngx_array_t *rules; /* array of ngx_http_access_rule_t */ + struct in6_addr addr; + struct in6_addr mask; + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_http_access_rule6_t; + +#endif + +typedef struct { + ngx_array_t *rules; /* array of ngx_http_access_rule_t */ +#if (NGX_HAVE_INET6) + ngx_array_t *rules6; /* array of ngx_http_access_rule6_t */ +#endif } ngx_http_access_loc_conf_t; static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf, in_addr_t addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf, u_char *p); +#endif +static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny); static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf); @@ -87,46 +106,59 @@ ngx_module_t ngx_http_access_module = { static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) { - ngx_uint_t i; struct sockaddr_in *sin; - ngx_http_access_rule_t *rule; - ngx_http_core_loc_conf_t *clcf; ngx_http_access_loc_conf_t *alcf; alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); - if (alcf->rules == NULL) { - return NGX_DECLINED; +#if (NGX_HAVE_INET6) + + if (alcf->rules6 && r->connection->sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + p = sin6->sin6_addr.s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + return ngx_http_access_inet(r, alcf, htonl(addr)); + } + + return ngx_http_access_inet6(r, alcf, p); } - /* AF_INET only */ +#endif - if (r->connection->sockaddr->sa_family != AF_INET) { - return NGX_DECLINED; + if (alcf->rules && r->connection->sockaddr->sa_family == AF_INET) { + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr); } - sin = (struct sockaddr_in *) r->connection->sockaddr; + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, + in_addr_t addr) +{ + ngx_uint_t i; + ngx_http_access_rule_t *rule; rule = alcf->rules->elts; for (i = 0; i < alcf->rules->nelts; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "access: %08XD %08XD %08XD", - sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); - - if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { - if (rule[i].deny) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + addr, rule[i].mask, rule[i].addr); - if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "access forbidden by rule"); - } - - return NGX_HTTP_FORBIDDEN; - } - - return NGX_OK; + if ((addr & rule[i].mask) == rule[i].addr) { + return ngx_http_access_found(r, rule[i].deny); } } @@ -134,62 +166,159 @@ ngx_http_access_handler(ngx_http_request } +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, + u_char *p) +{ + ngx_uint_t n; + ngx_uint_t i; + ngx_http_access_rule6_t *rule6; + + rule6 = alcf->rules6->elts; + for (i = 0; i < alcf->rules6->nelts; i++) { + +#if (NGX_DEBUG) + { + size_t cl, ml, al; + u_char ct[NGX_INET6_ADDRSTRLEN]; + u_char mt[NGX_INET6_ADDRSTRLEN]; + u_char at[NGX_INET6_ADDRSTRLEN]; + + cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); + ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); + al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "access: %*s %*s %*s", cl, ct, ml, mt, al, at); + } +#endif + + for (n = 0; n < 16; n++) { + if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { + goto next; + } + } + + return ngx_http_access_found(r, rule6[i].deny); + + next: + continue; + } + + return NGX_DECLINED; +} + +#endif + + +static ngx_int_t +ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny) +{ + ngx_http_core_loc_conf_t *clcf; + + if (deny) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "access forbidden by rule"); + } + + return NGX_HTTP_FORBIDDEN; + } + + return NGX_OK; +} + + static char * ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_access_loc_conf_t *alcf = conf; - ngx_int_t rc; - ngx_str_t *value; - ngx_cidr_t cidr; - ngx_http_access_rule_t *rule; + ngx_int_t rc; + ngx_uint_t all; + ngx_str_t *value; + ngx_cidr_t cidr; + ngx_http_access_rule_t *rule; +#if (NGX_HAVE_INET6) + ngx_http_access_rule6_t *rule6; +#endif - if (alcf->rules == NULL) { - alcf->rules = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_access_rule_t)); - if (alcf->rules == NULL) { - return NGX_CONF_ERROR; - } - } - - rule = ngx_array_push(alcf->rules); - if (rule == NULL) { - return NGX_CONF_ERROR; - } + ngx_memzero(&cidr, sizeof(ngx_cidr_t)); value = cf->args->elts; - rule->deny = (value[0].data[0] == 'd') ? 1 : 0; + all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); + + if (!all) { + + rc = ngx_ptocidr(&value[1], &cidr); - if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { - rule->mask = 0; - rule->addr = 0; + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } - return NGX_CONF_OK; + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } } - rc = ngx_ptocidr(&value[1], &cidr); + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + case 0: /* all */ - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", - &value[1]); - return NGX_CONF_ERROR; - } + if (alcf->rules6 == NULL) { + alcf->rules6 = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule6_t)); + if (alcf->rules6 == NULL) { + return NGX_CONF_ERROR; + } + } + + rule6 = ngx_array_push(alcf->rules6); + if (rule6 == NULL) { + return NGX_CONF_ERROR; + } + + rule6->mask = cidr.u.in6.mask; + rule6->addr = cidr.u.in6.addr; + rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"allow\" supports IPv4 only"); - return NGX_CONF_ERROR; - } + if (!all) { + break; + } + + /* "all" passes through */ +#endif + + default: /* AF_INET */ - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", &value[1]); + if (alcf->rules == NULL) { + alcf->rules = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule_t)); + if (alcf->rules == NULL) { + return NGX_CONF_ERROR; + } + } + + rule = ngx_array_push(alcf->rules); + if (rule == NULL) { + return NGX_CONF_ERROR; + } + + rule->mask = cidr.u.in.mask; + rule->addr = cidr.u.in.addr; + rule->deny = (value[0].data[0] == 'd') ? 1 : 0; } - rule->mask = cidr.u.in.mask; - rule->addr = cidr.u.in.addr; - return NGX_CONF_OK; } @@ -218,6 +347,12 @@ ngx_http_access_merge_loc_conf(ngx_conf_ conf->rules = prev->rules; } +#if (NGX_HAVE_INET6) + if (conf->rules6 == NULL) { + conf->rules6 = prev->rules6; + } +#endif + return NGX_CONF_OK; } 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, @@ -237,8 +237,8 @@ ngx_http_addition_merge_conf(ngx_conf_t ngx_conf_merge_str_value(conf->before_body, prev->before_body, ""); ngx_conf_merge_str_value(conf->after_body, prev->after_body, ""); - if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, - prev->types_keys, &prev->types, + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, ngx_http_html_default_types) != NGX_OK) { 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 @@ -1550,8 +1550,8 @@ ngx_http_charset_merge_loc_conf(ngx_conf ngx_http_charset_recode_t *recode; ngx_http_charset_main_conf_t *mcf; - if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, - prev->types_keys, &prev->types, + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, ngx_http_charset_default_types) != NGX_OK) { diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -52,7 +52,6 @@ ngx_http_chunked_header_filter(ngx_http_ { if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->headers_out.status == NGX_HTTP_NO_CONTENT - || r->headers_out.status == NGX_HTTP_CREATED || r != r->main || (r->method & NGX_HTTP_HEAD)) { 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 @@ -490,6 +490,7 @@ ngx_http_dav_mkcol_handler(ngx_http_requ p = ngx_http_map_uri_to_path(r, &path, &root, 0); *(p - 1) = '\0'; + r->uri.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http mkcol path: \"%s\"", path.data); @@ -516,8 +517,8 @@ ngx_http_dav_copy_move_handler(ngx_http_ size_t len, root; ngx_err_t err; ngx_int_t rc, depth; - ngx_uint_t overwrite, slash, dir; - ngx_str_t path, uri; + ngx_uint_t overwrite, slash, dir, flags; + ngx_str_t path, uri, duri, args; ngx_tree_ctx_t tree; ngx_copy_file_t cf; ngx_file_info_t fi; @@ -594,6 +595,14 @@ invalid_destination: destination_done: + duri.len = last - p; + duri.data = p; + flags = 0; + + if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { + goto invalid_destination; + } + if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) { @@ -656,9 +665,7 @@ overwrite_done: "http copy from: \"%s\"", path.data); uri = r->uri; - - r->uri.len = last - p; - r->uri.data = p; + r->uri = duri; ngx_http_map_uri_to_path(r, ©.path, &root, 0); diff --git a/src/http/modules/ngx_http_degradation_module.c b/src/http/modules/ngx_http_degradation_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_degradation_module.c @@ -0,0 +1,228 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + size_t sbrk_size; +} ngx_http_degradation_main_conf_t; + + +typedef struct { + ngx_uint_t degrade; +} ngx_http_degradation_loc_conf_t; + + +static ngx_conf_enum_t ngx_http_degrade[] = { + { ngx_string("204"), 204 }, + { ngx_string("444"), 444 }, + { ngx_null_string, 0 } +}; + + +static void *ngx_http_degradation_create_main_conf(ngx_conf_t *cf); +static void *ngx_http_degradation_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_degradation_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_degradation(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_degradation_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_degradation_commands[] = { + + { ngx_string("degradation"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_degradation, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("degrade"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_degradation_loc_conf_t, degrade), + &ngx_http_degrade }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_degradation_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_degradation_init, /* postconfiguration */ + + ngx_http_degradation_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_degradation_create_loc_conf, /* create location configuration */ + ngx_http_degradation_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_degradation_module = { + NGX_MODULE_V1, + &ngx_http_degradation_module_ctx, /* module context */ + ngx_http_degradation_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_degradation_handler(ngx_http_request_t *r) +{ + time_t now; + static size_t sbrk_size; + static time_t sbrk_time; + ngx_http_degradation_loc_conf_t *dlcf; + ngx_http_degradation_main_conf_t *dmcf; + + dlcf = ngx_http_get_module_loc_conf(r, ngx_http_degradation_module); + + if (dlcf->degrade == 0) { + return NGX_DECLINED; + } + + dmcf = ngx_http_get_module_main_conf(r, ngx_http_degradation_module); + + if (dmcf->sbrk_size) { + + now = ngx_time(); + + /* lock mutex */ + + if (now != sbrk_time) { + + /* + * ELF/i386 is loaded at 0x08000000, 128M + * ELF/amd64 is loaded at 0x00400000, 4M + * + * use a function address to substract the loading address + */ + + sbrk_size = (size_t) sbrk(0) - ((uintptr_t) ngx_palloc & ~0x3FFFFF); + sbrk_time = now; + } + + /* unlock mutex */ + + if (sbrk_size >= dmcf->sbrk_size) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "degradation sbrk: %uz", sbrk_size); + + return dlcf->degrade; + } + } + + return NGX_DECLINED; +} + + +static void * +ngx_http_degradation_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_degradation_main_conf_t *dmcf; + + dmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_degradation_main_conf_t)); + if (dmcf == NULL) { + return NULL; + } + + return dmcf; +} + + +static void * +ngx_http_degradation_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_degradation_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_degradation_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->degrade = NGX_CONF_UNSET_UINT; + + return conf; +} + + +static char * +ngx_http_degradation_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_degradation_loc_conf_t *prev = parent; + ngx_http_degradation_loc_conf_t *conf = child; + + ngx_conf_merge_uint_value(conf->degrade, prev->degrade, 0); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_degradation(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_degradation_main_conf_t *dmcf = conf; + + ngx_str_t *value, s; + + value = cf->args->elts; + + if (ngx_strncmp(value[1].data, "sbrk=", 5) == 0) { + + s.len = value[1].len - 5; + s.data = value[1].data + 5; + + dmcf->sbrk_size = ngx_parse_size(&s); + if (dmcf->sbrk_size == (size_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid sbrk size \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + + return NGX_CONF_ERROR; +} + + +static ngx_int_t +ngx_http_degradation_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_degradation_handler; + + return NGX_OK; +} 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 @@ -62,7 +62,8 @@ typedef struct { size_t length; size_t padding; - ngx_uint_t fastcgi_stdout; /* unsigned :1 */ + unsigned fastcgi_stdout:1; + unsigned large_stderr:1; ngx_array_t *split_parts; @@ -240,6 +241,13 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort), NULL }, + { ngx_string("fastcgi_bind"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_bind_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local), + NULL }, + { ngx_string("fastcgi_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -523,6 +531,23 @@ static ngx_str_t ngx_http_fastcgi_hide_ }; +#if (NGX_HTTP_CACHE) + +static ngx_str_t ngx_http_fastcgi_hide_cache_headers[] = { + ngx_string("Status"), + ngx_string("X-Accel-Expires"), + ngx_string("X-Accel-Redirect"), + ngx_string("X-Accel-Limit-Rate"), + ngx_string("X-Accel-Buffering"), + ngx_string("X-Accel-Charset"), + ngx_string("Set-Cookie"), + ngx_string("P3P"), + ngx_null_string +}; + +#endif + + static ngx_path_init_t ngx_http_fastcgi_temp_path = { ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 } }; @@ -1057,6 +1082,7 @@ ngx_http_fastcgi_reinit_request(ngx_http f->state = ngx_http_fastcgi_st_version; f->fastcgi_stdout = 0; + f->large_stderr = 0; return NGX_OK; } @@ -1075,6 +1101,7 @@ ngx_http_fastcgi_process_header(ngx_http ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_fastcgi_ctx_t *f; + ngx_http_fastcgi_header_t *fh; ngx_http_upstream_header_t *hh; ngx_http_fastcgi_loc_conf_t *flcf; ngx_http_fastcgi_split_part_t *part; @@ -1199,8 +1226,17 @@ ngx_http_fastcgi_process_header(ngx_http * of the PHP warnings to not allocate memory */ - u->buffer.pos = u->buffer.start; - u->buffer.last = u->buffer.start; +#if (NGX_HTTP_CACHE) + if (r->cache) { + u->buffer.pos = u->buffer.start + + r->cache->header_start; + } else { + u->buffer.pos = u->buffer.start; + } +#endif + + u->buffer.last = u->buffer.pos; + f->large_stderr = 1; } return NGX_AGAIN; @@ -1216,6 +1252,45 @@ ngx_http_fastcgi_process_header(ngx_http /* f->type == NGX_HTTP_FASTCGI_STDOUT */ +#if (NGX_HTTP_CACHE) + + if (f->large_stderr) { + u_char *start; + ssize_t len; + + start = u->buffer.start + r->cache->header_start; + + len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t); + + /* + * A tail of large stderr output before HTTP header is placed + * in a cache file without a FastCGI record header. + * To workaround it we put a dummy FastCGI record header at the + * start of the stderr output or update r->cache_header_start, + * if there is no enough place for the record header. + */ + + if (len >= 0) { + fh = (ngx_http_fastcgi_header_t *) start; + fh->version = 1; + fh->type = NGX_HTTP_FASTCGI_STDERR; + fh->request_id_hi = 0; + fh->request_id_lo = 1; + fh->content_length_hi = (u_char) ((len >> 8) & 0xff); + fh->content_length_lo = (u_char) (len & 0xff); + fh->padding_length = 0; + fh->reserved = 0; + + } else { + r->cache->header_start += u->buffer.pos - start + - sizeof(ngx_http_fastcgi_header_t); + } + + f->large_stderr = 0; + } + +#endif + f->fastcgi_stdout = 1; start = u->buffer.pos; @@ -1899,6 +1974,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf u_char *p; size_t size; uintptr_t *code; + ngx_str_t *h; ngx_uint_t i; ngx_keyval_t *src; ngx_hash_init_t hash; @@ -2119,10 +2195,18 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf hash.bucket_size = ngx_align(64, ngx_cacheline_size); hash.name = "fastcgi_hide_headers_hash"; +#if (NGX_HTTP_CACHE) + + h = conf->upstream.cache ? ngx_http_fastcgi_hide_cache_headers: + ngx_http_fastcgi_hide_headers; +#else + + h = ngx_http_fastcgi_hide_headers; + +#endif + if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, - &prev->upstream, - ngx_http_fastcgi_hide_headers, - &hash) + &prev->upstream, h, &hash) != NGX_OK) { return NGX_CONF_ERROR; @@ -2374,27 +2458,25 @@ ngx_http_fastcgi_split(ngx_http_request_ n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3); + if (n >= 0) { /* match */ + f->script_name.len = captures[3] - captures[2]; + f->script_name.data = r->uri.data; + + f->path_info.len = captures[5] - captures[4]; + f->path_info.data = r->uri.data + f->script_name.len; + + return f; + } + if (n == NGX_REGEX_NO_MATCHED) { f->script_name = r->uri; return f; } - if (n < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", - n, &r->uri, &flcf->split_name); - return NULL; - } - - /* match */ - - f->script_name.len = captures[3] - captures[2]; - f->script_name.data = r->uri.data; - - f->path_info.len = captures[5] - captures[4]; - f->path_info.data = r->uri.data + f->script_name.len; - - return f; + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", + n, &r->uri, &flcf->split_name); + return NULL; #else @@ -2485,39 +2567,34 @@ ngx_http_fastcgi_split_path_info(ngx_con #if (NGX_PCRE) ngx_http_fastcgi_loc_conf_t *flcf = conf; - ngx_int_t n; - ngx_str_t *value, err; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_str_t *value; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; value = cf->args->elts; flcf->split_name = value[1]; - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; - - flcf->split_regex = ngx_regex_compile(&value[1], 0, cf->pool, &err); - - if (flcf->split_regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = value[1]; + rc.pool = cf->pool; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + if (ngx_regex_compile(&rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); return NGX_CONF_ERROR; } - n = ngx_regex_capture_count(flcf->split_regex); - - if (n < 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - ngx_regex_capture_count_n " failed for " - "pattern \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } - - if (n != 2) { + if (rc.captures != 2) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "pattern \"%V\" must have 2 captures", &value[1]); return NGX_CONF_ERROR; } + flcf->split_regex = rc.regex; + return NGX_CONF_OK; #else 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 @@ -106,6 +106,7 @@ ngx_http_flv_handler(ngx_http_request_t ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; 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 @@ -589,7 +589,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n ngx_array_t *a; ngx_http_geo_range_t *range; - for (n = start; n <= end; n += 0x10000) { + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { h = n >> 16; diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -30,6 +30,9 @@ static ngx_int_t ngx_http_geoip_country_ ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_geoip_city_float_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r); static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf); static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); @@ -93,23 +96,32 @@ ngx_module_t ngx_http_geoip_module = { static ngx_http_variable_t ngx_http_geoip_vars[] = { - { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable, + { ngx_string("geoip_country_code"), NULL, + ngx_http_geoip_country_variable, (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 }, - { ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable, + { ngx_string("geoip_country_code3"), NULL, + ngx_http_geoip_country_variable, (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 }, - { ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable, + { ngx_string("geoip_country_name"), NULL, + ngx_http_geoip_country_variable, (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 }, - { ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable, + { ngx_string("geoip_city_continent_code"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, continent_code), 0, 0 }, + + { ngx_string("geoip_city_country_code"), NULL, + ngx_http_geoip_city_variable, offsetof(GeoIPRecord, country_code), 0, 0 }, { ngx_string("geoip_city_country_code3"), NULL, ngx_http_geoip_city_variable, offsetof(GeoIPRecord, country_code3), 0, 0 }, - { ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable, + { ngx_string("geoip_city_country_name"), NULL, + ngx_http_geoip_city_variable, offsetof(GeoIPRecord, country_name), 0, 0 }, { ngx_string("geoip_region"), NULL, @@ -124,6 +136,14 @@ static ngx_http_variable_t ngx_http_geo ngx_http_geoip_city_variable, offsetof(GeoIPRecord, postal_code), 0, 0 }, + { ngx_string("geoip_latitude"), NULL, + ngx_http_geoip_city_float_variable, + offsetof(GeoIPRecord, latitude), 0, 0 }, + + { ngx_string("geoip_longitude"), NULL, + ngx_http_geoip_city_float_variable, + offsetof(GeoIPRecord, longitude), 0, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -179,34 +199,16 @@ static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - u_long addr; - char *val; - size_t len; - GeoIPRecord *gr; - struct sockaddr_in *sin; - ngx_http_geoip_conf_t *gcf; - - gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + char *val; + size_t len; + GeoIPRecord *gr; - if (gcf->city == NULL) { - goto not_found; - } - - if (r->connection->sockaddr->sa_family != AF_INET) { - goto not_found; - } - - sin = (struct sockaddr_in *) r->connection->sockaddr; - addr = ntohl(sin->sin_addr.s_addr); - - gr = GeoIP_record_by_ipnum(gcf->city, addr); - + gr = ngx_http_geoip_get_city_record(r); if (gr == NULL) { goto not_found; } val = *(char **) ((char *) gr + data); - if (val == NULL) { goto no_value; } @@ -243,6 +245,56 @@ not_found: static ngx_int_t +ngx_http_geoip_city_float_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + float val; + GeoIPRecord *gr; + + gr = ngx_http_geoip_get_city_record(r); + if (gr == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN + 5); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + val = *(float *) ((char *) gr + data); + + v->len = ngx_sprintf(v->data, "%.4f", val) - v->data; + + GeoIPRecord_delete(gr); + + return NGX_OK; +} + + +static GeoIPRecord * +ngx_http_geoip_get_city_record(ngx_http_request_t *r) +{ + u_long addr; + struct sockaddr_in *sin; + ngx_http_geoip_conf_t *gcf; + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + + if (gcf->city && r->connection->sockaddr->sa_family == AF_INET) { + + sin = (struct sockaddr_in *) r->connection->sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + return GeoIP_record_by_ipnum(gcf->city, addr); + } + + return NULL; +} + + +static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf) { ngx_http_variable_t *var, *v; 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 @@ -246,17 +246,27 @@ ngx_http_gzip_header_filter(ngx_http_req || (r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_FORBIDDEN && r->headers_out.status != NGX_HTTP_NOT_FOUND) - || r->header_only || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) || (r->headers_out.content_length_n != -1 && r->headers_out.content_length_n < conf->min_length) || ngx_http_test_content_type(r, &conf->types) == NULL - || ngx_http_gzip_ok(r) != NGX_OK) + || r->header_only) { return ngx_http_next_header_filter(r); } + r->gzip_vary = 1; + + if (!r->gzip_tested) { + if (ngx_http_gzip_ok(r) != NGX_OK) { + return ngx_http_next_header_filter(r); + } + + } else if (!r->gzip_ok) { + return ngx_http_next_header_filter(r); + } + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -1113,8 +1123,8 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, MAX_MEM_LEVEL - 1); ngx_conf_merge_value(conf->min_length, prev->min_length, 20); - if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, - prev->types_keys, &prev->types, + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, ngx_http_html_default_types) != NGX_OK) { 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 @@ -95,7 +95,15 @@ ngx_http_gzip_static_handler(ngx_http_re 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; + } + + rc = ngx_http_gzip_ok(r); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (!clcf->gzip_vary && rc != NGX_OK) { return NGX_DECLINED; } @@ -116,10 +124,9 @@ 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.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; @@ -157,6 +164,12 @@ ngx_http_gzip_static_handler(ngx_http_re return NGX_DECLINED; } + r->gzip_vary = 1; + + if (rc != NGX_OK) { + return NGX_DECLINED; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { 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 @@ -291,7 +291,7 @@ ngx_http_set_expires(ngx_http_request_t ngx_http_time(expires->value.data, expires_time); - if (conf->expires_time < 0) { + if (conf->expires_time < 0 || max_age < 0) { cc->value.len = sizeof("no-cache") - 1; cc->value.data = (u_char *) "no-cache"; diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -40,6 +40,8 @@ typedef struct { 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; @@ -61,6 +63,7 @@ typedef struct { ngx_uint_t phase; ngx_uint_t type; + ngx_uint_t force; } ngx_http_image_filter_ctx_t; @@ -115,6 +118,13 @@ static ngx_command_t ngx_http_image_fil 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, @@ -492,7 +502,8 @@ ngx_http_image_process(ngx_http_request_ if (rc == NGX_OK && ctx->width <= ctx->max_width - && ctx->height <= ctx->max_height) + && ctx->height <= ctx->max_height + && !ctx->force) { return ngx_http_image_asis(r, ctx); } @@ -592,6 +603,7 @@ static ngx_int_t ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) { u_char *p, *last; + size_t len, app; ngx_uint_t width, height; p = ctx->image; @@ -602,26 +614,38 @@ ngx_http_image_size(ngx_http_request_t * p += 2; last = ctx->image + ctx->length - 10; + width = 0; + height = 0; + app = 0; while (p < last) { if (p[0] == 0xff && p[1] != 0xff) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "JPEG: %02xd %02xd", *p, *(p + 1)); + "JPEG: %02xd %02xd", p[0], p[1]); p++; - if (*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3 - || *p == 0xc9 || *p == 0xca || *p == 0xcb) + if ((*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3 + || *p == 0xc9 || *p == 0xca || *p == 0xcb) + && (width == 0 || height == 0)) { - goto found; + width = p[6] * 256 + p[7]; + height = p[4] * 256 + p[5]; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "JPEG: %02xd %02xd", p[1], p[2]); - p += p[1] * 256 + p[2]; + len = p[1] * 256 + p[2]; + + if (*p >= 0xe1 && *p <= 0xef) { + /* application data, e.g., EXIF, Adobe XMP, etc. */ + app += len; + } + + p += len; continue; } @@ -629,12 +653,16 @@ ngx_http_image_size(ngx_http_request_t * p++; } - return NGX_DECLINED; + if (width == 0 || height == 0) { + return NGX_DECLINED; + } - found: - - width = p[6] * 256 + p[7]; - height = p[4] * 256 + p[5]; + if (ctx->length / 20 < app) { + /* force conversion if application data consume more than 5% */ + ctx->force = 1; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "app data size: %uz", app); + } break; @@ -678,8 +706,9 @@ ngx_http_image_size(ngx_http_request_t * 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, - colors, transparent, red, green, blue, size; + 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; @@ -698,7 +727,8 @@ ngx_http_image_resize(ngx_http_request_t conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); - if ((ngx_uint_t) sx <= ctx->max_width + if (!ctx->force + && (ngx_uint_t) sx <= ctx->max_width && (ngx_uint_t) sy <= ctx->max_height) { gdImageDestroy(src); @@ -706,17 +736,29 @@ ngx_http_image_resize(ngx_http_request_t } colors = gdImageColorsTotal(src); - transparent = gdImageGetTransparent(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); - if (transparent != -1 && colors) { - red = gdImageRed(src, transparent); - green = gdImageGreen(src, transparent); - blue = gdImageBlue(src, transparent); - gdImageColorTransparent(src, -1); + goto transparent; + } + } - } else { - red = 0; green = 0; blue = 0; - } + palette = 0; + transparent = -1; + red = 0; + green = 0; + blue = 0; + +transparent: + + gdImageColorTransparent(src, -1); dx = sx; dy = sy; @@ -762,14 +804,23 @@ ngx_http_image_resize(ngx_http_request_t } if (resize) { - dst = ngx_http_image_new(r, dx, dy, colors); + 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 { @@ -810,8 +861,17 @@ ngx_http_image_resize(ngx_http_request_t "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); } } @@ -1021,6 +1081,7 @@ ngx_http_image_filter_create_conf(ngx_co 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; @@ -1050,6 +1111,8 @@ ngx_http_image_filter_merge_conf(ngx_con /* 75 is libjpeg default quality */ ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75); + ngx_conf_merge_value(conf->transparency, prev->transparency, 1); + ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 1 * 1024 * 1024); 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 @@ -205,6 +205,7 @@ ngx_http_index_handler(ngx_http_request_ ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; @@ -222,7 +223,10 @@ ngx_http_index_handler(ngx_http_request_ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) { + if (of.err == NGX_ENOTDIR + || of.err == NGX_ENAMETOOLONG + || of.err == NGX_EACCES) + { return ngx_http_index_error(r, clcf, path.data, of.err); } 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 @@ -42,7 +42,10 @@ typedef struct { ngx_shm_zone_t *shm_zone; /* integer value, 1 corresponds to 0.001 r/s */ ngx_uint_t burst; - ngx_uint_t nodelay;/* unsigned nodelay:1 */ + ngx_uint_t limit_log_level; + ngx_uint_t delay_log_level; + + ngx_uint_t nodelay; /* unsigned nodelay:1 */ } ngx_http_limit_req_conf_t; @@ -62,6 +65,15 @@ static char *ngx_http_limit_req(ngx_conf static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); +static ngx_conf_enum_t ngx_http_limit_req_log_levels[] = { + { ngx_string("info"), NGX_LOG_INFO }, + { ngx_string("notice"), NGX_LOG_NOTICE }, + { ngx_string("warn"), NGX_LOG_WARN }, + { ngx_string("error"), NGX_LOG_ERR }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_limit_req_commands[] = { { ngx_string("limit_req_zone"), @@ -78,6 +90,13 @@ static ngx_command_t ngx_http_limit_req 0, NULL }, + { ngx_string("limit_req_log_level"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_limit_req_conf_t, limit_log_level), + &ngx_http_limit_req_log_levels }, + ngx_null_command }; @@ -186,7 +205,7 @@ ngx_http_limit_req_handler(ngx_http_requ if (rc == NGX_BUSY) { ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, excess: %ui.%03ui by zone \"%V\"", excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); @@ -200,7 +219,7 @@ ngx_http_limit_req_handler(ngx_http_requ return NGX_DECLINED; } - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, "delaying request, excess: %ui.%03ui, by zone \"%V\"", excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); @@ -383,15 +402,16 @@ ngx_http_limit_req_lookup(ngx_http_limit excess = 0; } + if ((ngx_uint_t) excess > lrcf->burst) { + *lrp = lr; + return NGX_BUSY; + } + lr->excess = excess; lr->last = now; *lrp = lr; - if ((ngx_uint_t) excess > lrcf->burst) { - return NGX_BUSY; - } - if (excess) { return NGX_AGAIN; } @@ -548,6 +568,8 @@ ngx_http_limit_req_create_conf(ngx_conf_ * conf->nodelay = 0; */ + conf->limit_log_level = NGX_CONF_UNSET_UINT; + return conf; } @@ -562,6 +584,12 @@ ngx_http_limit_req_merge_conf(ngx_conf_t *conf = *prev; } + ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, + NGX_LOG_ERR); + + conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ? + NGX_LOG_INFO : conf->limit_log_level + 1; + return NGX_CONF_OK; } 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 @@ -33,6 +33,7 @@ typedef struct { typedef struct { ngx_shm_zone_t *shm_zone; ngx_uint_t conn; + ngx_uint_t log_level; } ngx_http_limit_zone_conf_t; @@ -48,6 +49,15 @@ static char *ngx_http_limit_conn(ngx_con static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf); +static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { + { ngx_string("info"), NGX_LOG_INFO }, + { ngx_string("notice"), NGX_LOG_NOTICE }, + { ngx_string("warn"), NGX_LOG_WARN }, + { ngx_string("error"), NGX_LOG_ERR }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_limit_zone_commands[] = { { ngx_string("limit_zone"), @@ -64,6 +74,13 @@ static ngx_command_t ngx_http_limit_zon 0, NULL }, + { ngx_string("limit_conn_log_level"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_limit_zone_conf_t, log_level), + &ngx_http_limit_conn_log_levels }, + ngx_null_command }; @@ -189,7 +206,7 @@ ngx_http_limit_zone_handler(ngx_http_req ngx_shmtx_unlock(&shpool->mutex); - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(lzcf->log_level, r->connection->log, 0, "limiting connections by zone \"%V\"", &lzcf->shm_zone->shm.name); @@ -391,6 +408,8 @@ ngx_http_limit_zone_create_conf(ngx_conf * conf->conn = 0; */ + conf->log_level = NGX_CONF_UNSET_UINT; + return conf; } @@ -405,6 +424,8 @@ ngx_http_limit_zone_merge_conf(ngx_conf_ *conf = *prev; } + ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); + return NGX_CONF_OK; } 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 @@ -542,8 +542,25 @@ ngx_http_log_request_time(ngx_http_reque static u_char * ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) { - return ngx_sprintf(buf, "%ui", - r->err_status ? r->err_status : r->headers_out.status); + ngx_uint_t status; + + if (r->err_status) { + status = r->err_status; + + } else if (r->headers_out.status) { + status = r->headers_out.status; + + } else if (r->http_version == NGX_HTTP_VERSION_9) { + *buf++ = '0'; + *buf++ = '0'; + *buf++ = '9'; + return buf; + + } else { + status = 0; + } + + return ngx_sprintf(buf, "%ui", status); } @@ -650,7 +667,7 @@ ngx_http_log_variable(ngx_http_request_t static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size) { - ngx_uint_t i, n; + ngx_uint_t n; static u_char hex[] = "0123456789ABCDEF"; static uint32_t escape[] = { @@ -678,17 +695,18 @@ ngx_http_log_escape(u_char *dst, u_char n = 0; - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { n++; } src++; + size--; } return (uintptr_t) n; } - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { *dst++ = '\\'; *dst++ = 'x'; @@ -699,6 +717,7 @@ ngx_http_log_escape(u_char *dst, u_char } else { *dst++ = *src++; } + size--; } return (uintptr_t) dst; 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 @@ -63,6 +63,13 @@ static ngx_command_t ngx_http_memcached 0, NULL }, + { ngx_string("memcached_bind"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_bind_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.local), + NULL }, + { ngx_string("memcached_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, 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 @@ -88,6 +88,11 @@ ngx_http_not_modified_header_filter(ngx_ ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); + if (r->headers_out.content_encoding) { + r->headers_out.content_encoding->hash = 0; + r->headers_out.content_encoding = NULL; + } + return ngx_http_next_header_filter(r); } 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 @@ -229,6 +229,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort), NULL }, + { ngx_string("proxy_bind"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_bind_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.local), + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -530,7 +537,7 @@ static ngx_keyval_t ngx_http_proxy_cach { ngx_string("Expect"), ngx_string("") }, { ngx_string("If-Modified-Since"), ngx_string("") }, { ngx_string("If-Unmodified-Since"), ngx_string("") }, - { ngx_string("If-Match-None"), ngx_string("") }, + { ngx_string("If-None-Match"), ngx_string("") }, { ngx_string("If-Match"), ngx_string("") }, { ngx_string("Range"), ngx_string("") }, { ngx_string("If-Range"), ngx_string("") }, @@ -717,17 +724,22 @@ ngx_http_proxy_eval(ngx_http_request_t * return NGX_ERROR; } - if (url.uri.len && url.uri.data[0] == '?') { - p = ngx_pnalloc(r->pool, url.uri.len + 1); - if (p == NULL) { - return NGX_ERROR; + if (url.uri.len) { + if (url.uri.data[0] == '?') { + p = ngx_pnalloc(r->pool, url.uri.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + *p++ = '/'; + ngx_memcpy(p, url.uri.data, url.uri.len); + + url.uri.len++; + url.uri.data = p - 1; } - *p++ = '/'; - ngx_memcpy(p, url.uri.data, url.uri.len); - - url.uri.len++; - url.uri.data = p - 1; + } else { + url.uri = r->unparsed_uri; } ctx->vars.key_start = u->schema; @@ -1218,7 +1230,6 @@ ngx_http_proxy_process_status_line(ngx_h if (r->cache) { r->http_version = NGX_HTTP_VERSION_9; - u->headers_in.status_n = NGX_HTTP_OK; return NGX_OK; } @@ -1234,7 +1245,6 @@ ngx_http_proxy_process_status_line(ngx_h #endif r->http_version = NGX_HTTP_VERSION_9; - u->headers_in.status_n = NGX_HTTP_OK; u->state->status = NGX_HTTP_OK; return NGX_OK; 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 @@ -175,7 +175,7 @@ ngx_http_random_index_handler(ngx_http_r len = ngx_de_namelen(&dir); - if (!dir.valid_type) { + if (dir.type == 0 || ngx_de_is_link(&dir)) { /* 1 byte for '/' and 1 byte for terminating '\0' */ 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 @@ -25,17 +25,23 @@ typedef struct { ngx_uint_t type; ngx_uint_t hash; ngx_str_t header; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_uint_t unixsock; /* unsigned unixsock:2; */ +#endif } ngx_http_realip_loc_conf_t; typedef struct { ngx_connection_t *connection; - in_addr_t addr; + struct sockaddr *sockaddr; + socklen_t socklen; ngx_str_t addr_text; } ngx_http_realip_ctx_t; static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip, + size_t len); static void ngx_http_realip_cleanup(void *data); static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -103,13 +109,11 @@ ngx_http_realip_handler(ngx_http_request { u_char *ip, *p; size_t len; - in_addr_t addr; ngx_uint_t i, hash; ngx_list_part_t *part; ngx_table_elt_t *header; struct sockaddr_in *sin; ngx_connection_t *c; - ngx_pool_cleanup_t *cln; ngx_http_realip_ctx_t *ctx; ngx_http_realip_from_t *from; ngx_http_realip_loc_conf_t *rlcf; @@ -120,14 +124,14 @@ ngx_http_realip_handler(ngx_http_request return NGX_DECLINED; } - cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t)); - if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module); - if (rlcf->from == NULL) { + if (rlcf->from == NULL +#if (NGX_HAVE_UNIX_DOMAIN) + && !rlcf->unixsock +#endif + ) + { return NGX_DECLINED; } @@ -207,52 +211,83 @@ found: /* AF_INET only */ - if (r->connection->sockaddr->sa_family != AF_INET) { - return NGX_DECLINED; + if (c->sockaddr->sa_family == AF_INET) { + sin = (struct sockaddr_in *) c->sockaddr; + + from = rlcf->from->elts; + for (i = 0; i < rlcf->from->nelts; i++) { + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "realip: %08XD %08XD %08XD", + sin->sin_addr.s_addr, from[i].mask, from[i].addr); + + if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) { + return ngx_http_realip_set_addr(r, ip, len); + } + } + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (c->sockaddr->sa_family == AF_UNIX && rlcf->unixsock) { + return ngx_http_realip_set_addr(r, ip, len); } - sin = (struct sockaddr_in *) c->sockaddr; +#endif - from = rlcf->from->elts; - for (i = 0; i < rlcf->from->nelts; i++) { + return NGX_DECLINED; +} - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "realip: %08XD %08XD %08XD", - sin->sin_addr.s_addr, from[i].mask, from[i].addr); - if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) { - - ctx = cln->data; - - ngx_http_set_ctx(r, ctx, ngx_http_realip_module); +static ngx_int_t +ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip, size_t len) +{ + u_char *p; + ngx_int_t rc; + ngx_addr_t addr; + ngx_connection_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_realip_ctx_t *ctx; - addr = inet_addr((char *) ip); + cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t)); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (addr == INADDR_NONE) { - return NGX_DECLINED; - } + ctx = cln->data; + ngx_http_set_ctx(r, ctx, ngx_http_realip_module); + + c = r->connection; + + rc = ngx_parse_addr(c->pool, &addr, ip, len); - p = ngx_pnalloc(c->pool, len); - if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + switch (rc) { + case NGX_DECLINED: + return NGX_DECLINED; + case NGX_ERROR: + return NGX_HTTP_INTERNAL_SERVER_ERROR; + default: /* NGX_OK */ + break; + } - ngx_memcpy(p, ip, len); - - cln->handler = ngx_http_realip_cleanup; + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - ctx->connection = c; - ctx->addr = sin->sin_addr.s_addr; - ctx->addr_text = c->addr_text; + ngx_memcpy(p, ip, len); - sin->sin_addr.s_addr = addr; + cln->handler = ngx_http_realip_cleanup; - c->addr_text.len = len; - c->addr_text.data = p; + ctx->connection = c; + ctx->sockaddr = c->sockaddr; + ctx->socklen = c->socklen; + ctx->addr_text = c->addr_text; - return NGX_DECLINED; - } - } + c->sockaddr = addr.sockaddr; + c->socklen = addr.socklen; + c->addr_text.len = len; + c->addr_text.data = p; return NGX_DECLINED; } @@ -263,14 +298,12 @@ ngx_http_realip_cleanup(void *data) { ngx_http_realip_ctx_t *ctx = data; - ngx_connection_t *c; - struct sockaddr_in *sin; + ngx_connection_t *c; c = ctx->connection; - sin = (struct sockaddr_in *) c->sockaddr; - sin->sin_addr.s_addr = ctx->addr; - + c->sockaddr = ctx->sockaddr; + c->socklen = ctx->socklen; c->addr_text = ctx->addr_text; } @@ -285,6 +318,17 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx ngx_cidr_t cidr; ngx_http_realip_from_t *from; + value = cf->args->elts; + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ngx_strcmp(value[1].data, "unix:") == 0) { + rlcf->unixsock = 1; + return NGX_CONF_OK; + } + +#endif + if (rlcf->from == NULL) { rlcf->from = ngx_array_create(cf->pool, 2, sizeof(ngx_http_realip_from_t)); @@ -298,8 +342,6 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - value = cf->args->elts; - rc = ngx_ptocidr(&value[1], &cidr); if (rc == NGX_ERROR) { @@ -310,7 +352,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx if (cidr.family != AF_INET) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"realip_from\" supports IPv4 only"); + "\"set_real_ip_from\" supports IPv4 only"); return NGX_CONF_ERROR; } @@ -372,6 +414,9 @@ ngx_http_realip_create_loc_conf(ngx_conf */ conf->type = NGX_CONF_UNSET_UINT; +#if (NGX_HAVE_UNIX_DOMAIN) + conf->unixsock = 2; +#endif return conf; } @@ -387,6 +432,12 @@ ngx_http_realip_merge_loc_conf(ngx_conf_ conf->from = prev->from; } +#if (NGX_HAVE_UNIX_DOMAIN) + if (conf->unixsock == 2) { + conf->unixsock = (prev->unixsock == 2) ? 0 : prev->unixsock; + } +#endif + ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP); if (conf->header.len == 0) { 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 @@ -124,18 +124,27 @@ ngx_http_referer_variable(ngx_http_reque len = r->headers_in.referer->value.len; ref = r->headers_in.referer->value.data; - if (len < sizeof("http://i.ru") - 1 - || (ngx_strncasecmp(ref, (u_char *) "http://", 7) != 0)) - { - if (rlcf->blocked_referer) { - goto valid; + if (len >= sizeof("http://i.ru") - 1) { + last = ref + len; + + if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) { + ref += 7; + goto valid_scheme; + + } else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) { + ref += 8; + goto valid_scheme; } - - goto invalid; } - last = ref + len; - ref += 7; + if (rlcf->blocked_referer) { + goto valid; + } + + goto invalid; + +valid_scheme: + i = 0; key = 0; @@ -412,7 +421,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, if (sn[n].regex) { if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name, - sn[n].regex) + sn[n].regex->regex) != NGX_OK) { return NGX_CONF_ERROR; @@ -502,9 +511,9 @@ ngx_http_add_regex_referer(ngx_conf_t *c ngx_str_t *name, ngx_regex_t *regex) { #if (NGX_PCRE) - ngx_str_t err; - ngx_regex_elt_t *re; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_regex_elt_t *re; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; if (name->len == 1) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name); @@ -530,19 +539,23 @@ ngx_http_add_regex_referer(ngx_conf_t *c return NGX_CONF_OK; } - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; - name->len--; name->data++; - re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); - if (re->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + rc.pattern = *name; + rc.pool = cf->pool; + rc.options = NGX_REGEX_CASELESS; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + if (ngx_regex_compile(&rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); return NGX_CONF_ERROR; } + re->regex = rc.regex; re->name = name->data; return NGX_CONF_OK; 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 @@ -294,9 +294,9 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com { ngx_http_rewrite_loc_conf_t *lcf = conf; - ngx_str_t *value, err; - ngx_int_t n; + ngx_str_t *value; ngx_uint_t last; + ngx_regex_compile_t rc; ngx_http_script_code_pt *code; ngx_http_script_compile_t sc; ngx_http_script_regex_code_t *regex; @@ -313,15 +313,16 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com value = cf->args->elts; - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = value[1]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; /* TODO: NGX_REGEX_CASELESS */ - regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err); - + regex->regex = ngx_http_regex_compile(cf, &rc); if (regex->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_CONF_ERROR; } @@ -394,7 +395,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com regex = sc.main; - regex->ncaptures = sc.ncaptures; regex->size = sc.size; regex->args = sc.args; @@ -402,31 +402,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com regex->lengths = NULL; } - n = ngx_regex_capture_count(regex->regex); - - if (n < 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - ngx_regex_capture_count_n " failed for " - "pattern \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } - - if (regex->ncaptures > (ngx_uint_t) n) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "pattern \"%V\" has less captures " - "than referrenced in substitution \"%V\"", - &value[1], &value[2]); - return NGX_CONF_ERROR; - } - - if (regex->ncaptures < (ngx_uint_t) n) { - regex->ncaptures = (ngx_uint_t) n; - } - - if (regex->ncaptures) { - regex->ncaptures = (regex->ncaptures + 1) * 3; - } - regex_end = ngx_http_script_add_code(lcf->codes, sizeof(ngx_http_script_regex_end_code_t), ®ex); @@ -446,7 +421,7 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com return NGX_CONF_ERROR; } - *code = (uintptr_t) NULL; + *code = NULL; } regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts @@ -624,8 +599,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t { u_char *p; size_t len; - ngx_str_t *value, err; - ngx_uint_t cur, last, n; + ngx_str_t *value; + ngx_uint_t cur, last; + ngx_regex_compile_t rc; ngx_http_script_code_pt *code; ngx_http_script_file_code_t *fop; ngx_http_script_regex_code_t *regex; @@ -733,15 +709,15 @@ ngx_http_rewrite_if_condition(ngx_conf_t ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t)); - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); - regex->regex = ngx_regex_compile(&value[last], - (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0, - cf->pool, &err); + rc.pattern = value[last]; + rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + regex->regex = ngx_http_regex_compile(cf, &rc); if (regex->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_CONF_ERROR; } @@ -753,12 +729,6 @@ ngx_http_rewrite_if_condition(ngx_conf_t } regex->name = value[last]; - n = ngx_regex_capture_count(regex->regex); - - if (n) { - regex->ncaptures = (n + 1) * 3; - } - return NGX_CONF_OK; } 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 @@ -1908,7 +1908,7 @@ ngx_http_ssi_include(ngx_http_request_t args.len = 0; args.data = NULL; - flags = 0; + flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { return NGX_HTTP_SSI_ERROR; @@ -2061,9 +2061,9 @@ ngx_http_ssi_stub_output(ngx_http_reques out = data; if (!r->header_sent) { - if (ngx_http_set_content_type(r) != NGX_OK) { - return NGX_ERROR; - } + r->headers_out.content_type_len = + r->parent->headers_out.content_type_len; + r->headers_out.content_type = r->parent->headers_out.content_type; if (ngx_http_send_header(r) == NGX_ERROR) { return NGX_ERROR; @@ -2450,27 +2450,28 @@ ngx_http_ssi_if(ngx_http_request_t *r, n } else { #if (NGX_PCRE) - ngx_str_t err; - ngx_regex_t *regex; - u_char errstr[NGX_MAX_CONF_ERRSTR]; - - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; + ngx_regex_compile_t rgc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; right.data[right.len] = '\0'; - regex = ngx_regex_compile(&right, 0, r->pool, &err); - - if (regex == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", err.data); + ngx_memzero(&rgc, sizeof(ngx_regex_compile_t)); + + rgc.pattern = right; + rgc.pool = r->pool; + rgc.err.len = NGX_MAX_CONF_ERRSTR; + rgc.err.data = errstr; + + if (ngx_regex_compile(&rgc) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err); return NGX_HTTP_SSI_ERROR; } - rc = ngx_regex_exec(regex, &left, NULL, 0); - - if (rc != NGX_REGEX_NO_MATCHED && rc < 0) { + rc = ngx_regex_exec(rgc.regex, &left, NULL, 0); + + if (rc < NGX_REGEX_NO_MATCHED) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", + ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", rc, &left, &right); return NGX_HTTP_SSI_ERROR; } @@ -2614,8 +2615,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx return NGX_ERROR; } - v->len = ngx_sprintf(v->data, "%T", tp->sec + (gmt ? 0 : tp->gmtoff)) - - v->data; + v->len = ngx_sprintf(v->data, "%T", tp->sec) - v->data; return NGX_OK; } @@ -2772,8 +2772,8 @@ ngx_http_ssi_merge_loc_conf(ngx_conf_t * ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024); ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256); - if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, - prev->types_keys, &prev->types, + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, ngx_http_html_default_types) != NGX_OK) { diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -13,7 +13,7 @@ typedef ngx_int_t (*ngx_ssl_variable_han ngx_pool_t *pool, ngx_str_t *s); -#define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" +#define NGX_DEFAULT_CIPHERS "HIGH:!ADH:!MD5" static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, @@ -184,6 +184,9 @@ static ngx_http_variable_t ngx_http_ssl { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable, (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -344,8 +347,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET - |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); + (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); @@ -406,9 +408,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 built with SNI support, however, now it is linked " + "dynamically to an OpenSSL library which has no tlsext support, " + "therefore SNI is not available"); } #endif 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 @@ -91,6 +91,7 @@ ngx_http_static_handler(ngx_http_request ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; 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 @@ -671,8 +671,8 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, conf->value = prev->value; } - if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, - prev->types_keys, &prev->types, + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, ngx_http_html_default_types) != NGX_OK) { 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 @@ -1230,8 +1230,8 @@ ngx_http_xslt_filter_merge_conf(ngx_conf conf->sheets = prev->sheets; } - if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, - prev->types_keys, &prev->types, + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, ngx_http_xslt_default_types) != NGX_OK) { 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.8.15'; +our $VERSION = '0.8.34'; 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 @@ -648,6 +648,7 @@ sendfile(r, filename, offset = -1, bytes ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; @@ -901,9 +902,6 @@ variable(r, name, value = NULL) XSRETURN_UNDEF; } - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "variable \"%V\" not found", &var); - XSRETURN_UNDEF; } @@ -946,6 +944,7 @@ sleep(r, sleep, next) ngx_add_timer(r->connection->write, sleep); r->write_event_handler = ngx_http_perl_sleep_handler; + r->main->count++; void 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 @@ -13,8 +13,8 @@ typedef struct { PerlInterpreter *perl; HV *nginx; - ngx_str_t modules; - ngx_array_t requires; + ngx_array_t *modules; + ngx_array_t *requires; } ngx_http_perl_main_conf_t; @@ -30,12 +30,6 @@ typedef struct { } ngx_http_perl_variable_t; -typedef struct { - SV *sv; - PerlInterpreter *perl; -} ngx_http_perl_cleanup_t; - - #if (NGX_HTTP_SSI) static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params); @@ -57,8 +51,6 @@ static char *ngx_http_perl_init_main_con static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -74,16 +66,16 @@ static ngx_command_t ngx_http_perl_comm { ngx_string("perl_modules"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_HTTP_MAIN_CONF_OFFSET, offsetof(ngx_http_perl_main_conf_t, modules), NULL }, { ngx_string("perl_require"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_http_perl_require, + ngx_conf_set_str_array_slot, NGX_HTTP_MAIN_CONF_OFFSET, - 0, + offsetof(ngx_http_perl_main_conf_t, requires), NULL }, { ngx_string("perl"), @@ -154,12 +146,13 @@ static ngx_http_ssi_command_t ngx_http_ #endif -static ngx_str_t ngx_null_name = ngx_null_string; - -static HV *nginx_stash; +static ngx_str_t ngx_null_name = ngx_null_string; +static HV *nginx_stash; #if (NGX_HAVE_PERL_MULTIPLICITY) -static ngx_uint_t ngx_perl_term; +static ngx_uint_t ngx_perl_term; +#else +static PerlInterpreter *perl; #endif @@ -463,27 +456,42 @@ ngx_http_perl_ssi(ngx_http_request_t *r, static char * ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { + ngx_str_t *m; + ngx_uint_t i; #if (NGX_HAVE_PERL_MULTIPLICITY) - ngx_pool_cleanup_t *cln; + ngx_pool_cleanup_t *cln; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } -#else - static PerlInterpreter *perl; #endif #ifdef NGX_PERL_MODULES - if (pmcf->modules.data == NULL) { - pmcf->modules.data = NGX_PERL_MODULES; + if (pmcf->modules == NGX_CONF_UNSET_PTR) { + + pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); + if (pmcf->modules == NULL) { + return NGX_CONF_ERROR; + } + + m = ngx_array_push(pmcf->modules); + if (m == NULL) { + return NGX_CONF_ERROR; + } + + m->len = sizeof(NGX_PERL_MODULES) - 1; + m->data = NGX_PERL_MODULES; } #endif - if (pmcf->modules.data) { - if (ngx_conf_full_name(cf->cycle, &pmcf->modules, 0) != NGX_OK) { - return NGX_CONF_ERROR; + if (pmcf->modules != NGX_CONF_UNSET_PTR) { + m = pmcf->modules->elts; + for (i = 0; i < pmcf->modules->nelts; i++) { + if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } } } @@ -495,7 +503,7 @@ ngx_http_perl_init_interpreter(ngx_conf_ return NGX_CONF_ERROR; } - if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) + if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) { return NGX_CONF_ERROR; @@ -543,7 +551,9 @@ ngx_http_perl_create_interpreter(ngx_con int n; STRLEN len; SV *sv; - char *ver, *embedding[6]; + char *ver, **embedding; + ngx_str_t *m; + ngx_uint_t i; PerlInterpreter *perl; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter"); @@ -569,15 +579,21 @@ ngx_http_perl_create_interpreter(ngx_con PL_exit_flags |= PERL_EXIT_DESTRUCT_END; #endif + n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0; + + embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *)); + if (embedding == NULL) { + goto fail; + } + embedding[0] = ""; - if (pmcf->modules.data) { - embedding[1] = "-I"; - embedding[2] = (char *) pmcf->modules.data; - n = 3; - - } else { - n = 1; + if (n++) { + m = pmcf->modules->elts; + for (i = 0; i < pmcf->modules->nelts; i++) { + embedding[2 * i + 1] = "-I"; + embedding[2 * i + 2] = (char *) m[i].data; + } } embedding[n++] = "-Mnginx"; @@ -601,7 +617,7 @@ ngx_http_perl_create_interpreter(ngx_con goto fail; } - if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) { + if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) { goto fail; } @@ -622,26 +638,28 @@ fail: static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log) { - char **script; + u_char *err; STRLEN len; - ngx_str_t err; + ngx_str_t *script; ngx_uint_t i; + if (requires == NGX_CONF_UNSET_PTR) { + return NGX_OK; + } + script = requires->elts; for (i = 0; i < requires->nelts; i++) { - require_pv(script[i]); + require_pv((char *) script[i].data); if (SvTRUE(ERRSV)) { - err.data = (u_char *) SvPV(ERRSV, len); - for (len--; err.data[len] == LF || err.data[len] == CR; len--) { - /* void */ - } - err.len = len + 1; + err = (u_char *) SvPV(ERRSV, len); + while (--len && (err[len] == CR || err[len] == LF)) { /* void */ } ngx_log_error(NGX_LOG_EMERG, log, 0, - "require_pv(\"%s\") failed: \"%V\"", script[i], &err); + "require_pv(\"%s\") failed: \"%*s\"", + script[i].data, len + 1, err); return NGX_ERROR; } @@ -658,8 +676,8 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt SV *sv; int n, status; char *line; + u_char *err; STRLEN len, n_a; - ngx_str_t err; ngx_uint_t i; ngx_connection_t *c; @@ -720,14 +738,11 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt if (SvTRUE(ERRSV)) { - err.data = (u_char *) SvPV(ERRSV, len); - for (len--; err.data[len] == LF || err.data[len] == CR; len--) { - /* void */ - } - err.len = len + 1; + err = (u_char *) SvPV(ERRSV, len); + while (--len && (err[len] == CR || err[len] == LF)) { /* void */ } ngx_log_error(NGX_LOG_ERR, c->log, 0, - "call_sv(\"%V\") failed: \"%V\"", handler, &err); + "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err); if (rv) { return NGX_ERROR; @@ -761,7 +776,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 */ @@ -783,11 +801,8 @@ ngx_http_perl_create_main_conf(ngx_conf_ return NULL; } - if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *)) - != NGX_OK) - { - return NULL; - } + pmcf->modules = NGX_CONF_UNSET_PTR; + pmcf->requires = NGX_CONF_UNSET_PTR; return pmcf; } @@ -894,28 +909,6 @@ ngx_http_perl_merge_loc_conf(ngx_conf_t static char * -ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_perl_main_conf_t *pmcf = conf; - - u_char **p; - ngx_str_t *value; - - value = cf->args->elts; - - p = ngx_array_push(&pmcf->requires); - - if (p == NULL) { - return NGX_CONF_ERROR; - } - - *p = value[1].data; - - return NGX_CONF_OK; -} - - -static char * ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_perl_loc_conf_t *plcf = conf; @@ -1064,19 +1057,21 @@ ngx_http_perl_exit(ngx_cycle_t *cycle) { #if (NGX_HAVE_PERL_MULTIPLICITY) + /* + * the master exit hook is run before global pool cleanup, + * therefore just set flag here + */ + ngx_perl_term = 1; #else - ngx_http_perl_main_conf_t *pmcf; - pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module); - - if (pmcf && nginx_stash) { + if (nginx_stash) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term"); - (void) perl_destruct(pmcf->perl); + (void) perl_destruct(perl); - perl_free(pmcf->perl); + perl_free(perl); PERL_SYS_TERM(); } 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 @@ -17,18 +17,13 @@ static ngx_int_t ngx_http_init_headers_i static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf); -static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf, - ngx_array_t *servers, ngx_array_t *ports); -static ngx_int_t ngx_http_add_ports(ngx_conf_t *cf, - ngx_http_core_srv_conf_t *cscf, ngx_array_t *ports, - ngx_http_listen_t *listen); static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, - ngx_http_listen_t *listen); + ngx_http_listen_opt_t *lsopt); static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, - ngx_http_listen_t *listen); -static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, + ngx_http_listen_opt_t *lsopt); +static ngx_int_t ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr); static char *ngx_http_merge_locations(ngx_conf_t *cf, @@ -122,7 +117,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma char *rv; ngx_uint_t mi, m, s; ngx_conf_t pcf; - ngx_array_t ports; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; @@ -362,19 +356,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } - /* - * create the lists of ports, addresses and server names - * to find quickly the server core module configuration at run-time - */ - - if (ngx_http_init_server_lists(cf, &cmcf->servers, &ports) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* optimize the lists of ports, addresses and server names */ - if (ngx_http_optimize_servers(cf, cmcf, &ports) != NGX_OK) { + if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) { return NGX_CONF_ERROR; } @@ -1109,72 +1093,55 @@ inclusive: } -static ngx_int_t -ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers, - ngx_array_t *ports) +ngx_int_t +ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_listen_opt_t *lsopt) { - ngx_uint_t s, i; - ngx_http_listen_t *listen; - ngx_http_core_srv_conf_t **cscfp; - - if (ngx_array_init(ports, cf->temp_pool, 2, sizeof(ngx_http_conf_port_t)) - != NGX_OK) - { - return NGX_ERROR; - } + in_port_t p; + ngx_uint_t i; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_http_conf_port_t *port; + ngx_http_core_main_conf_t *cmcf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif - /* "server" directives */ - - cscfp = servers->elts; - for (s = 0; s < servers->nelts; s++) { - - /* "listen" directives */ + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - listen = cscfp[s]->listen.elts; - for (i = 0; i < cscfp[s]->listen.nelts; i++) { - - if (ngx_http_add_ports(cf, cscfp[s], ports, &listen[i]) != NGX_OK) { - return NGX_ERROR; - } + if (cmcf->ports == NULL) { + cmcf->ports = ngx_array_create(cf->temp_pool, 2, + sizeof(ngx_http_conf_port_t)); + if (cmcf->ports == NULL) { + return NGX_ERROR; } } - return NGX_OK; -} - - -static ngx_int_t -ngx_http_add_ports(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, - ngx_array_t *ports, ngx_http_listen_t *listen) -{ - in_port_t p; - ngx_uint_t i; - struct sockaddr *sa; - struct sockaddr_in *sin; - ngx_http_conf_port_t *port; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - - sa = (struct sockaddr *) &listen->sockaddr; + sa = &lsopt->u.sockaddr; switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: - sin6 = (struct sockaddr_in6 *) sa; + sin6 = &lsopt->u.sockaddr_in6; p = sin6->sin6_port; break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + p = 0; + break; +#endif + default: /* AF_INET */ - sin = (struct sockaddr_in *) sa; + sin = &lsopt->u.sockaddr_in; p = sin->sin_port; break; } - port = ports->elts; - for (i = 0; i < ports->nelts; i++) { + port = cmcf->ports->elts; + for (i = 0; i < cmcf->ports->nelts; i++) { if (p != port[i].port || sa->sa_family != port[i].family) { continue; @@ -1182,12 +1149,12 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h /* a port is already in the port list */ - return ngx_http_add_addresses(cf, cscf, &port[i], listen); + return ngx_http_add_addresses(cf, cscf, &port[i], lsopt); } /* add a port to the port list */ - port = ngx_array_push(ports); + port = ngx_array_push(cmcf->ports); if (port == NULL) { return NGX_ERROR; } @@ -1196,26 +1163,29 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h port->port = p; port->addrs.elts = NULL; - return ngx_http_add_address(cf, cscf, port, listen); + return ngx_http_add_address(cf, cscf, port, lsopt); } static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, - ngx_http_conf_port_t *port, ngx_http_listen_t *listen) + ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) { u_char *p; size_t len, off; - ngx_uint_t i; + ngx_uint_t i, default_server; struct sockaddr *sa; ngx_http_conf_addr_t *addr; +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif /* * we can not compare whole sockaddr struct's as kernel * may fill some fields in inherited sockaddr struct's */ - sa = (struct sockaddr *) &listen->sockaddr; + sa = &lsopt->u.sockaddr; switch (sa->sa_family) { @@ -1226,54 +1196,71 @@ ngx_http_add_addresses(ngx_conf_t *cf, n break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + off = offsetof(struct sockaddr_un, sun_path); + len = sizeof(saun->sun_path); + break; +#endif + default: /* AF_INET */ off = offsetof(struct sockaddr_in, sin_addr); len = 4; break; } - p = listen->sockaddr + off; + p = lsopt->u.sockaddr_data + off; addr = port->addrs.elts; for (i = 0; i < port->addrs.nelts; i++) { - if (ngx_memcmp(p, (u_char *) addr[i].sockaddr + off, len) != 0) { + if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) { continue; } /* the address is already in the address list */ - if (ngx_http_add_names(cf, cscf, &addr[i]) != NGX_OK) { + if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) { return NGX_ERROR; } + /* preserve default_server bit during listen options overwriting */ + default_server = addr[i].opt.default_server; + + if (lsopt->set) { + + if (addr[i].opt.set) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "a duplicate listen options for %s", addr[i].opt.addr); + return NGX_ERROR; + } + + addr[i].opt = *lsopt; + } + /* check the duplicate "default" server for this address:port */ - if (listen->conf.default_server) { + if (lsopt->default_server) { - if (addr[i].default_server) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "the duplicate default server in %s:%ui", - listen->file_name, listen->line); - + if (default_server) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "a duplicate default server for %s", addr[i].opt.addr); return NGX_ERROR; } - addr[i].core_srv_conf = cscf; - addr[i].default_server = 1; -#if (NGX_HTTP_SSL) - addr[i].ssl = listen->conf.ssl; -#endif - addr[i].listen_conf = &listen->conf; + default_server = 1; + addr[i].default_server = cscf; } + addr[i].opt.default_server = default_server; + return NGX_OK; } /* add the address to the addresses list that bound to this port */ - return ngx_http_add_address(cf, cscf, port, listen); + return ngx_http_add_address(cf, cscf, port, lsopt); } @@ -1284,7 +1271,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, - ngx_http_conf_port_t *port, ngx_http_listen_t *listen) + ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) { ngx_http_conf_addr_t *addr; @@ -1302,68 +1289,56 @@ ngx_http_add_address(ngx_conf_t *cf, ngx return NGX_ERROR; } - addr->sockaddr = (struct sockaddr *) &listen->sockaddr; - addr->socklen = listen->socklen; + addr->opt = *lsopt; addr->hash.buckets = NULL; addr->hash.size = 0; addr->wc_head = NULL; addr->wc_tail = NULL; - addr->names.elts = NULL; #if (NGX_PCRE) addr->nregex = 0; addr->regex = NULL; #endif - addr->core_srv_conf = cscf; - addr->default_server = listen->conf.default_server; - addr->bind = listen->conf.bind; - addr->wildcard = listen->conf.wildcard; -#if (NGX_HTTP_SSL) - addr->ssl = listen->conf.ssl; -#endif - addr->listen_conf = &listen->conf; + addr->default_server = cscf; + addr->servers.elts = NULL; - return ngx_http_add_names(cf, cscf, addr); + return ngx_http_add_server(cf, cscf, addr); } -/* - * add the server names and the server core module - * configurations to the address:port - */ +/* add the server core module configuration to the address:port */ static ngx_int_t -ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, +ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr) { - ngx_uint_t i; - ngx_http_server_name_t *server_names, *name; + ngx_uint_t i; + ngx_http_core_srv_conf_t **server; - if (addr->names.elts == NULL) { - if (ngx_array_init(&addr->names, cf->temp_pool, 4, - sizeof(ngx_http_server_name_t)) + if (addr->servers.elts == NULL) { + if (ngx_array_init(&addr->servers, cf->temp_pool, 4, + sizeof(ngx_http_core_srv_conf_t *)) != NGX_OK) { return NGX_ERROR; } + + } else { + server = addr->servers.elts; + for (i = 0; i < addr->servers.nelts; i++) { + if (server[i] == cscf) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "a duplicate listen %s", addr->opt.addr); + return NGX_ERROR; + } + } } - server_names = cscf->server_names.elts; - - for (i = 0; i < cscf->server_names.nelts; i++) { - - ngx_strlow(server_names[i].name.data, server_names[i].name.data, - server_names[i].name.len); + server = ngx_array_push(&addr->servers); + if (server == NULL) { + return NGX_ERROR; + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "name: %V", &server_names[i].name); - - name = ngx_array_push(&addr->names); - if (name == NULL) { - return NGX_ERROR; - } - - *name = server_names[i]; - } + *server = cscf; return NGX_OK; } @@ -1373,10 +1348,13 @@ static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports) { - ngx_uint_t s, p, a; - ngx_http_conf_port_t *port; - ngx_http_conf_addr_t *addr; - ngx_http_server_name_t *name; + ngx_uint_t p, a; + ngx_http_conf_port_t *port; + ngx_http_conf_addr_t *addr; + + if (ports == NULL) { + return NGX_OK; + } port = ports->elts; for (p = 0; p < ports->nelts; p++) { @@ -1392,23 +1370,15 @@ ngx_http_optimize_servers(ngx_conf_t *cf addr = port[p].addrs.elts; for (a = 0; a < port[p].addrs.nelts; a++) { - name = addr[a].names.elts; - for (s = 0; s < addr[a].names.nelts; s++) { - - if (addr[a].core_srv_conf == name[s].core_srv_conf + if (addr[a].servers.nelts > 1 #if (NGX_PCRE) - && name[s].captures == 0 + || addr[a].default_server->captures #endif - ) - { - continue; - } - + ) + { if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) { return NGX_ERROR; } - - break; } } @@ -1425,13 +1395,14 @@ static ngx_int_t ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr) { - ngx_int_t rc; - ngx_uint_t s; - ngx_hash_init_t hash; - ngx_hash_keys_arrays_t ha; - ngx_http_server_name_t *name; + ngx_int_t rc; + ngx_uint_t n, s; + ngx_hash_init_t hash; + ngx_hash_keys_arrays_t ha; + ngx_http_server_name_t *name; + ngx_http_core_srv_conf_t **cscfp; #if (NGX_PCRE) - ngx_uint_t regex, i; + ngx_uint_t regex, i; regex = 0; #endif @@ -1449,35 +1420,40 @@ ngx_http_server_names(ngx_conf_t *cf, ng goto failed; } - name = addr->names.elts; + cscfp = addr->servers.elts; + + for (s = 0; s < addr->servers.nelts; s++) { - for (s = 0; s < addr->names.nelts; s++) { + name = cscfp[s]->server_names.elts; + + for (n = 0; n < cscfp[s]->server_names.nelts; n++) { #if (NGX_PCRE) - if (name[s].regex) { - regex++; - continue; - } + if (name[n].regex) { + regex++; + continue; + } #endif - rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, - NGX_HASH_WILDCARD_KEY); + rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server, + NGX_HASH_WILDCARD_KEY); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } + if (rc == NGX_ERROR) { + return NGX_ERROR; + } - if (rc == NGX_DECLINED) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "invalid server name or wildcard \"%V\" on %s", - &name[s].name, addr->listen_conf->addr); - return NGX_ERROR; - } + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid server name or wildcard \"%V\" on %s", + &name[n].name, addr->opt.addr); + return NGX_ERROR; + } - if (rc == NGX_BUSY) { + if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "conflicting server name \"%V\" on %s, ignored", - &name[s].name, addr->listen_conf->addr); + "conflicting server name \"%V\" on %s, ignored", + &name[n].name, addr->opt.addr); + } } } @@ -1546,9 +1522,16 @@ ngx_http_server_names(ngx_conf_t *cf, ng return NGX_ERROR; } - for (i = 0, s = 0; s < addr->names.nelts; s++) { - if (name[s].regex) { - addr->regex[i++] = name[s]; + i = 0; + + for (s = 0; s < addr->servers.nelts; s++) { + + name = cscfp[s]->server_names.elts; + + for (n = 0; n < cscfp[s]->server_names.nelts; n++) { + if (name[n].regex) { + addr->regex[i++] = name[n]; + } } } @@ -1572,17 +1555,17 @@ ngx_http_cmp_conf_addrs(const void *one, first = (ngx_http_conf_addr_t *) one; second = (ngx_http_conf_addr_t *) two; - if (first->wildcard) { + if (first->opt.wildcard) { /* a wildcard address must be the last resort, shift it to the end */ return 1; } - if (first->bind && !second->bind) { + if (first->opt.bind && !second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return -1; } - if (!first->bind && second->bind) { + if (!first->opt.bind && second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return 1; } @@ -1623,8 +1606,8 @@ ngx_http_init_listening(ngx_conf_t *cf, * implicit bindings go, and wildcard binding is in the end. */ - if (addr[last - 1].wildcard) { - addr[last - 1].bind = 1; + if (addr[last - 1].opt.wildcard) { + addr[last - 1].opt.bind = 1; bind_wildcard = 1; } else { @@ -1635,7 +1618,7 @@ ngx_http_init_listening(ngx_conf_t *cf, while (i < last) { - if (bind_wildcard && !addr[i].bind) { + if (bind_wildcard && !addr[i].opt.bind) { i++; continue; } @@ -1691,7 +1674,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - ls = ngx_create_listening(cf, addr->sockaddr, addr->socklen); + ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen); if (ls == NULL) { return NULL; } @@ -1700,7 +1683,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n ls->handler = ngx_http_init_connection; - cscf = addr->core_srv_conf; + cscf = addr->default_server; ls->pool_size = cscf->connection_pool_size; ls->post_accept_timeout = cscf->client_header_timeout; @@ -1721,20 +1704,20 @@ ngx_http_add_listening(ngx_conf_t *cf, n } #endif - ls->backlog = addr->listen_conf->backlog; - ls->rcvbuf = addr->listen_conf->rcvbuf; - ls->sndbuf = addr->listen_conf->sndbuf; + ls->backlog = addr->opt.backlog; + ls->rcvbuf = addr->opt.rcvbuf; + ls->sndbuf = addr->opt.sndbuf; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) - ls->accept_filter = addr->listen_conf->accept_filter; + ls->accept_filter = addr->opt.accept_filter; #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - ls->deferred_accept = addr->listen_conf->deferred_accept; + ls->deferred_accept = addr->opt.deferred_accept; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - ls->ipv6only = addr->listen_conf->ipv6only; + ls->ipv6only = addr->opt.ipv6only; #endif return ls; @@ -1760,11 +1743,11 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h for (i = 0; i < hport->naddrs; i++) { - sin = (struct sockaddr_in *) addr[i].sockaddr; + sin = &addr[i].opt.u.sockaddr_in; addrs[i].addr = sin->sin_addr.s_addr; - addrs[i].conf.core_srv_conf = addr[i].core_srv_conf; + addrs[i].conf.default_server = addr[i].default_server; #if (NGX_HTTP_SSL) - addrs[i].conf.ssl = addr[i].ssl; + addrs[i].conf.ssl = addr[i].opt.ssl; #endif if (addr[i].hash.buckets == NULL @@ -1821,11 +1804,11 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_ for (i = 0; i < hport->naddrs; i++) { - sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + sin6 = &addr[i].opt.u.sockaddr_in6; addrs6[i].addr6 = sin6->sin6_addr; - addrs6[i].conf.core_srv_conf = addr[i].core_srv_conf; + addrs6[i].conf.default_server = addr[i].default_server; #if (NGX_HTTP_SSL) - addrs6[i].conf.ssl = addr[i].ssl; + addrs6[i].conf.ssl = addr[i].opt.ssl; #endif if (addr[i].hash.buckets == NULL @@ -1871,6 +1854,10 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_ types = (ngx_array_t **) (p + cmd->offset); + if (*types == (void *) -1) { + return NGX_CONF_OK; + } + default_type = cmd->post; if (*types == NULL) { @@ -1896,6 +1883,11 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_ for (i = 1; i < cf->args->nelts; i++) { + if (value[i].len == 1 && value[i].data[0] == '*') { + *types = (void *) -1; + return NGX_CONF_OK; + } + hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len); value[i].data[value[i].len] = '\0'; @@ -1924,13 +1916,17 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_ char * -ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, ngx_hash_t *types_hash, - ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash, +ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t **keys, ngx_hash_t *types_hash, + ngx_array_t **prev_keys, ngx_hash_t *prev_types_hash, ngx_str_t *default_types) { ngx_hash_init_t hash; - if (keys) { + if (*keys) { + + if (*keys == (void *) -1) { + return NGX_CONF_OK; + } hash.hash = types_hash; hash.key = NULL; @@ -1940,7 +1936,7 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx hash.pool = cf->pool; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, keys->elts, keys->nelts) != NGX_OK) { + if (ngx_hash_init(&hash, (*keys)->elts, (*keys)->nelts) != NGX_OK) { return NGX_CONF_ERROR; } @@ -1949,13 +1945,17 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx if (prev_types_hash->buckets == NULL) { - if (prev_keys == NULL) { + if (*prev_keys == NULL) { - if (ngx_http_set_default_types(cf, &prev_keys, default_types) + if (ngx_http_set_default_types(cf, prev_keys, default_types) != NGX_OK) { return NGX_CONF_ERROR; } + + } else if (*prev_keys == (void *) -1) { + *keys = *prev_keys; + return NGX_CONF_OK; } hash.hash = prev_types_hash; @@ -1966,7 +1966,9 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx hash.pool = cf->pool; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, prev_keys->elts, prev_keys->nelts) != NGX_OK) { + if (ngx_hash_init(&hash, (*prev_keys)->elts, (*prev_keys)->nelts) + != NGX_OK) + { return NGX_CONF_ERROR; } } 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 @@ -57,6 +57,8 @@ struct ngx_http_log_ctx_s { ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, ngx_http_core_loc_conf_t *clcf); +ngx_int_t ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_listen_opt_t *lsopt); void ngx_http_init_connection(ngx_connection_t *c); @@ -92,7 +94,7 @@ void ngx_http_empty_handler(ngx_event_t void ngx_http_request_empty_handler(ngx_http_request_t *r); -#define ngx_http_ephemeral(r) (ngx_http_ephemeral_t *) (&r->uri_start) +#define ngx_http_ephemeral(r) (void *) (&r->uri_start) #define NGX_HTTP_LAST 1 @@ -118,14 +120,15 @@ size_t ngx_http_get_time(char *buf, time ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r); +void ngx_http_discarded_request_body_handler(ngx_http_request_t *r); void ngx_http_block_reading(ngx_http_request_t *r); void ngx_http_test_reading(ngx_http_request_t *r); char *ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, - ngx_hash_t *types_hash, ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash, - ngx_str_t *default_types); +char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t **keys, + ngx_hash_t *types_hash, ngx_array_t **prev_keys, + ngx_hash_t *prev_types_hash, ngx_str_t *default_types); ngx_int_t ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, ngx_str_t *default_type); 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 @@ -118,7 +118,7 @@ ngx_http_copy_filter(ngx_http_request_t ctx->filter_ctx = r; #if (NGX_HAVE_FILE_AIO) - if (clcf->aio) { + if (ngx_file_aio && clcf->aio) { ctx->aio_handler = ngx_http_copy_aio_handler; #if (NGX_HAVE_AIO_SENDFILE) c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE); 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 @@ -408,6 +408,13 @@ static ngx_command_t ngx_http_core_comm #endif + { ngx_string("read_ahead"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, read_ahead), + NULL }, + { ngx_string("directio"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_core_directio, @@ -776,14 +783,24 @@ ngx_http_handler(ngx_http_request_t *r) break; } - if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) { - - /* - * MSIE may wait for some time if an response for - * a POST request was sent over a keepalive connection - */ - - r->keepalive = 0; + if (r->keepalive) { + + if (r->headers_in.msie6) { + if (r->method == NGX_HTTP_POST) { + /* + * MSIE may wait for some time if an response for + * a POST request was sent over a keepalive connection + */ + r->keepalive = 0; + } + + } else if (r->headers_in.safari) { + /* + * Safari may send a POST request to a closed keepalive + * connection and stalls for some time + */ + r->keepalive = 0; + } } if (r->headers_in.content_length_n > 0) { @@ -805,7 +822,11 @@ ngx_http_handler(ngx_http_request_t *r) } r->valid_location = 1; - r->gzip = 0; +#if (NGX_HTTP_GZIP) + r->gzip_tested = 0; + r->gzip_ok = 0; + r->gzip_vary = 0; +#endif r->write_event_handler = ngx_http_core_run_phases; ngx_http_core_run_phases(r); @@ -994,7 +1015,6 @@ ngx_http_core_post_rewrite_phase(ngx_htt "rewrite or internal redirection cycle " "while processing \"%V\"", &r->uri); - r->main->count++; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } @@ -1233,7 +1253,10 @@ ngx_http_core_try_files_phase(ngx_http_r if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { - if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) { + if (of.err != NGX_ENOENT + && of.err != NGX_ENOTDIR + && of.err != NGX_ENAMETOOLONG) + { ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); } @@ -1407,7 +1430,7 @@ ngx_http_core_find_location(ngx_http_req ngx_int_t rc; ngx_http_core_loc_conf_t *pclcf; #if (NGX_PCRE) - ngx_int_t n, len; + ngx_int_t n; ngx_uint_t noregex; ngx_http_core_loc_conf_t *clcf, **clcfp; @@ -1441,51 +1464,28 @@ ngx_http_core_find_location(ngx_http_req if (noregex == 0 && pclcf->regex_locations) { - len = 0; - for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "test location: ~ \"%V\"", &(*clcfp)->name); - if ((*clcfp)->captures) { - - len = (NGX_HTTP_MAX_CAPTURES + 1) * 3; - - if (r->captures == NULL) { - r->captures = ngx_palloc(r->pool, len * sizeof(int)); - if (r->captures == NULL) { - return NGX_ERROR; - } - } + n = ngx_http_regex_exec(r, (*clcfp)->regex, &r->uri); + + if (n == NGX_OK) { + r->loc_conf = (*clcfp)->loc_conf; + + /* look up nested locations */ + + rc = ngx_http_core_find_location(r); + + return (rc == NGX_ERROR) ? rc : NGX_OK; } - n = ngx_regex_exec((*clcfp)->regex, &r->uri, r->captures, len); - - if (n == NGX_REGEX_NO_MATCHED) { + if (n == NGX_DECLINED) { continue; } - if (n < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n - " failed: %d on \"%V\" using \"%V\"", - n, &r->uri, &(*clcfp)->name); - return NGX_ERROR; - } - - /* match */ - - r->loc_conf = (*clcfp)->loc_conf; - - r->ncaptures = len; - r->captures_data = r->uri.data; - - /* look up nested locations */ - - rc = ngx_http_core_find_location(r); - - return (rc == NGX_ERROR) ? rc : NGX_OK; + return NGX_ERROR; } } #endif @@ -1582,6 +1582,10 @@ ngx_http_test_content_type(ngx_http_requ size_t len; ngx_uint_t i, hash; + if (types_hash->size == 0) { + return (void *) 4; + } + if (r->headers_out.content_type.len == 0) { return NULL; } @@ -1765,7 +1769,7 @@ ngx_http_map_uri_to_path(ngx_http_reques #if (NGX_PCRE) ngx_uint_t captures; - captures = alias && clcf->captures; + captures = alias && clcf->regex; reserved += captures ? 1 : r->uri.len - alias + 1; #else reserved += r->uri.len - alias + 1; @@ -1882,15 +1886,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r) ngx_table_elt_t *e, *d; ngx_http_core_loc_conf_t *clcf; - if (r->gzip == 1) { - return NGX_OK; - } - - if (r->gzip == 2) { - return NGX_DECLINED; - } - - r->gzip = 2; + r->gzip_tested = 1; if (r != r->main || r->headers_in.accept_encoding == NULL @@ -2025,7 +2021,7 @@ ok: #endif - r->gzip = 1; + r->gzip_ok = 1; return NGX_OK; } @@ -2591,26 +2587,27 @@ ngx_http_core_regex_location(ngx_conf_t ngx_str_t *regex, ngx_uint_t caseless) { #if (NGX_PCRE) - ngx_str_t err; - u_char errstr[NGX_MAX_CONF_ERRSTR]; - - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = *regex; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; #if (NGX_HAVE_CASELESS_FILESYSTEM) - caseless = 1; + rc.options = NGX_REGEX_CASELESS; +#else + rc.options = caseless; #endif - clcf->regex = ngx_regex_compile(regex, caseless ? NGX_REGEX_CASELESS: 0, - cf->pool, &err); - + clcf->regex = ngx_http_regex_compile(cf, &rc); if (clcf->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_ERROR; } clcf->name = *regex; - clcf->captures = (ngx_regex_capture_count(clcf->regex) > 0); return NGX_OK; @@ -2628,14 +2625,14 @@ ngx_http_core_regex_location(ngx_conf_t static char * ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; char *rv; ngx_conf_t save; - if (lcf->types == NULL) { - lcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t)); - if (lcf->types == NULL) { + if (clcf->types == NULL) { + clcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t)); + if (clcf->types == NULL) { return NGX_CONF_ERROR; } } @@ -2655,7 +2652,7 @@ ngx_http_core_types(ngx_conf_t *cf, ngx_ static char * ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; ngx_str_t *value, *content_type, *old, file; ngx_uint_t i, n, hash; @@ -2686,8 +2683,8 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len); - type = lcf->types->elts; - for (n = 0; n < lcf->types->nelts; n++) { + type = clcf->types->elts; + for (n = 0; n < clcf->types->nelts; n++) { if (ngx_strcmp(value[i].data, type[n].key.data) == 0) { old = type[n].value; type[n].value = content_type; @@ -2702,7 +2699,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c } - type = ngx_array_push(lcf->types); + type = ngx_array_push(clcf->types); if (type == NULL) { return NGX_CONF_ERROR; } @@ -2778,6 +2775,10 @@ ngx_http_core_init_main_conf(ngx_conf_t cmcf->variables_hash_bucket_size = ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size); + if (cmcf->ncaptures) { + cmcf->ncaptures = (cmcf->ncaptures + 1) * 3; + } + return NGX_CONF_OK; } @@ -2798,13 +2799,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t * conf->client_large_buffers.num = 0; */ - if (ngx_array_init(&cscf->listen, cf->temp_pool, 4, - sizeof(ngx_http_listen_t)) - != NGX_OK) - { - return NULL; - } - if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) @@ -2830,58 +2824,12 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ngx_http_core_srv_conf_t *prev = parent; ngx_http_core_srv_conf_t *conf = child; - ngx_http_listen_t *ls; struct sockaddr_in *sin; + ngx_http_listen_opt_t lsopt; ngx_http_server_name_t *sn; /* TODO: it does not merge, it inits only */ - if (conf->listen.nelts == 0) { - ls = ngx_array_push(&conf->listen); - if (ls == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memzero(ls, sizeof(ngx_http_listen_t)); - - sin = (struct sockaddr_in *) &ls->sockaddr; - - sin->sin_family = AF_INET; -#if (NGX_WIN32) - sin->sin_port = htons(80); -#else - sin->sin_port = htons((getuid() == 0) ? 80 : 8000); -#endif - sin->sin_addr.s_addr = INADDR_ANY; - - ls->socklen = sizeof(struct sockaddr_in); - - ls->conf.backlog = NGX_LISTEN_BACKLOG; - ls->conf.rcvbuf = -1; - ls->conf.sndbuf = -1; - ls->conf.wildcard = 1; - - (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr, - NGX_SOCKADDR_STRLEN, 1); - } - - if (conf->server_name.data == NULL) { - conf->server_name = cf->cycle->hostname; - - sn = ngx_array_push(&conf->server_names); - if (sn == NULL) { - return NGX_CONF_ERROR; - } - -#if (NGX_PCRE) - sn->regex = NULL; - sn->captures = 0; -#endif - sn->core_srv_conf = conf; - sn->name.len = conf->server_name.len; - sn->name.data = conf->server_name.data; - } - ngx_conf_merge_size_value(conf->connection_pool_size, prev->connection_pool_size, 256); ngx_conf_merge_size_value(conf->request_pool_size, @@ -2892,7 +2840,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t prev->client_header_buffer_size, 1024); ngx_conf_merge_bufs_value(conf->large_client_header_buffers, prev->large_client_header_buffers, - 4, ngx_pagesize); + 4, 8192); if (conf->large_client_header_buffers.size < conf->connection_pool_size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -2909,6 +2857,50 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ngx_conf_merge_value(conf->underscores_in_headers, prev->underscores_in_headers, 0); + if (!conf->listen) { + ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); + + sin = &lsopt.u.sockaddr_in; + + sin->sin_family = AF_INET; +#if (NGX_WIN32) + sin->sin_port = htons(80); +#else + sin->sin_port = htons((getuid() == 0) ? 80 : 8000); +#endif + sin->sin_addr.s_addr = INADDR_ANY; + + lsopt.socklen = sizeof(struct sockaddr_in); + + lsopt.backlog = NGX_LISTEN_BACKLOG; + lsopt.rcvbuf = -1; + lsopt.sndbuf = -1; + lsopt.wildcard = 1; + + (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr, + NGX_SOCKADDR_STRLEN, 1); + + if (ngx_http_add_listen(cf, conf, &lsopt) == NGX_OK) { + return NGX_CONF_OK; + } + } + + if (conf->server_name.data == NULL) { + conf->server_name = cf->cycle->hostname; + + sn = ngx_array_push(&conf->server_names); + if (sn == NULL) { + return NGX_CONF_ERROR; + } + +#if (NGX_PCRE) + sn->regex = NULL; +#endif + sn->server = conf; + sn->name.len = conf->server_name.len; + sn->name.data = conf->server_name.data; + } + return NGX_CONF_OK; } @@ -2916,88 +2908,89 @@ ngx_http_core_merge_srv_conf(ngx_conf_t static void * ngx_http_core_create_loc_conf(ngx_conf_t *cf) { - ngx_http_core_loc_conf_t *lcf; - - lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)); - if (lcf == NULL) { + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)); + if (clcf == NULL) { return NULL; } /* * set by ngx_pcalloc(): * - * lcf->root = { 0, NULL }; - * lcf->limit_except = 0; - * lcf->post_action = { 0, NULL }; - * lcf->types = NULL; - * lcf->default_type = { 0, NULL }; - * lcf->error_log = NULL; - * lcf->error_pages = NULL; - * lcf->try_files = NULL; - * lcf->client_body_path = NULL; - * lcf->regex = NULL; - * lcf->exact_match = 0; - * lcf->auto_redirect = 0; - * lcf->alias = 0; - * lcf->gzip_proxied = 0; + * clcf->root = { 0, NULL }; + * clcf->limit_except = 0; + * clcf->post_action = { 0, NULL }; + * clcf->types = NULL; + * clcf->default_type = { 0, NULL }; + * clcf->error_log = NULL; + * clcf->error_pages = NULL; + * clcf->try_files = NULL; + * clcf->client_body_path = NULL; + * clcf->regex = NULL; + * clcf->exact_match = 0; + * clcf->auto_redirect = 0; + * clcf->alias = 0; + * clcf->gzip_proxied = 0; */ - lcf->client_max_body_size = NGX_CONF_UNSET; - lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; - lcf->client_body_timeout = NGX_CONF_UNSET_MSEC; - lcf->satisfy = NGX_CONF_UNSET_UINT; - lcf->if_modified_since = NGX_CONF_UNSET_UINT; - lcf->client_body_in_file_only = NGX_CONF_UNSET_UINT; - lcf->client_body_in_single_buffer = NGX_CONF_UNSET; - lcf->internal = NGX_CONF_UNSET; - lcf->sendfile = NGX_CONF_UNSET; - lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; + clcf->client_max_body_size = NGX_CONF_UNSET; + clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; + clcf->client_body_timeout = NGX_CONF_UNSET_MSEC; + clcf->satisfy = NGX_CONF_UNSET_UINT; + clcf->if_modified_since = NGX_CONF_UNSET_UINT; + clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT; + clcf->client_body_in_single_buffer = NGX_CONF_UNSET; + clcf->internal = NGX_CONF_UNSET; + clcf->sendfile = NGX_CONF_UNSET; + clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; #if (NGX_HAVE_FILE_AIO) - lcf->aio = NGX_CONF_UNSET; + clcf->aio = NGX_CONF_UNSET; #endif - lcf->directio = NGX_CONF_UNSET; - lcf->directio_alignment = NGX_CONF_UNSET; - lcf->tcp_nopush = NGX_CONF_UNSET; - lcf->tcp_nodelay = NGX_CONF_UNSET; - lcf->send_timeout = NGX_CONF_UNSET_MSEC; - lcf->send_lowat = NGX_CONF_UNSET_SIZE; - lcf->postpone_output = NGX_CONF_UNSET_SIZE; - lcf->limit_rate = NGX_CONF_UNSET_SIZE; - lcf->limit_rate_after = NGX_CONF_UNSET_SIZE; - lcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; - lcf->keepalive_header = NGX_CONF_UNSET; - lcf->keepalive_requests = NGX_CONF_UNSET_UINT; - lcf->lingering_time = NGX_CONF_UNSET_MSEC; - lcf->lingering_timeout = NGX_CONF_UNSET_MSEC; - lcf->resolver_timeout = NGX_CONF_UNSET_MSEC; - lcf->reset_timedout_connection = NGX_CONF_UNSET; - lcf->server_name_in_redirect = NGX_CONF_UNSET; - lcf->port_in_redirect = NGX_CONF_UNSET; - lcf->msie_padding = NGX_CONF_UNSET; - lcf->msie_refresh = NGX_CONF_UNSET; - lcf->log_not_found = NGX_CONF_UNSET; - lcf->log_subrequest = NGX_CONF_UNSET; - lcf->recursive_error_pages = NGX_CONF_UNSET; - lcf->server_tokens = NGX_CONF_UNSET; - lcf->types_hash_max_size = NGX_CONF_UNSET_UINT; - lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT; - - lcf->open_file_cache = NGX_CONF_UNSET_PTR; - lcf->open_file_cache_valid = NGX_CONF_UNSET; - lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT; - lcf->open_file_cache_errors = NGX_CONF_UNSET; - lcf->open_file_cache_events = NGX_CONF_UNSET; + clcf->read_ahead = NGX_CONF_UNSET_SIZE; + clcf->directio = NGX_CONF_UNSET; + clcf->directio_alignment = NGX_CONF_UNSET; + clcf->tcp_nopush = NGX_CONF_UNSET; + clcf->tcp_nodelay = NGX_CONF_UNSET; + clcf->send_timeout = NGX_CONF_UNSET_MSEC; + clcf->send_lowat = NGX_CONF_UNSET_SIZE; + clcf->postpone_output = NGX_CONF_UNSET_SIZE; + clcf->limit_rate = NGX_CONF_UNSET_SIZE; + clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; + clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; + clcf->keepalive_header = NGX_CONF_UNSET; + clcf->keepalive_requests = NGX_CONF_UNSET_UINT; + clcf->lingering_time = NGX_CONF_UNSET_MSEC; + clcf->lingering_timeout = NGX_CONF_UNSET_MSEC; + clcf->resolver_timeout = NGX_CONF_UNSET_MSEC; + clcf->reset_timedout_connection = NGX_CONF_UNSET; + clcf->server_name_in_redirect = NGX_CONF_UNSET; + clcf->port_in_redirect = NGX_CONF_UNSET; + clcf->msie_padding = NGX_CONF_UNSET; + clcf->msie_refresh = NGX_CONF_UNSET; + clcf->log_not_found = NGX_CONF_UNSET; + clcf->log_subrequest = NGX_CONF_UNSET; + clcf->recursive_error_pages = NGX_CONF_UNSET; + clcf->server_tokens = NGX_CONF_UNSET; + clcf->types_hash_max_size = NGX_CONF_UNSET_UINT; + clcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT; + + clcf->open_file_cache = NGX_CONF_UNSET_PTR; + clcf->open_file_cache_valid = NGX_CONF_UNSET; + clcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT; + clcf->open_file_cache_errors = NGX_CONF_UNSET; + clcf->open_file_cache_events = NGX_CONF_UNSET; #if (NGX_HTTP_GZIP) - lcf->gzip_vary = NGX_CONF_UNSET; - lcf->gzip_http_version = NGX_CONF_UNSET_UINT; + clcf->gzip_vary = NGX_CONF_UNSET; + clcf->gzip_http_version = NGX_CONF_UNSET_UINT; #if (NGX_PCRE) - lcf->gzip_disable = NGX_CONF_UNSET_PTR; - lcf->gzip_disable_msie6 = 3; + clcf->gzip_disable = NGX_CONF_UNSET_PTR; + clcf->gzip_disable_msie6 = 3; #endif #endif - return lcf; + return clcf; } @@ -3156,6 +3149,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t #if (NGX_HAVE_FILE_AIO) ngx_conf_merge_value(conf->aio, prev->aio, 0); #endif + ngx_conf_merge_size_value(conf->read_ahead, prev->read_ahead, 0); ngx_conf_merge_off_value(conf->directio, prev->directio, NGX_MAX_OFF_T_VALUE); ngx_conf_merge_off_value(conf->directio_alignment, prev->directio_alignment, @@ -3262,17 +3256,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t static char * ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_srv_conf_t *scf = conf; - - ngx_str_t *value, size; - ngx_url_t u; - ngx_uint_t n; - ngx_http_listen_t *ls; - - /* - * TODO: check duplicate 'listen' directives, - * add resolved name to server names ??? - */ + ngx_http_core_srv_conf_t *cscf = conf; + + ngx_str_t *value, size; + ngx_url_t u; + ngx_uint_t n; + ngx_http_listen_opt_t lsopt; + + cscf->listen = 1; value = cf->args->elts; @@ -3292,58 +3283,40 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - ls = ngx_array_push(&scf->listen); - if (ls == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memzero(ls, sizeof(ngx_http_listen_t)); - - ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); - - ls->socklen = u.socklen; - ls->file_name = cf->conf_file->file.name.data; - ls->line = cf->conf_file->line; - ls->conf.backlog = NGX_LISTEN_BACKLOG; - ls->conf.rcvbuf = -1; - ls->conf.sndbuf = -1; - ls->conf.wildcard = u.wildcard; - - (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr, + ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); + + ngx_memcpy(&lsopt.u.sockaddr, u.sockaddr, u.socklen); + + lsopt.socklen = u.socklen; + lsopt.backlog = NGX_LISTEN_BACKLOG; + lsopt.rcvbuf = -1; + lsopt.sndbuf = -1; + lsopt.wildcard = u.wildcard; + + (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr, NGX_SOCKADDR_STRLEN, 1); - if (cf->args->nelts == 2) { - return NGX_CONF_OK; - } - - if (ngx_strcmp(value[2].data, "default") == 0) { - ls->conf.default_server = 1; - n = 3; - - } else { - n = 2; - } - - for ( /* void */ ; n < cf->args->nelts; n++) { - - if (ls->conf.default_server == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" parameter can be specified for " - "the default \"listen\" directive only", - &value[n]); - return NGX_CONF_ERROR; + for (n = 2; n < cf->args->nelts; n++) { + + if (ngx_strcmp(value[n].data, "default_server") == 0 + || ngx_strcmp(value[n].data, "default") == 0) + { + lsopt.default_server = 1; + continue; } if (ngx_strcmp(value[n].data, "bind") == 0) { - ls->conf.bind = 1; + lsopt.set = 1; + lsopt.bind = 1; continue; } if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) { - ls->conf.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8); - ls->conf.bind = 1; - - if (ls->conf.backlog == NGX_ERROR || ls->conf.backlog == 0) { + lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8); + lsopt.set = 1; + lsopt.bind = 1; + + if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid backlog \"%V\"", &value[n]); return NGX_CONF_ERROR; @@ -3356,10 +3329,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx size.len = value[n].len - 7; size.data = value[n].data + 7; - ls->conf.rcvbuf = ngx_parse_size(&size); - ls->conf.bind = 1; - - if (ls->conf.rcvbuf == NGX_ERROR) { + lsopt.rcvbuf = ngx_parse_size(&size); + lsopt.set = 1; + lsopt.bind = 1; + + if (lsopt.rcvbuf == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid rcvbuf \"%V\"", &value[n]); return NGX_CONF_ERROR; @@ -3372,10 +3346,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx size.len = value[n].len - 7; size.data = value[n].data + 7; - ls->conf.sndbuf = ngx_parse_size(&size); - ls->conf.bind = 1; - - if (ls->conf.sndbuf == NGX_ERROR) { + lsopt.sndbuf = ngx_parse_size(&size); + lsopt.set = 1; + lsopt.bind = 1; + + if (lsopt.sndbuf == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid sndbuf \"%V\"", &value[n]); return NGX_CONF_ERROR; @@ -3386,8 +3361,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx if (ngx_strncmp(value[n].data, "accept_filter=", 14) == 0) { #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) - ls->conf.accept_filter = (char *) &value[n].data[14]; - ls->conf.bind = 1; + lsopt.accept_filter = (char *) &value[n].data[14]; + lsopt.set = 1; + lsopt.bind = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "accept filters \"%V\" are not supported " @@ -3399,8 +3375,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx if (ngx_strcmp(value[n].data, "deferred") == 0) { #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - ls->conf.deferred_accept = 1; - ls->conf.bind = 1; + lsopt.deferred_accept = 1; + lsopt.set = 1; + lsopt.bind = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the deferred accept is not supported " @@ -3413,15 +3390,15 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) struct sockaddr *sa; - sa = (struct sockaddr *) ls->sockaddr; + sa = &lsopt.u.sockaddr; if (sa->sa_family == AF_INET6) { if (ngx_strcmp(&value[n].data[10], "n") == 0) { - ls->conf.ipv6only = 1; + lsopt.ipv6only = 1; } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) { - ls->conf.ipv6only = 2; + lsopt.ipv6only = 2; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3430,13 +3407,13 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - ls->conf.bind = 1; + lsopt.set = 1; + lsopt.bind = 1; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "ipv6only is not supported " - "on addr \"%s\", ignored", - ls->conf.addr); + "on addr \"%s\", ignored", lsopt.addr); } continue; @@ -3450,7 +3427,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx if (ngx_strcmp(value[n].data, "ssl") == 0) { #if (NGX_HTTP_SSL) - ls->conf.ssl = 1; + lsopt.set = 1; + lsopt.ssl = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3465,7 +3443,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - return NGX_CONF_OK; + if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) { + return NGX_CONF_OK; + } + + return NGX_CONF_ERROR; } @@ -3537,19 +3519,20 @@ ngx_http_core_server_name(ngx_conf_t *cf #if (NGX_PCRE) sn->regex = NULL; - sn->captures = 0; #endif - sn->core_srv_conf = cscf; + sn->server = cscf; sn->name = value[i]; if (value[i].data[0] != '~') { + ngx_strlow(sn->name.data, sn->name.data, sn->name.len); continue; } #if (NGX_PCRE) { - ngx_str_t err; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + u_char *p; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; if (value[i].len == 1) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3557,21 +3540,29 @@ ngx_http_core_server_name(ngx_conf_t *cf return NGX_CONF_ERROR; } - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; - value[i].len--; value[i].data++; - sn->regex = ngx_regex_compile(&value[i], 0, cf->pool, &err); - + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = value[i]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + for (p = value[i].data; p < value[i].data + value[i].len; p++) { + if (*p >= 'A' && *p <= 'Z') { + rc.options = NGX_REGEX_CASELESS; + break; + } + } + + sn->regex = ngx_http_regex_compile(cf, &rc); if (sn->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_CONF_ERROR; } - sn->captures = (ngx_regex_capture_count(sn->regex) > 0); sn->name = value[i]; + cscf->captures = (rc.captures > 0); } #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3589,7 +3580,7 @@ ngx_http_core_server_name(ngx_conf_t *cf static char * ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; ngx_str_t *value; ngx_uint_t alias, n; @@ -3597,11 +3588,11 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0; - if (lcf->root.data) { + if (clcf->root.data) { /* the (ngx_uint_t) cast is required by gcc 2.7.2.3 */ - if ((ngx_uint_t) lcf->alias == alias) { + if ((ngx_uint_t) clcf->alias == alias) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" directive is duplicate", &cmd->name); @@ -3609,13 +3600,13 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" directive is duplicate, " "\"%s\" directive is specified before", - &cmd->name, lcf->alias ? "alias" : "root"); + &cmd->name, clcf->alias ? "alias" : "root"); } return NGX_CONF_ERROR; } - if (lcf->named && alias) { + if (clcf->named && alias) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"alias\" directive may not be used " "inside named location"); @@ -3647,28 +3638,28 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - lcf->alias = alias; - lcf->root = value[1]; - - if (!alias && lcf->root.data[lcf->root.len - 1] == '/') { - lcf->root.len--; + clcf->alias = alias; + clcf->root = value[1]; + + if (!alias && clcf->root.data[clcf->root.len - 1] == '/') { + clcf->root.len--; } - if (lcf->root.data[0] != '$') { - if (ngx_conf_full_name(cf->cycle, &lcf->root, 0) != NGX_OK) { + if (clcf->root.data[0] != '$') { + if (ngx_conf_full_name(cf->cycle, &clcf->root, 0) != NGX_OK) { return NGX_CONF_ERROR; } } - n = ngx_http_script_variables_count(&lcf->root); + n = ngx_http_script_variables_count(&clcf->root); ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); if (n) { sc.cf = cf; - sc.source = &lcf->root; - sc.lengths = &lcf->root_lengths; - sc.values = &lcf->root_values; + sc.source = &clcf->root; + sc.lengths = &clcf->root_lengths; + sc.values = &clcf->root_values; sc.variables = n; sc.complete_lengths = 1; sc.complete_values = 1; @@ -3678,20 +3669,6 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c } } -#if (NGX_PCRE) - - if (alias && lcf->regex - && (ngx_regex_capture_count(lcf->regex) <= 0 || sc.ncaptures == 0)) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the \"alias\" directive must use captures " - "inside location given by regular expression"); - - return NGX_CONF_ERROR; - } - -#endif - return NGX_CONF_OK; } @@ -3843,7 +3820,7 @@ ngx_http_core_directio(ngx_conf_t *cf, n static char * ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; u_char *p; ngx_int_t overwrite; @@ -3853,10 +3830,10 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_http_complex_value_t cv; ngx_http_compile_complex_value_t ccv; - if (lcf->error_pages == NULL) { - lcf->error_pages = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_err_page_t)); - if (lcf->error_pages == NULL) { + if (clcf->error_pages == NULL) { + clcf->error_pages = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_err_page_t)); + if (clcf->error_pages == NULL) { return NGX_CONF_ERROR; } } @@ -3920,7 +3897,7 @@ ngx_http_core_error_page(ngx_conf_t *cf, } for (i = 1; i < cf->args->nelts - n; i++) { - err = ngx_array_push(lcf->error_pages); + err = ngx_array_push(clcf->error_pages); if (err == NULL) { return NGX_CONF_ERROR; } @@ -3933,9 +3910,9 @@ ngx_http_core_error_page(ngx_conf_t *cf, return NGX_CONF_ERROR; } - if (err->status < 400 || err->status > 599) { + if (err->status < 300 || err->status > 599) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "value \"%V\" must be between 400 and 599", + "value \"%V\" must be between 300 and 599", &value[i]); return NGX_CONF_ERROR; } @@ -4048,14 +4025,14 @@ ngx_http_core_try_files(ngx_conf_t *cf, static char * ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; time_t inactive; ngx_str_t *value, s; ngx_int_t max; ngx_uint_t i; - if (lcf->open_file_cache != NGX_CONF_UNSET_PTR) { + if (clcf->open_file_cache != NGX_CONF_UNSET_PTR) { return "is duplicate"; } @@ -4091,7 +4068,7 @@ ngx_http_core_open_file_cache(ngx_conf_t if (ngx_strcmp(value[i].data, "off") == 0) { - lcf->open_file_cache = NULL; + clcf->open_file_cache = NULL; continue; } @@ -4104,7 +4081,7 @@ ngx_http_core_open_file_cache(ngx_conf_t return NGX_CONF_ERROR; } - if (lcf->open_file_cache == NULL) { + if (clcf->open_file_cache == NULL) { return NGX_CONF_OK; } @@ -4114,8 +4091,8 @@ ngx_http_core_open_file_cache(ngx_conf_t return NGX_CONF_ERROR; } - lcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive); - if (lcf->open_file_cache) { + clcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive); + if (clcf->open_file_cache) { return NGX_CONF_OK; } @@ -4126,50 +4103,50 @@ ngx_http_core_open_file_cache(ngx_conf_t static char * ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; ngx_str_t *value; - if (lcf->error_log) { + if (clcf->error_log) { return "is duplicate"; } value = cf->args->elts; - lcf->error_log = ngx_log_create(cf->cycle, &value[1]); - if (lcf->error_log == NULL) { + clcf->error_log = ngx_log_create(cf->cycle, &value[1]); + if (clcf->error_log == NULL) { return NGX_CONF_ERROR; } if (cf->args->nelts == 2) { - lcf->error_log->log_level = NGX_LOG_ERR; + clcf->error_log->log_level = NGX_LOG_ERR; return NGX_CONF_OK; } - return ngx_log_set_levels(cf, lcf->error_log); + return ngx_log_set_levels(cf, clcf->error_log); } static char * ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; + ngx_http_core_loc_conf_t *clcf = conf; ngx_str_t *value; - if (lcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) { + if (clcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) { return "is duplicate"; } value = cf->args->elts; - lcf->keepalive_timeout = ngx_parse_time(&value[1], 0); - - if (lcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) { + clcf->keepalive_timeout = ngx_parse_time(&value[1], 0); + + if (clcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) { return "invalid value"; } - if (lcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) { + if (clcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) { return "value must be less than 597 hours"; } @@ -4177,13 +4154,13 @@ ngx_http_core_keepalive(ngx_conf_t *cf, return NGX_CONF_OK; } - lcf->keepalive_header = ngx_parse_time(&value[2], 1); - - if (lcf->keepalive_header == NGX_ERROR) { + clcf->keepalive_header = ngx_parse_time(&value[2], 1); + + if (clcf->keepalive_header == NGX_ERROR) { return "invalid value"; } - if (lcf->keepalive_header == NGX_PARSE_LARGE_TIME) { + if (clcf->keepalive_header == NGX_PARSE_LARGE_TIME) { return "value must be less than 68 years"; } @@ -4194,13 +4171,13 @@ ngx_http_core_keepalive(ngx_conf_t *cf, static char * ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_loc_conf_t *lcf = conf; - - if (lcf->internal != NGX_CONF_UNSET) { + ngx_http_core_loc_conf_t *clcf = conf; + + if (clcf->internal != NGX_CONF_UNSET) { return "is duplicate"; } - lcf->internal = 1; + clcf->internal = 1; return NGX_CONF_OK; } @@ -4248,10 +4225,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng #if (NGX_PCRE) - ngx_str_t err, *value; - ngx_uint_t i; - ngx_regex_elt_t *re; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_str_t *value; + ngx_uint_t i; + ngx_regex_elt_t *re; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) { clcf->gzip_disable = ngx_array_create(cf->pool, 2, @@ -4263,8 +4241,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng value = cf->args->elts; - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pool = cf->pool; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; for (i = 1; i < cf->args->nelts; i++) { @@ -4278,14 +4259,15 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng return NGX_CONF_ERROR; } - re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool, - &err); - - if (re->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + rc.pattern = value[1]; + rc.options = NGX_REGEX_CASELESS; + + if (ngx_regex_compile(&rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); return NGX_CONF_ERROR; } + re->regex = rc.regex; re->name = value[i].data; } @@ -4348,8 +4330,15 @@ ngx_http_core_pool_size(ngx_conf_t *cf, if (*sp < NGX_MIN_POOL_SIZE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "pool must be no less than %uz", NGX_MIN_POOL_SIZE); - + "the pool size must be no less than %uz", + NGX_MIN_POOL_SIZE); + return NGX_CONF_ERROR; + } + + if (*sp % NGX_POOL_ALIGNMENT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the pool size must be a multiple of %uz", + NGX_POOL_ALIGNMENT); return NGX_CONF_ERROR; } 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 @@ -43,6 +43,21 @@ typedef struct ngx_http_core_loc_conf_s typedef struct { + union { + struct sockaddr sockaddr; + struct sockaddr_in sockaddr_in; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 sockaddr_in6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un sockaddr_un; +#endif + u_char sockaddr_data[NGX_SOCKADDRLEN]; + } u; + + socklen_t socklen; + + unsigned set:1; unsigned default_server:1; unsigned bind:1; unsigned wildcard:1; @@ -65,18 +80,7 @@ typedef struct { #endif u_char addr[NGX_SOCKADDR_STRLEN + 1]; -} ngx_http_listen_conf_t; - - -typedef struct { - u_char sockaddr[NGX_SOCKADDRLEN]; - socklen_t socklen; - - u_char *file_name; - ngx_uint_t line; - - ngx_http_listen_conf_t conf; -} ngx_http_listen_t; +} ngx_http_listen_opt_t; typedef enum { @@ -133,6 +137,7 @@ typedef struct { ngx_hash_t variables_hash; ngx_array_t variables; /* ngx_http_variable_t */ + ngx_uint_t ncaptures; ngx_uint_t server_names_hash_max_size; ngx_uint_t server_names_hash_bucket_size; @@ -142,6 +147,8 @@ typedef struct { ngx_hash_keys_arrays_t *variables_keys; + ngx_array_t *ports; + ngx_uint_t try_files; /* unsigned try_files:1 */ ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1]; @@ -149,9 +156,6 @@ typedef struct { typedef struct { - /* array of the ngx_http_listen_t, "listen" directive */ - ngx_array_t listen; - /* array of the ngx_http_server_name_t, "server_name" directive */ ngx_array_t server_names; @@ -172,6 +176,11 @@ typedef struct { ngx_flag_t merge_slashes; ngx_flag_t underscores_in_headers; + unsigned listen:1; +#if (NGX_PCRE) + unsigned captures:1; +#endif + ngx_http_core_loc_conf_t **named_locations; } ngx_http_core_srv_conf_t; @@ -181,7 +190,7 @@ typedef struct { typedef struct { /* the default server configuration for this address:port */ - ngx_http_core_srv_conf_t *core_srv_conf; + ngx_http_core_srv_conf_t *default_server; ngx_http_virtual_names_t *virtual_names; @@ -222,40 +231,28 @@ typedef struct { typedef struct { - struct sockaddr *sockaddr; - socklen_t socklen; + ngx_http_listen_opt_t opt; ngx_hash_t hash; ngx_hash_wildcard_t *wc_head; ngx_hash_wildcard_t *wc_tail; - ngx_array_t names; /* array of ngx_http_server_name_t */ - #if (NGX_PCRE) ngx_uint_t nregex; ngx_http_server_name_t *regex; #endif /* the default server configuration for this address:port */ - ngx_http_core_srv_conf_t *core_srv_conf; - - unsigned default_server:1; - unsigned bind:1; - unsigned wildcard:1; -#if (NGX_HTTP_SSL) - unsigned ssl:1; -#endif - - ngx_http_listen_conf_t *listen_conf; + ngx_http_core_srv_conf_t *default_server; + ngx_array_t servers; /* array of ngx_http_core_srv_conf_t */ } ngx_http_conf_addr_t; struct ngx_http_server_name_s { #if (NGX_PCRE) - ngx_regex_t *regex; - ngx_uint_t captures; /* unsigned captures:1; */ + ngx_http_regex_t *regex; #endif - ngx_http_core_srv_conf_t *core_srv_conf; /* virtual name server conf */ + ngx_http_core_srv_conf_t *server; /* virtual name server conf */ ngx_str_t name; }; @@ -282,9 +279,7 @@ struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ #if (NGX_PCRE) - ngx_regex_t *regex; - - unsigned captures:1; + ngx_http_regex_t *regex; #endif unsigned noname:1; /* "if () {}" block or limit_except */ @@ -332,6 +327,7 @@ struct ngx_http_core_loc_conf_s { size_t limit_rate; /* limit_rate */ size_t limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ + size_t read_ahead; /* read_ahead */ ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t send_timeout; /* send_timeout */ 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 @@ -12,6 +12,8 @@ static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); +static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, + ngx_http_cache_t *c); #if (NGX_HAVE_FILE_AIO) static void ngx_http_cache_aio_event_handler(ngx_event_t *ev); #endif @@ -281,6 +283,7 @@ ngx_http_file_cache_open(ngx_http_reques of.min_uses = clcf->open_file_cache_min_uses; of.events = clcf->open_file_cache_events; of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + of.read_ahead = clcf->read_ahead; if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) != NGX_OK) @@ -329,40 +332,13 @@ ngx_http_file_cache_read(ngx_http_reques c = r->cache; -#if (NGX_HAVE_FILE_AIO) - { - ngx_http_core_loc_conf_t *clcf; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->aio) { - n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); - - if (n == NGX_AGAIN) { - c->file.aio->data = r; - c->file.aio->handler = ngx_http_cache_aio_event_handler; + n = ngx_http_file_cache_aio_read(r, c); - r->main->blocked++; - r->aio = 1; - - return NGX_AGAIN; - } - - } else { - n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); - } - } -#else - - n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); - -#endif - - if (n == NGX_ERROR) { + if (n < 0) { return n; } - if ((size_t) n <= c->header_start) { + if ((size_t) n < c->header_start) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" is too small", c->file.name.data); return NGX_ERROR; @@ -370,7 +346,7 @@ ngx_http_file_cache_read(ngx_http_reques h = (ngx_http_file_cache_header_t *) c->buf->pos; - if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) { + if (h->crc32 != c->crc32) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has md5 collision", c->file.name.data); return NGX_DECLINED; @@ -382,6 +358,7 @@ ngx_http_file_cache_read(ngx_http_reques c->last_modified = h->last_modified; c->date = h->date; c->valid_msec = h->valid_msec; + c->header_start = h->header_start; c->body_start = h->body_start; r->cached = 1; @@ -431,8 +408,46 @@ ngx_http_file_cache_read(ngx_http_reques } +static ssize_t +ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) +{ #if (NGX_HAVE_FILE_AIO) + ssize_t n; + ngx_http_core_loc_conf_t *clcf; + if (!ngx_file_aio) { + goto noaio; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (!clcf->aio) { + goto noaio; + } + + n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); + + if (n != NGX_AGAIN) { + return n; + } + + c->file.aio->data = r; + c->file.aio->handler = ngx_http_cache_aio_event_handler; + + r->main->blocked++; + r->aio = 1; + + return NGX_AGAIN; + +noaio: + +#endif + + return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); +} + + +#if (NGX_HAVE_FILE_AIO) static void ngx_http_cache_aio_event_handler(ngx_event_t *ev) @@ -691,7 +706,7 @@ ngx_http_file_cache_set_header(ngx_http_ void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) { - off_t size; + off_t size, length; ngx_int_t rc; ngx_file_uniq_t uniq; ngx_file_info_t fi; @@ -713,6 +728,7 @@ ngx_http_file_cache_update(ngx_http_requ cache = c->file_cache; uniq = 0; + length = 0; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache rename: \"%s\" to \"%s\"", @@ -737,10 +753,11 @@ ngx_http_file_cache_update(ngx_http_requ } else { uniq = ngx_file_uniq(&fi); + length = ngx_file_size(&fi); } } - size = (c->length + cache->bsize - 1) / cache->bsize; + size = (length + cache->bsize - 1) / cache->bsize; ngx_shmtx_lock(&cache->shpool->mutex); @@ -750,7 +767,7 @@ ngx_http_file_cache_update(ngx_http_requ size = size - (c->node->length + cache->bsize - 1) / cache->bsize; - c->node->length = c->length; + c->node->length = length; cache->sh->size += size; @@ -789,6 +806,8 @@ ngx_http_cache_send(ngx_http_request_t * return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->header_only = (c->length - c->body_start) == 0; + rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { @@ -798,7 +817,7 @@ ngx_http_cache_send(ngx_http_request_t * b->file_pos = c->body_start; b->file_last = c->length; - b->in_file = (c->length - c->body_start) ? 1: 0; + b->in_file = 1; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; 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 @@ -132,10 +132,6 @@ static ngx_str_t ngx_http_status_lines[] ngx_http_header_out_t ngx_http_headers_out[] = { { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) }, { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) }, -#if 0 - { ngx_string("Content-Type"), - offsetof(ngx_http_headers_out_t, content_type) }, -#endif { ngx_string("Content-Length"), offsetof(ngx_http_headers_out_t, content_length) }, { ngx_string("Content-Encoding"), @@ -399,8 +395,13 @@ ngx_http_header_filter(ngx_http_request_ } #if (NGX_HTTP_GZIP) - if (r->gzip && clcf->gzip_vary) { - len += sizeof("Vary: Accept-Encoding" CRLF) - 1; + if (r->gzip_vary) { + if (clcf->gzip_vary) { + len += sizeof("Vary: Accept-Encoding" CRLF) - 1; + + } else { + r->gzip_vary = 0; + } } #endif @@ -533,8 +534,8 @@ ngx_http_header_filter(ngx_http_request_ r->headers_out.location->value.len = b->last - p; r->headers_out.location->value.data = p; - r->headers_out.location->key.len = sizeof("Location: ") - 1; - r->headers_out.location->key.data = (u_char *) "Location: "; + r->headers_out.location->key.len = sizeof("Location") - 1; + r->headers_out.location->key.data = (u_char *) "Location"; *b->last++ = CR; *b->last++ = LF; } @@ -559,7 +560,7 @@ ngx_http_header_filter(ngx_http_request_ } #if (NGX_HTTP_GZIP) - if (r->gzip && clcf->gzip_vary) { + if (r->gzip_vary) { b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF, sizeof("Vary: Accept-Encoding" CRLF) - 1); } 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 @@ -1322,8 +1322,10 @@ ngx_http_parse_unsafe_uri(ngx_http_reque unsafe: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unsafe URI \"%V\" was detected", uri); + if (*flags & NGX_HTTP_LOG_UNSAFE) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unsafe URI \"%V\" was detected", uri); + } return NGX_ERROR; } diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -8,13 +8,15 @@ #include -static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t ngx_http_parse_time(u_char *value, size_t len) { - u_char *p, *end; - int day, month, year, hour, min, sec; + u_char *p, *end; + ngx_int_t month; + ngx_uint_t day, year, hour, min, sec; + uint64_t time; enum { no = 0, rfc822, /* Tue, 10 Nov 2002 23:50:13 */ @@ -229,14 +231,6 @@ ngx_http_parse_time(u_char *value, size_ return NGX_ERROR; } -#if (NGX_TIME_T_SIZE <= 4) - - if (year >= 2038) { - return NGX_ERROR; - } - -#endif - /* * shift new year to March 1 and start months from 1 (not 0), * it is needed for Gauss' formula @@ -249,7 +243,7 @@ ngx_http_parse_time(u_char *value, size_ /* Gauss' formula for Grigorian days since March 1, 1 BC */ - return ( + time = (uint64_t) ( /* days in years including leap years since March 1, 1 BC */ 365 * year + year / 4 - year / 100 + year / 400 @@ -268,4 +262,14 @@ ngx_http_parse_time(u_char *value, size_ */ - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec; + +#if (NGX_TIME_T_SIZE <= 4) + + if (time > 0x7fffffff) { + return NGX_ERROR; + } + +#endif + + return (time_t) time; } 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 @@ -31,7 +31,8 @@ static ngx_int_t ngx_http_process_cookie static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); static void ngx_http_process_request(ngx_http_request_t *r); -static ssize_t ngx_http_validate_host(u_char *host, size_t len); +static ssize_t ngx_http_validate_host(ngx_http_request_t *r, u_char **host, + size_t len, ngx_uint_t alloc); static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len); @@ -380,7 +381,7 @@ ngx_http_init_request(ngx_event_t *rev) r->virtual_names = addr_conf->virtual_names; /* the default server configuration for the address:port */ - cscf = addr_conf->core_srv_conf; + cscf = addr_conf->default_server; r->main_conf = cscf->ctx->main_conf; r->srv_conf = cscf->ctx->srv_conf; @@ -627,6 +628,7 @@ int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { size_t len; + u_char *host; const char *servername; ngx_connection_t *c; ngx_http_request_t *r; @@ -651,7 +653,15 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * r = c->data; - if (ngx_http_find_virtual_server(r, (u_char *) servername, len) != NGX_OK) { + host = (u_char *) servername; + + len = ngx_http_validate_host(r, &host, len, 1); + + if (len <= 0) { + return SSL_TLSEXT_ERR_NOACK; + } + + if (ngx_http_find_virtual_server(r, host, len) != NGX_OK) { return SSL_TLSEXT_ERR_NOACK; } @@ -670,6 +680,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * static void ngx_http_process_request_line(ngx_event_t *rev) { + u_char *host; ssize_t n; ngx_int_t rc, rv; ngx_connection_t *c; @@ -777,9 +788,11 @@ ngx_http_process_request_line(ngx_event_ p = r->uri.data + r->uri.len - 1; - if (*p == '.') { - - while (--p > r->uri.data && *p == '.') { /* void */ } + if (*p == '.' || *p == ' ') { + + while (--p > r->uri.data && (*p == '.' || *p == ' ')) { + /* void */ + } r->uri.len = p + 1 - r->uri.data; @@ -801,18 +814,25 @@ ngx_http_process_request_line(ngx_event_ "http exten: \"%V\"", &r->exten); if (r->host_start && r->host_end) { - n = ngx_http_validate_host(r->host_start, - r->host_end - r->host_start); - - if (n <= 0) { + + host = r->host_start; + n = ngx_http_validate_host(r, &host, + r->host_end - r->host_start, 0); + + if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent invalid host in request line"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } + if (n < 0) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + r->headers_in.server.len = n; - r->headers_in.server.data = r->host_start; + r->headers_in.server.data = host; } if (r->http_version < NGX_HTTP_VERSION_10) { @@ -936,9 +956,17 @@ ngx_http_process_request_headers(ngx_eve } if (rv == NGX_DECLINED) { - len = r->header_in->end - r->header_name_start; p = r->header_name_start; + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too large request"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; + } + + len = r->header_in->end - p; + if (len > NGX_MAX_ERROR_STR - 300) { len = NGX_MAX_ERROR_STR - 300; p[len++] = '.'; p[len++] = '.'; p[len++] = '.'; @@ -1312,27 +1340,34 @@ static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ssize_t len; + u_char *host; + ssize_t len; if (r->headers_in.host == NULL) { r->headers_in.host = h; } - len = ngx_http_validate_host(h->value.data, h->value.len); - - if (len <= 0) { + host = h->value.data; + len = ngx_http_validate_host(r, &host, h->value.len, 0); + + if (len == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent invalid host header"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } + if (len < 0) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + if (r->headers_in.server.len) { return NGX_OK; } r->headers_in.server.len = len; - r->headers_in.server.data = h->value.data; + r->headers_in.server.data = host; return NGX_OK; } @@ -1412,6 +1447,12 @@ ngx_http_process_user_agent(ngx_http_req if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { r->headers_in.gecko = 1; + } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) { + r->headers_in.chrome = 1; + + } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1)) { + r->headers_in.safari = 1; + } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { r->headers_in.konqueror = 1; } @@ -1588,21 +1629,23 @@ ngx_http_process_request(ngx_http_reques static ssize_t -ngx_http_validate_host(u_char *host, size_t len) +ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len, + ngx_uint_t alloc) { - u_char ch; - size_t i, last; - ngx_uint_t dot; + u_char *h, ch; + size_t i, last; + ngx_uint_t dot; last = len; + h = *host; dot = 0; for (i = 0; i < len; i++) { - ch = host[i]; + ch = h[i]; if (ch == '.') { if (dot) { - return -1; + return 0; } dot = 1; @@ -1617,7 +1660,11 @@ ngx_http_validate_host(u_char *host, siz } if (ngx_path_separator(ch) || ch == '\0') { - return -1; + return 0; + } + + if (ch >= 'A' || ch < 'Z') { + alloc = 1; } } @@ -1625,6 +1672,15 @@ ngx_http_validate_host(u_char *host, siz last--; } + if (alloc) { + *host = ngx_pnalloc(r->pool, last) ; + if (*host == NULL) { + return -1; + } + + ngx_strlow(*host, h, last); + } + return last; } @@ -1632,29 +1688,15 @@ ngx_http_validate_host(u_char *host, siz static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len) { - u_char *server; - ngx_uint_t hash; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - u_char buf[32]; if (r->virtual_names == NULL) { return NGX_DECLINED; } - if (len <= 32) { - server = buf; - - } else { - server = ngx_pnalloc(r->pool, len); - if (server == NULL) { - return NGX_ERROR; - } - } - - hash = ngx_hash_strlow(server, host, len); - - cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len); + cscf = ngx_hash_find_combined(&r->virtual_names->names, + ngx_hash_key(host, len), host, len); if (cscf) { goto found; @@ -1662,64 +1704,31 @@ ngx_http_find_virtual_server(ngx_http_re #if (NGX_PCRE) - if (r->virtual_names->nregex) { - size_t ncaptures; + if (len && r->virtual_names->nregex) { ngx_int_t n; ngx_uint_t i; ngx_str_t name; ngx_http_server_name_t *sn; name.len = len; - name.data = server; - - ncaptures = 0; + name.data = host; sn = r->virtual_names->regex; for (i = 0; i < r->virtual_names->nregex; i++) { - if (sn[i].captures && r->captures == NULL) { - - ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3; - - r->captures = ngx_palloc(r->pool, ncaptures * sizeof(int)); - if (r->captures == NULL) { - return NGX_ERROR; - } - - if (server == buf) { - server = ngx_pnalloc(r->pool, len); - if (server == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(server, buf, len); - name.data = server; - } + n = ngx_http_regex_exec(r, sn[i].regex, &name); + + if (n == NGX_OK) { + cscf = sn[i].server; + goto found; } - n = ngx_regex_exec(sn[i].regex, &name, r->captures, ncaptures); - - if (n == NGX_REGEX_NO_MATCHED) { + if (n == NGX_DECLINED) { continue; } - if (n < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n - " failed: %d on \"%V\" using \"%V\"", - n, &name, &sn[i].name); - return NGX_ERROR; - } - - /* match */ - - cscf = sn[i].core_srv_conf; - - r->ncaptures = ncaptures; - r->captures_data = server; - - goto found; + return NGX_ERROR; } } @@ -1993,6 +2002,7 @@ ngx_http_finalize_request(ngx_http_reque } r->done = 1; + r->write_event_handler = ngx_http_request_empty_handler; if (!r->post_action) { r->request_complete = 1; @@ -2032,6 +2042,10 @@ ngx_http_terminate_request(ngx_http_requ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http terminate request count:%d", mr->count); + if (rc > 0 && (mr->headers_out.status == 0 || mr->connection->sent == 0)) { + mr->headers_out.status = rc; + } + cln = mr->cleanup; mr->cleanup = NULL; @@ -2081,13 +2095,24 @@ ngx_http_finalize_connection(ngx_http_re { ngx_http_core_loc_conf_t *clcf; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (r->main->count != 1) { + + if (r->discard_body) { + r->read_event_handler = ngx_http_discarded_request_body_handler; + + if (r->lingering_time == 0) { + r->lingering_time = ngx_time() + + (time_t) (clcf->lingering_time / 1000); + ngx_add_timer(r->connection->read, clcf->lingering_timeout); + } + } + ngx_http_close_request(r, 0); return; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (!ngx_terminate && !ngx_exiting && r->keepalive @@ -2113,7 +2138,9 @@ ngx_http_set_write_handler(ngx_http_requ r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; - r->read_event_handler = ngx_http_test_reading; + r->read_event_handler = r->discard_body ? + ngx_http_discarded_request_body_handler: + ngx_http_test_reading; r->write_event_handler = ngx_http_writer; wev = r->connection->write; @@ -2215,6 +2242,8 @@ ngx_http_writer(ngx_http_request_t *r) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer done: \"%V?%V\"", &r->uri, &r->args); + r->write_event_handler = ngx_http_request_empty_handler; + ngx_http_finalize_request(r, rc); } @@ -2391,6 +2420,8 @@ ngx_http_set_keepalive(ngx_http_request_ } } + r->keepalive = 0; + ngx_http_free_request(r, 0); c->data = hc; @@ -2820,6 +2851,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; 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 @@ -10,7 +10,6 @@ #define NGX_HTTP_MAX_URI_CHANGES 10 #define NGX_HTTP_MAX_SUBREQUESTS 50 -#define NGX_HTTP_MAX_CAPTURES 9 /* must be 2^n */ #define NGX_HTTP_LC_HEADER_LEN 32 @@ -60,6 +59,7 @@ #define NGX_HTTP_ZERO_IN_URI 1 #define NGX_HTTP_SUBREQUEST_IN_MEMORY 2 #define NGX_HTTP_SUBREQUEST_WAITED 4 +#define NGX_HTTP_LOG_UNSAFE 8 #define NGX_HTTP_OK 200 @@ -219,6 +219,8 @@ typedef struct { unsigned msie6:1; unsigned opera:1; unsigned gecko:1; + unsigned chrome:1; + unsigned safari:1; unsigned konqueror:1; } ngx_http_headers_in_t; @@ -456,7 +458,12 @@ struct ngx_http_request_s { #if (NGX_HTTP_CACHE) unsigned cached:1; #endif - unsigned gzip:2; + +#if (NGX_HTTP_GZIP) + unsigned gzip_tested:1; + unsigned gzip_ok:1; + unsigned gzip_vary:1; +#endif unsigned proxy:1; unsigned bypass_cache:1; 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 @@ -13,7 +13,6 @@ static void ngx_http_read_client_request static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body); -static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); @@ -460,6 +459,7 @@ ngx_http_discard_request_body(ngx_http_r if (size) { if (r->headers_in.content_length_n > size) { + r->header_in->pos += size; r->headers_in.content_length_n -= size; } else { @@ -469,23 +469,26 @@ ngx_http_discard_request_body(ngx_http_r } } - r->discard_body = 1; - - r->read_event_handler = ngx_http_read_discarded_request_body_handler; + r->read_event_handler = ngx_http_discarded_request_body_handler; if (ngx_handle_read_event(rev, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->count++; - (void) ngx_http_read_discarded_request_body(r); + if (ngx_http_read_discarded_request_body(r) == NGX_OK) { + r->lingering_close = 0; + + } else { + r->count++; + r->discard_body = 1; + } return NGX_OK; } -static void -ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r) +void +ngx_http_discarded_request_body_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_msec_t timer; @@ -499,7 +502,7 @@ ngx_http_read_discarded_request_body_han if (rev->timedout) { c->timedout = 1; c->error = 1; - ngx_http_finalize_request(r, 0); + ngx_http_finalize_request(r, NGX_ERROR); return; } @@ -508,7 +511,8 @@ ngx_http_read_discarded_request_body_han if (timer <= 0) { r->discard_body = 0; - ngx_http_finalize_request(r, 0); + r->lingering_close = 0; + ngx_http_finalize_request(r, NGX_ERROR); return; } @@ -519,13 +523,9 @@ ngx_http_read_discarded_request_body_han rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) { - r->discard_body = 0; - - if (r->done) { - ngx_http_finalize_request(r, 0); - } - + r->lingering_close = 0; + ngx_http_finalize_request(r, NGX_DONE); return; } @@ -533,7 +533,7 @@ ngx_http_read_discarded_request_body_han if (ngx_handle_read_event(rev, 0) != NGX_OK) { c->error = 1; - ngx_http_finalize_request(r, rc); + ngx_http_finalize_request(r, NGX_ERROR); return; } @@ -562,12 +562,16 @@ ngx_http_read_discarded_request_body(ngx ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http read discarded body"); - do { + for ( ;; ) { if (r->headers_in.content_length_n == 0) { r->read_event_handler = ngx_http_block_reading; return NGX_OK; } + if (!r->connection->read->ready) { + return NGX_AGAIN; + } + size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ? NGX_HTTP_DISCARD_BUFFER_SIZE: (size_t) r->headers_in.content_length_n; @@ -588,10 +592,7 @@ ngx_http_read_discarded_request_body(ngx } r->headers_in.content_length_n -= n; - - } while (r->connection->read->ready); - - return NGX_AGAIN; + } } 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 @@ -251,8 +251,6 @@ ngx_http_script_compile(ngx_http_script_ { ngx_uint_t n; - /* NGX_HTTP_MAX_CAPTURES is 9 */ - if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { n = sc->source->data[i] - '0'; @@ -828,20 +826,9 @@ ngx_http_script_regex_start_code(ngx_htt e->line.data = e->sp->data; } - if (code->ncaptures && r->captures == NULL) { + rc = ngx_http_regex_exec(r, code->regex, &e->line); - r->captures = ngx_palloc(r->pool, - (NGX_HTTP_MAX_CAPTURES + 1) * 3 * sizeof(int)); - if (r->captures == NULL) { - e->ip = ngx_http_script_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - } - - rc = ngx_regex_exec(code->regex, &e->line, r->captures, code->ncaptures); - - if (rc == NGX_REGEX_NO_MATCHED) { + if (rc == NGX_DECLINED) { if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) { ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "\"%V\" does not match \"%V\"", @@ -870,11 +857,7 @@ ngx_http_script_regex_start_code(ngx_htt return; } - if (rc < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", - rc, &e->line, &code->name); - + if (rc == NGX_ERROR) { e->ip = ngx_http_script_exit; e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; return; @@ -885,9 +868,6 @@ ngx_http_script_regex_start_code(ngx_htt "\"%V\" matches \"%V\"", &code->name, &e->line); } - r->ncaptures = code->ncaptures; - r->captures_data = e->line.data; - if (code->test) { if (code->negative_test) { e->sp->len = 0; @@ -930,14 +910,14 @@ ngx_http_script_regex_start_code(ngx_htt e->buf.len = code->size; if (code->uri) { - if (rc && (r->quoted_uri || r->plus_in_uri)) { + if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) { e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_ARGS); } } - for (n = 1; n < (ngx_uint_t) rc; n++) { - e->buf.len += r->captures[2 * n + 1] - r->captures[2 * n]; + for (n = 2; n < r->ncaptures; n += 2) { + e->buf.len += r->captures[n + 1] - r->captures[n]; } } else { @@ -1407,6 +1387,7 @@ ngx_http_script_file_code(ngx_http_scrip ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; @@ -1417,7 +1398,10 @@ ngx_http_script_file_code(ngx_http_scrip if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { - if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) { + if (of.err != NGX_ENOENT + && of.err != NGX_ENOTDIR + && of.err != NGX_ENAMETOOLONG) + { ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, value->data); } 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 @@ -114,10 +114,9 @@ typedef struct { typedef struct { ngx_http_script_code_pt code; - ngx_regex_t *regex; + ngx_http_regex_t *regex; ngx_array_t *lengths; uintptr_t size; - uintptr_t ncaptures; uintptr_t status; uintptr_t next; 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 @@ -31,13 +31,13 @@ static u_char ngx_http_error_tail[] = ; -static u_char ngx_http_msie_stub[] = -"" CRLF -"" CRLF -"" CRLF -"" CRLF -"" CRLF -"" CRLF +static u_char ngx_http_msie_padding[] = +"" CRLF +"" CRLF +"" CRLF +"" CRLF +"" CRLF +"" CRLF ; @@ -598,12 +598,12 @@ ngx_http_send_special_response(ngx_http_ r->headers_out.content_length_n = ngx_http_error_pages[err].len + len; if (clcf->msie_padding - && r->headers_in.msie + && (r->headers_in.msie || r->headers_in.chrome) && r->http_version >= NGX_HTTP_VERSION_10 && err >= NGX_HTTP_LEVEL_300) { r->headers_out.content_length_n += - sizeof(ngx_http_msie_stub) - 1; + sizeof(ngx_http_msie_padding) - 1; msie_padding = 1; } @@ -671,8 +671,8 @@ ngx_http_send_special_response(ngx_http_ } b->memory = 1; - b->pos = ngx_http_msie_stub; - b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; + b->pos = ngx_http_msie_padding; + b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1; out[1].next = &out[2]; out[2].buf = b; 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 @@ -366,6 +366,7 @@ ngx_http_upstream_create(ngx_http_reques r->main->count++; ngx_http_upstream_cleanup(r); *u->cleanup = NULL; + u->cleanup = NULL; } u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); @@ -479,6 +480,8 @@ ngx_http_upstream_init_request(ngx_http_ return; } + u->peer.local = u->conf->local; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.alignment = clcf->directio_alignment; @@ -532,7 +535,8 @@ ngx_http_upstream_init_request(ngx_http_ if (ngx_http_upstream_create_round_robin_peer(r, u->resolved) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -564,7 +568,8 @@ ngx_http_upstream_init_request(ngx_http_ ctx = ngx_resolve_start(clcf->resolver, &temp); if (ctx == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -572,7 +577,7 @@ ngx_http_upstream_init_request(ngx_http_ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no resolver defined to resolve %V", host); - ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); return; } @@ -586,7 +591,8 @@ ngx_http_upstream_init_request(ngx_http_ if (ngx_resolve_name(ctx) != NGX_OK) { u->resolved->ctx = NULL; - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -596,7 +602,8 @@ ngx_http_upstream_init_request(ngx_http_ found: if (uscf->peer.init(r, uscf) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -746,6 +753,11 @@ ngx_http_upstream_cache_send(ngx_http_re r->cached = 1; c = r->cache; + if (c->header_start == c->body_start) { + r->http_version = NGX_HTTP_VERSION_9; + return ngx_http_cache_send(r); + } + /* TODO: cache stack */ u->buffer = *c->buf; @@ -789,11 +801,13 @@ static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) { ngx_http_request_t *r; + ngx_http_upstream_t *u; ngx_http_upstream_resolved_t *ur; r = ctx->data; - r->upstream->resolved->ctx = NULL; + u = r->upstream; + ur = u->resolved; if (ctx->state) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -801,12 +815,10 @@ ngx_http_upstream_resolve_handler(ngx_re &ctx->name, ctx->state, ngx_resolver_strerror(ctx->state)); - ngx_resolve_name_done(ctx); - ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); return; } - ur = r->upstream->resolved; ur->naddrs = ctx->naddrs; ur->addrs = ctx->addrs; @@ -827,14 +839,15 @@ ngx_http_upstream_resolve_handler(ngx_re #endif if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) { - ngx_resolve_name_done(ctx); - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_resolve_name_done(ctx); - - ngx_http_upstream_connect(r, r->upstream); + ur->ctx = NULL; + + ngx_http_upstream_connect(r, u); } @@ -921,10 +934,6 @@ ngx_http_upstream_check_broken_connectio return; } - if (u->peer.connection == NULL) { - return; - } - #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -956,7 +965,6 @@ ngx_http_upstream_check_broken_connectio if (u->peer.connection == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; } return; @@ -1019,7 +1027,6 @@ ngx_http_upstream_check_broken_connectio if (u->peer.connection == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; } } @@ -1542,7 +1549,7 @@ ngx_http_upstream_process_header(ngx_htt /* rc == NGX_OK */ - if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST) { + if (u->headers_in.status_n > NGX_HTTP_SPECIAL_RESPONSE) { if (r->subrequest_in_memory) { u->buffer.last = u->buffer.pos; @@ -1797,7 +1804,7 @@ ngx_http_upstream_process_headers(ngx_ht uri = &u->headers_in.x_accel_redirect->value; args.len = 0; args.data = NULL; - flags = 0; + flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); @@ -2099,11 +2106,6 @@ ngx_http_upstream_send_response(ngx_http r->cache->date = now; r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start); - if (r->headers_out.content_length_n != -1) { - r->cache->length = r->cache->body_start - + r->headers_out.content_length_n; - } - ngx_http_file_cache_set_header(r, u->buffer.start); } else { @@ -2837,6 +2839,7 @@ ngx_http_upstream_cleanup(void *data) if (u->resolved && u->resolved->ctx) { ngx_resolve_name_done(u->resolved->ctx); + u->resolved->ctx = NULL; } ngx_http_upstream_finalize_request(r, u, NGX_DONE); @@ -2854,6 +2857,12 @@ ngx_http_upstream_finalize_request(ngx_h if (u->cleanup) { *u->cleanup = NULL; + u->cleanup = NULL; + } + + if (u->resolved && u->resolved->ctx) { + ngx_resolve_name_done(u->resolved->ctx); + u->resolved->ctx = NULL; } if (u->state && u->state->response_sec) { @@ -3035,7 +3044,7 @@ ngx_http_upstream_process_cache_control( n = 0; for (p += 8; p < last; p++) { - if (*p == ';' || *p == ' ') { + if (*p == ',' || *p == ';' || *p == ' ') { break; } @@ -4196,6 +4205,41 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng } +char * +ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_int_t rc; + ngx_str_t *value; + ngx_addr_t **paddr; + + paddr = (ngx_addr_t **) (p + cmd->offset); + + *paddr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); + if (*paddr == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + rc = ngx_parse_addr(cf->pool, *paddr, value[1].data, value[1].len); + + switch (rc) { + case NGX_OK: + (*paddr)->name = value[1]; + return NGX_CONF_OK; + + case NGX_DECLINED: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid address \"%V\"", &value[1]); + default: + return NGX_CONF_ERROR; + } +} + + ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, 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 @@ -80,7 +80,7 @@ typedef struct { typedef struct { - ngx_peer_addr_t *addrs; + ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; ngx_uint_t max_fails; @@ -152,6 +152,8 @@ typedef struct { ngx_array_t *hide_headers; ngx_array_t *pass_headers; + ngx_addr_t *local; + #if (NGX_HTTP_CACHE) ngx_shm_zone_t *cache; @@ -321,6 +323,8 @@ ngx_int_t ngx_http_upstream_create(ngx_h void ngx_http_upstream_init(ngx_http_request_t *r); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); +char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, ngx_str_t *default_hide_headers, ngx_hash_init_t *hash); @@ -334,5 +338,4 @@ extern ngx_module_t ngx_http_upst extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[]; - #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -81,5 +81,4 @@ void ngx_http_upstream_save_round_robin_ #endif - #endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_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 @@ -14,6 +14,8 @@ static ngx_int_t ngx_http_variable_reque ngx_http_variable_value_t *v, uintptr_t data); static void ngx_http_variable_request_set(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, @@ -25,6 +27,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, @@ -164,8 +168,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 }, @@ -193,7 +196,8 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 }, { ngx_string("request_method"), NULL, - ngx_http_variable_request_method, 0, 0, 0 }, + ngx_http_variable_request_method, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 }, @@ -237,7 +241,7 @@ static ngx_http_variable_t ngx_http_cor offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 }, { ngx_string("limit_rate"), ngx_http_variable_request_set_size, - ngx_http_variable_request, + ngx_http_variable_request_get_size, offsetof(ngx_http_request_t, limit_rate), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -491,7 +495,7 @@ ngx_http_get_variable(ngx_http_request_t return NULL; } - if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) { + if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) { if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) == NGX_OK) @@ -567,6 +571,28 @@ ngx_http_variable_request_set(ngx_http_r } +static ngx_int_t +ngx_http_variable_request_get_size(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + size_t *sp; + + sp = (size_t *) ((char *) r + data); + + v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -751,6 +777,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) { @@ -850,7 +912,7 @@ ngx_http_variable_binary_remote_addr(ngx v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = (u_char *) &sin6->sin6_addr; + v->data = sin6->sin6_addr.s6_addr; break; #endif @@ -1605,6 +1667,161 @@ ngx_http_variable_pid(ngx_http_request_t } +#if (NGX_PCRE) + +static ngx_int_t +ngx_http_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + v->not_found = 1; + return NGX_OK; +} + + +ngx_http_regex_t * +ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) +{ + u_char *p; + size_t size; + ngx_str_t name; + ngx_uint_t i, n; + ngx_http_variable_t *v; + ngx_http_regex_t *re; + ngx_http_regex_variable_t *rv; + ngx_http_core_main_conf_t *cmcf; + + rc->pool = cf->pool; + + if (ngx_regex_compile(rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err); + return NULL; + } + + re = ngx_pcalloc(cf->pool, sizeof(ngx_http_regex_t)); + if (re == NULL) { + return NULL; + } + + re->regex = rc->regex; + re->ncaptures = rc->captures; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures); + + n = (ngx_uint_t) rc->named_captures; + + if (n == 0) { + return re; + } + + rv = ngx_palloc(rc->pool, n * sizeof(ngx_http_regex_variable_t)); + if (rv == NULL) { + return NULL; + } + + re->variables = rv; + re->nvariables = n; + re->name = rc->pattern; + + size = rc->name_size; + p = rc->names; + + for (i = 0; i < n; i++) { + rv[i].capture = 2 * ((p[0] << 8) + p[1]); + + name.data = &p[2]; + name.len = ngx_strlen(name.data); + + v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); + if (v == NULL) { + return NULL; + } + + rv[i].index = ngx_http_get_variable_index(cf, &name); + if (rv[i].index == NGX_ERROR) { + return NULL; + } + + v->get_handler = ngx_http_variable_not_found; + + p += size; + } + + return re; +} + + +ngx_int_t +ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s) +{ + ngx_int_t rc, index; + ngx_uint_t i, n, len; + ngx_http_variable_value_t *vv; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + if (re->ncaptures) { + len = cmcf->ncaptures; + + if (r->captures == NULL) { + r->captures = ngx_palloc(r->pool, len * sizeof(int)); + if (r->captures == NULL) { + return NGX_ERROR; + } + } + + } else { + len = 0; + } + + rc = ngx_regex_exec(re->regex, s, r->captures, len); + + if (rc == NGX_REGEX_NO_MATCHED) { + return NGX_DECLINED; + } + + if (rc < 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", + rc, s, &re->name); + return NGX_ERROR; + } + + for (i = 0; i < re->nvariables; i++) { + + n = re->variables[i].capture; + index = re->variables[i].index; + vv = &r->variables[index]; + + vv->len = r->captures[n + 1] - r->captures[n]; + vv->valid = 1; + vv->no_cacheable = 0; + vv->not_found = 0; + vv->data = &s->data[r->captures[n]]; + +#if (NGX_DEBUG) + { + ngx_http_variable_t *v; + + v = cmcf->variables.elts; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http regex set $%V to \"%*s\"", + &v[index].name, vv->len, vv->data); + } +#endif + } + + r->ncaptures = rc * 2; + r->captures_data = s->data; + + return NGX_OK; +} + +#endif + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -59,6 +59,31 @@ ngx_int_t ngx_http_variable_unknown_head #define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL; +#if (NGX_PCRE) + +typedef struct { + ngx_uint_t capture; + ngx_int_t index; +} ngx_http_regex_variable_t; + + +typedef struct { + ngx_regex_t *regex; + ngx_uint_t ncaptures; + ngx_http_regex_variable_t *variables; + ngx_uint_t nvariables; + ngx_str_t name; +} ngx_http_regex_t; + + +ngx_http_regex_t *ngx_http_regex_compile(ngx_conf_t *cf, + ngx_regex_compile_t *rc); +ngx_int_t ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, + ngx_str_t *s); + +#endif + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf); ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf); 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 @@ -394,7 +394,7 @@ char *ngx_mail_capabilities(ngx_conf_t * /* STUB */ -void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer); +void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer); void ngx_mail_auth_http_init(ngx_mail_session_t *s); /**/ 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 @@ -12,7 +12,7 @@ typedef struct { - ngx_peer_addr_t *peer; + ngx_addr_t *peer; ngx_msec_t timeout; @@ -457,7 +457,7 @@ ngx_mail_auth_http_process_headers(ngx_m time_t timer; size_t len, size; ngx_int_t rc, port, n; - ngx_peer_addr_t *peer; + ngx_addr_t *peer; struct sockaddr_in *sin; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, @@ -764,7 +764,7 @@ ngx_mail_auth_http_process_headers(ngx_m return; } - peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t)); + peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t)); if (peer == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); @@ -795,8 +795,7 @@ ngx_mail_auth_http_process_headers(ngx_m sin->sin_port = htons((in_port_t) port); - ctx->addr.data[ctx->addr.len] = '\0'; - sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data); + sin->sin_addr.s_addr = ngx_inet_addr(ctx->addr.data, ctx->addr.len); if (sin->sin_addr.s_addr == INADDR_NONE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " @@ -1406,7 +1405,14 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c ahcf->peer = u.addrs; - ahcf->host_header = u.host; + if (u.family != AF_UNIX) { + ahcf->host_header = u.host; + + } else { + ahcf->host_header.len = sizeof("localhost") - 1; + ahcf->host_header.data = (u_char *) "localhost"; + } + ahcf->uri = u.uri; if (ahcf->uri.len == 0) { diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -188,7 +188,6 @@ ngx_mail_pop3_auth_state(ngx_event_t *re default: rc = NGX_MAIL_PARSE_INVALID_COMMAND; - s->mail_state = ngx_pop3_start; break; } @@ -215,7 +214,6 @@ ngx_mail_pop3_auth_state(ngx_event_t *re default: rc = NGX_MAIL_PARSE_INVALID_COMMAND; - s->mail_state = ngx_pop3_start; break; } 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 @@ -108,7 +108,7 @@ static u_char smtp_auth_ok[] = "235 2.0 void -ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer) +ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) { int keepalive; ngx_int_t rc; 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 @@ -191,7 +191,7 @@ ngx_mail_smtp_resolve_name_handler(ngx_r if (ctx->state) { ngx_log_error(NGX_LOG_ERR, c->log, 0, - "%V could not be resolved (%i: %s)", + "\"%V\" could not be resolved (%i: %s)", &ctx->name, ctx->state, ngx_resolver_strerror(ctx->state)); diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -9,7 +9,7 @@ #include -#define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" +#define NGX_DEFAULT_CIPHERS "HIGH:!ADH:!MD5" static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); @@ -198,8 +198,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET - |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); + (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); diff --git a/src/os/unix/ngx_alloc.c b/src/os/unix/ngx_alloc.c --- a/src/os/unix/ngx_alloc.c +++ b/src/os/unix/ngx_alloc.c @@ -21,7 +21,7 @@ ngx_alloc(size_t size, ngx_log_t *log) p = malloc(size); if (p == NULL) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - "malloc() %uz bytes failed", size); + "malloc(%uz) failed", size); } ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size); @@ -51,15 +51,18 @@ void * ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) { void *p; + int err; - if (posix_memalign(&p, alignment, size) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - "posix_memalign() %uz bytes aligned to %uz failed", - size, alignment); + err = posix_memalign(&p, alignment, size); + + if (err) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "posix_memalign(%uz, %uz) failed", alignment, size); + p = NULL; } - ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, - "posix_memalign: %p:%uz", p, size); + ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0, + "posix_memalign: %p:%uz @%uz", p, size, alignment); return p; } @@ -74,12 +77,11 @@ ngx_memalign(size_t alignment, size_t si p = memalign(alignment, size); if (p == NULL) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - "memalign() %uz bytes aligned to %uz failed", - size, alignment); + "memalign(%uz, %uz) failed", alignment, size); } - ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, - "memalign: %p:%uz", p, size); + ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0, + "memalign: %p:%uz @%uz", p, size, alignment); return p; } diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -12,7 +12,32 @@ #include -#if (NGX_DARWIN_ATOMIC) +#if (NGX_HAVE_LIBATOMIC) + +#define AO_REQUIRE_CAS +#include + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef AO_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +#define ngx_atomic_cmp_set(lock, old, new) \ + AO_compare_and_swap(lock, old, new) +#define ngx_atomic_fetch_add(value, add) \ + AO_fetch_and_add(value, add) +#define ngx_memory_barrier() AO_nop() +#define ngx_cpu_pause() + + +#elif (NGX_DARWIN_ATOMIC) /* * use Darwin 8 atomic(3) and barrier(3) operations @@ -31,7 +56,7 @@ typedef int64_t ngx_atomic_int_t; typedef uint64_t ngx_atomic_uint_t; -#define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) #define ngx_atomic_cmp_set(lock, old, new) \ OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock) @@ -43,7 +68,7 @@ typedef uint64_t ngx_ typedef int32_t ngx_atomic_int_t; typedef uint32_t ngx_atomic_uint_t; -#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) #define ngx_atomic_cmp_set(lock, old, new) \ OSAtomicCompareAndSwap32Barrier(old, new, (int32_t *) lock) @@ -60,15 +85,45 @@ typedef uint32_t ngx_ typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#else /* !(NGX_DARWIN) */ +#elif (NGX_HAVE_GCC_ATOMIC) + +/* GCC 4.1 builtin atomic operations */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef unsigned long ngx_atomic_uint_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#if ( __i386__ || __i386 ) +#define ngx_atomic_cmp_set(lock, old, set) \ + __sync_bool_compare_and_swap(lock, old, set) + +#define ngx_atomic_fetch_add(value, add) \ + __sync_fetch_and_add(value, add) + +#define ngx_memory_barrier() __sync_synchronize() + +#if ( __i386__ || __i386 || __amd64__ || __amd64 ) +#define ngx_cpu_pause() __asm__ ("pause") +#else +#define ngx_cpu_pause() +#endif + + +#elif ( __i386__ || __i386 ) typedef int32_t ngx_atomic_int_t; typedef uint32_t ngx_atomic_uint_t; typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) #if ( __SUNPRO_C ) @@ -109,7 +164,7 @@ ngx_cpu_pause(void); typedef int64_t ngx_atomic_int_t; typedef uint64_t ngx_atomic_uint_t; typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) #if ( __SUNPRO_C ) @@ -151,13 +206,13 @@ ngx_cpu_pause(void); typedef int64_t ngx_atomic_int_t; typedef uint64_t ngx_atomic_uint_t; -#define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) #else typedef int32_t ngx_atomic_int_t; typedef uint32_t ngx_atomic_uint_t; -#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) #endif @@ -188,13 +243,13 @@ typedef volatile ngx_atomic_uint_t ngx_ typedef int64_t ngx_atomic_int_t; typedef uint64_t ngx_atomic_uint_t; -#define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) #else typedef int32_t ngx_atomic_int_t; typedef uint32_t ngx_atomic_uint_t; -#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) #endif @@ -203,9 +258,6 @@ typedef volatile ngx_atomic_uint_t ngx_ #include "ngx_gcc_atomic_ppc.h" - -#endif - #endif @@ -216,7 +268,7 @@ typedef volatile ngx_atomic_uint_t ngx_ typedef int32_t ngx_atomic_int_t; typedef uint32_t ngx_atomic_uint_t; typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) static ngx_inline ngx_atomic_uint_t diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -36,7 +36,18 @@ ngx_write_channel(ngx_socket_t s, ngx_ch cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.cm.cmsg_level = SOL_SOCKET; cmsg.cm.cmsg_type = SCM_RIGHTS; - *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; + + /* + * We have to use ngx_memcpy() instead of simple + * *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; + * because some gcc 4.4 with -O2/3/s optimization issues the warning: + * dereferencing type-punned pointer will break strict-aliasing rules + * + * Fortunately, gcc with -O1 compiles this ngx_memcpy() + * in the same simple assigment as in the code above + */ + + ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int)); } msg.msg_flags = 0; @@ -153,7 +164,9 @@ ngx_read_channel(ngx_socket_t s, ngx_cha return NGX_ERROR; } - ch->fd = *(int *) CMSG_DATA(&cmsg.cm); + /* ch->fd = *(int *) CMSG_DATA(&cmsg.cm); */ + + ngx_memcpy(&ch->fd, CMSG_DATA(&cmsg.cm), sizeof(int)); } if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c --- a/src/os/unix/ngx_file_aio_read.c +++ b/src/os/unix/ngx_file_aio_read.c @@ -39,12 +39,11 @@ ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) { - int n; - ngx_event_t *ev; - ngx_event_aio_t *aio; - static ngx_uint_t enosys = 0; + int n; + ngx_event_t *ev; + ngx_event_aio_t *aio; - if (enosys) { + if (!ngx_file_aio) { return ngx_read_file(file, buf, size, offset); } @@ -116,7 +115,7 @@ ngx_file_aio_read(ngx_file_t *file, u_ch "aio_read(\"%V\") failed", &file->name); if (n == NGX_ENOSYS) { - enosys = 1; + ngx_file_aio = 0; return ngx_read_file(file, buf, size, offset); } diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -8,6 +8,13 @@ #include +#if (NGX_HAVE_FILE_AIO) + +ngx_uint_t ngx_file_aio = 1; + +#endif + + ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { @@ -22,7 +29,7 @@ ngx_read_file(ngx_file_t *file, u_char * if (n == -1) { ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, - "pread() failed, file \"%s\"", file->name.data); + "pread() \"%s\" failed", file->name.data); return NGX_ERROR; } @@ -30,7 +37,8 @@ ngx_read_file(ngx_file_t *file, u_char * if (file->sys_offset != offset) { if (lseek(file->fd, offset, SEEK_SET) == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed"); + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "lseek() \"%s\" failed", file->name.data); return NGX_ERROR; } @@ -40,7 +48,8 @@ ngx_read_file(ngx_file_t *file, u_char * n = read(file->fd, buf, size); if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "read() failed"); + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "read() \"%s\" failed", file->name.data); return NGX_ERROR; } @@ -57,57 +66,66 @@ ngx_read_file(ngx_file_t *file, u_char * ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { - ssize_t n; + ssize_t n, written; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "write: %d, %p, %uz, %O", file->fd, buf, size, offset); + written = 0; + #if (NGX_HAVE_PWRITE) - n = pwrite(file->fd, buf, size, offset); + for ( ;; ) { + n = pwrite(file->fd, buf, size, offset); + + if (n == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "pwrite() \"%s\" failed", file->name.data); + return NGX_ERROR; + } - if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pwrite() failed"); - return NGX_ERROR; - } + file->offset += n; + written += n; - if ((size_t) n != size) { - ngx_log_error(NGX_LOG_CRIT, file->log, 0, - "pwrite() has written only %z of %uz", n, size); - return NGX_ERROR; + if ((size_t) n == size) { + return written; + } + + offset += n; + size -= n; } #else if (file->sys_offset != offset) { if (lseek(file->fd, offset, SEEK_SET) == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed"); + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "lseek() \"%s\" failed", file->name.data); return NGX_ERROR; } file->sys_offset = offset; } - n = write(file->fd, buf, size); + for ( ;; ) { + n = write(file->fd, buf, size); - if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "write() failed"); - return NGX_ERROR; - } + if (n == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "write() \"%s\" failed", file->name.data); + return NGX_ERROR; + } - if ((size_t) n != size) { - ngx_log_error(NGX_LOG_CRIT, file->log, 0, - "write() has written only %z of %uz", n, size); - return NGX_ERROR; - } + file->offset += n; + written += n; - file->sys_offset += n; - -#endif + if ((size_t) n == size) { + return written; + } - file->offset += n; - - return n; + size -= n; + } +#endif } @@ -191,7 +209,7 @@ ngx_write_chain_to_file(ngx_file_t *file if (file->sys_offset != offset) { if (lseek(file->fd, offset, SEEK_SET) == -1) { ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, - "lseek() failed"); + "lseek() \"%s\" failed", file->name.data); return NGX_ERROR; } @@ -202,13 +220,14 @@ ngx_write_chain_to_file(ngx_file_t *file if (n == -1) { ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, - "writev() failed"); + "writev() \"%s\" failed", file->name.data); return NGX_ERROR; } if ((size_t) n != size) { ngx_log_error(NGX_LOG_CRIT, file->log, 0, - "writev() has written only %z of %uz", n, size); + "writev() \"%s\" has written only %z of %uz", + file->name.data, n, size); return NGX_ERROR; } @@ -262,9 +281,8 @@ ngx_read_dir(ngx_dir_t *dir) if (dir->de) { #if (NGX_HAVE_D_TYPE) dir->type = dir->de->d_type; - dir->valid_type = dir->type ? 1 : 0; #else - dir->valid_type = 0; + dir->type = 0; #endif return NGX_OK; } @@ -384,6 +402,26 @@ ngx_unlock_fd(ngx_fd_t fd) } +#if (NGX_HAVE_POSIX_FADVISE) + +ngx_int_t +ngx_read_ahead(ngx_fd_t fd, size_t n) +{ + int err; + + err = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); + + if (err == 0) { + return 0; + } + + ngx_set_errno(err); + return NGX_FILE_ERROR; +} + +#endif + + #if (NGX_HAVE_O_DIRECT) ngx_int_t @@ -394,7 +432,7 @@ ngx_directio_on(ngx_fd_t fd) flags = fcntl(fd, F_GETFL); if (flags == -1) { - return -1; + return NGX_FILE_ERROR; } return fcntl(fd, F_SETFL, flags | O_DIRECT); @@ -409,7 +447,7 @@ ngx_directio_off(ngx_fd_t fd) flags = fcntl(fd, F_GETFL); if (flags == -1) { - return -1; + return NGX_FILE_ERROR; } return fcntl(fd, F_SETFL, flags & ~O_DIRECT); 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 @@ -24,7 +24,6 @@ typedef struct { unsigned type:8; unsigned valid_info:1; - unsigned valid_type:1; } ngx_dir_t; @@ -142,7 +141,7 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_is_dir(sb) (S_ISDIR((sb)->st_mode)) #define ngx_is_file(sb) (S_ISREG((sb)->st_mode)) #define ngx_is_link(sb) (S_ISLNK((sb)->st_mode)) -#define ngx_is_exec(sb) ((sb)->st_mode & S_IXUSR) +#define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) #define ngx_file_access(sb) ((sb)->st_mode & 0777) #define ngx_file_size(sb) (sb)->st_size #define ngx_file_mtime(sb) (sb)->st_mtime @@ -200,31 +199,31 @@ ngx_int_t ngx_read_dir(ngx_dir_t *dir); #else #define ngx_de_namelen(dir) ngx_strlen((dir)->de->d_name) #endif -#define ngx_de_info(name, dir) stat((const char *) name, &(dir)->info) + +static ngx_inline ngx_int_t +ngx_de_info(u_char *name, ngx_dir_t *dir) +{ + dir->type = 0; + return stat((const char *) name, &dir->info); +} + #define ngx_de_info_n "stat()" #define ngx_de_link_info(name, dir) lstat((const char *) name, &(dir)->info) #define ngx_de_link_info_n "lstat()" #if (NGX_HAVE_D_TYPE) -#if (NGX_LINUX) - -/* XFS on Linux does not set dirent.d_type */ +/* + * some file systems (e.g. XFS on Linux and CD9660 on FreeBSD) + * do not set dirent.d_type + */ #define ngx_de_is_dir(dir) \ (((dir)->type) ? ((dir)->type == DT_DIR) : (S_ISDIR((dir)->info.st_mode))) #define ngx_de_is_file(dir) \ (((dir)->type) ? ((dir)->type == DT_REG) : (S_ISREG((dir)->info.st_mode))) #define ngx_de_is_link(dir) \ - (((dir)->type) ? ((dir)->type == DT_LINK) : (S_ISLNK((dir)->info.st_mode))) - -#else - -#define ngx_de_is_dir(dir) ((dir)->type == DT_DIR) -#define ngx_de_is_file(dir) ((dir)->type == DT_REG) -#define ngx_de_is_link(dir) ((dir)->type == DT_LINK) - -#endif /* NGX_LINUX */ + (((dir)->type) ? ((dir)->type == DT_LNK) : (S_ISLNK((dir)->info.st_mode))) #else @@ -254,6 +253,28 @@ ngx_err_t ngx_unlock_fd(ngx_fd_t fd); #define ngx_unlock_fd_n "fcntl(F_SETLK, F_UNLCK)" +#if (NGX_HAVE_F_READAHEAD) + +#define NGX_HAVE_READ_AHEAD 1 + +#define ngx_read_ahead(fd, n) fcntl(fd, F_READAHEAD, (int) n) +#define ngx_read_ahead_n "fcntl(fd, F_READAHEAD)" + +#elif (NGX_HAVE_POSIX_FADVISE) + +#define NGX_HAVE_READ_AHEAD 1 + +ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n); +#define ngx_read_ahead_n "posix_fadvise(POSIX_FADV_SEQUENTIAL)" + +#else + +#define ngx_read_ahead(fd, n) 0 +#define ngx_read_ahead_n "ngx_read_ahead_n" + +#endif + + #if (NGX_HAVE_O_DIRECT) ngx_int_t ngx_directio_on(ngx_fd_t fd); @@ -292,6 +313,8 @@ size_t ngx_fs_bsize(u_char *name); ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); +extern ngx_uint_t ngx_file_aio; + #endif diff --git a/src/os/unix/ngx_freebsd_rfork_thread.h b/src/os/unix/ngx_freebsd_rfork_thread.h --- a/src/os/unix/ngx_freebsd_rfork_thread.h +++ b/src/os/unix/ngx_freebsd_rfork_thread.h @@ -118,5 +118,4 @@ void ngx_mutex_unlock(ngx_mutex_t *m); typedef int (*ngx_rfork_thread_func_pt)(void *arg); - #endif /* _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_gcc_atomic_x86.h b/src/os/unix/ngx_gcc_atomic_x86.h --- a/src/os/unix/ngx_gcc_atomic_x86.h +++ b/src/os/unix/ngx_gcc_atomic_x86.h @@ -122,5 +122,5 @@ ngx_atomic_fetch_add(ngx_atomic_t *value #define ngx_memory_barrier() __asm__ volatile ("" ::: "memory") -/* old as does not support "pause" opcode */ +/* old "as" does not support "pause" opcode */ #define ngx_cpu_pause() __asm__ (".byte 0xf3, 0x90") diff --git a/src/os/unix/ngx_linux_aio_read.c b/src/os/unix/ngx_linux_aio_read.c --- a/src/os/unix/ngx_linux_aio_read.c +++ b/src/os/unix/ngx_linux_aio_read.c @@ -27,13 +27,12 @@ ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) { - long n; - struct iocb *piocb[1]; - ngx_event_t *ev; - ngx_event_aio_t *aio; - static ngx_uint_t enosys = 0; + long n; + struct iocb *piocb[1]; + ngx_event_t *ev; + ngx_event_aio_t *aio; - if (enosys) { + if (!ngx_file_aio) { return ngx_read_file(file, buf, size, offset); } @@ -109,7 +108,7 @@ ngx_file_aio_read(ngx_file_t *file, u_ch "io_submit(\"%V\") failed", &file->name); if (n == NGX_ENOSYS) { - enosys = 1; + ngx_file_aio = 0; return ngx_read_file(file, buf, size, offset); } diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -44,8 +44,6 @@ ngx_os_init(ngx_log_t *log) ngx_pagesize = getpagesize(); ngx_cacheline_size = NGX_CPU_CACHE_LINE; - n = ngx_pagesize; - for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ } if (ngx_ncpu == 0) { 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 @@ -388,6 +388,7 @@ ngx_signal_handler(int signo) break; case NGX_PROCESS_WORKER: + case NGX_PROCESS_HELPER: switch (signo) { case ngx_signal_value(NGX_NOACCEPT_SIGNAL): 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 @@ -86,7 +86,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy u_char *p; size_t size; ngx_int_t i; - ngx_uint_t n; + ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; @@ -139,11 +139,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_new_binary = 0; delay = 0; + sigio = 0; live = 1; for ( ;; ) { if (delay) { if (ngx_sigalrm) { + sigio = 0; delay *= 2; ngx_sigalrm = 0; } @@ -168,7 +170,8 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_time_update(0, 0); - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up"); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "wake up, sigio %i", sigio); if (ngx_reap) { ngx_reap = 0; @@ -186,6 +189,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy delay = 50; } + if (sigio) { + sigio--; + continue; + } + + sigio = ccf->worker_processes + 2 /* cache processes */; + if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { @@ -675,6 +685,8 @@ ngx_master_process_exit(ngx_cycle_t *cyc } } + ngx_close_listening_sockets(cycle); + /* * Copy ngx_cycle->log related data to the special static exit cycle, * log, and log file structures enough to allow a signal handler to log. @@ -702,6 +714,8 @@ ngx_worker_process_cycle(ngx_cycle_t *cy ngx_uint_t i; ngx_connection_t *c; + ngx_process = NGX_PROCESS_WORKER; + ngx_worker_process_init(cycle, 1); ngx_setproctitle("worker process"); @@ -817,8 +831,6 @@ ngx_worker_process_init(ngx_cycle_t *cyc ngx_core_conf_t *ccf; ngx_listening_t *ls; - ngx_process = NGX_PROCESS_WORKER; - if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); @@ -1277,6 +1289,8 @@ ngx_cache_manager_process_cycle(ngx_cycl cycle->connection_n = 512; + ngx_process = NGX_PROCESS_HELPER; + ngx_worker_process_init(cycle, 0); ngx_close_listening_sockets(cycle); 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 @@ -21,8 +21,9 @@ #define NGX_PROCESS_SINGLE 0 #define NGX_PROCESS_MASTER 1 -#define NGX_PROCESS_WORKER 2 -#define NGX_PROCESS_SIGNALLER 3 +#define NGX_PROCESS_SIGNALLER 2 +#define NGX_PROCESS_WORKER 3 +#define NGX_PROCESS_HELPER 4 typedef struct { diff --git a/src/os/unix/ngx_setproctitle.h b/src/os/unix/ngx_setproctitle.h --- a/src/os/unix/ngx_setproctitle.h +++ b/src/os/unix/ngx_setproctitle.h @@ -13,7 +13,7 @@ /* FreeBSD, NetBSD, OpenBSD */ #define ngx_init_setproctitle(log) -#define ngx_setproctitle setproctitle +#define ngx_setproctitle(title) setproctitle("%s", title) #else /* !NGX_HAVE_SETPROCTITLE */ diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h --- a/src/os/unix/ngx_thread.h +++ b/src/os/unix/ngx_thread.h @@ -124,5 +124,4 @@ ngx_int_t ngx_cond_signal(ngx_cond_t *cv #endif - #endif /* _NGX_THREAD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_user.h b/src/os/unix/ngx_user.h --- a/src/os/unix/ngx_user.h +++ b/src/os/unix/ngx_user.h @@ -20,5 +20,4 @@ ngx_int_t ngx_crypt(ngx_pool_t *pool, u_ u_char **encrypted); - #endif /* _NGX_USER_H_INCLUDED_ */