diff options
author | 2014-06-12 15:27:08 +0000 | |
---|---|---|
committer | 2014-06-12 15:27:08 +0000 | |
commit | 48c5ce6cae7e303dfeee3a51091514ba4307bd3d (patch) | |
tree | 2c947b91869e053e1c22daedc8be6fc26be784d6 | |
parent | Disable the "switch to insertion sort" optimization to avoid quadratic (diff) | |
download | wireguard-openbsd-48c5ce6cae7e303dfeee3a51091514ba4307bd3d.tar.xz wireguard-openbsd-48c5ce6cae7e303dfeee3a51091514ba4307bd3d.zip |
update to 1.6.0 with official syslog support backported from the 1.7 branch
tested by several, ok sthen@
167 files changed, 8479 insertions, 2736 deletions
diff --git a/usr.sbin/nginx/CHANGES b/usr.sbin/nginx/CHANGES index 4d9e62aa65b..1b502bf91c4 100644 --- a/usr.sbin/nginx/CHANGES +++ b/usr.sbin/nginx/CHANGES @@ -1,5 +1,37 @@ -Changes with nginx 1.4.7 18 Mar 2014 +Changes with nginx 1.6.0 24 Apr 2014 + + *) 1.6.x stable branch. + + +Changes with nginx 1.5.13 08 Apr 2014 + + *) Change: improved hash table handling; the default values of the + "variables_hash_max_size" and "types_hash_bucket_size" were changed + to 1024 and 64 respectively. + + *) Feature: the ngx_http_mp4_module now supports the "end" argument. + + *) Feature: byte ranges support in the ngx_http_mp4_module and while + saving responses to cache. + + *) Bugfix: alerts "ngx_slab_alloc() failed: no memory" no longer logged + when using shared memory in the "ssl_session_cache" directive and in + the ngx_http_limit_req_module. + + *) Bugfix: the "underscores_in_headers" directive did not allow + underscore as a first character of a header. + Thanks to Piotr Sikora. + + *) Bugfix: cache manager might hog CPU on exit in nginx/Windows. + + *) Bugfix: nginx/Windows terminated abnormally if the + "ssl_session_cache" directive was used with the "shared" parameter. + + *) Bugfix: in the ngx_http_spdy_module. + + +Changes with nginx 1.5.12 18 Mar 2014 *) Security: a heap memory buffer overflow might occur in a worker process while handling a specially crafted request by @@ -8,11 +40,23 @@ Changes with nginx 1.4.7 18 Mar 2014 Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr. Manuel Sadosky, Buenos Aires, Argentina. + *) Feature: the "proxy_protocol" parameters of the "listen" and + "real_ip_header" directives, the $proxy_protocol_addr variable. + *) Bugfix: in the "fastcgi_next_upstream" directive. Thanks to Lucas Molas. -Changes with nginx 1.4.6 04 Mar 2014 +Changes with nginx 1.5.11 04 Mar 2014 + + *) Security: memory corruption might occur in a worker process on 32-bit + platforms while handling a specially crafted request by + ngx_http_spdy_module, potentially resulting in arbitrary code + execution (CVE-2014-0088); the bug had appeared in 1.5.10. + Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr. + Manuel Sadosky, Buenos Aires, Argentina. + + *) Feature: the $ssl_session_reused variable. *) Bugfix: the "client_max_body_size" directive might not work when reading a request body using chunked transfer encoding; the bug had @@ -22,15 +66,71 @@ Changes with nginx 1.4.6 04 Mar 2014 *) Bugfix: a segmentation fault might occur in a worker process when proxying WebSocket connections. + *) Bugfix: a segmentation fault might occur in a worker process if the + ngx_http_spdy_module was used on 32-bit platforms; the bug had + appeared in 1.5.10. + + *) Bugfix: the $upstream_status variable might contain wrong data if the + "proxy_cache_use_stale" or "proxy_cache_revalidate" directives were + used. + Thanks to Piotr Sikora. + + *) Bugfix: a segmentation fault might occur in a worker process if + errors with code 400 were redirected to a named location using the + "error_page" directive. + + *) Bugfix: nginx/Windows could not be built with Visual Studio 2013. + + +Changes with nginx 1.5.10 04 Feb 2014 + + *) Feature: the ngx_http_spdy_module now uses SPDY 3.1 protocol. + Thanks to Automattic and MaxCDN for sponsoring this work. + + *) Feature: the ngx_http_mp4_module now skips tracks too short for a + seek requested. + + *) Bugfix: a segmentation fault might occur in a worker process if the + $ssl_session_id variable was used in logs; the bug had appeared in + 1.5.9. + + *) Bugfix: the $date_local and $date_gmt variables used wrong format + outside of the ngx_http_ssi_filter_module. + + *) Bugfix: client connections might be immediately closed if deferred + accept was used; the bug had appeared in 1.3.15. + + *) Bugfix: alerts "getsockopt(TCP_FASTOPEN) ... failed" appeared in logs + during binary upgrade on Linux; the bug had appeared in 1.5.8. + Thanks to Piotr Sikora. + + +Changes with nginx 1.5.9 22 Jan 2014 + + *) Change: now nginx expects escaped URIs in "X-Accel-Redirect" headers. + + *) Feature: the "ssl_buffer_size" directive. + + *) Feature: the "limit_rate" directive can now be used to rate limit + responses sent in SPDY connections. -Changes with nginx 1.4.5 11 Feb 2014 + *) Feature: the "spdy_chunk_size" directive. + + *) Feature: the "ssl_session_tickets" directive. + Thanks to Dirkjan Bussink. *) Bugfix: the $ssl_session_id variable contained full session serialized instead of just a session id. Thanks to Ivan Ristić. - *) Bugfix: client connections might be immediately closed if deferred - accept was used; the bug had appeared in 1.3.15. + *) Bugfix: nginx incorrectly handled escaped "?" character in the + "include" SSI command. + + *) Bugfix: the ngx_http_dav_module did not unescape destination URI of + the COPY and MOVE methods. + + *) Bugfix: resolver did not understand domain names with a trailing dot. + Thanks to Yichun Zhang. *) Bugfix: alerts "zero size buf in output" might appear in logs while proxying; the bug had appeared in 1.3.9. @@ -41,53 +141,217 @@ Changes with nginx 1.4.5 11 Feb 2014 *) Bugfix: proxied WebSocket connections might hang right after handshake if the select, poll, or /dev/poll methods were used. + *) Bugfix: the "xclient" directive of the mail proxy module incorrectly + handled IPv6 client addresses. + + +Changes with nginx 1.5.8 17 Dec 2013 + + *) Feature: IPv6 support in resolver. + + *) Feature: the "listen" directive supports the "fastopen" parameter. + Thanks to Mathew Rodley. + + *) Feature: SSL support in the ngx_http_uwsgi_module. + Thanks to Roberto De Ioris. + + *) Feature: vim syntax highlighting scripts were added to contrib. + Thanks to Evan Miller. + *) Bugfix: a timeout might occur while reading client request body in an SSL connection using chunked transfer encoding. - *) Bugfix: memory leak in nginx/Windows. + *) Bugfix: the "master_process" directive did not work correctly in + nginx/Windows. + + *) Bugfix: the "setfib" parameter of the "listen" directive might not + work. + + *) Bugfix: in the ngx_http_spdy_module. -Changes with nginx 1.4.4 19 Nov 2013 +Changes with nginx 1.5.7 19 Nov 2013 *) Security: a character following an unescaped space in a request line was handled incorrectly (CVE-2013-4547); the bug had appeared in 0.8.41. Thanks to Ivan Fratric of the Google Security Team. + *) Change: a logging level of auth_basic errors about no user/password + provided has been lowered from "error" to "info". -Changes with nginx 1.4.3 08 Oct 2013 + *) Feature: the "proxy_cache_revalidate", "fastcgi_cache_revalidate", + "scgi_cache_revalidate", and "uwsgi_cache_revalidate" directives. - *) Bugfix: a segmentation fault might occur in a worker process if the - ngx_http_spdy_module was used with the "client_body_in_file_only" - directive. + *) Feature: the "ssl_session_ticket_key" directive. + Thanks to Piotr Sikora. - *) Bugfix: a segmentation fault might occur on start or during - reconfiguration if the "try_files" directive was used with an empty - parameter. + *) Bugfix: the directive "add_header Cache-Control ''" added a + "Cache-Control" response header line with an empty value. - *) Bugfix: the $request_time variable did not work in nginx/Windows. + *) Bugfix: the "satisfy any" directive might return 403 error instead of + 401 if auth_request and auth_basic directives were used. + Thanks to Jan Marc Hoffmann. + + *) Bugfix: the "accept_filter" and "deferred" parameters of the "listen" + directive were ignored for listen sockets created during binary + upgrade. + Thanks to Piotr Sikora. + + *) Bugfix: some data received from a backend with unbufferred proxy + might not be sent to a client immediately if "gzip" or "gunzip" + directives were used. + Thanks to Yichun Zhang. + + *) Bugfix: in error handling in ngx_http_gunzip_filter_module. + + *) Bugfix: responses might hang if the ngx_http_spdy_module was used + with the "auth_request" directive. + + *) Bugfix: memory leak in nginx/Windows. + + +Changes with nginx 1.5.6 01 Oct 2013 + + *) Feature: the "fastcgi_buffering" directive. + + *) Feature: the "proxy_ssl_protocols" and "proxy_ssl_ciphers" + directives. + Thanks to Piotr Sikora. + + *) Feature: optimization of SSL handshakes when using long certificate + chains. + + *) Feature: the mail proxy supports SMTP pipelining. *) Bugfix: in the ngx_http_auth_basic_module when using "$apr1$" password encryption method. Thanks to Markus Linnala. - *) Bugfix: in the ngx_http_autoindex_module. + *) Bugfix: in MacOSX, Cygwin, and nginx/Windows incorrect location might + be used to process a request if locations were given using characters + in different cases. + + *) Bugfix: automatic redirect with appended trailing slash for proxied + locations might not work. *) Bugfix: in the mail proxy server. + *) Bugfix: in the ngx_http_spdy_module. + + +Changes with nginx 1.5.5 17 Sep 2013 + + *) Change: now nginx assumes HTTP/1.0 by default if it is not able to + detect protocol reliably. + + *) Feature: the "disable_symlinks" directive now uses O_PATH on Linux. + + *) Feature: now nginx uses EPOLLRDHUP events to detect premature + connection close by clients if the "epoll" method is used. + + *) Bugfix: in the "valid_referers" directive if the "server_names" + parameter was used. + + *) Bugfix: the $request_time variable did not work in nginx/Windows. + + *) Bugfix: in the "image_filter" directive. + Thanks to Lanshun Zhou. + + *) Bugfix: OpenSSL 1.0.1f compatibility. + Thanks to Piotr Sikora. + + +Changes with nginx 1.5.4 27 Aug 2013 + + *) Change: the "js" extension MIME type has been changed to + "application/javascript"; default value of the "charset_types" + directive was changed accordingly. + + *) Change: now the "image_filter" directive with the "size" parameter + returns responses with the "application/json" MIME type. -Changes with nginx 1.4.2 17 Jul 2013 + *) Feature: the ngx_http_auth_request_module. + + *) Bugfix: a segmentation fault might occur on start or during + reconfiguration if the "try_files" directive was used with an empty + parameter. + + *) Bugfix: memory leak if relative paths were specified using variables + in the "root" or "auth_basic_user_file" directives. + + *) Bugfix: the "valid_referers" directive incorrectly executed regular + expressions if a "Referer" header started with "https://". + Thanks to Liangbin Li. + + *) Bugfix: responses might hang if subrequests were used and an SSL + handshake error happened during subrequest processing. + Thanks to Aviram Cohen. + + *) Bugfix: in the ngx_http_autoindex_module. + + *) Bugfix: in the ngx_http_spdy_module. + + +Changes with nginx 1.5.3 30 Jul 2013 + + *) Change in internal API: now u->length defaults to -1 if working with + backends in unbuffered mode. + + *) Change: now after receiving an incomplete response from a backend + server nginx tries to send an available part of the response to a + client, and then closes client connection. + + *) Bugfix: a segmentation fault might occur in a worker process if the + ngx_http_spdy_module was used with the "client_body_in_file_only" + directive. + + *) Bugfix: the "so_keepalive" parameter of the "listen" directive might + be handled incorrectly on DragonFlyBSD. + Thanks to Sepherosa Ziehau. + + *) Bugfix: in the ngx_http_xslt_filter_module. + + *) Bugfix: in the ngx_http_sub_filter_module. + + +Changes with nginx 1.5.2 02 Jul 2013 + + *) Feature: now several "error_log" directives can be used. *) Bugfix: the $r->header_in() embedded perl method did not return value of the "Cookie" and "X-Forwarded-For" request header lines; the bug had appeared in 1.3.14. + *) Bugfix: in the ngx_http_spdy_module. + Thanks to Jim Radford. + + *) Bugfix: nginx could not be built on Linux with x32 ABI. + Thanks to Serguei Ivantsov. + + +Changes with nginx 1.5.1 04 Jun 2013 + + *) Feature: the "ssi_last_modified", "sub_filter_last_modified", and + "xslt_last_modified" directives. + Thanks to Alexey Kolpakov. + + *) Feature: the "http_403" parameter of the "proxy_next_upstream", + "fastcgi_next_upstream", "scgi_next_upstream", and + "uwsgi_next_upstream" directives. + + *) Feature: the "allow" and "deny" directives now support unix domain + sockets. + *) Bugfix: nginx could not be built with the ngx_mail_ssl_module, but without ngx_http_ssl_module; the bug had appeared in 1.3.14. *) Bugfix: in the "proxy_set_body" directive. Thanks to Lanshun Zhou. + *) Bugfix: in the "lingering_time" directive. + Thanks to Lanshun Zhou. + *) Bugfix: the "fail_timeout" parameter of the "server" directive in the "upstream" context might not work if "max_fails" parameter was used; the bug had appeared in 1.3.0. @@ -96,11 +360,14 @@ Changes with nginx 1.4.2 17 Jul 2013 "ssl_stapling" directive was used. Thanks to Piotr Sikora. + *) Bugfix: in the mail proxy server. + Thanks to Filipe Da Silva. + *) Bugfix: nginx/Windows might stop accepting connections if several worker processes were used. -Changes with nginx 1.4.1 07 May 2013 +Changes with nginx 1.5.0 07 May 2013 *) Security: a stack-based buffer overflow might occur in a worker process while handling a specially crafted request, potentially @@ -6097,7 +6364,7 @@ Changes with nginx 0.1.16 25 Jan 2005 *) Bugfix: the compressed response encrypted by SSL may not transferred complete. - *) Bugfix: the TCP-specific TCP_NODELAY, TCP_NOPSUH, and TCP_CORK + *) Bugfix: the TCP-specific TCP_NODELAY, TCP_NOPUSH, and TCP_CORK options, are not used for the unix domain sockets. *) Feature: the rewrite directive supports the arguments rewriting. diff --git a/usr.sbin/nginx/CHANGES.ru b/usr.sbin/nginx/CHANGES.ru index 2f9f3012ff5..5915dd854f2 100644 --- a/usr.sbin/nginx/CHANGES.ru +++ b/usr.sbin/nginx/CHANGES.ru @@ -1,5 +1,38 @@ -Изменения в nginx 1.4.7 18.03.2014 +Изменения в nginx 1.6.0 24.04.2014 + + *) Стабильная ветка 1.6.x. + + +Изменения в nginx 1.5.13 08.04.2014 + + *) Изменение: улучшена обработка хэш-таблиц; в директивах + variables_hash_max_size и types_hash_bucket_size значения по + умолчанию изменены на 1024 и 64 соответственно. + + *) Добавление: модуль ngx_http_mp4_module теперь понимает аргумент end. + + *) Добавление: поддержка byte ranges модулем ngx_http_mp4_module и при + сохранении ответов в кэш. + + *) Исправление: теперь nginx не пишет в лог сообщения "ngx_slab_alloc() + failed: no memory" при использовании разделяемой памяти в + ssl_session_cache и в модуле ngx_http_limit_req_module. + + *) Исправление: директива underscores_in_headers не разрешала + подчёркивание в первом символе заголовка. + Спасибо Piotr Sikora. + + *) Исправление: cache manager мог нагружать процессор при выходе в + nginx/Windows. + + *) Исправление: при использовании ssl_session_cache с параметром shared + рабочий процесс nginx/Windows завершался аварийно. + + *) Исправление: в модуле ngx_http_spdy_module. + + +Изменения в nginx 1.5.12 18.03.2014 *) Безопасность: при обработке специально созданного запроса модулем ngx_http_spdy_module могло происходить переполнение буфера в рабочем @@ -8,11 +41,24 @@ Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel Sadosky, Buenos Aires, Argentina. + *) Добавление: параметр proxy_protocol в директивах listen и + real_ip_header, переменная $proxy_protocol_addr. + *) Исправление: в директиве fastcgi_next_upstream. Спасибо Lucas Molas. -Изменения в nginx 1.4.6 04.03.2014 +Изменения в nginx 1.5.11 04.03.2014 + + *) Безопасность: при обработке специально созданного запроса модулем + ngx_http_spdy_module на 32-битных платформах могла повреждаться + память рабочего процесса, что потенциально могло приводить к + выполнению произвольного кода (CVE-2014-0088); ошибка появилась в + 1.5.10. + Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel Sadosky, + Buenos Aires, Argentina. + + *) Добавление: переменная $ssl_session_reused. *) Исправление: директива client_max_body_size могла не работать при чтении тела запроса с использованием chunked transfer encoding; @@ -22,15 +68,74 @@ *) Исправление: при проксировании WebSocket-соединений в рабочем процессе мог произойти segmentation fault. + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовался модуль ngx_http_spdy_module на 32-битных + платформах; ошибка появилась в 1.5.10. + + *) Исправление: значение переменной $upstream_status могло быть + неверным, если использовались директивы proxy_cache_use_stale или + proxy_cache_revalidate. + Спасибо Piotr Sikora. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если ошибки с кодом 400 с помощью директивы error_page + перенаправлялись в именованный location. + + *) Исправление: nginx/Windows не собирался с Visual Studio 2013. + + +Изменения в nginx 1.5.10 04.02.2014 + + *) Добавление: модуль ngx_http_spdy_module теперь использует протокол + SPDY 3.1. + Спасибо Automattic и MaxCDN за спонсирование разработки. + + *) Добавление: модуль ngx_http_mp4_module теперь пропускает дорожки, + имеющие меньшую длину, чем запрошенная перемотка. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если переменная $ssl_session_id использовалась при логгировании; + ошибка появилась в 1.5.9. + + *) Исправление: переменные $date_local и $date_gmt использовали неверный + формат вне модуля ngx_http_ssi_filter_module. + + *) Исправление: клиентские соединения могли сразу закрываться, если + использовался отложенный accept; ошибка появилась в 1.3.15. + + *) Исправление: сообщения "getsockopt(TCP_FASTOPEN) ... failed" + записывались в лог в процессе обновления исполняемого файла на Linux; + ошибка появилась в 1.5.8. + Спасибо Piotr Sikora. + + +Изменения в nginx 1.5.9 22.01.2014 + + *) Изменение: теперь в заголовке X-Accel-Redirect nginx ожидает + закодированный URI. + + *) Добавление: директива ssl_buffer_size. + + *) Добавление: директиву limit_rate теперь можно использовать для + ограничения скорости передачи ответов клиенту в SPDY-соединениях. + + *) Добавление: директива spdy_chunk_size. -Изменения в nginx 1.4.5 11.02.2014 + *) Добавление: директива ssl_session_tickets. + Спасибо Dirkjan Bussink. *) Исправление: переменная $ssl_session_id содержала всю сессию в сериализованном виде вместо её идентификатора. Спасибо Ivan Ristić. - *) Исправление: клиентские соединения могли сразу закрываться, если - использовался отложенный accept; ошибка появилась в 1.3.15. + *) Исправление: nginx неправильно обрабатывал закодированный символ "?" + в команде SSI include. + + *) Исправление: модуль ngx_http_dav_module не раскодировал целевой URI + при обработке методов COPY и MOVE. + + *) Исправление: resolver не понимал доменные имена с точкой в конце. + Спасибо Yichun Zhang. *) Исправление: при проксировании в логах могли появляться сообщения "zero size buf in output"; ошибка появилась в 1.3.9. @@ -42,53 +147,219 @@ poll и /dev/poll проксируемые WebSocket-соединения могли зависать сразу после открытия. + *) Исправление: директива xclient почтового прокси-сервера некорректно + передавала IPv6-адреса. + + +Изменения в nginx 1.5.8 17.12.2013 + + *) Добавление: теперь resolver поддерживает IPv6. + + *) Добавление: директива listen поддерживает параметр fastopen. + Спасибо Mathew Rodley. + + *) Добавление: поддержка SSL в модуле ngx_http_uwsgi_module. + Спасибо Roberto De Ioris. + + *) Добавление: скрипты подсветки синтаксиса для vim добавлены в contrib. + Спасибо Evan Miller. + *) Исправление: при чтении тела запроса с использованием chunked transfer encoding по SSL-соединению мог произойти таймаут. - *) Исправление: утечки памяти в nginx/Windows. + *) Исправление: директива master_process работала неправильно в + nginx/Windows. + + *) Исправление: параметр setfib директивы listen мог не работать. + + *) Исправление: в модуле ngx_http_spdy_module. -Изменения в nginx 1.4.4 19.11.2013 +Изменения в nginx 1.5.7 19.11.2013 *) Безопасность: символ, следующий за незакодированным пробелом в строке запроса, обрабатывался неправильно (CVE-2013-4547); ошибка появилась в 0.8.41. Спасибо Ivan Fratric из Google Security Team. + *) Изменение: уровень логгирования ошибок auth_basic об отсутствии + пароля понижен с уровня error до info. -Изменения в nginx 1.4.3 08.10.2013 + *) Добавление: директивы proxy_cache_revalidate, + fastcgi_cache_revalidate, scgi_cache_revalidate и + uwsgi_cache_revalidate. - *) Исправление: в рабочем процессе мог произойти segmentation fault, - если использовался модуль ngx_http_spdy_module и директива - client_body_in_file_only. + *) Добавление: директива ssl_session_ticket_key. + Спасибо Piotr Sikora. - *) Исправление: на старте или во время переконфигурации мог произойти - segmentation fault, если использовалась директива try_files с пустым - параметром. + *) Исправление: директива "add_header Cache-Control ''" добавляла строку + заголовка ответа "Cache-Control" с пустым значением. - *) Исправление: переменная $request_time не работала в nginx/Windows. + *) Исправление: директива "satisfy any" могла вернуть ошибку 403 вместо + 401 при использовании директив auth_request и auth_basic. + Спасибо Jan Marc Hoffmann. + + *) Исправление: параметры accept_filter и deferred директивы listen + игнорировались для listen-сокетов, создаваемых в процессе обновления + исполняемого файла. + Спасибо Piotr Sikora. + + *) Исправление: часть данных, полученных от бэкенда при + небуферизированном проксировании, могла не отправляться клиенту + сразу, если использовались директивы gzip или gunzip. + Спасибо Yichun Zhang. + + *) Исправление: в обработке ошибок в модуле + ngx_http_gunzip_filter_module. + + *) Исправление: ответы могли зависать, если использовался модуль + ngx_http_spdy_module и директива auth_request. + + *) Исправление: утечки памяти в nginx/Windows. + + +Изменения в nginx 1.5.6 01.10.2013 + + *) Добавление: директива fastcgi_buffering. + + *) Добавление: директивы proxy_ssl_protocols и proxy_ssl_ciphers. + Спасибо Piotr Sikora. + + *) Добавление: оптимизация SSL handshake при использовании длинных + цепочек сертификатов. + + *) Добавление: почтовый прокси-сервер поддерживает SMTP pipelining. *) Исправление: в модуле ngx_http_auth_basic_module при использовании метода шифрования паролей "$apr1$". Спасибо Markus Linnala. - *) Исправление: в модуле ngx_http_autoindex_module. + *) Исправление: на MacOSX, Cygwin и nginx/Windows для обработки запроса + мог использоваться неверный location, если для задания location'ов + использовались символы разных регистров. + + *) Исправление: автоматическое перенаправление с добавлением + завершающего слэша для проксированных location'ов могло не работать. *) Исправление: в почтовом прокси-сервере. + *) Исправление: в модуле ngx_http_spdy_module. + + +Изменения в nginx 1.5.5 17.09.2013 -Изменения в nginx 1.4.2 17.07.2013 + *) Изменение: теперь nginx по умолчанию использует HTTP/1.0, если точно + определить протокол не удалось. + + *) Добавление: директива disable_symlinks теперь использует O_PATH на + Linux. + + *) Добавление: для определения того, что клиент закрыл соединение, при + использовании метода epoll теперь используются события EPOLLRDHUP. + + *) Исправление: в директиве valid_referers при использовании параметра + server_names. + + *) Исправление: переменная $request_time не работала в nginx/Windows. + + *) Исправление: в директиве image_filter. + Спасибо Lanshun Zhou. + + *) Исправление: совместимость с OpenSSL 1.0.1f. + Спасибо Piotr Sikora. + + +Изменения в nginx 1.5.4 27.08.2013 + + *) Изменение: MIME-тип для расширения js изменён на + "application/javascript"; значение по умолчанию директивы + charset_types изменено соответственно. + + *) Изменение: теперь директива image_filter с параметром size возвращает + ответ с MIME-типом "application/json". + + *) Добавление: модуль ngx_http_auth_request_module. + + *) Исправление: на старте или во время переконфигурации мог произойти + segmentation fault, если использовалась директива try_files с пустым + параметром. + + *) Исправление: утечки памяти при использовании в директивах root и + auth_basic_user_file относительных путей, заданных с помощью + переменных. + + *) Исправление: директива valid_referers неправильно выполняла + регулярные выражения, если заголовок Referer начинался с "https://". + Спасибо Liangbin Li. + + *) Исправление: ответы могли зависать, если использовались подзапросы и + при обработке подзапроса происходила ошибка во время SSL handshake с + бэкендом. + Спасибо Aviram Cohen. + + *) Исправление: в модуле ngx_http_autoindex_module. + + *) Исправление: в модуле ngx_http_spdy_module. + + +Изменения в nginx 1.5.3 30.07.2013 + + *) Изменение во внутреннем API: теперь при небуферизированной работе с + бэкендами u->length по умолчанию устанавливается в -1. + + *) Изменение: теперь при получении неполного ответа от бэкенда nginx + отправляет полученную часть ответа, после чего закрывает соединение с + клиентом. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовался модуль ngx_http_spdy_module и директива + client_body_in_file_only. + + *) Исправление: параметр so_keepalive директивы listen мог работать + некорректно на DragonFlyBSD. + Спасибо Sepherosa Ziehau. + + *) Исправление: в модуле ngx_http_xslt_filter_module. + + *) Исправление: в модуле ngx_http_sub_filter_module. + + +Изменения в nginx 1.5.2 02.07.2013 + + *) Добавление: теперь можно использовать несколько директив error_log. *) Исправление: метод $r->header_in() встроенного перла не возвращал значения строк "Cookie" и "X-Forwarded-For" из заголовка запроса; ошибка появилась в 1.3.14. + *) Исправление: в модуле ngx_http_spdy_module. + Спасибо Jim Radford. + + *) Исправление: nginx не собирался на Linux при использовании x32 ABI. + Спасибо Сергею Иванцову. + + +Изменения в nginx 1.5.1 04.06.2013 + + *) Добавление: директивы ssi_last_modified, sub_filter_last_modified и + xslt_last_modified. + Спасибо Алексею Колпакову. + + *) Добавление: параметр http_403 в директивах proxy_next_upstream, + fastcgi_next_upstream, scgi_next_upstream и uwsgi_next_upstream. + + *) Добавление: директивы allow и deny теперь поддерживают unix domain + сокеты. + *) Исправление: nginx не собирался с модулем ngx_mail_ssl_module, но без модуля ngx_http_ssl_module; ошибка появилась в 1.3.14. *) Исправление: в директиве proxy_set_body. Спасибо Lanshun Zhou. + *) Исправление: в директиве lingering_time. + Спасибо Lanshun Zhou. + *) Исправление: параметр fail_timeout директивы server в блоке upstream мог не работать, если использовался параметр max_fails; ошибка появилась в 1.3.0. @@ -97,11 +368,14 @@ если использовалась директива ssl_stapling. Спасибо Piotr Sikora. + *) Исправление: в почтовом прокси-сервере. + Спасибо Filipe Da Silva. + *) Исправление: nginx/Windows мог перестать принимать соединения, если использовалось несколько рабочих процессов. -Изменения в nginx 1.4.1 07.05.2013 +Изменения в nginx 1.5.0 07.05.2013 *) Безопасность: при обработке специально созданного запроса мог перезаписываться стек рабочего процесса, что могло приводить к @@ -427,7 +701,7 @@ *) Изменение: параметр single директивы keepalive теперь игнорируется. *) Изменение: сжатие SSL теперь отключено в том числе при использовании - OpenSSL cтарее 1.0.0. + OpenSSL старее 1.0.0. *) Добавление: директиву "ip_hash" теперь можно использовать для балансировки IPv6 клиентов. @@ -2704,7 +2978,7 @@ умолчанию; ошибка появилась в 0.7.18. Спасибо Максиму Дунину. - *) Исправление: при проксировании SMPT nginx выдавал сообщение + *) Исправление: при проксировании SMTP nginx выдавал сообщение "250 2.0.0 OK" вместо "235 2.0.0 OK"; ошибка появилась в 0.7.22. Спасибо Максиму Дунину. @@ -6190,7 +6464,7 @@ *) Исправление: при использовании SSL сжатый ответ мог передаваться не до конца. - *) Исправление: опции TCP_NODELAY, TCP_NOPSUH и TCP_CORK, специфичные + *) Исправление: опции TCP_NODELAY, TCP_NOPUSH и TCP_CORK, специфичные для TCP сокетов, не используются для unix domain сокетов. *) Добавление: директива rewrite поддерживает перезаписывание @@ -6254,7 +6528,7 @@ *) Изменение: если в URI встречался символ %3F, то он считался началом строки аргументов. - *) Добавление: поддержка unix domain сoкетов в модуле + *) Добавление: поддержка unix domain сокетов в модуле ngx_http_proxy_module. *) Добавление: директивы ssl_engine и ssl_ciphers. diff --git a/usr.sbin/nginx/Makefile.bsd-wrapper b/usr.sbin/nginx/Makefile.bsd-wrapper index f09b516d6a1..a9321ca953b 100644 --- a/usr.sbin/nginx/Makefile.bsd-wrapper +++ b/usr.sbin/nginx/Makefile.bsd-wrapper @@ -1,5 +1,5 @@ # Build wrapper for Nginx -# $OpenBSD: Makefile.bsd-wrapper,v 1.16 2014/05/18 05:27:49 jsg Exp $ +# $OpenBSD: Makefile.bsd-wrapper,v 1.17 2014/06/12 15:27:08 robert Exp $ LNDIR= /usr/bin/lndir @@ -23,7 +23,6 @@ CONFIGURE_ARGS= --prefix=/var/www \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-ipv6 \ - --with-cc-opt="-DNGX_ENABLE_SYSLOG" \ --without-mail_pop3_module \ --without-mail_imap_module \ --without-mail_smtp_module diff --git a/usr.sbin/nginx/auto/cc/clang b/usr.sbin/nginx/auto/cc/clang index 9f60d7b3a2b..baaf4baa23a 100644 --- a/usr.sbin/nginx/auto/cc/clang +++ b/usr.sbin/nginx/auto/cc/clang @@ -5,8 +5,8 @@ # clang -NGX_CLANG_VER=`$CC -v 2>&1 | grep 'clang version' 2>&1 \ - | sed -e 's/^.*clang version \(.*\)/\1/'` +NGX_CLANG_VER=`$CC -v 2>&1 | grep '\(clang\|LLVM\) version' 2>&1 \ + | sed -e 's/^.* version \(.*\)/\1/'` echo " + clang version: $NGX_CLANG_VER" @@ -82,13 +82,14 @@ fi # warnings CFLAGS="$CFLAGS $NGX_CLANG_OPT -Wall -Wextra -Wpointer-arith" +CFLAGS="$CFLAGS -Wconditional-uninitialized" #CFLAGS="$CFLAGS -Wmissing-prototypes" # we have a lot of unused function arguments CFLAGS="$CFLAGS -Wno-unused-parameter" # stop on warning -#CFLAGS="$CFLAGS -Werror" +CFLAGS="$CFLAGS -Werror" # debug CFLAGS="$CFLAGS -g" diff --git a/usr.sbin/nginx/auto/cc/conf b/usr.sbin/nginx/auto/cc/conf index 8027b980502..edc6d74ddfa 100644 --- a/usr.sbin/nginx/auto/cc/conf +++ b/usr.sbin/nginx/auto/cc/conf @@ -43,6 +43,29 @@ if test -n "$CFLAGS"; then ngx_include_opt="-I" ;; + sunc) + + case "$NGX_MACHINE" in + + i86pc) + NGX_AUX=" src/os/unix/ngx_sunpro_x86.il" + ;; + + sun4u | sun4v) + NGX_AUX=" src/os/unix/ngx_sunpro_sparc64.il" + ;; + + esac + + case $CPU in + + amd64) + NGX_AUX=" src/os/unix/ngx_sunpro_amd64.il" + ;; + + esac + ;; + esac else diff --git a/usr.sbin/nginx/auto/cc/msvc b/usr.sbin/nginx/auto/cc/msvc index 1bf675e19e9..393ba321499 100644 --- a/usr.sbin/nginx/auto/cc/msvc +++ b/usr.sbin/nginx/auto/cc/msvc @@ -106,6 +106,7 @@ fi # precompiled headers CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" +CORE_LINK="$CORE_LINK $NGX_OBJS/ngx_pch.obj" NGX_PCH="$NGX_OBJS/ngx_config.pch" NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch" NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch" diff --git a/usr.sbin/nginx/auto/cc/name b/usr.sbin/nginx/auto/cc/name index 7a5656c6475..51a7ed92e1d 100644 --- a/usr.sbin/nginx/auto/cc/name +++ b/usr.sbin/nginx/auto/cc/name @@ -67,7 +67,7 @@ elif `$CC -v 2>&1 | grep 'gcc version' >/dev/null 2>&1`; then NGX_CC_NAME=gcc echo " + using GNU C compiler" -elif `$CC -v 2>&1 | grep 'clang version' >/dev/null 2>&1`; then +elif `$CC -v 2>&1 | grep '\(clang\|LLVM\) version' >/dev/null 2>&1`; then NGX_CC_NAME=clang echo " + using Clang C compiler" diff --git a/usr.sbin/nginx/auto/cc/owc b/usr.sbin/nginx/auto/cc/owc index 22eb4c1259a..a063aa34121 100644 --- a/usr.sbin/nginx/auto/cc/owc +++ b/usr.sbin/nginx/auto/cc/owc @@ -65,10 +65,10 @@ have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have # the precompiled headers -CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" -NGX_PCH="$NGX_OBJS/ngx_config.pch" -NGX_BUILD_PCH="-fhq=$NGX_OBJS/ngx_config.pch" -NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pch" +#CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" +#NGX_PCH="$NGX_OBJS/ngx_config.pch" +#NGX_BUILD_PCH="-fhq=$NGX_OBJS/ngx_config.pch" +#NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pch" # the link flags, built target is NT GUI mode application diff --git a/usr.sbin/nginx/auto/cc/sunc b/usr.sbin/nginx/auto/cc/sunc index dd9ccedfbaa..8f12d7cd7fe 100644 --- a/usr.sbin/nginx/auto/cc/sunc +++ b/usr.sbin/nginx/auto/cc/sunc @@ -30,7 +30,7 @@ if [ -x $NGX_AUTOTEST ]; then ngx_sunc_ver=`$NGX_AUTOTEST` fi -rm $NGX_AUTOTEST* +rm -rf $NGX_AUTOTEST* # 1424 == 0x590, Sun Studio 12 diff --git a/usr.sbin/nginx/auto/endianness b/usr.sbin/nginx/auto/endianness index 87311a0f16e..93da2f80d99 100644 --- a/usr.sbin/nginx/auto/endianness +++ b/usr.sbin/nginx/auto/endianness @@ -34,10 +34,10 @@ if [ -x $NGX_AUTOTEST ]; then echo " big endian" fi - rm $NGX_AUTOTEST* + rm -rf $NGX_AUTOTEST* else - rm $NGX_AUTOTEST* + rm -rf $NGX_AUTOTEST* echo echo "$0: error: cannot detect system byte ordering" diff --git a/usr.sbin/nginx/auto/feature b/usr.sbin/nginx/auto/feature index c13e51dfb82..1145f28684b 100644 --- a/usr.sbin/nginx/auto/feature +++ b/usr.sbin/nginx/auto/feature @@ -120,4 +120,4 @@ else echo "----------" >> $NGX_AUTOCONF_ERR fi -rm $NGX_AUTOTEST* +rm -rf $NGX_AUTOTEST* diff --git a/usr.sbin/nginx/auto/include b/usr.sbin/nginx/auto/include index 3466fda15b3..e34dabdae1d 100644 --- a/usr.sbin/nginx/auto/include +++ b/usr.sbin/nginx/auto/include @@ -58,4 +58,4 @@ else echo "----------" >> $NGX_AUTOCONF_ERR fi -rm $NGX_AUTOTEST* +rm -rf $NGX_AUTOTEST* diff --git a/usr.sbin/nginx/auto/lib/libatomic/make b/usr.sbin/nginx/auto/lib/libatomic/make index 023ed18fb98..c90318ea122 100644 --- a/usr.sbin/nginx/auto/lib/libatomic/make +++ b/usr.sbin/nginx/auto/lib/libatomic/make @@ -9,6 +9,8 @@ $NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile cd $NGX_LIBATOMIC && \$(MAKE) $NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE - cd $NGX_LIBATOMIC && ./configure + cd $NGX_LIBATOMIC \\ + && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ + && ./configure END diff --git a/usr.sbin/nginx/auto/lib/openssl/conf b/usr.sbin/nginx/auto/lib/openssl/conf index 528ee1794e9..a65815f6364 100644 --- a/usr.sbin/nginx/auto/lib/openssl/conf +++ b/usr.sbin/nginx/auto/lib/openssl/conf @@ -33,6 +33,10 @@ if [ $OPENSSL != NONE ]; then CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a" CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a" CORE_LIBS="$CORE_LIBS $NGX_LIBDL" + + if [ "$NGX_PLATFORM" = win32 ]; then + CORE_LIBS="$CORE_LIBS -lgdi32 -lcrypt32 -lws2_32" + fi ;; esac diff --git a/usr.sbin/nginx/auto/lib/openssl/make b/usr.sbin/nginx/auto/lib/openssl/make index 9090fcbfd34..e64acd973ec 100644 --- a/usr.sbin/nginx/auto/lib/openssl/make +++ b/usr.sbin/nginx/auto/lib/openssl/make @@ -55,7 +55,7 @@ END $OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE cd $OPENSSL \\ - && \$(MAKE) clean \\ + && if [ -f Makefile ]; then \$(MAKE) clean; fi \\ && ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\ && \$(MAKE) \\ && \$(MAKE) install LIBDIR=lib diff --git a/usr.sbin/nginx/auto/lib/pcre/conf b/usr.sbin/nginx/auto/lib/pcre/conf index 69e87ea77b2..eeecffb0dc9 100644 --- a/usr.sbin/nginx/auto/lib/pcre/conf +++ b/usr.sbin/nginx/auto/lib/pcre/conf @@ -73,6 +73,11 @@ if [ $PCRE != NONE ]; then *) have=NGX_PCRE . auto/have + + if [ "$NGX_PLATFORM" = win32 ]; then + have=PCRE_STATIC . auto/have + fi + CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a" diff --git a/usr.sbin/nginx/auto/lib/pcre/make b/usr.sbin/nginx/auto/lib/pcre/make index 834779b9cce..0a27a112c11 100644 --- a/usr.sbin/nginx/auto/lib/pcre/make +++ b/usr.sbin/nginx/auto/lib/pcre/make @@ -23,16 +23,19 @@ case "$NGX_CC_NAME" in ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; -esac + *) + ngx_makefile= + ;; +esac -case "$NGX_PLATFORM" in - win32) +if [ -n "$ngx_makefile" ]; then - cat << END >> $NGX_MAKEFILE + cat << END >> $NGX_MAKEFILE -`echo "$PCRE/pcre.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` +`echo "$PCRE/pcre.lib: $PCRE/pcre.h $NGX_MAKEFILE" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` \$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre $ngx_opt `echo "$PCRE/pcre.h:" | sed -e "s/\//$ngx_regex_dirsep/g"` @@ -40,10 +43,9 @@ case "$NGX_PLATFORM" in END - ;; +else - *) - cat << END >> $NGX_MAKEFILE + cat << END >> $NGX_MAKEFILE $PCRE/pcre.h: $PCRE/Makefile @@ -59,6 +61,4 @@ $PCRE/.libs/libpcre.a: $PCRE/Makefile END - ;; - -esac +fi diff --git a/usr.sbin/nginx/auto/lib/pcre/makefile.bcc b/usr.sbin/nginx/auto/lib/pcre/makefile.bcc index 1c140d668b7..7a0f2beafc6 100644 --- a/usr.sbin/nginx/auto/lib/pcre/makefile.bcc +++ b/usr.sbin/nginx/auto/lib/pcre/makefile.bcc @@ -4,7 +4,8 @@ CFLAGS = -q -O2 -tWM -w-8004 $(CPU_OPT) -PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 +PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 \ + -DSUPPORT_PCRE8 -DHAVE_MEMMOVE pcre.lib: @@ -12,8 +13,8 @@ pcre.lib: bcc32 -c $(CFLAGS) -I. $(PCREFLAGS) pcre_*.c - > pcre.lst - for %n in (*.obj) do @echo +%n & >> pcre.lst + copy /y nul pcre.lst + for %n in (*.obj) do @echo +%n ^^& >> pcre.lst echo + >> pcre.lst tlib pcre.lib @pcre.lst diff --git a/usr.sbin/nginx/auto/lib/pcre/makefile.msvc b/usr.sbin/nginx/auto/lib/pcre/makefile.msvc index 7a8da715818..07fd9a2853a 100644 --- a/usr.sbin/nginx/auto/lib/pcre/makefile.msvc +++ b/usr.sbin/nginx/auto/lib/pcre/makefile.msvc @@ -4,7 +4,8 @@ CFLAGS = -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 +PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 \ + -DSUPPORT_PCRE8 -DHAVE_MEMMOVE pcre.lib: diff --git a/usr.sbin/nginx/auto/lib/pcre/makefile.owc b/usr.sbin/nginx/auto/lib/pcre/makefile.owc index bfb69206879..122fd5b27f2 100644 --- a/usr.sbin/nginx/auto/lib/pcre/makefile.owc +++ b/usr.sbin/nginx/auto/lib/pcre/makefile.owc @@ -4,7 +4,8 @@ CFLAGS = -c -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT) -PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 +PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 & + -DSUPPORT_PCRE8 -DHAVE_MEMMOVE pcre.lib: diff --git a/usr.sbin/nginx/auto/lib/perl/make b/usr.sbin/nginx/auto/lib/perl/make index 260bd95a0b7..d1c1b9e48c1 100644 --- a/usr.sbin/nginx/auto/lib/perl/make +++ b/usr.sbin/nginx/auto/lib/perl/make @@ -18,6 +18,7 @@ $NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext: \\ $NGX_OBJS/src/http/modules/perl/Makefile: \\ + $NGX_AUTO_CONFIG_H \\ src/core/nginx.h \\ src/http/modules/perl/Makefile.PL \\ src/http/modules/perl/nginx.pm \\ diff --git a/usr.sbin/nginx/auto/lib/test b/usr.sbin/nginx/auto/lib/test index 907e2353b7f..ba943a29d40 100644 --- a/usr.sbin/nginx/auto/lib/test +++ b/usr.sbin/nginx/auto/lib/test @@ -37,4 +37,4 @@ else echo " not found" fi -rm $NGX_AUTOTEST* +rm -rf $NGX_AUTOTEST* diff --git a/usr.sbin/nginx/auto/lib/zlib/make b/usr.sbin/nginx/auto/lib/zlib/make index 9401a1d1a8e..7875ef67fe0 100644 --- a/usr.sbin/nginx/auto/lib/zlib/make +++ b/usr.sbin/nginx/auto/lib/zlib/make @@ -24,6 +24,10 @@ case "$NGX_CC_NAME" in ngx_zlib=`echo \-DZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"` ;; + *) + ngx_makefile= + ;; + esac @@ -33,13 +37,30 @@ done=NO case "$NGX_PLATFORM" in win32) - cat << END >> $NGX_MAKEFILE + + if [ -n "$ngx_makefile" ]; then + cat << END >> $NGX_MAKEFILE `echo "$ZLIB/zlib.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` \$(MAKE) -f auto/lib/zlib/$ngx_makefile $ngx_opt $ngx_zlib END + else + + cat << END >> $NGX_MAKEFILE + +$ZLIB/libz.a: $NGX_MAKEFILE + cd $ZLIB \\ + && \$(MAKE) distclean \\ + && \$(MAKE) -f win32/Makefile.gcc \\ + CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\ + libz.a + +END + + fi + done=YES ;; diff --git a/usr.sbin/nginx/auto/modules b/usr.sbin/nginx/auto/modules index a78e785e5c0..e1eda943fd3 100644 --- a/usr.sbin/nginx/auto/modules +++ b/usr.sbin/nginx/auto/modules @@ -42,6 +42,7 @@ fi if [ $NGX_TEST_BUILD_EPOLL = YES ]; then have=NGX_HAVE_EPOLL . auto/have + have=NGX_HAVE_EPOLLRDHUP . auto/have have=NGX_HAVE_EVENTFD . auto/have have=NGX_TEST_BUILD_EPOLL . auto/have EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE" @@ -220,6 +221,11 @@ if [ $HTTP_RANDOM_INDEX = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS" fi +if [ $HTTP_AUTH_REQUEST = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_REQUEST_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_REQUEST_SRCS" +fi + if [ $HTTP_AUTH_BASIC = YES ]; then USE_MD5=YES USE_SHA1=YES @@ -477,6 +483,8 @@ if [ $MAIL = YES ]; then modules="$modules $MAIL_PROXY_MODULE" MAIL_SRCS="$MAIL_SRCS $MAIL_PROXY_SRCS" + + NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(MAIL_DEPS)" fi diff --git a/usr.sbin/nginx/auto/options b/usr.sbin/nginx/auto/options index 6713379e3b9..6cea8c7c200 100644 --- a/usr.sbin/nginx/auto/options +++ b/usr.sbin/nginx/auto/options @@ -71,6 +71,7 @@ HTTP_ADDITION=NO HTTP_DAV=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES +HTTP_AUTH_REQUEST=NO HTTP_USERID=YES HTTP_AUTOINDEX=YES HTTP_RANDOM_INDEX=NO @@ -215,6 +216,7 @@ do --with-http_mp4_module) HTTP_MP4=YES ;; --with-http_gunzip_module) HTTP_GUNZIP=YES ;; --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; + --with-http_auth_request_module) HTTP_AUTH_REQUEST=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 ;; @@ -363,6 +365,7 @@ cat << END --with-http_mp4_module enable ngx_http_mp4_module --with-http_gunzip_module enable ngx_http_gunzip_module --with-http_gzip_static_module enable ngx_http_gzip_static_module + --with-http_auth_request_module enable ngx_http_auth_request_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 diff --git a/usr.sbin/nginx/auto/os/darwin b/usr.sbin/nginx/auto/os/darwin index 590e03697db..b97518a6ea0 100644 --- a/usr.sbin/nginx/auto/os/darwin +++ b/usr.sbin/nginx/auto/os/darwin @@ -112,5 +112,5 @@ ngx_feature_incs="#include <libkern/OSAtomic.h>" ngx_feature_path= ngx_feature_libs= ngx_feature_test="int32_t lock, n; - n = OSAtomicCompareAndSwap32Barrier(0, 1, lock)" + n = OSAtomicCompareAndSwap32Barrier(0, 1, &lock)" . auto/feature diff --git a/usr.sbin/nginx/auto/os/linux b/usr.sbin/nginx/auto/os/linux index c506d3dc3ad..19bf832ce3e 100644 --- a/usr.sbin/nginx/auto/os/linux +++ b/usr.sbin/nginx/auto/os/linux @@ -65,9 +65,41 @@ if [ $ngx_found = yes ]; then CORE_SRCS="$CORE_SRCS $EPOLL_SRCS" EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE" EVENT_FOUND=YES + + + # EPOLLRDHUP appeared in Linux 2.6.17, glibc 2.8 + + ngx_feature="EPOLLRDHUP" + ngx_feature_name="NGX_HAVE_EPOLLRDHUP" + ngx_feature_run=no + ngx_feature_incs="#include <sys/epoll.h>" + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="int efd = 0, fd = 0; + struct epoll_event ee; + ee.events = EPOLLIN|EPOLLRDHUP|EPOLLET; + ee.data.ptr = NULL; + epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)" + . auto/feature fi +# O_PATH and AT_EMPTY_PATH were introduced in 2.6.39, glibc 2.14 + +ngx_feature="O_PATH" +ngx_feature_name="NGX_HAVE_O_PATH" +ngx_feature_run=no +ngx_feature_incs="#include <sys/types.h> + #include <sys/stat.h> + #include <fcntl.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int fd; struct stat sb; + fd = openat(AT_FDCWD, \".\", O_PATH|O_DIRECTORY|O_NOFOLLOW); + if (fstatat(fd, \"\", &sb, AT_EMPTY_PATH) != 0) return 1" +. auto/feature + + # sendfile() CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE" diff --git a/usr.sbin/nginx/auto/os/win32 b/usr.sbin/nginx/auto/os/win32 index 21a54ba11e5..0b9b461875f 100644 --- a/usr.sbin/nginx/auto/os/win32 +++ b/usr.sbin/nginx/auto/os/win32 @@ -9,10 +9,21 @@ CORE_INCS="$WIN32_INCS" CORE_DEPS="$WIN32_DEPS" CORE_SRCS="$WIN32_SRCS $IOCP_SRCS" OS_CONFIG="$WIN32_CONFIG" -CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib" NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS +case "$NGX_CC_NAME" in + + gcc) + CORE_LIBS="$CORE_LIBS -ladvapi32 -lws2_32" + ;; + + *) + CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib" + ;; + +esac + EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE" EVENT_FOUND=YES diff --git a/usr.sbin/nginx/auto/sources b/usr.sbin/nginx/auto/sources index 56701ebb973..613a39a17e4 100644 --- a/usr.sbin/nginx/auto/sources +++ b/usr.sbin/nginx/auto/sources @@ -36,7 +36,9 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_conf_file.h \ src/core/ngx_resolver.h \ src/core/ngx_open_file_cache.h \ - src/core/ngx_crypt.h" + src/core/ngx_crypt.h \ + src/core/ngx_proxy_protocol.h \ + src/core/ngx_syslog.h" CORE_SRCS="src/core/nginx.c \ @@ -67,7 +69,9 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_conf_file.c \ src/core/ngx_resolver.c \ src/core/ngx_open_file_cache.c \ - src/core/ngx_crypt.c" + src/core/ngx_crypt.c \ + src/core/ngx_proxy_protocol.c \ + src/core/ngx_syslog.c" REGEX_MODULE=ngx_regex_module @@ -398,6 +402,10 @@ HTTP_AUTH_BASIC_MODULE=ngx_http_auth_basic_module HTTP_AUTH_BASIC_SRCS=src/http/modules/ngx_http_auth_basic_module.c +HTTP_AUTH_REQUEST_MODULE=ngx_http_auth_request_module +HTTP_AUTH_REQUEST_SRCS=src/http/modules/ngx_http_auth_request_module.c + + HTTP_AUTOINDEX_MODULE=ngx_http_autoindex_module HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c diff --git a/usr.sbin/nginx/auto/types/sizeof b/usr.sbin/nginx/auto/types/sizeof index e1d405c6500..9215a545fc4 100644 --- a/usr.sbin/nginx/auto/types/sizeof +++ b/usr.sbin/nginx/auto/types/sizeof @@ -45,7 +45,7 @@ if [ -x $NGX_AUTOTEST ]; then fi -rm -f $NGX_AUTOTEST +rm -rf $NGX_AUTOTEST* case $ngx_size in diff --git a/usr.sbin/nginx/auto/types/typedef b/usr.sbin/nginx/auto/types/typedef index d81229331fd..8b5c3689ced 100644 --- a/usr.sbin/nginx/auto/types/typedef +++ b/usr.sbin/nginx/auto/types/typedef @@ -49,7 +49,7 @@ END fi fi - rm -f $NGX_AUTOTEST + rm -rf $NGX_AUTOTEST* if [ $ngx_found = no ]; then echo $ngx_n " $ngx_try not found$ngx_c" diff --git a/usr.sbin/nginx/auto/types/uintptr_t b/usr.sbin/nginx/auto/types/uintptr_t index 2f19080352b..f3cdccb2274 100644 --- a/usr.sbin/nginx/auto/types/uintptr_t +++ b/usr.sbin/nginx/auto/types/uintptr_t @@ -33,7 +33,7 @@ else echo $ngx_n " uintptr_t not found" $ngx_c fi -rm $NGX_AUTOTEST* +rm -rf $NGX_AUTOTEST* if [ $found = no ]; then diff --git a/usr.sbin/nginx/auto/unix b/usr.sbin/nginx/auto/unix index cd4209e7b2f..10fd3d29334 100755 --- a/usr.sbin/nginx/auto/unix +++ b/usr.sbin/nginx/auto/unix @@ -330,7 +330,7 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_DEFER_ACCEPT, NULL, 0)" . auto/feature -ngx_feature="TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT" +ngx_feature="TCP_KEEPIDLE" ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE" ngx_feature_run=no ngx_feature_incs="#include <sys/socket.h> @@ -344,6 +344,18 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_KEEPIDLE, NULL, 0); . auto/feature +ngx_feature="TCP_FASTOPEN" +ngx_feature_name="NGX_HAVE_TCP_FASTOPEN" +ngx_feature_run=no +ngx_feature_incs="#include <sys/socket.h> + #include <netinet/in.h> + #include <netinet/tcp.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_FASTOPEN, NULL, 0)" +. auto/feature + + ngx_feature="TCP_INFO" ngx_feature_name="NGX_HAVE_TCP_INFO" ngx_feature_run=no diff --git a/usr.sbin/nginx/conf/mime.types b/usr.sbin/nginx/conf/mime.types index 854873a1615..fb1c1b7c424 100644 --- a/usr.sbin/nginx/conf/mime.types +++ b/usr.sbin/nginx/conf/mime.types @@ -1,4 +1,4 @@ -# $OpenBSD: mime.types,v 1.6 2013/11/26 10:43:06 sthen Exp $ +# $OpenBSD: mime.types,v 1.7 2014/06/12 15:27:08 robert Exp $ types { text/html html htm shtml; @@ -6,7 +6,7 @@ types { text/xml xml; image/gif gif; image/jpeg jpeg jpg; - application/x-javascript js; + application/javascript js; application/atom+xml atom; application/rss+xml rss; @@ -25,13 +25,17 @@ types { image/svg+xml svg svgz; image/webp webp; + application/font-woff woff; application/java-archive jar war ear; + application/json json; application/mac-binhex40 hqx; application/msword doc; application/pdf pdf; application/postscript ps eps ai; application/rtf rtf; + application/vnd.apple.mpegurl m3u8; application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; application/vnd.wap.wmlc wmlc; application/vnd.google-earth.kml+xml kml; @@ -88,6 +92,7 @@ types { audio/x-realaudio ra; video/3gpp 3gpp 3gp; + video/mp2t ts; video/mp4 mp4; video/mpeg mpeg mpg; video/quicktime mov; diff --git a/usr.sbin/nginx/conf/nginx.conf b/usr.sbin/nginx/conf/nginx.conf index d6cfc0b554b..ee8d684a47f 100644 --- a/usr.sbin/nginx/conf/nginx.conf +++ b/usr.sbin/nginx/conf/nginx.conf @@ -1,16 +1,14 @@ -# $OpenBSD: nginx.conf,v 1.19 2014/04/18 20:22:17 tedu Exp $ +# $OpenBSD: nginx.conf,v 1.20 2014/06/12 15:27:08 robert Exp $ # Take note of http://wiki.nginx.org/Pitfalls #user www; worker_processes 1; -#syslog local5 nginx; - #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; -#error_log syslog:notice|logs/error.log; +#error_log syslog:server=unix:/dev/log,severity=notice; #pid logs/nginx.pid; @@ -30,7 +28,7 @@ http { # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; - #access_log syslog:notice|logs/access.log main; + #access_log syslog:server=unix:/dev/log,severity=notice main; #tcp_nopush on; diff --git a/usr.sbin/nginx/contrib/README b/usr.sbin/nginx/contrib/README index 094aa52cde3..fec4b200863 100644 --- a/usr.sbin/nginx/contrib/README +++ b/usr.sbin/nginx/contrib/README @@ -13,3 +13,9 @@ unicode2nginx by Maxim Dounin configuration file format. Two generated full maps for windows-1251 and koi8-r. + +vim by Evan Miller + + Syntax highlighting of nginx configuration for vim, to be + placed into ~/.vim/. + diff --git a/usr.sbin/nginx/src/core/nginx.c b/usr.sbin/nginx/src/core/nginx.c index 7f0011d879f..5960fa85658 100644 --- a/usr.sbin/nginx/src/core/nginx.c +++ b/usr.sbin/nginx/src/core/nginx.c @@ -389,13 +389,8 @@ main(int argc, char *const *argv) return 1; } - if (cycle->log->file->fd != ngx_stderr) { - - if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - ngx_set_stderr_n " failed"); - return 1; - } + if (ngx_log_redirect_stderr(cycle) != NGX_OK) { + return 1; } if (log->file->fd != ngx_stderr) { diff --git a/usr.sbin/nginx/src/core/nginx.h b/usr.sbin/nginx/src/core/nginx.h index 77c88bf5f94..0ef0f2e110f 100644 --- a/usr.sbin/nginx/src/core/nginx.h +++ b/usr.sbin/nginx/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1004007 -#define NGINX_VERSION "1.4.7" +#define nginx_version 1006000 +#define NGINX_VERSION "1.6.0" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.c b/usr.sbin/nginx/src/core/ngx_conf_file.c index a262672139c..f61bfcabf99 100644 --- a/usr.sbin/nginx/src/core/ngx_conf_file.c +++ b/usr.sbin/nginx/src/core/ngx_conf_file.c @@ -12,7 +12,6 @@ static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); -static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name); static void ngx_conf_flush_files(ngx_cycle_t *cycle); @@ -225,6 +224,11 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) * "types { ... }" directive */ + if (rc == NGX_CONF_BLOCK_START) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\""); + goto failed; + } + rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; @@ -796,95 +800,11 @@ ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix) { - size_t len; - u_char *p, *n, *prefix; - ngx_int_t rc; - - rc = ngx_conf_test_full_name(name); - - if (rc == NGX_OK) { - return rc; - } - - if (conf_prefix) { - len = cycle->conf_prefix.len; - prefix = cycle->conf_prefix.data; - - } else { - len = cycle->prefix.len; - prefix = cycle->prefix.data; - } - -#if (NGX_WIN32) - - if (rc == 2) { - len = rc; - } - -#endif - - n = ngx_pnalloc(cycle->pool, len + name->len + 1); - if (n == NULL) { - return NGX_ERROR; - } - - p = ngx_cpymem(n, prefix, len); - ngx_cpystrn(p, name->data, name->len + 1); - - name->len += len; - name->data = n; - - return NGX_OK; -} - - -static ngx_int_t -ngx_conf_test_full_name(ngx_str_t *name) -{ -#if (NGX_WIN32) - u_char c0, c1; - - c0 = name->data[0]; - - if (name->len < 2) { - if (c0 == '/') { - return 2; - } + ngx_str_t *prefix; - return NGX_DECLINED; - } - - c1 = name->data[1]; - - if (c1 == ':') { - c0 |= 0x20; + prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix; - if ((c0 >= 'a' && c0 <= 'z')) { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if (c1 == '/') { - return NGX_OK; - } - - if (c0 == '/') { - return 2; - } - - return NGX_DECLINED; - -#else - - if (name->data[0] == '/') { - return NGX_OK; - } - - return NGX_DECLINED; - -#endif + return ngx_get_full_name(cycle->pool, prefix, name); } diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.h b/usr.sbin/nginx/src/core/ngx_conf_file.h index 237e6ecea6e..d73a6c8bf55 100644 --- a/usr.sbin/nginx/src/core/ngx_conf_file.h +++ b/usr.sbin/nginx/src/core/ngx_conf_file.h @@ -5,8 +5,8 @@ */ -#ifndef _NGX_HTTP_CONF_FILE_H_INCLUDED_ -#define _NGX_HTTP_CONF_FILE_H_INCLUDED_ +#ifndef _NGX_CONF_FILE_H_INCLUDED_ +#define _NGX_CONF_FILE_H_INCLUDED_ #include <ngx_config.h> @@ -337,4 +337,4 @@ extern ngx_uint_t ngx_max_module; extern ngx_module_t *ngx_modules[]; -#endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */ +#endif /* _NGX_CONF_FILE_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_config.h b/usr.sbin/nginx/src/core/ngx_config.h index b0cb17fca80..1da71f8d1a1 100644 --- a/usr.sbin/nginx/src/core/ngx_config.h +++ b/usr.sbin/nginx/src/core/ngx_config.h @@ -80,8 +80,8 @@ typedef uintptr_t ngx_uint_t; typedef intptr_t ngx_flag_t; -#define NGX_INT32_LEN sizeof("-2147483648") - 1 -#define NGX_INT64_LEN sizeof("-9223372036854775808") - 1 +#define NGX_INT32_LEN (sizeof("-2147483648") - 1) +#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1) #if (NGX_PTR_SIZE == 4) #define NGX_INT_T_LEN NGX_INT32_LEN diff --git a/usr.sbin/nginx/src/core/ngx_connection.c b/usr.sbin/nginx/src/core/ngx_connection.c index 986bf0d0208..6b6e3b3a512 100644 --- a/usr.sbin/nginx/src/core/ngx_connection.c +++ b/usr.sbin/nginx/src/core/ngx_connection.c @@ -41,7 +41,7 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) ls->sockaddr = sa; ls->socklen = socklen; - len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1); ls->addr_text.len = len; switch (ls->sockaddr->sa_family) { @@ -82,6 +82,10 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) ls->setfib = -1; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = -1; +#endif + return ls; } @@ -93,8 +97,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) ngx_uint_t i; ngx_listening_t *ls; socklen_t olen; -#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) +#if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN) ngx_err_t err; +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) struct accept_filter_arg af; #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) @@ -123,7 +129,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_INET6) case AF_INET6: ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; - len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; break; #endif @@ -152,7 +158,8 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, len, 1); + len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen, + ls[i].addr_text.data, len, 1); if (len == 0) { return NGX_ERROR; } @@ -192,7 +199,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_SETFIB) - if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB, + olen = sizeof(int); + + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB, (void *) &ls[i].setfib, &olen) == -1) { @@ -206,6 +215,27 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #endif #endif +#if (NGX_HAVE_TCP_FASTOPEN) + + olen = sizeof(int); + + if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN, + (void *) &ls[i].fastopen, &olen) + == -1) + { + err = ngx_socket_errno; + + if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, + "getsockopt(TCP_FASTOPEN) %V failed, ignored", + &ls[i].addr_text); + } + + ls[i].fastopen = -1; + } + +#endif + #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_memzero(&af, sizeof(struct accept_filter_arg)); @@ -214,7 +244,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen) == -1) { - err = ngx_errno; + err = ngx_socket_errno; if (err == NGX_EINVAL) { continue; @@ -247,7 +277,13 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen) == -1) { - ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno, + err = ngx_socket_errno; + + if (err == NGX_EOPNOTSUPP) { + continue; + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored", &ls[i].addr_text); continue; @@ -296,7 +332,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) continue; } - if (ls[i].fd != -1) { + if (ls[i].fd != (ngx_socket_t) -1) { continue; } @@ -311,7 +347,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); - if (s == -1) { + if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %V failed", &ls[i].addr_text); return NGX_ERROR; @@ -463,16 +499,13 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) void ngx_configure_listening_sockets(ngx_cycle_t *cycle) { - int keepalive; + int value; ngx_uint_t i; ngx_listening_t *ls; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) struct accept_filter_arg af; #endif -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - int timeout; -#endif ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -502,39 +535,51 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) } if (ls[i].keepalive) { - keepalive = (ls[i].keepalive == 1) ? 1 : 0; + value = (ls[i].keepalive == 1) ? 1 : 0; if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE, - (const void *) &keepalive, sizeof(int)) + (const void *) &value, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_KEEPALIVE, %d) %V failed, ignored", - keepalive, &ls[i].addr_text); + value, &ls[i].addr_text); } } #if (NGX_HAVE_KEEPALIVE_TUNABLE) if (ls[i].keepidle) { + value = ls[i].keepidle; + +#if (NGX_KEEPALIVE_FACTOR) + value *= NGX_KEEPALIVE_FACTOR; +#endif + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE, - (const void *) &ls[i].keepidle, sizeof(int)) + (const void *) &value, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored", - ls[i].keepidle, &ls[i].addr_text); + value, &ls[i].addr_text); } } if (ls[i].keepintvl) { + value = ls[i].keepintvl; + +#if (NGX_KEEPALIVE_FACTOR) + value *= NGX_KEEPALIVE_FACTOR; +#endif + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL, - (const void *) &ls[i].keepintvl, sizeof(int)) + (const void *) &value, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored", - ls[i].keepintvl, &ls[i].addr_text); + value, &ls[i].addr_text); } } @@ -564,6 +609,19 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) } #endif +#if (NGX_HAVE_TCP_FASTOPEN) + if (ls[i].fastopen != -1) { + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN, + (const void *) &ls[i].fastopen, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(TCP_FASTOPEN, %d) %V failed, ignored", + ls[i].fastopen, &ls[i].addr_text); + } + } +#endif + #if 0 if (1) { int tcp_nodelay = 1; @@ -603,7 +661,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_ACCEPTFILTER, NULL) " "for %V failed, ignored", &ls[i].addr_text); @@ -630,7 +688,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) &af, sizeof(struct accept_filter_arg)) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_ACCEPTFILTER, \"%s\") " "for %V failed, ignored", ls[i].accept_filter, &ls[i].addr_text); @@ -653,20 +711,20 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) * if syncookies were used), hence we use 1 second timeout * here. */ - timeout = 1; + value = 1; } else { - timeout = 0; + value = 0; } if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, - &timeout, sizeof(int)) + &value, sizeof(int)) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, " "ignored", - timeout, &ls[i].addr_text); + value, &ls[i].addr_text); continue; } @@ -859,7 +917,7 @@ ngx_close_connection(ngx_connection_t *c) ngx_uint_t log_error, level; ngx_socket_t fd; - if (c->fd == -1) { + if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } @@ -1034,6 +1092,10 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, struct sockaddr_in6 *sin6; #endif + if (c->local_socklen == 0) { + return NGX_ERROR; + } + switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) @@ -1047,6 +1109,12 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + addr = 1; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; addr = sin->sin_addr.s_addr; @@ -1068,13 +1136,16 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, } ngx_memcpy(c->local_sockaddr, &sa, len); + + c->local_socklen = len; } if (s == NULL) { return NGX_OK; } - s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, port); + s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen, + s->data, s->len, port); return NGX_OK; } diff --git a/usr.sbin/nginx/src/core/ngx_connection.h b/usr.sbin/nginx/src/core/ngx_connection.h index 3daf2eee4cb..ed14e6023e7 100644 --- a/usr.sbin/nginx/src/core/ngx_connection.h +++ b/usr.sbin/nginx/src/core/ngx_connection.h @@ -80,6 +80,10 @@ struct ngx_listening_s { int setfib; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + int fastopen; +#endif + }; @@ -108,6 +112,7 @@ typedef enum { #define NGX_LOWLEVEL_BUFFERED 0x0f #define NGX_SSL_BUFFERED 0x01 +#define NGX_SPDY_BUFFERED 0x02 struct ngx_connection_s { @@ -134,11 +139,14 @@ struct ngx_connection_s { socklen_t socklen; ngx_str_t addr_text; + ngx_str_t proxy_protocol_addr; + #if (NGX_SSL) ngx_ssl_connection_t *ssl; #endif struct sockaddr *local_sockaddr; + socklen_t local_socklen; ngx_buf_t *buffer; @@ -166,12 +174,15 @@ struct ngx_connection_s { unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */ unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ + unsigned need_last_buf:1; + #if (NGX_HAVE_IOCP) unsigned accept_context_updated:1; #endif #if (NGX_HAVE_AIO_SENDFILE) unsigned aio_sendfile:1; + unsigned busy_count:2; ngx_buf_t *busy_sendfile; #endif diff --git a/usr.sbin/nginx/src/core/ngx_core.h b/usr.sbin/nginx/src/core/ngx_core.h index dfcf2d56cf8..c479a59546d 100644 --- a/usr.sbin/nginx/src/core/ngx_core.h +++ b/usr.sbin/nginx/src/core/ngx_core.h @@ -77,6 +77,8 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include <ngx_open_file_cache.h> #include <ngx_os.h> #include <ngx_connection.h> +#include <ngx_syslog.h> +#include <ngx_proxy_protocol.h> #define LF (u_char) 10 diff --git a/usr.sbin/nginx/src/core/ngx_cycle.c b/usr.sbin/nginx/src/core/ngx_cycle.c index 0c354c65665..aa42406ffe3 100644 --- a/usr.sbin/nginx/src/core/ngx_cycle.c +++ b/usr.sbin/nginx/src/core/ngx_cycle.c @@ -11,7 +11,6 @@ static void ngx_destroy_cycle_pools(ngx_conf_t *conf); -static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2); static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *shm_zone); static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log); @@ -36,8 +35,6 @@ ngx_tls_key_t ngx_core_tls_key; static ngx_connection_t dumb; /* STUB */ -static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); - ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) @@ -84,13 +81,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->pool = pool; cycle->log = log; - cycle->new_log.log_level = NGX_LOG_ERR; -#if (NGX_ENABLE_SYSLOG) - cycle->new_log.facility = SYSLOG_FACILITY; - cycle->new_log.facility = ERR_SYSLOG_PRIORITY; - cycle->new_log.syslog_on = 0; - cycle->new_log.syslog_set = 0; -#endif cycle->old_cycle = old_cycle; cycle->conf_prefix.len = old_cycle->conf_prefix.len; @@ -345,11 +335,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } - if (cycle->new_log.file == NULL) { - cycle->new_log.file = ngx_conf_open_file(cycle, &error_log); - if (cycle->new_log.file == NULL) { - goto failed; - } + if (ngx_log_open_default(cycle) != NGX_OK) { + goto failed; } /* open the new files */ @@ -506,13 +493,15 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) continue; } - if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK) + if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, + ls[i].sockaddr, ls[i].socklen, 1) + == NGX_OK) { nls[n].fd = ls[i].fd; nls[n].previous = &ls[i]; ls[i].remain = 1; - if (ls[n].backlog != nls[i].backlog) { + if (ls[i].backlog != nls[n].backlog) { nls[n].listen = 1; } @@ -543,7 +532,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - if (ls[n].deferred_accept && !nls[n].deferred_accept) { + if (ls[i].deferred_accept && !nls[n].deferred_accept) { nls[n].delete_deferred = 1; } else if (ls[i].deferred_accept != nls[n].deferred_accept) @@ -555,8 +544,18 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } } - if (nls[n].fd == -1) { + if (nls[n].fd == (ngx_socket_t) -1) { nls[n].open = 1; +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + if (nls[n].accept_filter) { + nls[n].add_deferred = 1; + } +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + if (nls[n].deferred_accept) { + nls[n].add_deferred = 1; + } +#endif } } @@ -588,12 +587,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) /* commit the new cycle configuration */ - if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) { - - if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - ngx_set_stderr_n " failed"); - } + if (!ngx_use_stderr) { + (void) ngx_log_redirect_stderr(cycle); } pool->log = cycle->log; @@ -665,7 +660,7 @@ old_shm_zone_done: ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { - if (ls[i].remain || ls[i].fd == -1) { + if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) { continue; } @@ -829,7 +824,7 @@ failed: ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - if (ls[i].fd == -1 || !ls[i].open) { + if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) { continue; } @@ -855,74 +850,6 @@ ngx_destroy_cycle_pools(ngx_conf_t *conf) static ngx_int_t -ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2) -{ - struct sockaddr_in *sin1, *sin2; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin61, *sin62; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un *saun1, *saun2; -#endif - - if (sa1->sa_family != sa2->sa_family) { - return NGX_DECLINED; - } - - switch (sa1->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin61 = (struct sockaddr_in6 *) sa1; - sin62 = (struct sockaddr_in6 *) sa2; - - if (sin61->sin6_port != sin62->sin6_port) { - return NGX_DECLINED; - } - - if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { - return NGX_DECLINED; - } - - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - saun1 = (struct sockaddr_un *) sa1; - saun2 = (struct sockaddr_un *) sa2; - - if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, - sizeof(saun1->sun_path)) - != 0) - { - return NGX_DECLINED; - } - - break; -#endif - - default: /* AF_INET */ - - sin1 = (struct sockaddr_in *) sa1; - sin2 = (struct sockaddr_in *) sa2; - - if (sin1->sin_port != sin2->sin_port) { - return NGX_DECLINED; - } - - if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { - return NGX_DECLINED; - } - - break; - } - - return NGX_OK; -} - - -static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) { u_char *file; @@ -1238,16 +1165,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) file[i].fd = fd; } -#if !(NGX_WIN32) - - if (cycle->log->file->fd != STDERR_FILENO) { - if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "dup2(STDERR) failed"); - } - } - -#endif + (void) ngx_log_redirect_stderr(cycle); } diff --git a/usr.sbin/nginx/src/core/ngx_cycle.h b/usr.sbin/nginx/src/core/ngx_cycle.h index 2e4bc4ba278..21bf5ca3f25 100644 --- a/usr.sbin/nginx/src/core/ngx_cycle.h +++ b/usr.sbin/nginx/src/core/ngx_cycle.h @@ -41,6 +41,8 @@ struct ngx_cycle_s { ngx_log_t *log; ngx_log_t new_log; + ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */ + ngx_connection_t **files; ngx_connection_t *free_connections; ngx_uint_t free_connection_n; diff --git a/usr.sbin/nginx/src/core/ngx_file.c b/usr.sbin/nginx/src/core/ngx_file.c index ce09bb6021f..4bbdc940211 100644 --- a/usr.sbin/nginx/src/core/ngx_file.c +++ b/usr.sbin/nginx/src/core/ngx_file.c @@ -9,11 +9,102 @@ #include <ngx_core.h> +static ngx_int_t ngx_test_full_name(ngx_str_t *name); + + static ngx_atomic_t temp_number = 0; ngx_atomic_t *ngx_temp_number = &temp_number; ngx_atomic_int_t ngx_random_number = 123456; +ngx_int_t +ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name) +{ + size_t len; + u_char *p, *n; + ngx_int_t rc; + + rc = ngx_test_full_name(name); + + if (rc == NGX_OK) { + return rc; + } + + len = prefix->len; + +#if (NGX_WIN32) + + if (rc == 2) { + len = rc; + } + +#endif + + n = ngx_pnalloc(pool, len + name->len + 1); + if (n == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(n, prefix->data, len); + ngx_cpystrn(p, name->data, name->len + 1); + + name->len += len; + name->data = n; + + return NGX_OK; +} + + +static ngx_int_t +ngx_test_full_name(ngx_str_t *name) +{ +#if (NGX_WIN32) + u_char c0, c1; + + c0 = name->data[0]; + + if (name->len < 2) { + if (c0 == '/') { + return 2; + } + + return NGX_DECLINED; + } + + c1 = name->data[1]; + + if (c1 == ':') { + c0 |= 0x20; + + if ((c0 >= 'a' && c0 <= 'z')) { + return NGX_OK; + } + + return NGX_DECLINED; + } + + if (c1 == '/') { + return NGX_OK; + } + + if (c0 == '/') { + return 2; + } + + return NGX_DECLINED; + +#else + + if (name->data[0] == '/') { + return NGX_OK; + } + + return NGX_DECLINED; + +#endif +} + + ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) { @@ -268,9 +359,6 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NULL; } - path->len = 0; - path->manager = NULL; - path->loader = NULL; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -311,7 +399,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, return NGX_CONF_OK; } - *path = ngx_palloc(cf->pool, sizeof(ngx_path_t)); + *path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); if (*path == NULL) { return NGX_CONF_ERROR; } @@ -330,10 +418,6 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, + init->level[1] + (init->level[1] ? 1 : 0) + init->level[2] + (init->level[2] ? 1 : 0); - (*path)->manager = NULL; - (*path)->loader = NULL; - (*path)->conf_file = NULL; - if (ngx_add_path(cf, path) != NGX_OK) { return NGX_CONF_ERROR; } @@ -417,6 +501,14 @@ ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot) if (p[i]->name.len == path->name.len && ngx_strcmp(p[i]->name.data, path->name.data) == 0) { + if (p[i]->data != path->data) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the same path name \"%V\" " + "used in %s:%ui and", + &p[i]->name, p[i]->conf_file, p[i]->line); + return NGX_ERROR; + } + for (n = 0; n < 3; n++) { if (p[i]->level[n] != path->level[n]) { if (path->conf_file == NULL) { diff --git a/usr.sbin/nginx/src/core/ngx_file.h b/usr.sbin/nginx/src/core/ngx_file.h index 18abf142316..3ea6c28c863 100644 --- a/usr.sbin/nginx/src/core/ngx_file.h +++ b/usr.sbin/nginx/src/core/ngx_file.h @@ -122,6 +122,9 @@ struct ngx_tree_ctx_s { }; +ngx_int_t ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, + ngx_str_t *name); + ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain); ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean, diff --git a/usr.sbin/nginx/src/core/ngx_hash.c b/usr.sbin/nginx/src/core/ngx_hash.c index b532945027c..c7bfed70979 100644 --- a/usr.sbin/nginx/src/core/ngx_hash.c +++ b/usr.sbin/nginx/src/core/ngx_hash.c @@ -282,7 +282,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) start = hinit->max_size - 1000; } - for (size = start; size < hinit->max_size; size++) { + for (size = start; size <= hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); @@ -312,15 +312,12 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) continue; } - ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, - "could not build the %s, you should increase " - "either %s_max_size: %i or %s_bucket_size: %i", + ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0, + "could not build optimal %s, you should increase " + "either %s_max_size: %i or %s_bucket_size: %i; " + "ignoring %s_bucket_size", hinit->name, hinit->name, hinit->max_size, - hinit->name, hinit->bucket_size); - - ngx_free(test); - - return NGX_ERROR; + hinit->name, hinit->bucket_size, hinit->name); found: diff --git a/usr.sbin/nginx/src/core/ngx_inet.c b/usr.sbin/nginx/src/core/ngx_inet.c index 7757ab7d905..26c5bc4b0bb 100644 --- a/usr.sbin/nginx/src/core/ngx_inet.c +++ b/usr.sbin/nginx/src/core/ngx_inet.c @@ -174,7 +174,8 @@ ngx_inet6_addr(u_char *p, size_t len, u_char *addr) size_t -ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) +ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, + ngx_uint_t port) { u_char *p; struct sockaddr_in *sin; @@ -230,9 +231,18 @@ ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) case AF_UNIX: saun = (struct sockaddr_un *) sa; + /* on Linux sockaddr might not include sun_path at all */ + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) { + p = ngx_snprintf(text, len, "unix:%Z"); + + } else { + p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path); + } + /* we do not include trailing zero in address length */ - return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1; + return (p - text - 1); #endif @@ -953,6 +963,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) ngx_memzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; +#ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; +#endif if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) { u->err = "host not found"; @@ -1020,7 +1033,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) goto failed; } - len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; @@ -1053,7 +1066,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) goto failed; } - len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1); + len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p, + len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; @@ -1138,7 +1152,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } - len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + len = ngx_sock_ntop((struct sockaddr *) sin, + sizeof(struct sockaddr_in), p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; @@ -1181,3 +1196,76 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) } #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ + + +ngx_int_t +ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, + struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port) +{ + struct sockaddr_in *sin1, *sin2; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin61, *sin62; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun1, *saun2; +#endif + + if (sa1->sa_family != sa2->sa_family) { + return NGX_DECLINED; + } + + switch (sa1->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + + sin61 = (struct sockaddr_in6 *) sa1; + sin62 = (struct sockaddr_in6 *) sa2; + + if (cmp_port && sin61->sin6_port != sin62->sin6_port) { + return NGX_DECLINED; + } + + if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { + return NGX_DECLINED; + } + + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + /* TODO length */ + + saun1 = (struct sockaddr_un *) sa1; + saun2 = (struct sockaddr_un *) sa2; + + if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, + sizeof(saun1->sun_path)) + != 0) + { + return NGX_DECLINED; + } + + break; +#endif + + default: /* AF_INET */ + + sin1 = (struct sockaddr_in *) sa1; + sin2 = (struct sockaddr_in *) sa2; + + if (cmp_port && sin1->sin_port != sin2->sin_port) { + return NGX_DECLINED; + } + + if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { + return NGX_DECLINED; + } + + break; + } + + return NGX_OK; +} diff --git a/usr.sbin/nginx/src/core/ngx_inet.h b/usr.sbin/nginx/src/core/ngx_inet.h index 6a5a3687d8c..05557509d65 100644 --- a/usr.sbin/nginx/src/core/ngx_inet.h +++ b/usr.sbin/nginx/src/core/ngx_inet.h @@ -107,14 +107,16 @@ in_addr_t ngx_inet_addr(u_char *text, size_t len); 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_sock_ntop(struct sockaddr *sa, socklen_t socklen, 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); +ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, + struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port); #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_list.c b/usr.sbin/nginx/src/core/ngx_list.c index 89ea8235275..d0eb15930a8 100644 --- a/usr.sbin/nginx/src/core/ngx_list.c +++ b/usr.sbin/nginx/src/core/ngx_list.c @@ -19,18 +19,10 @@ ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size) return NULL; } - list->part.elts = ngx_palloc(pool, n * size); - if (list->part.elts == NULL) { + if (ngx_list_init(list, pool, n, size) != NGX_OK) { return NULL; } - list->part.nelts = 0; - list->part.next = NULL; - list->last = &list->part; - list->size = size; - list->nalloc = n; - list->pool = pool; - return list; } diff --git a/usr.sbin/nginx/src/core/ngx_log.c b/usr.sbin/nginx/src/core/ngx_log.c index ddc2bbf6847..375d52f65d4 100644 --- a/usr.sbin/nginx/src/core/ngx_log.c +++ b/usr.sbin/nginx/src/core/ngx_log.c @@ -10,15 +10,8 @@ static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if (NGX_ENABLE_SYSLOG) -static char *ngx_set_syslog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -void log_exit(ngx_cycle_t *cycle); - -typedef struct{ - ngx_str_t name; - ngx_int_t macro; -} ngx_string_to_macro_t; -#endif +static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); +static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log); static ngx_command_t ngx_errlog_commands[] = { @@ -30,15 +23,6 @@ static ngx_command_t ngx_errlog_commands[] = { 0, NULL}, -#if (NGX_ENABLE_SYSLOG) - {ngx_string("syslog"), - NGX_MAIN_CONF|NGX_CONF_TAKE12, - ngx_set_syslog, - 0, - 0, - NULL}, -#endif - ngx_null_command }; @@ -61,11 +45,7 @@ ngx_module_t ngx_errlog_module = { NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ -#if (NGX_ENABLE_SYSLOG) - log_exit, /* exit master */ -#else - NULL, -#endif + NULL, /* exit master */ NGX_MODULE_V1_PADDING }; @@ -74,48 +54,6 @@ static ngx_log_t ngx_log; static ngx_open_file_t ngx_log_file; ngx_uint_t ngx_use_stderr = 1; -#if (NGX_ENABLE_SYSLOG) -static ngx_string_to_macro_t ngx_syslog_facilities[] = { - {ngx_string("auth"), LOG_AUTH}, -#if !(NGX_SOLARIS) - {ngx_string("authpriv"), LOG_AUTHPRIV}, -#endif - {ngx_string("cron"), LOG_CRON}, - {ngx_string("daemon"), LOG_DAEMON}, -#if !(NGX_SOLARIS) - {ngx_string("ftp"), LOG_FTP}, -#endif - {ngx_string("kern"), LOG_KERN}, - {ngx_string("local0"), LOG_LOCAL0}, - {ngx_string("local1"), LOG_LOCAL1}, - {ngx_string("local2"), LOG_LOCAL2}, - {ngx_string("local3"), LOG_LOCAL3}, - {ngx_string("local4"), LOG_LOCAL4}, - {ngx_string("local5"), LOG_LOCAL5}, - {ngx_string("local6"), LOG_LOCAL6}, - {ngx_string("local7"), LOG_LOCAL7}, - {ngx_string("lpr"), LOG_LPR}, - {ngx_string("mail"), LOG_MAIL}, - {ngx_string("news"), LOG_NEWS}, - {ngx_string("syslog"), LOG_SYSLOG}, - {ngx_string("user"), LOG_USER}, - {ngx_string("uucp"), LOG_UUCP}, - { ngx_null_string, 0} -}; - -static ngx_string_to_macro_t ngx_syslog_priorities[] = { - {ngx_string("emerg"), LOG_EMERG}, - {ngx_string("alert"), LOG_ALERT}, - {ngx_string("crit"), LOG_CRIT}, - {ngx_string("error"), LOG_ERR}, - {ngx_string("err"), LOG_ERR}, - {ngx_string("warn"), LOG_WARNING}, - {ngx_string("notice"),LOG_NOTICE}, - {ngx_string("info"), LOG_INFO}, - {ngx_string("debug"), LOG_DEBUG}, - { ngx_null_string, 0} -}; -#endif static ngx_str_t err_levels[] = { ngx_null_string, @@ -150,19 +88,11 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, #endif { #if (NGX_HAVE_VARIADIC_MACROS) - va_list args; -#endif - u_char *p, *last, *msg; -#if (NGX_ENABLE_SYSLOG) - u_char *errstr_syslog; -#endif - u_char errstr[NGX_MAX_ERROR_STR]; - -#if !(NGX_ENABLE_SYSLOG) - if (log->file->fd == NGX_INVALID_FILE) { - return; - } + va_list args; #endif + u_char *p, *last, *msg; + u_char errstr[NGX_MAX_ERROR_STR]; + ngx_uint_t wrote_stderr, debug_connection; last = errstr + NGX_MAX_ERROR_STR; @@ -171,10 +101,6 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, p = errstr + ngx_cached_err_log_time.len; -#if (NGX_ENABLE_SYSLOG) - errstr_syslog = p; -#endif - p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]); /* pid#tid */ @@ -213,27 +139,33 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, ngx_linefeed(p); -#if (NGX_ENABLE_SYSLOG) - if (log->file != NULL && log->file->name.len != 0) { - (void) ngx_write_fd(log->file->fd, errstr, p - errstr); - } + wrote_stderr = 0; + debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0; + + while (log) { + + if (log->log_level < level && !debug_connection) { + break; + } + + if (log->writer) { + log->writer(log, level, errstr, p - errstr); + log = log->next; + continue; + } + + (void) ngx_write_fd(log->file->fd, errstr, p - errstr); - /* Don't send the debug level info to syslog */ - if (log->syslog_on && level < NGX_LOG_DEBUG) { - /* write to syslog */ - syslog(log->priority, "%.*s", (int)(p - errstr_syslog), errstr_syslog); + if (log->file->fd == ngx_stderr) { + wrote_stderr = 1; + } + + log = log->next; } -#else - (void) ngx_write_fd(log->file->fd, errstr, p - errstr); -#endif if (!ngx_use_stderr || level > NGX_LOG_WARN -#if (NGX_ENABLE_SYSLOG) - || (log->file != NULL && log->file->fd == ngx_stderr)) -#else - || log->file->fd == ngx_stderr) -#endif + || wrote_stderr) { return; } @@ -437,75 +369,93 @@ ngx_log_init(u_char *prefix) } -ngx_log_t * -ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name) +ngx_int_t +ngx_log_open_default(ngx_cycle_t *cycle) { - ngx_log_t *log; + ngx_log_t *log; + static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); + + if (ngx_log_get_file_log(&cycle->new_log) != NULL) { + return NGX_OK; + } + + if (cycle->new_log.log_level != 0) { + /* there are some error logs, but no files */ - log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); - if (log == NULL) { - return NULL; + log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); + if (log == NULL) { + return NGX_ERROR; + } + + log->log_level = NGX_LOG_ERR; + ngx_log_insert(&cycle->new_log, log); + + } else { + /* no error logs at all */ + log = &cycle->new_log; + log->log_level = NGX_LOG_ERR; } - log->file = ngx_conf_open_file(cycle, name); + log->file = ngx_conf_open_file(cycle, &error_log); if (log->file == NULL) { - return NULL; + return NGX_ERROR; } - return log; + return NGX_OK; } -#if (NGX_ENABLE_SYSLOG) ngx_int_t -ngx_log_get_priority(ngx_conf_t *cf, ngx_str_t *priority) +ngx_log_redirect_stderr(ngx_cycle_t *cycle) { - ngx_int_t p = 0; - ngx_uint_t n, match = 0; - - for (n = 0; ngx_syslog_priorities[n].name.len != 0; n++) { - if (ngx_strncmp(priority->data, ngx_syslog_priorities[n].name.data, - ngx_syslog_priorities[n].name.len) == 0) { - p = ngx_syslog_priorities[n].macro; - match = 1; - } + ngx_fd_t fd; + + if (cycle->log_use_stderr) { + return NGX_OK; } - if (!match) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid syslog priority \"%V\"", priority); - return -1; + /* file log always exists when we are called */ + fd = ngx_log_get_file_log(cycle->log)->file->fd; + + if (fd != ngx_stderr) { + if (ngx_set_stderr(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_set_stderr_n " failed"); + + return NGX_ERROR; + } } - return p; + return NGX_OK; } -char * -ngx_log_set_priority(ngx_conf_t *cf, ngx_str_t *priority, ngx_log_t *log) +ngx_log_t * +ngx_log_get_file_log(ngx_log_t *head) { - log->priority = ERR_SYSLOG_PRIORITY; - - if (priority->len == 0) { - return NGX_CONF_OK; - } + ngx_log_t *log; - log->priority = ngx_log_get_priority(cf, priority); - if (log->priority == (-1)) { - return NGX_CONF_ERROR; + for (log = head; log; log = log->next) { + if (log->file != NULL) { + return log; + } } - return NGX_CONF_OK; + return NULL; } -#endif -char * +static char * ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) { ngx_uint_t i, n, d, found; ngx_str_t *value; + if (cf->args->nelts == 2) { + log->log_level = NGX_LOG_ERR; + return NGX_CONF_OK; + } + value = cf->args->elts; for (i = 2; i < cf->args->nelts; i++) { @@ -561,136 +511,109 @@ ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) static char * ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_str_t *value, name; -#if (NGX_ENABLE_SYSLOG) - u_char *off = NULL; - ngx_str_t priority; + ngx_log_t *dummy; - ngx_str_null(&name); - ngx_str_null(&priority); -#endif + dummy = &cf->cycle->new_log; - if (cf->cycle->new_log.file) { - return "is duplicate"; - } + return ngx_log_set_log(cf, &dummy); +} - value = cf->args->elts; -#if (NGX_ENABLE_SYSLOG) - if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) { - if (!cf->cycle->new_log.syslog_set) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "You must set the syslog directive and enable it first."); +char * +ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) +{ + ngx_log_t *new_log; + ngx_str_t *value, name; + ngx_syslog_peer_t *peer; + + if (*head != NULL && (*head)->log_level == 0) { + new_log = *head; + + } else { + + new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t)); + if (new_log == NULL) { return NGX_CONF_ERROR; } - cf->cycle->new_log.syslog_on = 1; + if (*head == NULL) { + *head = new_log; + } + } - if (value[1].data[sizeof("syslog") - 1] == ':') { - priority.len = value[1].len - sizeof("syslog"); - priority.data = value[1].data + sizeof("syslog"); + value = cf->args->elts; - off = (u_char *)ngx_strchr(priority.data, (int) '|'); - if (off != NULL) { - priority.len = off - priority.data; + if (ngx_strcmp(value[1].data, "stderr") == 0) { + ngx_str_null(&name); + cf->cycle->log_use_stderr = 1; - off++; - name.len = value[1].data + value[1].len - off; - name.data = off; - } + new_log->file = ngx_conf_open_file(cf->cycle, &name); + if (new_log->file == NULL) { + return NGX_CONF_ERROR; } - else { - if (value[1].len > sizeof("syslog")) { - name.len = value[1].len - sizeof("syslog"); - name.data = value[1].data + sizeof("syslog"); - } + + + } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { + peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); + if (peer == NULL) { + return NGX_CONF_ERROR; } - if (ngx_log_set_priority(cf, &priority, &cf->cycle->new_log) == NGX_CONF_ERROR) { + if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { return NGX_CONF_ERROR; } - } - else if (ngx_strcmp(value[1].data, "stderr") == 0) { -#else - if (ngx_strcmp(value[1].data, "stderr") == 0) { -#endif - ngx_str_null(&name); + + new_log->writer = ngx_syslog_writer; + new_log->wdata = peer; } else { - name = value[1]; + new_log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (new_log->file == NULL) { + return NGX_CONF_ERROR; + } } - cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name); - if (cf->cycle->new_log.file == NULL) { - return NULL; + if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) { + return NGX_CONF_ERROR; } - if (cf->args->nelts == 2) { - cf->cycle->new_log.log_level = NGX_LOG_ERR; - return NGX_CONF_OK; + if (*head != new_log) { + ngx_log_insert(*head, new_log); } - cf->cycle->new_log.log_level = 0; - - return ngx_log_set_levels(cf, &cf->cycle->new_log); + return NGX_CONF_OK; } -#if (NGX_ENABLE_SYSLOG) - -#define SYSLOG_IDENT_NAME "nginx" - -static char * -ngx_set_syslog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static void +ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log) { - char *program; - ngx_str_t *value; - ngx_int_t facility = SYSLOG_FACILITY, match = 0; - ngx_uint_t n; + ngx_log_t tmp; - value = cf->args->elts; + if (new_log->log_level > log->log_level) { - if (cf->cycle->new_log.syslog_set) { - return "is duplicate"; - } + /* + * list head address is permanent, insert new log after + * head and swap its contents with head + */ - cf->cycle->new_log.syslog_set = 1; + tmp = *log; + *log = *new_log; + *new_log = tmp; - for (n = 0; ngx_syslog_facilities[n].name.len != 0; n++) { - if (ngx_strncmp(value[1].data, ngx_syslog_facilities[n].name.data, - ngx_syslog_facilities[n].name.len) == 0) { - facility = ngx_syslog_facilities[n].macro; - match = 1; - break; - } + log->next = new_log; + return; } - if (match) { - cf->cycle->new_log.facility = facility; - cf->cycle->new_log.priority = ERR_SYSLOG_PRIORITY; - } - else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid syslog facility \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } + while (log->next) { + if (new_log->log_level > log->next->log_level) { + new_log->next = log->next; + log->next = new_log; + return; + } - program = SYSLOG_IDENT_NAME; - if (cf->args->nelts > 2) { - program = (char *) value[2].data; + log = log->next; } - openlog(program, LOG_ODELAY, facility); - - return NGX_CONF_OK; + log->next = new_log; } - - -void log_exit(ngx_cycle_t *cycle) -{ - if (cycle->new_log.syslog_set) { - closelog(); - } -} -#endif - diff --git a/usr.sbin/nginx/src/core/ngx_log.h b/usr.sbin/nginx/src/core/ngx_log.h index 5e7fdbf4b4e..c1a52c44f0b 100644 --- a/usr.sbin/nginx/src/core/ngx_log.h +++ b/usr.sbin/nginx/src/core/ngx_log.h @@ -12,13 +12,6 @@ #include <ngx_config.h> #include <ngx_core.h> -#if (NGX_ENABLE_SYSLOG) -#include <syslog.h> - -#define SYSLOG_FACILITY LOG_LOCAL5 -#define ERR_SYSLOG_PRIORITY LOG_ERR -#endif - #define NGX_LOG_STDERR 0 #define NGX_LOG_EMERG 1 @@ -50,6 +43,8 @@ typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len); +typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level, + u_char *buf, size_t len); struct ngx_log_s { @@ -61,6 +56,9 @@ struct ngx_log_s { ngx_log_handler_pt handler; void *data; + ngx_log_writer_pt writer; + void *wdata; + /* * we declare "action" as "char *" because the actions are usually * the static strings and in the "u_char *" case we have to override @@ -69,12 +67,7 @@ struct ngx_log_s { char *action; -#if (NGX_ENABLE_SYSLOG) - ngx_int_t priority; - ngx_int_t facility; - unsigned syslog_on:1; /* unsigned :1 syslog_on */ - unsigned syslog_set:1; /*unsigned :1 syslog_set */ -#endif + ngx_log_t *next; }; @@ -234,15 +227,13 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, /*********************************/ ngx_log_t *ngx_log_init(u_char *prefix); -ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name); -#if (NGX_ENABLE_SYSLOG) -ngx_int_t ngx_log_get_priority(ngx_conf_t *cf, ngx_str_t *priority); -char * ngx_log_set_priority(ngx_conf_t *cf, ngx_str_t *priority, ngx_log_t *log); -#endif -char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...); void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...); u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); +ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle); +ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle); +ngx_log_t *ngx_log_get_file_log(ngx_log_t *head); +char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head); /* diff --git a/usr.sbin/nginx/src/core/ngx_open_file_cache.c b/usr.sbin/nginx/src/core/ngx_open_file_cache.c index c44ac96b8b7..4df2134b2bd 100644 --- a/usr.sbin/nginx/src/core/ngx_open_file_cache.c +++ b/usr.sbin/nginx/src/core/ngx_open_file_cache.c @@ -25,6 +25,10 @@ static void ngx_open_file_cache_cleanup(void *data); #if (NGX_HAVE_OPENAT) static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); +#if (NGX_HAVE_O_PATH) +static ngx_int_t ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, + ngx_log_t *log); +#endif #endif static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, @@ -124,7 +128,7 @@ ngx_open_file_cache_cleanup(void *data) if (cache->current) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "%d items still leave in open file cache", + "%ui items still leave in open file cache", cache->current); } @@ -517,10 +521,17 @@ ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, goto failed; } +#if (NGX_HAVE_O_PATH) + if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) { + err = ngx_errno; + goto failed; + } +#else if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { err = ngx_errno; goto failed; } +#endif if (fi.st_uid != atfi.st_uid) { err = NGX_ELOOP; @@ -541,8 +552,63 @@ failed: return NGX_INVALID_FILE; } + +#if (NGX_HAVE_O_PATH) + +static ngx_int_t +ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log) +{ + static ngx_uint_t use_fstat = 1; + + /* + * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain + * a descriptor without actually opening file or directory. It requires + * less permissions for path components, but till Linux 3.6 fstat() returns + * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag + * should be used instead. + * + * Three scenarios are handled in this function: + * + * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was + * backported by vendor. Then fstat() is used. + * + * 2) The kernel is newer than 2.6.39 but older than 3.6. In this case + * the first call of fstat() returns EBADF and we fallback to fstatat() + * with AT_EMPTY_PATH which was introduced at the same time as O_PATH. + * + * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH + * support. Since descriptors are opened with O_PATH|O_RDONLY flags + * and O_PATH is ignored by the kernel then the O_RDONLY flag is + * actually used. In this case fstat() just works. + */ + + if (use_fstat) { + if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) { + return NGX_OK; + } + + if (ngx_errno != NGX_EBADF) { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "fstat(O_PATH) failed with EBADF, " + "switching to fstatat(AT_EMPTY_PATH)"); + + use_fstat = 0; + } + + if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) { + return NGX_OK; + } + + return NGX_ERROR; +} + #endif +#endif /* NGX_HAVE_OPENAT */ + static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, diff --git a/usr.sbin/nginx/src/core/ngx_palloc.c b/usr.sbin/nginx/src/core/ngx_palloc.c index efbc24452bd..1f70f9eee29 100644 --- a/usr.sbin/nginx/src/core/ngx_palloc.c +++ b/usr.sbin/nginx/src/core/ngx_palloc.c @@ -105,11 +105,14 @@ ngx_reset_pool(ngx_pool_t *pool) } } - pool->large = NULL; - for (p = pool; p; p = p->d.next) { p->d.last = (u_char *) p + sizeof(ngx_pool_t); + p->d.failed = 0; } + + pool->current = pool; + pool->chain = NULL; + pool->large = NULL; } diff --git a/usr.sbin/nginx/src/core/ngx_proxy_protocol.c b/usr.sbin/nginx/src/core/ngx_proxy_protocol.c new file mode 100644 index 00000000000..59ef010fc06 --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_proxy_protocol.c @@ -0,0 +1,91 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +u_char * +ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, u_char *last) +{ + size_t len; + u_char ch, *p, *addr; + + p = buf; + len = last - buf; + + if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) { + goto invalid; + } + + p += 6; + len -= 6; + + if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol unknown protocol"); + p += 7; + goto skip; + } + + if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0 + || (p[3] != '4' && p[3] != '6') || p[4] != ' ') + { + goto invalid; + } + + p += 5; + addr = p; + + for ( ;; ) { + if (p == last) { + goto invalid; + } + + ch = *p++; + + if (ch == ' ') { + break; + } + + if (ch != ':' && ch != '.' + && (ch < 'a' || ch > 'f') + && (ch < 'A' || ch > 'F') + && (ch < '0' || ch > '9')) + { + goto invalid; + } + } + + len = p - addr - 1; + c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len); + + if (c->proxy_protocol_addr.data == NULL) { + return NULL; + } + + ngx_memcpy(c->proxy_protocol_addr.data, addr, len); + c->proxy_protocol_addr.len = len; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol address: \"%V\"", &c->proxy_protocol_addr); + +skip: + + for ( /* void */ ; p < last - 1; p++) { + if (p[0] == CR && p[1] == LF) { + return p + 2; + } + } + +invalid: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "broken header: \"%*s\"", (size_t) (last - buf), buf); + + return NULL; +} diff --git a/usr.sbin/nginx/src/core/ngx_proxy_protocol.h b/usr.sbin/nginx/src/core/ngx_proxy_protocol.h new file mode 100644 index 00000000000..4f3912512f1 --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_proxy_protocol.h @@ -0,0 +1,23 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROXY_PROTOCOL_H_INCLUDED_ +#define _NGX_PROXY_PROTOCOL_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_PROXY_PROTOCOL_MAX_HEADER 107 + + +u_char *ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, + u_char *last); + + +#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_resolver.c b/usr.sbin/nginx/src/core/ngx_resolver.c index d59d0c47162..645738ce531 100644 --- a/usr.sbin/nginx/src/core/ngx_resolver.c +++ b/usr.sbin/nginx/src/core/ngx_resolver.c @@ -26,7 +26,7 @@ typedef struct { u_char nns_lo; u_char nar_hi; u_char nar_lo; -} ngx_resolver_query_t; +} ngx_resolver_hdr_t; typedef struct { @@ -70,7 +70,8 @@ static void ngx_resolver_read_response(ngx_event_t *rev); static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n); static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, - ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans); + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, + ngx_uint_t nan, ngx_uint_t ans); static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, @@ -88,10 +89,17 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size); static void ngx_resolver_free(ngx_resolver_t *r, void *p); static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); -static in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, - ngx_uint_t n); +static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r, + ngx_resolver_node_t *rn, ngx_uint_t rotate); static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len); +#if (NGX_HAVE_INET6) +static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r, + struct in6_addr *addr, uint32_t hash); +#endif + ngx_resolver_t * ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) @@ -134,6 +142,17 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) ngx_queue_init(&r->name_expire_queue); ngx_queue_init(&r->addr_expire_queue); +#if (NGX_HAVE_INET6) + r->ipv6 = 1; + + ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel, + ngx_resolver_rbtree_insert_addr6_value); + + ngx_queue_init(&r->addr6_resend_queue); + + ngx_queue_init(&r->addr6_expire_queue); +#endif + r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; @@ -171,6 +190,25 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) continue; } +#if (NGX_HAVE_INET6) + if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) { + + if (ngx_strcmp(&names[i].data[5], "on") == 0) { + r->ipv6 = 1; + + } else if (ngx_strcmp(&names[i].data[5], "off") == 0) { + r->ipv6 = 0; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter: %V", &names[i]); + return NULL; + } + + continue; + } +#endif + ngx_memzero(&u, sizeof(ngx_url_t)); u.url = names[i]; @@ -220,6 +258,10 @@ ngx_resolver_cleanup(void *data) ngx_resolver_cleanup_tree(r, &r->addr_rbtree); +#if (NGX_HAVE_INET6) + ngx_resolver_cleanup_tree(r, &r->addr6_rbtree); +#endif + if (r->event) { ngx_free(r->event); } @@ -281,7 +323,11 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) temp->state = NGX_OK; temp->naddrs = 1; temp->addrs = &temp->addr; - temp->addr = addr; + temp->addr.sockaddr = (struct sockaddr *) &temp->sin; + temp->addr.socklen = sizeof(struct sockaddr_in); + ngx_memzero(&temp->sin, sizeof(struct sockaddr_in)); + temp->sin.sin_family = AF_INET; + temp->sin.sin_addr.s_addr = addr; temp->quick = 1; return temp; @@ -310,6 +356,10 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) r = ctx->resolver; + if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') { + ctx->name.len--; + } + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve: \"%V\"", &ctx->name); @@ -411,18 +461,18 @@ done: } -/* NGX_RESOLVE_A only */ - static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) { uint32_t hash; - in_addr_t addr, *addrs; ngx_int_t rc; ngx_uint_t naddrs; + ngx_addr_t *addrs; ngx_resolver_ctx_t *next; ngx_resolver_node_t *rn; + ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len); + hash = ngx_crc32_short(ctx->name.data, ctx->name.len); rn = ngx_resolver_lookup_name(r, &ctx->name, hash); @@ -439,22 +489,21 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); - naddrs = rn->naddrs; + naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs; +#if (NGX_HAVE_INET6) + naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6; +#endif if (naddrs) { - /* NGX_RESOLVE_A answer */ + if (naddrs == 1 && rn->naddrs == 1) { + addrs = NULL; - if (naddrs != 1) { - addr = 0; - addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs); + } else { + addrs = ngx_resolver_export(r, rn, 1); if (addrs == NULL) { return NGX_ERROR; } - - } else { - addr = rn->u.addr; - addrs = NULL; } ctx->next = rn->waiting; @@ -465,8 +514,19 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) do { ctx->state = NGX_OK; ctx->naddrs = naddrs; - ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; - ctx->addr = addr; + + if (addrs == NULL) { + ctx->addrs = &ctx->addr; + ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin; + ctx->addr.socklen = sizeof(struct sockaddr_in); + ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in)); + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_addr.s_addr = rn->u.addr; + + } else { + ctx->addrs = addrs; + } + next = ctx->next; ctx->handler(ctx); @@ -474,7 +534,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ctx = next; } while (ctx); - if (addrs) { + if (addrs != NULL) { + ngx_resolver_free(r, addrs->sockaddr); ngx_resolver_free(r, addrs); } @@ -524,16 +585,25 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) if (rn->query) { ngx_resolver_free_locked(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif } if (rn->cnlen) { ngx_resolver_free_locked(r, rn->u.cname); } - if (rn->naddrs > 1) { + if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) { ngx_resolver_free_locked(r, rn->u.addrs); } +#if (NGX_HAVE_INET6) + if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) { + ngx_resolver_free_locked(r, rn->u6.addrs6); + } +#endif + /* unlock alloc mutex */ } else { @@ -552,6 +622,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) rn->node.key = hash; rn->nlen = (u_short) ctx->name.len; rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif ngx_rbtree_insert(&r->name_rbtree, &rn->node); } @@ -575,6 +648,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) return NGX_OK; } + rn->naddrs = (u_short) -1; +#if (NGX_HAVE_INET6) + rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; +#endif + if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } @@ -601,9 +679,10 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); + rn->code = 0; rn->cnlen = 0; - rn->naddrs = 0; rn->valid = 0; + rn->ttl = NGX_MAX_UINT32_VALUE; rn->waiting = ctx; ctx->state = NGX_AGAIN; @@ -630,16 +709,57 @@ ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx) { u_char *name; + in_addr_t addr; + ngx_queue_t *resend_queue, *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_t *r; + struct sockaddr_in *sin; ngx_resolver_node_t *rn; +#if (NGX_HAVE_INET6) + uint32_t hash; + struct sockaddr_in6 *sin6; +#endif + +#if (NGX_SUPPRESS_WARN) + addr = 0; +#if (NGX_HAVE_INET6) + hash = 0; + sin6 = NULL; +#endif +#endif r = ctx->resolver; - ctx->addr = ntohl(ctx->addr); + switch (ctx->addr.sockaddr->sa_family) { - /* lock addr mutex */ +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; + hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16); + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash); + + tree = &r->addr6_rbtree; + resend_queue = &r->addr6_resend_queue; + expire_queue = &r->addr6_expire_queue; + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) ctx->addr.sockaddr; + addr = ntohl(sin->sin_addr.s_addr); - rn = ngx_resolver_lookup_addr(r, ctx->addr); + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, addr); + + tree = &r->addr_rbtree; + resend_queue = &r->addr_resend_queue; + expire_queue = &r->addr_expire_queue; + } if (rn) { @@ -651,7 +771,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) rn->expire = ngx_time() + r->expire; - ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue); + ngx_queue_insert_head(expire_queue, &rn->queue); name = ngx_resolver_dup(r, rn->name, rn->nlen); if (name == NULL) { @@ -687,6 +807,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ngx_resolver_free(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif } else { rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); @@ -694,16 +817,36 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) goto failed; } - rn->node.key = ctx->addr; + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + rn->addr6 = sin6->sin6_addr; + rn->node.key = hash; + break; +#endif + + default: /* AF_INET */ + rn->node.key = addr; + } + rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif - ngx_rbtree_insert(&r->addr_rbtree, &rn->node); + ngx_rbtree_insert(tree, &rn->node); } if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) { goto failed; } + rn->naddrs = (u_short) -1; +#if (NGX_HAVE_INET6) + rn->naddrs6 = (u_short) -1; +#endif + if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } @@ -720,19 +863,20 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ngx_add_timer(ctx->event, ctx->timeout); - if (ngx_queue_empty(&r->addr_resend_queue)) { + if (ngx_queue_empty(resend_queue)) { ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); } rn->expire = ngx_time() + r->resend_timeout; - ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue); + ngx_queue_insert_head(resend_queue, &rn->queue); + rn->code = 0; rn->cnlen = 0; - rn->naddrs = 0; rn->name = NULL; rn->nlen = 0; rn->valid = 0; + rn->ttl = NGX_MAX_UINT32_VALUE; rn->waiting = ctx; /* unlock addr mutex */ @@ -744,7 +888,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) failed: if (rn) { - ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); if (rn->query) { ngx_resolver_free(r, rn->query); @@ -769,12 +913,33 @@ void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) { in_addr_t addr; + ngx_queue_t *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_t *r; ngx_resolver_ctx_t *w, **p; + struct sockaddr_in *sin; ngx_resolver_node_t *rn; +#if (NGX_HAVE_INET6) + uint32_t hash; + struct sockaddr_in6 *sin6; +#endif r = ctx->resolver; + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + tree = &r->addr6_rbtree; + expire_queue = &r->addr6_expire_queue; + break; +#endif + + default: /* AF_INET */ + tree = &r->addr_rbtree; + expire_queue = &r->addr_expire_queue; + } + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve addr done: %i", ctx->state); @@ -786,7 +951,21 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { - rn = ngx_resolver_lookup_addr(r, ctx->addr); + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; + hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16); + rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) ctx->addr.sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + rn = ngx_resolver_lookup_addr(r, addr); + } if (rn) { p = &rn->waiting; @@ -804,17 +983,22 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) } } - addr = ntohl(ctx->addr); + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addrtext; - ngx_log_error(NGX_LOG_ALERT, r->log, 0, - "could not cancel %ud.%ud.%ud.%ud resolving", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + addrtext.data = text; + addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_error(NGX_LOG_ALERT, r->log, 0, + "could not cancel %V resolving", &addrtext); + } } done: - ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue); + ngx_resolver_expire(r, tree, expire_queue); /* unlock addr mutex */ @@ -896,16 +1080,33 @@ ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) uc->connection->read->resolver = 1; } - n = ngx_send(uc->connection, rn->query, rn->qlen); + if (rn->naddrs == (u_short) -1) { + n = ngx_send(uc->connection, rn->query, rn->qlen); - if (n == -1) { - return NGX_ERROR; + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) rn->qlen) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); + return NGX_ERROR; + } } - if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); - return NGX_ERROR; +#if (NGX_HAVE_INET6) + if (rn->query6 && rn->naddrs6 == (u_short) -1) { + n = ngx_send(uc->connection, rn->query6, rn->qlen); + + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) rn->qlen) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); + return NGX_ERROR; + } } +#endif return NGX_OK; } @@ -915,6 +1116,9 @@ static void ngx_resolver_resend_handler(ngx_event_t *ev) { time_t timer, atimer, ntimer; +#if (NGX_HAVE_INET6) + time_t a6timer; +#endif ngx_resolver_t *r; r = ev->data; @@ -934,16 +1138,36 @@ ngx_resolver_resend_handler(ngx_event_t *ev) /* unlock addr mutex */ - if (ntimer == 0) { +#if (NGX_HAVE_INET6) + + /* lock addr6 mutex */ + + a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue); + + /* unlock addr6 mutex */ + +#endif + + timer = ntimer; + + if (timer == 0) { timer = atimer; - } else if (atimer == 0) { - timer = ntimer; + } else if (atimer) { + timer = ngx_min(timer, atimer); + } - } else { - timer = (atimer < ntimer) ? atimer : ntimer; +#if (NGX_HAVE_INET6) + + if (timer == 0) { + timer = a6timer; + + } else if (a6timer) { + timer = ngx_min(timer, a6timer); } +#endif + if (timer) { ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000)); } @@ -1021,39 +1245,42 @@ ngx_resolver_read_response(ngx_event_t *rev) static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) { - char *err; - size_t len; - ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, - qtype, qclass; - ngx_queue_t *q; - ngx_resolver_qs_t *qs; - ngx_resolver_node_t *rn; - ngx_resolver_query_t *query; - - if ((size_t) n < sizeof(ngx_resolver_query_t)) { + char *err; + ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, + qtype, qclass; +#if (NGX_HAVE_INET6) + ngx_uint_t qident6; +#endif + ngx_queue_t *q; + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *response; + ngx_resolver_node_t *rn; + + if (n < sizeof(ngx_resolver_hdr_t)) { goto short_response; } - query = (ngx_resolver_query_t *) buf; + response = (ngx_resolver_hdr_t *) buf; - ident = (query->ident_hi << 8) + query->ident_lo; - flags = (query->flags_hi << 8) + query->flags_lo; - nqs = (query->nqs_hi << 8) + query->nqs_lo; - nan = (query->nan_hi << 8) + query->nan_lo; + ident = (response->ident_hi << 8) + response->ident_lo; + flags = (response->flags_hi << 8) + response->flags_lo; + nqs = (response->nqs_hi << 8) + response->nqs_lo; + nan = (response->nan_hi << 8) + response->nan_lo; ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", ident, flags, nqs, nan, - (query->nns_hi << 8) + query->nns_lo, - (query->nar_hi << 8) + query->nar_lo); + (response->nns_hi << 8) + response->nns_lo, + (response->nar_hi << 8) + response->nar_lo); - if (!(flags & 0x8000)) { + /* response to a standard query */ + if ((flags & 0xf870) != 0x8000) { ngx_log_error(r->log_level, r->log, 0, "invalid DNS response %ui fl:%04Xui", ident, flags); return; } - code = flags & 0x7f; + code = flags & 0xf; if (code == NGX_RESOLVE_FORMERR) { @@ -1067,12 +1294,18 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) qident = (rn->query[0] << 8) + rn->query[1]; if (qident == ident) { - ngx_log_error(r->log_level, r->log, 0, - "DNS error (%ui: %s), query id:%ui, name:\"%*s\"", - code, ngx_resolver_strerror(code), ident, - rn->nlen, rn->name); - return; + goto dns_error_name; + } + +#if (NGX_HAVE_INET6) + if (rn->query6) { + qident6 = (rn->query6[0] << 8) + rn->query6[1]; + + if (qident6 == ident) { + goto dns_error_name; + } } +#endif } goto dns_error; @@ -1087,22 +1320,21 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) goto done; } - i = sizeof(ngx_resolver_query_t); + i = sizeof(ngx_resolver_hdr_t); while (i < (ngx_uint_t) n) { if (buf[i] == '\0') { goto found; } - len = buf[i]; - i += 1 + len; + i += 1 + buf[i]; } goto short_response; found: - if (i++ == 0) { + if (i++ == sizeof(ngx_resolver_hdr_t)) { err = "zero-length domain name in DNS response"; goto done; } @@ -1130,8 +1362,11 @@ found: switch (qtype) { case NGX_RESOLVE_A: +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: +#endif - ngx_resolver_process_a(r, buf, n, ident, code, nan, + ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, i + sizeof(ngx_resolver_qs_t)); break; @@ -1152,7 +1387,7 @@ found: short_response: - err = "short dns response"; + err = "short DNS response"; done: @@ -1160,6 +1395,14 @@ done: return; +dns_error_name: + + ngx_log_error(r->log_level, r->log, 0, + "DNS error (%ui: %s), query id:%ui, name:\"%*s\"", + code, ngx_resolver_strerror(code), ident, + rn->nlen, rn->name); + return; + dns_error: ngx_log_error(r->log_level, r->log, 0, @@ -1171,21 +1414,29 @@ dns_error: static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, - ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans) + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, + ngx_uint_t nan, ngx_uint_t ans) { char *err; u_char *cname; size_t len; int32_t ttl; uint32_t hash; - in_addr_t addr, *addrs; + in_addr_t *addr; ngx_str_t name; - ngx_uint_t qtype, qident, naddrs, a, i, n, start; + ngx_addr_t *addrs; + ngx_uint_t type, class, qident, naddrs, a, i, n, start; +#if (NGX_HAVE_INET6) + struct in6_addr *addr6; +#endif ngx_resolver_an_t *an; ngx_resolver_ctx_t *ctx, *next; ngx_resolver_node_t *rn; - if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) { + if (ngx_resolver_copy(r, &name, buf, + buf + sizeof(ngx_resolver_hdr_t), buf + last) + != NGX_OK) + { return; } @@ -1197,28 +1448,113 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, rn = ngx_resolver_lookup_name(r, &name, hash); - if (rn == NULL || rn->query == NULL) { + if (rn == NULL) { ngx_log_error(r->log_level, r->log, 0, "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); goto failed; } - qident = (rn->query[0] << 8) + rn->query[1]; + switch (qtype) { + +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: + + if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; + } + + rn->naddrs6 = 0; + qident = (rn->query6[0] << 8) + rn->query6[1]; + + break; +#endif + + default: /* NGX_RESOLVE_A */ + + if (rn->query == NULL || rn->naddrs != (u_short) -1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; + } + + rn->naddrs = 0; + qident = (rn->query[0] << 8) + rn->query[1]; + } if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, "wrong ident %ui response for %V, expect %ui", ident, &name, qident); + ngx_resolver_free(r, name.data); goto failed; } ngx_resolver_free(r, name.data); + if (code == 0 && rn->code) { + code = rn->code; + } + if (code == 0 && nan == 0) { - code = 3; /* NXDOMAIN */ + +#if (NGX_HAVE_INET6) + switch (qtype) { + + case NGX_RESOLVE_AAAA: + + if (rn->naddrs == (u_short) -1) { + goto next; + } + + if (rn->naddrs) { + goto export; + } + + break; + + default: /* NGX_RESOLVE_A */ + + if (rn->naddrs6 == (u_short) -1) { + goto next; + } + + if (rn->naddrs6) { + goto export; + } + } +#endif + + code = NGX_RESOLVE_NXDOMAIN; } if (code) { + +#if (NGX_HAVE_INET6) + switch (qtype) { + + case NGX_RESOLVE_AAAA: + + if (rn->naddrs == (u_short) -1) { + rn->code = (u_char) code; + goto next; + } + + break; + + default: /* NGX_RESOLVE_A */ + + if (rn->naddrs6 == (u_short) -1) { + rn->code = (u_char) code; + goto next; + } + } +#endif + next = rn->waiting; rn->waiting = NULL; @@ -1231,11 +1567,11 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, /* unlock name mutex */ while (next) { - ctx = next; - ctx->state = code; - next = ctx->next; + ctx = next; + ctx->state = code; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); } return; @@ -1243,11 +1579,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, i = ans; naddrs = 0; - addr = 0; - addrs = NULL; cname = NULL; - qtype = 0; - ttl = 0; for (a = 0; a < nan; a++) { @@ -1273,7 +1605,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, test_length: if (i - start < 2) { - err = "invalid name in dns response"; + err = "invalid name in DNS response"; goto invalid; } @@ -1285,115 +1617,239 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, an = (ngx_resolver_an_t *) &buf[i]; - qtype = (an->type_hi << 8) + an->type_lo; + type = (an->type_hi << 8) + an->type_lo; + class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + if (ttl < 0) { ttl = 0; } - if (qtype == NGX_RESOLVE_A) { + rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl); - i += sizeof(ngx_resolver_an_t); + i += sizeof(ngx_resolver_an_t); + + switch (type) { + + case NGX_RESOLVE_A: + + if (qtype != NGX_RESOLVE_A) { + err = "unexpected A record in DNS response"; + goto invalid; + } - if (i + len > last) { + if (len != 4) { + err = "invalid A record in DNS response"; + goto invalid; + } + + if (i + 4 > last) { goto short_response; } - addr = htonl((buf[i] << 24) + (buf[i + 1] << 16) - + (buf[i + 2] << 8) + (buf[i + 3])); + naddrs++; + + break; + +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: + + if (qtype != NGX_RESOLVE_AAAA) { + err = "unexpected AAAA record in DNS response"; + goto invalid; + } + + if (len != 16) { + err = "invalid AAAA record in DNS response"; + goto invalid; + } + + if (i + 16 > last) { + goto short_response; + } naddrs++; - i += len; + break; +#endif - } else if (qtype == NGX_RESOLVE_CNAME) { - cname = &buf[i] + sizeof(ngx_resolver_an_t); - i += sizeof(ngx_resolver_an_t) + len; + case NGX_RESOLVE_CNAME: - } else if (qtype == NGX_RESOLVE_DNAME) { - i += sizeof(ngx_resolver_an_t) + len; + cname = &buf[i]; + + break; + + case NGX_RESOLVE_DNAME: + + break; + + default: - } else { ngx_log_error(r->log_level, r->log, 0, - "unexpected qtype %ui", qtype); + "unexpected RR type %ui", type); } + + i += len; } ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver naddrs:%ui cname:%p ttl:%d", - naddrs, cname, ttl); + "resolver naddrs:%ui cname:%p ttl:%uD", + naddrs, cname, rn->ttl); if (naddrs) { - if (naddrs == 1) { - rn->u.addr = addr; + switch (qtype) { - } else { +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: - addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t)); - if (addrs == NULL) { - return; + if (naddrs == 1) { + addr6 = &rn->u6.addr6; + rn->naddrs6 = 1; + + } else { + addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr)); + if (addr6 == NULL) { + goto failed; + } + + rn->u6.addrs6 = addr6; + rn->naddrs6 = (u_short) naddrs; } - n = 0; - i = ans; +#if (NGX_SUPPRESS_WARN) + addr = NULL; +#endif - for (a = 0; a < nan; a++) { + break; +#endif - for ( ;; ) { + default: /* NGX_RESOLVE_A */ - if (buf[i] & 0xc0) { - i += 2; - goto ok; - } + if (naddrs == 1) { + addr = &rn->u.addr; + rn->naddrs = 1; - if (buf[i] == 0) { - i++; - goto ok; - } + } else { + addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t)); + if (addr == NULL) { + goto failed; + } + + rn->u.addrs = addr; + rn->naddrs = (u_short) naddrs; + } + +#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN) + addr6 = NULL; +#endif + } - i += 1 + buf[i]; + n = 0; + i = ans; + + for (a = 0; a < nan; a++) { + + for ( ;; ) { + + if (buf[i] & 0xc0) { + i += 2; + break; + } + + if (buf[i] == 0) { + i++; + break; } - ok: + i += 1 + buf[i]; + } + + an = (ngx_resolver_an_t *) &buf[i]; - an = (ngx_resolver_an_t *) &buf[i]; + type = (an->type_hi << 8) + an->type_lo; + len = (an->len_hi << 8) + an->len_lo; - qtype = (an->type_hi << 8) + an->type_lo; - len = (an->len_hi << 8) + an->len_lo; + i += sizeof(ngx_resolver_an_t); - i += sizeof(ngx_resolver_an_t); + if (type == NGX_RESOLVE_A) { - if (qtype == NGX_RESOLVE_A) { + addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16) + + (buf[i + 2] << 8) + (buf[i + 3])); - addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16) - + (buf[i + 2] << 8) + (buf[i + 3])); + if (++n == naddrs) { - if (n == naddrs) { - break; +#if (NGX_HAVE_INET6) + if (rn->naddrs6 == (u_short) -1) { + goto next; } +#endif + + break; } + } + +#if (NGX_HAVE_INET6) + else if (type == NGX_RESOLVE_AAAA) { + + ngx_memcpy(addr6[n].s6_addr, &buf[i], 16); + + if (++n == naddrs) { + + if (rn->naddrs == (u_short) -1) { + goto next; + } - i += len; + break; + } } +#endif - rn->u.addrs = addrs; + i += len; + } + } - addrs = ngx_resolver_dup(r, rn->u.addrs, - naddrs * sizeof(in_addr_t)); + if (rn->naddrs != (u_short) -1 +#if (NGX_HAVE_INET6) + && rn->naddrs6 != (u_short) -1 +#endif + && rn->naddrs +#if (NGX_HAVE_INET6) + + rn->naddrs6 +#endif + > 0) + { + +#if (NGX_HAVE_INET6) + export: +#endif + + naddrs = rn->naddrs; +#if (NGX_HAVE_INET6) + naddrs += rn->naddrs6; +#endif + + if (naddrs == 1 && rn->naddrs == 1) { + addrs = NULL; + + } else { + addrs = ngx_resolver_export(r, rn, 0); if (addrs == NULL) { - return; + goto failed; } } - rn->naddrs = (u_short) naddrs; - ngx_queue_remove(&rn->queue); - rn->valid = ngx_time() + (r->valid ? r->valid : ttl); + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); rn->expire = ngx_time() + r->expire; ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); @@ -1404,31 +1860,56 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, /* unlock name mutex */ while (next) { - ctx = next; - ctx->state = NGX_OK; - ctx->naddrs = naddrs; - ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; - ctx->addr = addr; - next = ctx->next; + ctx = next; + ctx->state = NGX_OK; + ctx->naddrs = naddrs; + + if (addrs == NULL) { + ctx->addrs = &ctx->addr; + ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin; + ctx->addr.socklen = sizeof(struct sockaddr_in); + ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in)); + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_addr.s_addr = rn->u.addr; + + } else { + ctx->addrs = addrs; + } - ctx->handler(ctx); + next = ctx->next; + + ctx->handler(ctx); } - if (naddrs > 1) { + if (addrs != NULL) { + ngx_resolver_free(r, addrs->sockaddr); ngx_resolver_free(r, addrs); } ngx_resolver_free(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif return; + } - } else if (cname) { + if (cname) { /* CNAME only */ - if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) { - return; + if (rn->naddrs == (u_short) -1 +#if (NGX_HAVE_INET6) + || rn->naddrs6 == (u_short) -1 +#endif + ) + { + goto next; + } + + if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) { + goto failed; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, @@ -1439,7 +1920,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, rn->cnlen = (u_short) name.len; rn->u.cname = name.data; - rn->valid = ngx_time() + (r->valid ? r->valid : ttl); + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); rn->expire = ngx_time() + r->expire; ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); @@ -1455,18 +1936,22 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_resolver_free(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif + + /* unlock name mutex */ return; } ngx_log_error(r->log_level, r->log, 0, - "no A or CNAME types in DNS responses, unknown query type: %ui", - qtype); + "no A or CNAME types in DNS response"); return; short_response: - err = "short dns response"; + err = "short DNS response"; invalid: @@ -1478,9 +1963,9 @@ invalid: failed: - /* unlock name mutex */ +next: - ngx_resolver_free(r, name.data); + /* unlock name mutex */ return; } @@ -1492,47 +1977,123 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, { char *err; size_t len; + u_char text[NGX_SOCKADDR_STRLEN]; in_addr_t addr; int32_t ttl; - ngx_int_t digit; + ngx_int_t octet; ngx_str_t name; - ngx_uint_t i, mask, qident; + ngx_uint_t i, mask, qident, class; + ngx_queue_t *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_an_t *an; ngx_resolver_ctx_t *ctx, *next; ngx_resolver_node_t *rn; +#if (NGX_HAVE_INET6) + uint32_t hash; + ngx_int_t digit; + struct in6_addr addr6; +#endif - if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) { - goto invalid_in_addr_arpa; + if (ngx_resolver_copy(r, NULL, buf, + buf + sizeof(ngx_resolver_hdr_t), buf + n) + != NGX_OK) + { + return; } + /* AF_INET */ + addr = 0; - i = 12; + i = sizeof(ngx_resolver_hdr_t); for (mask = 0; mask < 32; mask += 8) { len = buf[i++]; - digit = ngx_atoi(&buf[i], len); - if (digit == NGX_ERROR || digit > 255) { + octet = ngx_atoi(&buf[i], len); + if (octet == NGX_ERROR || octet > 255) { goto invalid_in_addr_arpa; } - addr += digit << mask; + addr += octet << mask; i += len; } - if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) { - goto invalid_in_addr_arpa; + if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) { + i += sizeof("\7in-addr\4arpa"); + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, addr); + + tree = &r->addr_rbtree; + expire_queue = &r->addr_expire_queue; + + addr = htonl(addr); + name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN); + name.data = text; + + goto valid; } - /* lock addr mutex */ +invalid_in_addr_arpa: + +#if (NGX_HAVE_INET6) + + i = sizeof(ngx_resolver_hdr_t); + + for (octet = 15; octet >= 0; octet--) { + if (buf[i++] != '\1') { + goto invalid_ip6_arpa; + } + + digit = ngx_hextoi(&buf[i++], 1); + if (digit == NGX_ERROR) { + goto invalid_ip6_arpa; + } + + addr6.s6_addr[octet] = (u_char) digit; + + if (buf[i++] != '\1') { + goto invalid_ip6_arpa; + } + + digit = ngx_hextoi(&buf[i++], 1); + if (digit == NGX_ERROR) { + goto invalid_ip6_arpa; + } + + addr6.s6_addr[octet] += (u_char) (digit * 16); + } + + if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) { + i += sizeof("\3ip6\4arpa"); + + /* lock addr mutex */ + + hash = ngx_crc32_short(addr6.s6_addr, 16); + rn = ngx_resolver_lookup_addr6(r, &addr6, hash); + + tree = &r->addr6_rbtree; + expire_queue = &r->addr6_expire_queue; + + name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN); + name.data = text; + + goto valid; + } - rn = ngx_resolver_lookup_addr(r, addr); +invalid_ip6_arpa: +#endif + + ngx_log_error(r->log_level, r->log, 0, + "invalid in-addr.arpa or ip6.arpa name in DNS response"); + return; + +valid: if (rn == NULL || rn->query == NULL) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + "unexpected response for %V", &name); goto failed; } @@ -1540,14 +2101,13 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui", - ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff, qident); + "wrong ident %ui response for %V, expect %ui", + ident, &name, qident); goto failed; } if (code == 0 && nan == 0) { - code = 3; /* NXDOMAIN */ + code = NGX_RESOLVE_NXDOMAIN; } if (code) { @@ -1556,42 +2116,49 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_queue_remove(&rn->queue); - ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); ngx_resolver_free_node(r, rn); /* unlock addr mutex */ while (next) { - ctx = next; - ctx->state = code; - next = ctx->next; + ctx = next; + ctx->state = code; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); } return; } - i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t); + i += sizeof(ngx_resolver_qs_t); - if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) { + if (i + 2 + sizeof(ngx_resolver_an_t) >= n) { goto short_response; } - /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */ + /* compression pointer to *.arpa */ - if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) { - err = "invalid in-addr.arpa name in DNS response"; + if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) { + err = "invalid in-addr.arpa or ip6.arpa name in DNS response"; goto invalid; } an = (ngx_resolver_an_t *) &buf[i + 2]; + class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + if (ttl < 0) { ttl = 0; } @@ -1599,16 +2166,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qt:%ui cl:%ui len:%uz", (an->type_hi << 8) + an->type_lo, - (an->class_hi << 8) + an->class_lo, len); + class, len); i += 2 + sizeof(ngx_resolver_an_t); - if (i + len > (ngx_uint_t) n) { + if (i + len > n) { goto short_response; } - if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) { - return; + if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) { + goto failed; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name); @@ -1634,7 +2201,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, rn->valid = ngx_time() + (r->valid ? r->valid : ttl); rn->expire = ngx_time() + r->expire; - ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue); + ngx_queue_insert_head(expire_queue, &rn->queue); next = rn->waiting; rn->waiting = NULL; @@ -1642,24 +2209,18 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, /* unlock addr mutex */ while (next) { - ctx = next; - ctx->state = NGX_OK; - ctx->name = name; - next = ctx->next; + ctx = next; + ctx->state = NGX_OK; + ctx->name = name; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); } ngx_resolver_free(r, name.data); return; -invalid_in_addr_arpa: - - ngx_log_error(r->log_level, r->log, 0, - "invalid in-addr.arpa name in DNS response"); - return; - short_response: err = "short DNS response"; @@ -1752,6 +2313,52 @@ ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr) } +#if (NGX_HAVE_INET6) + +static ngx_resolver_node_t * +ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_resolver_node_t *rn; + + node = r->addr6_rbtree.root; + sentinel = r->addr6_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + rn = (ngx_resolver_node_t *) node; + + rc = ngx_memcmp(addr, &rn->addr6, 16); + + if (rc == 0) { + return rn; + } + + node = (rc < 0) ? node->left : node->right; + } + + /* not found */ + + return NULL; +} + +#endif + + static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) @@ -1793,20 +2400,74 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, } +#if (NGX_HAVE_INET6) + +static void +ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_resolver_node_t *rn, *rn_temp; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + rn = (ngx_resolver_node_t *) node; + rn_temp = (ngx_resolver_node_t *) temp; + + p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16) + < 0) ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + +#endif + + 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, nlen; - ngx_uint_t ident; - ngx_resolver_qs_t *qs; - ngx_resolver_query_t *query; + u_char *p, *s; + size_t len, nlen; + ngx_uint_t ident; +#if (NGX_HAVE_INET6) + ngx_resolver_t *r; +#endif + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *query; nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1; - len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t); + len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); +#if (NGX_HAVE_INET6) + r = ctx->resolver; + + p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len); +#else p = ngx_resolver_alloc(ctx->resolver, len); +#endif if (p == NULL) { return NGX_ERROR; } @@ -1814,12 +2475,18 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) rn->qlen = (u_short) len; rn->query = p; - query = (ngx_resolver_query_t *) p; +#if (NGX_HAVE_INET6) + if (r->ipv6) { + rn->query6 = p + len; + } +#endif + + query = (ngx_resolver_hdr_t *) p; ident = ngx_random(); ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, - "resolve: \"%V\" %i", &ctx->name, ident & 0xffff); + "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff); query->ident_hi = (u_char) ((ident >> 8) & 0xff); query->ident_lo = (u_char) (ident & 0xff); @@ -1833,14 +2500,14 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) query->nns_hi = 0; query->nns_lo = 0; query->nar_hi = 0; query->nar_lo = 0; - p += sizeof(ngx_resolver_query_t) + nlen; + p += sizeof(ngx_resolver_hdr_t) + nlen; qs = (ngx_resolver_qs_t *) p; /* query type */ - qs->type_hi = 0; qs->type_lo = (u_char) ctx->type; + qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A; - /* IP query class */ + /* IN query class */ qs->class_hi = 0; qs->class_lo = 1; /* convert "www.example.com" to "\3www\7example\3com\0" */ @@ -1876,24 +2543,66 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) *p = (u_char) len; +#if (NGX_HAVE_INET6) + if (!r->ipv6) { + return NGX_OK; + } + + p = rn->query6; + + ngx_memcpy(p, rn->query, rn->qlen); + + query = (ngx_resolver_hdr_t *) p; + + ident = ngx_random(); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, + "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + + p += sizeof(ngx_resolver_hdr_t) + nlen; + + qs = (ngx_resolver_qs_t *) p; + + qs->type_lo = NGX_RESOLVE_AAAA; +#endif + return NGX_OK; } -/* AF_INET only */ - static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) { - u_char *p, *d; - size_t len; - ngx_int_t n; - ngx_uint_t ident; - ngx_resolver_query_t *query; + u_char *p, *d; + size_t len; + in_addr_t addr; + ngx_int_t n; + ngx_uint_t ident; + ngx_resolver_hdr_t *query; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (ctx->addr.sockaddr->sa_family) { - len = sizeof(ngx_resolver_query_t) - + sizeof(".255.255.255.255.in-addr.arpa.") - 1 - + sizeof(ngx_resolver_qs_t); +#if (NGX_HAVE_INET6) + case AF_INET6: + len = sizeof(ngx_resolver_hdr_t) + + 64 + sizeof(".ip6.arpa.") - 1 + + sizeof(ngx_resolver_qs_t); + + break; +#endif + + default: /* AF_INET */ + len = sizeof(ngx_resolver_hdr_t) + + sizeof(".255.255.255.255.in-addr.arpa.") - 1 + + sizeof(ngx_resolver_qs_t); + } p = ngx_resolver_alloc(ctx->resolver, len); if (p == NULL) { @@ -1901,7 +2610,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) } rn->query = p; - query = (ngx_resolver_query_t *) p; + query = (ngx_resolver_hdr_t *) p; ident = ngx_random(); @@ -1917,20 +2626,43 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) query->nns_hi = 0; query->nns_lo = 0; query->nar_hi = 0; query->nar_lo = 0; - p += sizeof(ngx_resolver_query_t); + p += sizeof(ngx_resolver_hdr_t); + + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; + + for (n = 15; n >= 0; n--) { + p = ngx_sprintf(p, "\1%xd\1%xd", + sin6->sin6_addr.s6_addr[n] & 0xf, + (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf); + } + + p = ngx_cpymem(p, "\3ip6\4arpa\0", 10); - for (n = 0; n < 32; n += 8) { - d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff); - *p = (u_char) (d - &p[1]); - p = d; + break; +#endif + + default: /* AF_INET */ + + sin = (struct sockaddr_in *) ctx->addr.sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + for (n = 0; n < 32; n += 8) { + d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff); + *p = (u_char) (d - &p[1]); + p = d; + } + + p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14); } - /* query type "PTR", IP query class */ - ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18); + /* query type "PTR", IN query class */ + p = ngx_cpymem(p, "\0\14\0\1", 4); - rn->qlen = (u_short) - (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t) - - rn->query); + rn->qlen = (u_short) (p - rn->query); return NGX_OK; } @@ -2012,7 +2744,7 @@ done: n = *src++; } else { - ngx_memcpy(dst, src, n); + ngx_strlow(dst, src, n); dst += n; src += n; @@ -2061,10 +2793,16 @@ ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) ngx_resolver_free_locked(r, rn->u.cname); } - if (rn->naddrs > 1) { + if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) { ngx_resolver_free_locked(r, rn->u.addrs); } +#if (NGX_HAVE_INET6) + if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) { + ngx_resolver_free_locked(r, rn->u6.addrs6); + } +#endif + ngx_resolver_free_locked(r, rn); /* unlock alloc mutex */ @@ -2136,27 +2874,84 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size) } -static in_addr_t * -ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n) +static ngx_addr_t * +ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, + ngx_uint_t rotate) { - void *dst, *p; - ngx_uint_t j; + ngx_addr_t *dst; + ngx_uint_t d, i, j, n; + u_char (*sockaddr)[NGX_SOCKADDRLEN]; + in_addr_t *addr; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr *addr6; + struct sockaddr_in6 *sin6; +#endif - dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t)); + n = rn->naddrs; +#if (NGX_HAVE_INET6) + n += rn->naddrs6; +#endif + dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t)); if (dst == NULL) { - return dst; + return NULL; } - j = ngx_random() % n; + sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN); + if (sockaddr == NULL) { + ngx_resolver_free(r, dst); + return NULL; + } - if (j == 0) { - ngx_memcpy(dst, src, n * sizeof(in_addr_t)); - return dst; + i = 0; + d = rotate ? ngx_random() % n : 0; + + if (rn->naddrs) { + j = rotate ? ngx_random() % rn->naddrs : 0; + + addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs; + + do { + sin = (struct sockaddr_in *) sockaddr[d]; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = addr[j++]; + dst[d].sockaddr = (struct sockaddr *) sin; + dst[d++].socklen = sizeof(struct sockaddr_in); + + if (d == n) { + d = 0; + } + + if (j == rn->naddrs) { + j = 0; + } + } while (++i < rn->naddrs); } - p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t)); - ngx_memcpy(p, src, j * sizeof(in_addr_t)); +#if (NGX_HAVE_INET6) + if (rn->naddrs6) { + j = rotate ? ngx_random() % rn->naddrs6 : 0; + + addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6; + + do { + sin6 = (struct sockaddr_in6 *) sockaddr[d]; + sin6->sin6_family = AF_INET6; + ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16); + dst[d].sockaddr = (struct sockaddr *) sin6; + dst[d++].socklen = sizeof(struct sockaddr_in6); + + if (d == n) { + d = 0; + } + + if (j == rn->naddrs6) { + j = 0; + } + } while (++i < n); + } +#endif return dst; } @@ -2221,7 +3016,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s); - if (s == -1) { + if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; @@ -2242,14 +3037,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); - ngx_free_connection(c); - - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - - return NGX_ERROR; + goto failed; } rev = c->read; @@ -2274,7 +3062,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) #endif ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, - "connect to %V, fd:%d #%d", &uc->server, s, c->number); + "connect to %V, fd:%d #%uA", &uc->server, s, c->number); rc = connect(s, uc->sockaddr, uc->socklen); @@ -2284,7 +3072,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "connect() failed"); - return NGX_ERROR; + goto failed; } /* UDP sockets are always ready to write */ @@ -2298,16 +3086,23 @@ ngx_udp_connect(ngx_udp_connection_t *uc) /* eventport event type has no meaning: oneshot only */ if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } } else { /* rtsig */ if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; + goto failed; } } return NGX_OK; + +failed: + + ngx_close_connection(c); + uc->connection = NULL; + + return NGX_ERROR; } diff --git a/usr.sbin/nginx/src/core/ngx_resolver.h b/usr.sbin/nginx/src/core/ngx_resolver.h index ae34ca56d3a..264c8c42b98 100644 --- a/usr.sbin/nginx/src/core/ngx_resolver.h +++ b/usr.sbin/nginx/src/core/ngx_resolver.h @@ -18,6 +18,9 @@ #define NGX_RESOLVE_PTR 12 #define NGX_RESOLVE_MX 15 #define NGX_RESOLVE_TXT 16 +#if (NGX_HAVE_INET6) +#define NGX_RESOLVE_AAAA 28 +#endif #define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 @@ -54,10 +57,18 @@ typedef struct { /* PTR: resolved name, A: name to resolve */ u_char *name; +#if (NGX_HAVE_INET6) + /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */ + struct in6_addr addr6; +#endif + u_short nlen; u_short qlen; u_char *query; +#if (NGX_HAVE_INET6) + u_char *query6; +#endif union { in_addr_t addr; @@ -65,11 +76,22 @@ typedef struct { u_char *cname; } u; + u_char code; u_short naddrs; u_short cnlen; +#if (NGX_HAVE_INET6) + union { + struct in6_addr addr6; + struct in6_addr *addrs6; + } u6; + + u_short naddrs6; +#endif + time_t expire; time_t valid; + uint32_t ttl; ngx_resolver_ctx_t *waiting; } ngx_resolver_node_t; @@ -100,6 +122,14 @@ typedef struct { ngx_queue_t name_expire_queue; ngx_queue_t addr_expire_queue; +#if (NGX_HAVE_INET6) + ngx_uint_t ipv6; /* unsigned ipv6:1; */ + ngx_rbtree_t addr6_rbtree; + ngx_rbtree_node_t addr6_sentinel; + ngx_queue_t addr6_resend_queue; + ngx_queue_t addr6_expire_queue; +#endif + time_t resend_timeout; time_t expire; time_t valid; @@ -117,12 +147,12 @@ struct ngx_resolver_ctx_s { ngx_int_t ident; ngx_int_t state; - ngx_int_t type; ngx_str_t name; ngx_uint_t naddrs; - in_addr_t *addrs; - in_addr_t addr; + ngx_addr_t *addrs; + ngx_addr_t addr; + struct sockaddr_in sin; ngx_resolver_handler_pt handler; void *data; diff --git a/usr.sbin/nginx/src/core/ngx_slab.c b/usr.sbin/nginx/src/core/ngx_slab.c index ae9d6f3fc0e..be7927ce067 100644 --- a/usr.sbin/nginx/src/core/ngx_slab.c +++ b/usr.sbin/nginx/src/core/ngx_slab.c @@ -129,6 +129,7 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->slab = pages; } + pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; } @@ -440,7 +441,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1)); n /= (sizeof(uintptr_t) * 8); - bitmap = (uintptr_t *) ((uintptr_t) p & ~(ngx_pagesize - 1)); + bitmap = (uintptr_t *) + ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1)); if (bitmap[n] & m) { @@ -657,7 +659,10 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages) } } - ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory"); + if (pool->log_nomem) { + ngx_slab_error(pool, NGX_LOG_CRIT, + "ngx_slab_alloc() failed: no memory"); + } return NULL; } diff --git a/usr.sbin/nginx/src/core/ngx_slab.h b/usr.sbin/nginx/src/core/ngx_slab.h index c5e420bfa8e..5735e3bb3b9 100644 --- a/usr.sbin/nginx/src/core/ngx_slab.h +++ b/usr.sbin/nginx/src/core/ngx_slab.h @@ -39,6 +39,8 @@ typedef struct { u_char *log_ctx; u_char zero; + unsigned log_nomem:1; + void *data; void *addr; } ngx_slab_pool_t; diff --git a/usr.sbin/nginx/src/core/ngx_string.c b/usr.sbin/nginx/src/core/ngx_string.c index 1d1989da24d..a4cfcdc7a5e 100644 --- a/usr.sbin/nginx/src/core/ngx_string.c +++ b/usr.sbin/nginx/src/core/ngx_string.c @@ -11,6 +11,8 @@ static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width); +static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, + const u_char *basis, ngx_uint_t padding); static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis); @@ -486,7 +488,7 @@ ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, if (hexadecimal == 0) { - if (ui64 <= NGX_MAX_UINT32_VALUE) { + if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) { /* * To divide 64-bit numbers and to find remainders @@ -853,6 +855,46 @@ ngx_dns_strcmp(u_char *s1, u_char *s2) ngx_int_t +ngx_filename_cmp(u_char *s1, u_char *s2, size_t n) +{ + ngx_uint_t c1, c2; + + while (n) { + c1 = (ngx_uint_t) *s1++; + c2 = (ngx_uint_t) *s2++; + +#if (NGX_HAVE_CASELESS_FILESYSTEM) + c1 = tolower(c1); + c2 = tolower(c2); +#endif + + if (c1 == c2) { + + if (c1) { + n--; + continue; + } + + return 0; + } + + /* we need '/' to be the lowest character */ + + if (c1 == 0 || c2 == 0) { + return c1 - c2; + } + + c1 = (c1 == '/') ? 0 : c1; + c2 = (c2 == '/') ? 0 : c2; + + return c1 - c2; + } + + return 0; +} + + +ngx_int_t ngx_atoi(u_char *line, size_t n) { ngx_int_t value; @@ -1060,38 +1102,61 @@ ngx_hex_dump(u_char *dst, u_char *src, size_t len) void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src) { - u_char *d, *s; - size_t len; static u_char basis64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + ngx_encode_base64_internal(dst, src, basis64, 1); +} + + +void +ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src) +{ + static u_char basis64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + + ngx_encode_base64_internal(dst, src, basis64, 0); +} + + +static void +ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis, + ngx_uint_t padding) +{ + u_char *d, *s; + size_t len; + len = src->len; s = src->data; d = dst->data; while (len > 2) { - *d++ = basis64[(s[0] >> 2) & 0x3f]; - *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)]; - *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)]; - *d++ = basis64[s[2] & 0x3f]; + *d++ = basis[(s[0] >> 2) & 0x3f]; + *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; + *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)]; + *d++ = basis[s[2] & 0x3f]; s += 3; len -= 3; } if (len) { - *d++ = basis64[(s[0] >> 2) & 0x3f]; + *d++ = basis[(s[0] >> 2) & 0x3f]; if (len == 1) { - *d++ = basis64[(s[0] & 3) << 4]; - *d++ = '='; + *d++ = basis[(s[0] & 3) << 4]; + if (padding) { + *d++ = '='; + } } else { - *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)]; - *d++ = basis64[(s[1] & 0x0f) << 2]; + *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; + *d++ = basis[(s[1] & 0x0f) << 2]; } - *d++ = '='; + if (padding) { + *d++ = '='; + } } dst->len = d - dst->data; diff --git a/usr.sbin/nginx/src/core/ngx_string.h b/usr.sbin/nginx/src/core/ngx_string.h index 52c6f338d89..dc0be5b5532 100644 --- a/usr.sbin/nginx/src/core/ngx_string.h +++ b/usr.sbin/nginx/src/core/ngx_string.h @@ -167,6 +167,7 @@ ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2); ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2); +ngx_int_t ngx_filename_cmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_atoi(u_char *line, size_t n); ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point); @@ -182,6 +183,7 @@ u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len); #define ngx_base64_decoded_length(len) (((len + 3) / 4) * 3) void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src); +void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src); diff --git a/usr.sbin/nginx/src/core/ngx_syslog.c b/usr.sbin/nginx/src/core/ngx_syslog.c new file mode 100644 index 00000000000..7c5de38b6cb --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_syslog.c @@ -0,0 +1,342 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +#define NGX_SYSLOG_MAX_STR \ + NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \ + + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \ + + 32 /* tag */ + 2 /* colon, space */ + + +static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer); +static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer); +static void ngx_syslog_cleanup(void *data); + + +static char *facilities[] = { + "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp", + "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0", + "local1", "local2", "local3", "local4", "local5", "local6", "local7", + NULL +}; + +/* note 'error/warn' like in nginx.conf, not 'err/warning' */ +static char *severities[] = { + "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL +}; + +static ngx_log_t ngx_syslog_dummy_log; +static ngx_event_t ngx_syslog_dummy_event; + + +char * +ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) +{ + peer->pool = cf->pool; + peer->facility = NGX_CONF_UNSET_UINT; + peer->severity = NGX_CONF_UNSET_UINT; + + if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + if (peer->server.sockaddr == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no syslog server specified"); + return NGX_CONF_ERROR; + } + + if (peer->facility == NGX_CONF_UNSET_UINT) { + peer->facility = 23; /* local7 */ + } + + if (peer->severity == NGX_CONF_UNSET_UINT) { + peer->severity = 6; /* info */ + } + + if (peer->tag.data == NULL) { + ngx_str_set(&peer->tag, "nginx"); + } + + peer->conn.fd = (ngx_socket_t) -1; + + return NGX_CONF_OK; +} + + +static char * +ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer) +{ + u_char *p, *comma, c; + size_t len; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t i; + + value = cf->args->elts; + + p = value[1].data + sizeof("syslog:") - 1; + + for ( ;; ) { + comma = (u_char *) ngx_strchr(p, ','); + + if (comma != NULL) { + len = comma - p; + *comma = '\0'; + + } else { + len = value[1].data + value[1].len - p; + } + + if (ngx_strncmp(p, "server=", 7) == 0) { + + if (peer->server.sockaddr != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"server\""); + return NGX_CONF_ERROR; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url.data = p + 7; + u.url.len = len - 7; + u.default_port = 514; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in syslog server \"%V\"", + u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + peer->server = u.addrs[0]; + + } else if (ngx_strncmp(p, "facility=", 9) == 0) { + + if (peer->facility != NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"facility\""); + return NGX_CONF_ERROR; + } + + for (i = 0; facilities[i] != NULL; i++) { + + if (ngx_strcmp(p + 9, facilities[i]) == 0) { + peer->facility = i; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog facility \"%s\"", p + 9); + return NGX_CONF_ERROR; + + } else if (ngx_strncmp(p, "severity=", 9) == 0) { + + if (peer->severity != NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"severity\""); + return NGX_CONF_ERROR; + } + + for (i = 0; severities[i] != NULL; i++) { + + if (ngx_strcmp(p + 9, severities[i]) == 0) { + peer->severity = i; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog severity \"%s\"", p + 9); + return NGX_CONF_ERROR; + + } else if (ngx_strncmp(p, "tag=", 4) == 0) { + + if (peer->tag.data != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"tag\""); + return NGX_CONF_ERROR; + } + + /* + * RFC 3164: the TAG is a string of ABNF alphanumeric characters + * that MUST NOT exceed 32 characters. + */ + if (len - 4 > 32) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "syslog tag length exceeds 32"); + return NGX_CONF_ERROR; + } + + for (i = 4; i < len; i++) { + c = ngx_tolower(p[i]); + + if (c < '0' || (c > '9' && c < 'a') || c > 'z') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "syslog \"tag\" only allows " + "alphanumeric characters"); + return NGX_CONF_ERROR; + } + } + + peer->tag.data = p + 4; + peer->tag.len = len - 4; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog parameter \"%s\"", p); + return NGX_CONF_ERROR; + } + + next: + + if (comma == NULL) { + break; + } + + p = comma + 1; + } + + return NGX_CONF_OK; +} + + +u_char * +ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf) +{ + ngx_uint_t pri; + + pri = peer->facility * 8 + peer->severity; + + return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time, + &ngx_cycle->hostname, &peer->tag); +} + + +void +ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len) +{ + u_char *p, msg[NGX_SYSLOG_MAX_STR]; + ngx_uint_t head_len; + ngx_syslog_peer_t *peer; + + peer = log->wdata; + + if (peer->processing) { + return; + } + + peer->processing = 1; + peer->severity = level - 1; + + p = ngx_syslog_add_header(peer, msg); + head_len = p - msg; + + len -= NGX_LINEFEED_SIZE; + + if (len > NGX_SYSLOG_MAX_STR - head_len) { + len = NGX_SYSLOG_MAX_STR - head_len; + } + + p = ngx_snprintf(p, len, "%s", buf); + + (void) ngx_syslog_send(peer, msg, p - msg); + + peer->processing = 0; +} + + +ssize_t +ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) +{ + if (peer->conn.fd == (ngx_socket_t) -1) { + if (ngx_syslog_init_peer(peer) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_send) { + return ngx_send(&peer->conn, buf, len); + + } else { + /* event module has not yet set ngx_io */ + return ngx_os_io.send(&peer->conn, buf, len); + } +} + + +static ngx_int_t +ngx_syslog_init_peer(ngx_syslog_peer_t *peer) +{ + ngx_socket_t fd; + ngx_pool_cleanup_t *cln; + + peer->conn.read = &ngx_syslog_dummy_event; + peer->conn.write = &ngx_syslog_dummy_event; + peer->conn.log = &ngx_syslog_dummy_log; + + ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log; + + fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0); + if (fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + if (ngx_nonblocking(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_nonblocking_n " failed"); + goto failed; + } + + if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + "connect() failed"); + goto failed; + } + + cln = ngx_pool_cleanup_add(peer->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = peer; + cln->handler = ngx_syslog_cleanup; + + peer->conn.fd = fd; + return NGX_OK; + +failed: + + if (ngx_close_socket(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; +} + + +static void +ngx_syslog_cleanup(void *data) +{ + ngx_syslog_peer_t *peer = data; + + if (ngx_close_socket(peer->conn.fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } +} diff --git a/usr.sbin/nginx/src/core/ngx_syslog.h b/usr.sbin/nginx/src/core/ngx_syslog.h new file mode 100644 index 00000000000..92d47d5f5fd --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_syslog.h @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SYSLOG_H_INCLUDED_ +#define _NGX_SYSLOG_H_INCLUDED_ + + +typedef struct { + ngx_pool_t *pool; + ngx_uint_t facility; + ngx_uint_t severity; + ngx_str_t tag; + + ngx_addr_t server; + ngx_connection_t conn; + ngx_uint_t processing; /* unsigned processing:1; */ +} ngx_syslog_peer_t; + + +char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer); +u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf); +void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len); +ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len); + + +#endif /* _NGX_SYSLOG_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_times.c b/usr.sbin/nginx/src/core/ngx_times.c index 77490faf045..595c1224d0e 100644 --- a/usr.sbin/nginx/src/core/ngx_times.c +++ b/usr.sbin/nginx/src/core/ngx_times.c @@ -29,6 +29,7 @@ volatile ngx_str_t ngx_cached_err_log_time; volatile ngx_str_t ngx_cached_http_time; volatile ngx_str_t ngx_cached_http_log_time; volatile ngx_str_t ngx_cached_http_log_iso8601; +volatile ngx_str_t ngx_cached_syslog_time; #if !(NGX_WIN32) @@ -50,6 +51,8 @@ static u_char cached_http_log_time[NGX_TIME_SLOTS] [sizeof("28/Sep/1970:12:00:00 +0600")]; static u_char cached_http_log_iso8601[NGX_TIME_SLOTS] [sizeof("1970-09-28T12:00:00+06:00")]; +static u_char cached_syslog_time[NGX_TIME_SLOTS] + [sizeof("Sep 28 12:00:00")]; static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; @@ -63,6 +66,7 @@ ngx_time_init(void) ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1; ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1; + ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1; ngx_cached_time = &cached_time[0]; @@ -73,7 +77,7 @@ ngx_time_init(void) void ngx_time_update(void) { - u_char *p0, *p1, *p2, *p3; + u_char *p0, *p1, *p2, *p3, *p4; ngx_tm_t tm, gmt; time_t sec; ngx_uint_t msec; @@ -166,6 +170,11 @@ ngx_time_update(void) tp->gmtoff < 0 ? '-' : '+', ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); + p4 = &cached_syslog_time[slot][0]; + + (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d", + months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); ngx_memory_barrier(); @@ -174,6 +183,7 @@ ngx_time_update(void) ngx_cached_err_log_time.data = p1; ngx_cached_http_log_time.data = p2; ngx_cached_http_log_iso8601.data = p3; + ngx_cached_syslog_time.data = p4; ngx_unlock(&ngx_time_lock); } @@ -184,7 +194,7 @@ ngx_time_update(void) void ngx_time_sigsafe_update(void) { - u_char *p; + u_char *p, *p2; ngx_tm_t tm; time_t sec; ngx_time_t *tp; @@ -224,9 +234,16 @@ ngx_time_sigsafe_update(void) tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + p2 = &cached_syslog_time[slot][0]; + + (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d", + months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + ngx_memory_barrier(); ngx_cached_err_log_time.data = p; + ngx_cached_syslog_time.data = p2; ngx_unlock(&ngx_time_lock); } diff --git a/usr.sbin/nginx/src/core/ngx_times.h b/usr.sbin/nginx/src/core/ngx_times.h index c4b26a2ed0b..94aedcdc94c 100644 --- a/usr.sbin/nginx/src/core/ngx_times.h +++ b/usr.sbin/nginx/src/core/ngx_times.h @@ -40,6 +40,7 @@ extern volatile ngx_str_t ngx_cached_err_log_time; extern volatile ngx_str_t ngx_cached_http_time; extern volatile ngx_str_t ngx_cached_http_log_time; extern volatile ngx_str_t ngx_cached_http_log_iso8601; +extern volatile ngx_str_t ngx_cached_syslog_time; /* * milliseconds elapsed since epoch and truncated to ngx_msec_t, diff --git a/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c b/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c index 6fdd00233e6..0506103e616 100644 --- a/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c +++ b/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c @@ -425,7 +425,7 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, case -1: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "ioctl(DP_ISPOLLED) failed for socket %d, event", + "ioctl(DP_ISPOLLED) failed for socket %d, event %04Xd", fd, revents); break; @@ -449,7 +449,7 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, != (ssize_t) sizeof(struct pollfd)) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "write(/dev/poll) for %d failed, fd"); + "write(/dev/poll) for %d failed", fd); } if (close(fd) == -1) { diff --git a/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c b/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c index ee77d8e4aff..f5f66317943 100644 --- a/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c +++ b/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c @@ -25,6 +25,8 @@ #define EPOLLERR 0x008 #define EPOLLHUP 0x010 +#define EPOLLRDHUP 0x2000 + #define EPOLLET 0x80000000 #define EPOLLONESHOT 0x40000000 @@ -396,13 +398,13 @@ ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) if (event == NGX_READ_EVENT) { e = c->write; prev = EPOLLOUT; -#if (NGX_READ_EVENT != EPOLLIN) - events = EPOLLIN; +#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP) + events = EPOLLIN|EPOLLRDHUP; #endif } else { e = c->read; - prev = EPOLLIN; + prev = EPOLLIN|EPOLLRDHUP; #if (NGX_WRITE_EVENT != EPOLLOUT) events = EPOLLOUT; #endif @@ -466,7 +468,7 @@ ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) } else { e = c->read; - prev = EPOLLIN; + prev = EPOLLIN|EPOLLRDHUP; } if (e->active) { @@ -501,7 +503,7 @@ ngx_epoll_add_connection(ngx_connection_t *c) { struct epoll_event ee; - ee.events = EPOLLIN|EPOLLOUT|EPOLLET; + ee.events = EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP; ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -666,6 +668,12 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) if ((revents & EPOLLIN) && rev->active) { +#if (NGX_HAVE_EPOLLRDHUP) + if (revents & EPOLLRDHUP) { + rev->pending_eof = 1; + } +#endif + if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) { rev->posted_ready = 1; diff --git a/usr.sbin/nginx/src/event/modules/ngx_select_module.c b/usr.sbin/nginx/src/event/modules/ngx_select_module.c index ed71368e985..51690558e91 100644 --- a/usr.sbin/nginx/src/event/modules/ngx_select_module.c +++ b/usr.sbin/nginx/src/event/modules/ngx_select_module.c @@ -288,7 +288,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_log_error(level, cycle->log, err, "select() failed"); - if (err == EBADF) { + if (err == NGX_EBADF) { ngx_select_repair_fd_sets(cycle); } diff --git a/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c b/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c index 0a02ffca0b0..eb5382d4e0b 100644 --- a/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c +++ b/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c @@ -148,8 +148,8 @@ ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) return NGX_ERROR; } - if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE) - || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE)) + if ((event == NGX_READ_EVENT && max_read >= FD_SETSIZE) + || (event == NGX_WRITE_EVENT && max_write >= FD_SETSIZE)) { ngx_log_error(NGX_LOG_ERR, ev->log, 0, "maximum number of descriptors " diff --git a/usr.sbin/nginx/src/event/ngx_event.c b/usr.sbin/nginx/src/event/ngx_event.c index c4c61204b78..e2857f0c05c 100644 --- a/usr.sbin/nginx/src/event/ngx_event.c +++ b/usr.sbin/nginx/src/event/ngx_event.c @@ -56,7 +56,6 @@ ngx_uint_t ngx_accept_events; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; ngx_int_t ngx_accept_disabled; -ngx_file_t ngx_accept_mutex_lock_file; #if (NGX_STAT_STUB) diff --git a/usr.sbin/nginx/src/event/ngx_event.h b/usr.sbin/nginx/src/event/ngx_event.h index 93c457c7b9a..530c9486c51 100644 --- a/usr.sbin/nginx/src/event/ngx_event.h +++ b/usr.sbin/nginx/src/event/ngx_event.h @@ -69,13 +69,9 @@ struct ngx_event_s { unsigned delayed:1; - unsigned read_discarded:1; - - unsigned unexpected_eof:1; - unsigned deferred_accept:1; - /* the pending eof reported by kqueue or in aio chain operation */ + /* the pending eof reported by kqueue, epoll or in aio chain operation */ unsigned pending_eof:1; #if !(NGX_THREADS) @@ -353,6 +349,11 @@ extern ngx_event_actions_t ngx_event_actions; #define NGX_VNODE_EVENT 0 +#if (NGX_HAVE_EPOLL) && !(NGX_HAVE_EPOLLRDHUP) +#define EPOLLRDHUP 0 +#endif + + #if (NGX_HAVE_KQUEUE) #define NGX_READ_EVENT EVFILT_READ @@ -396,7 +397,7 @@ extern ngx_event_actions_t ngx_event_actions; #elif (NGX_HAVE_EPOLL) -#define NGX_READ_EVENT EPOLLIN +#define NGX_READ_EVENT (EPOLLIN|EPOLLRDHUP) #define NGX_WRITE_EVENT EPOLLOUT #define NGX_LEVEL_EVENT 0 diff --git a/usr.sbin/nginx/src/event/ngx_event_accept.c b/usr.sbin/nginx/src/event/ngx_event_accept.c index 6087d60daaf..bf67ecee062 100644 --- a/usr.sbin/nginx/src/event/ngx_event_accept.c +++ b/usr.sbin/nginx/src/event/ngx_event_accept.c @@ -70,7 +70,7 @@ ngx_event_accept(ngx_event_t *ev) s = accept(lc->fd, (struct sockaddr *) sa, &socklen); #endif - if (s == -1) { + if (s == (ngx_socket_t) -1) { err = ngx_socket_errno; if (err == NGX_EAGAIN) { @@ -212,6 +212,7 @@ 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; @@ -275,7 +276,8 @@ ngx_event_accept(ngx_event_t *ev) return; } - c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data, + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); @@ -296,7 +298,7 @@ ngx_event_accept(ngx_event_t *ev) cidr = ecf->debug_connection.elts; for (i = 0; i < ecf->debug_connection.nelts; i++) { - if (cidr[i].family != c->sockaddr->sa_family) { + if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) { goto next; } @@ -342,7 +344,7 @@ ngx_event_accept(ngx_event_t *ev) #endif ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, - "*%d accept: %V fd:%d", c->number, &c->addr_text, s); + "*%uA accept: %V fd:%d", c->number, &c->addr_text, s); if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { diff --git a/usr.sbin/nginx/src/event/ngx_event_connect.c b/usr.sbin/nginx/src/event/ngx_event_connect.c index e6ae6564e6c..5fcabcfd1fa 100644 --- a/usr.sbin/nginx/src/event/ngx_event_connect.c +++ b/usr.sbin/nginx/src/event/ngx_event_connect.c @@ -31,7 +31,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); - if (s == -1) { + if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; @@ -122,7 +122,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, - "connect to %V, fd:%d #%d", pc->name, s, c->number); + "connect to %V, fd:%d #%uA", pc->name, s, c->number); rc = connect(s, pc->sockaddr, pc->socklen); diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl.c b/usr.sbin/nginx/src/event/ngx_event_openssl.c index 81a1e42d81c..6290a57fe0c 100644 --- a/usr.sbin/nginx/src/event/ngx_event_openssl.c +++ b/usr.sbin/nginx/src/event/ngx_event_openssl.c @@ -15,7 +15,7 @@ typedef struct { } ngx_openssl_conf_t; -static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); +static int ngx_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); @@ -38,6 +38,12 @@ static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB +static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, + unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, + HMAC_CTX *hctx, int enc); +#endif + static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); @@ -82,6 +88,7 @@ ngx_module_t ngx_openssl_module = { int ngx_ssl_connection_index; int ngx_ssl_server_conf_index; int ngx_ssl_session_cache_index; +int ngx_ssl_session_ticket_keys_index; int ngx_ssl_certificate_index; int ngx_ssl_stapling_index; @@ -139,6 +146,14 @@ ngx_ssl_init(ngx_log_t *log) return NGX_ERROR; } + ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, + NULL, NULL); + if (ngx_ssl_session_ticket_keys_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "SSL_CTX_get_ex_new_index() failed"); + return NGX_ERROR; + } + ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (ngx_ssl_certificate_index == -1) { @@ -175,6 +190,8 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) return NGX_ERROR; } + ssl->buffer_size = NGX_SSL_BUFSIZE; + /* client side options */ SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG); @@ -185,8 +202,10 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); +#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */ SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); +#endif SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); @@ -276,6 +295,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set_ex_data() failed"); + X509_free(x509); + BIO_free(bio); return NGX_ERROR; } @@ -340,7 +361,7 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, { STACK_OF(X509_NAME) *list; - SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback); + SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback); SSL_CTX_set_verify_depth(ssl->ctx, depth); @@ -361,6 +382,13 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } + /* + * SSL_CTX_load_verify_locations() may leave errors in the error queue + * while returning success + */ + + ERR_clear_error(); + list = SSL_load_client_CA_file((char *) cert->data); if (list == NULL) { @@ -405,6 +433,13 @@ ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } + /* + * SSL_CTX_load_verify_locations() may leave errors in the error queue + * while returning success + */ + + ERR_clear_error(); + return NGX_OK; } @@ -455,7 +490,7 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl) static int -ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) +ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) { #if (NGX_DEBUG) char *subject, *issuer; @@ -501,6 +536,7 @@ 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) { + BIO *rbio, *wbio; ngx_connection_t *c; if (where & SSL_CB_HANDSHAKE_START) { @@ -511,11 +547,37 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation"); } } + + if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP) { + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + + if (!c->ssl->handshake_buffer_set) { + /* + * By default OpenSSL uses 4k buffer during a handshake, + * which is too low for long certificate chains and might + * result in extra round-trips. + * + * To adjust a buffer size we detect that buffering was added + * to write side of the connection by comparing rbio and wbio. + * If they are different, we assume that it's due to buffering + * added to wbio, and set buffer size. + */ + + rbio = SSL_get_rbio((ngx_ssl_conn_t *) ssl_conn); + wbio = SSL_get_wbio((ngx_ssl_conn_t *) ssl_conn); + + if (rbio != wbio) { + (void) BIO_set_write_buffer_size(wbio, NGX_SSL_BUFSIZE); + c->ssl->handshake_buffer_set = 1; + } + } + } } RSA * -ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length) +ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, + int key_length) { static RSA *key; @@ -664,6 +726,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) } sc->buffer = ((flags & NGX_SSL_BUFFER) != 0); + sc->buffer_size = ssl->buffer_size; sc->connection = SSL_new(ssl->ctx); @@ -1160,7 +1223,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) buf = c->ssl->buf; if (buf == NULL) { - buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); + buf = ngx_create_temp_buf(c->pool, c->ssl->buffer_size); if (buf == NULL) { return NGX_CHAIN_ERROR; } @@ -1169,14 +1232,14 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } if (buf->start == NULL) { - buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE); + buf->start = ngx_palloc(c->pool, c->ssl->buffer_size); if (buf->start == NULL) { return NGX_CHAIN_ERROR; } buf->pos = buf->start; buf->last = buf->start; - buf->end = buf->start + NGX_SSL_BUFSIZE; + buf->end = buf->start + c->ssl->buffer_size; } send = buf->last - buf->pos; @@ -1662,6 +1725,8 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, { long cache_mode; + SSL_CTX_set_timeout(ssl->ctx, (long) timeout); + if (builtin_session_cache == NGX_SSL_NO_SCACHE) { SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF); return NGX_OK; @@ -1707,8 +1772,6 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, } } - SSL_CTX_set_timeout(ssl->ctx, (long) timeout); - if (shm_zone) { SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session); SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session); @@ -1739,13 +1802,13 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) return NGX_OK; } + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + if (shm_zone->shm.exists) { - shm_zone->data = data; + shm_zone->data = shpool->data; return NGX_OK; } - shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t)); if (cache == NULL) { return NGX_ERROR; @@ -1769,6 +1832,8 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z", &shm_zone->shm.name); + shpool->log_nomem = 0; + return NGX_OK; } @@ -1921,7 +1986,7 @@ failed: ngx_shmtx_unlock(&shpool->mutex); ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "could not add new SSL session to the session cache"); + "could not allocate new session%s", shpool->log_ctx); return 0; } @@ -2198,6 +2263,218 @@ ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, } +#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB + +ngx_int_t +ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) +{ + u_char buf[48]; + ssize_t n; + ngx_str_t *path; + ngx_file_t file; + ngx_uint_t i; + ngx_array_t *keys; + ngx_file_info_t fi; + ngx_ssl_session_ticket_key_t *key; + + if (paths == NULL) { + return NGX_OK; + } + + keys = ngx_array_create(cf->pool, paths->nelts, + sizeof(ngx_ssl_session_ticket_key_t)); + if (keys == NULL) { + return NGX_ERROR; + } + + path = paths->elts; + for (i = 0; i < paths->nelts; i++) { + + if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) { + return NGX_ERROR; + } + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.name = path[i]; + file.log = cf->log; + + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0); + if (file.fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%V\" failed", &file.name); + return NGX_ERROR; + } + + if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_fd_info_n " \"%V\" failed", &file.name); + goto failed; + } + + if (ngx_file_size(&fi) != 48) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" must be 48 bytes", &file.name); + goto failed; + } + + n = ngx_read_file(&file, buf, 48, 0); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_read_file_n " \"%V\" failed", &file.name); + goto failed; + } + + if (n != 48) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, + ngx_read_file_n " \"%V\" returned only " + "%z bytes instead of 48", &file.name, n); + goto failed; + } + + key = ngx_array_push(keys); + if (key == NULL) { + goto failed; + } + + ngx_memcpy(key->name, buf, 16); + ngx_memcpy(key->aes_key, buf + 16, 16); + ngx_memcpy(key->hmac_key, buf + 32, 16); + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &file.name); + } + } + + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + return NGX_ERROR; + } + + if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx, + ngx_ssl_session_ticket_key_callback) + == 0) + { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "nginx was built with Session Tickets support, however, " + "now it is linked dynamically to an OpenSSL library " + "which has no tlsext support, therefore Session Tickets " + "are not available"); + } + + return NGX_OK; + +failed: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &file.name); + } + + return NGX_ERROR; +} + + +#ifdef OPENSSL_NO_SHA256 +#define ngx_ssl_session_ticket_md EVP_sha1 +#else +#define ngx_ssl_session_ticket_md EVP_sha256 +#endif + + +static int +ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, + unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, + HMAC_CTX *hctx, int enc) +{ + SSL_CTX *ssl_ctx; + ngx_uint_t i; + ngx_array_t *keys; + ngx_ssl_session_ticket_key_t *key; +#if (NGX_DEBUG) + u_char buf[32]; + ngx_connection_t *c; +#endif + + ssl_ctx = SSL_get_SSL_CTX(ssl_conn); + + keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index); + if (keys == NULL) { + return -1; + } + + key = keys->elts; + +#if (NGX_DEBUG) + c = ngx_ssl_get_connection(ssl_conn); +#endif + + if (enc == 1) { + /* encrypt session ticket */ + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session ticket encrypt, key: \"%*s\" (%s session)", + ngx_hex_dump(buf, key[0].name, 16) - buf, buf, + SSL_session_reused(ssl_conn) ? "reused" : "new"); + + RAND_pseudo_bytes(iv, 16); + EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv); + HMAC_Init_ex(hctx, key[0].hmac_key, 16, + ngx_ssl_session_ticket_md(), NULL); + memcpy(name, key[0].name, 16); + + return 0; + + } else { + /* decrypt session ticket */ + + for (i = 0; i < keys->nelts; i++) { + if (ngx_memcmp(name, key[i].name, 16) == 0) { + goto found; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session ticket decrypt, key: \"%*s\" not found", + ngx_hex_dump(buf, name, 16) - buf, buf); + + return 0; + + found: + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session ticket decrypt, key: \"%*s\"%s", + ngx_hex_dump(buf, key[i].name, 16) - buf, buf, + (i == 0) ? " (default)" : ""); + + HMAC_Init_ex(hctx, key[i].hmac_key, 16, + ngx_ssl_session_ticket_md(), NULL); + EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv); + + return (i == 0) ? 1 : 2 /* renew */; + } +} + +#else + +ngx_int_t +ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) +{ + if (paths) { + ngx_log_error(NGX_LOG_WARN, ssl->log, 0, + "\"ssl_session_ticket_keys\" ignored, not supported"); + } + + return NGX_OK; +} + +#endif + + void ngx_ssl_cleanup_ctx(void *data) { @@ -2252,6 +2529,20 @@ ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t +ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + if (SSL_session_reused(c->ssl->connection)) { + ngx_str_set(s, "r"); + + } else { + ngx_str_set(s, "."); + } + + 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; diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl.h b/usr.sbin/nginx/src/event/ngx_event_openssl.h index bf81d2529c9..b7f85001948 100644 --- a/usr.sbin/nginx/src/event/ngx_event_openssl.h +++ b/usr.sbin/nginx/src/event/ngx_event_openssl.h @@ -29,6 +29,7 @@ typedef struct { SSL_CTX *ctx; ngx_log_t *log; + size_t buffer_size; } ngx_ssl_t; @@ -37,6 +38,7 @@ typedef struct { ngx_int_t last; ngx_buf_t *buf; + size_t buffer_size; ngx_connection_handler_pt handler; @@ -48,6 +50,7 @@ typedef struct { unsigned buffer:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; + unsigned handshake_buffer_set:1; } ngx_ssl_connection_t; @@ -82,6 +85,16 @@ typedef struct { } ngx_ssl_session_cache_t; +#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB + +typedef struct { + u_char name[16]; + u_char aes_key[16]; + u_char hmac_key[16]; +} ngx_ssl_session_ticket_key_t; + +#endif + #define NGX_SSL_SSLv2 0x0002 #define NGX_SSL_SSLv3 0x0004 @@ -109,11 +122,14 @@ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify); ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); -RSA *ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length); +RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, + int key_length); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout); +ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_array_t *paths); ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags); @@ -141,6 +157,8 @@ 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_session_reused(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, @@ -171,6 +189,7 @@ void ngx_ssl_cleanup_ctx(void *data); extern int ngx_ssl_connection_index; extern int ngx_ssl_server_conf_index; extern int ngx_ssl_session_cache_index; +extern int ngx_ssl_session_ticket_keys_index; extern int ngx_ssl_certificate_index; extern int ngx_ssl_stapling_index; diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c b/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c index 77baeb98f1f..3a3cc7f9e03 100644 --- a/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c +++ b/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c @@ -792,7 +792,6 @@ ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx) } resolve->name = ctx->host; - resolve->type = NGX_RESOLVE_A; resolve->handler = ngx_ssl_ocsp_resolve_handler; resolve->data = ctx; resolve->timeout = ctx->resolver_timeout; @@ -816,13 +815,14 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve) { ngx_ssl_ocsp_ctx_t *ctx = resolve->data; - u_char *p; - size_t len; - in_port_t port; - ngx_uint_t i; - struct sockaddr_in *sin; + u_char *p; + size_t len; + in_port_t port; + socklen_t socklen; + ngx_uint_t i; + struct sockaddr *sockaddr; - ngx_log_debug0(NGX_LOG_ALERT, ctx->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp resolve handler"); if (resolve->state) { @@ -835,15 +835,19 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve) #if (NGX_DEBUG) { - in_addr_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; + + addr.data = text; for (i = 0; i < resolve->naddrs; i++) { - addr = ntohl(resolve->addrs[i]); + addr.len = ngx_sock_ntop(resolve->addrs[i].sockaddr, + resolve->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "name was resolved to %V", &addr); - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0, - "name was resolved to %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); } } #endif @@ -859,26 +863,34 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve) for (i = 0; i < resolve->naddrs; i++) { - sin = ngx_pcalloc(ctx->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { + socklen = resolve->addrs[i].socklen; + + sockaddr = ngx_palloc(ctx->pool, socklen); + if (sockaddr == NULL) { goto failed; } - sin->sin_family = AF_INET; - sin->sin_port = port; - sin->sin_addr.s_addr = resolve->addrs[i]; + ngx_memcpy(sockaddr, resolve->addrs[i].sockaddr, socklen); - ctx->addrs[i].sockaddr = (struct sockaddr *) sin; - ctx->addrs[i].socklen = sizeof(struct sockaddr_in); + switch (sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + ((struct sockaddr_in6 *) sockaddr)->sin6_port = port; + break; +#endif + default: /* AF_INET */ + ((struct sockaddr_in *) sockaddr)->sin_port = port; + } - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + ctx->addrs[i].sockaddr = sockaddr; + ctx->addrs[i].socklen = socklen; - p = ngx_pnalloc(ctx->pool, len); + p = ngx_pnalloc(ctx->pool, NGX_SOCKADDR_STRLEN); if (p == NULL) { goto failed; } - len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); ctx->addrs[i].name.len = len; ctx->addrs[i].name.data = p; diff --git a/usr.sbin/nginx/src/event/ngx_event_pipe.c b/usr.sbin/nginx/src/event/ngx_event_pipe.c index 476d56e30e3..eed807d61b8 100644 --- a/usr.sbin/nginx/src/event/ngx_event_pipe.c +++ b/usr.sbin/nginx/src/event/ngx_event_pipe.c @@ -57,7 +57,7 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) do_write = 1; } - if (p->upstream->fd != -1) { + if (p->upstream->fd != (ngx_socket_t) -1) { rev = p->upstream->read; flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0; @@ -74,7 +74,9 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) } } - if (p->downstream->fd != -1 && p->downstream->data == p->output_ctx) { + if (p->downstream->fd != (ngx_socket_t) -1 + && p->downstream->data == p->output_ctx) + { wev = p->downstream->write; if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) { return NGX_ABORT; @@ -220,8 +222,8 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) { /* - * if it is allowed, then save some bufs from r->in - * to a temporary file, and add them to a r->out chain + * if it is allowed, then save some bufs from p->in + * to a temporary file, and add them to a p->out chain */ rc = ngx_event_pipe_write_chain_to_temp_file(p); @@ -454,7 +456,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) size_t bsize; ngx_int_t rc; ngx_uint_t flush, flushed, prev_last_shadow; - ngx_chain_t *out, **ll, *cl, file; + ngx_chain_t *out, **ll, *cl; ngx_connection_t *downstream; downstream = p->downstream; @@ -514,13 +516,10 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) } if (p->cacheable && p->buf_to_file) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe write chain"); - file.buf = p->buf_to_file; - file.next = NULL; - - if (ngx_write_chain_to_temp_file(p->temp_file, &file) - == NGX_ERROR) - { + if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { return NGX_ABORT; } } @@ -858,19 +857,13 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_OK; } - if (p->free) { - cl = p->free; - b = cl->buf; - p->free = cl->next; - ngx_free_chain(p->pool, cl); - - } else { - b = ngx_alloc_buf(p->pool); - if (b == NULL) { - return NGX_ERROR; - } + cl = ngx_chain_get_free_buf(p->pool, &p->free); + if (cl == NULL) { + return NGX_ERROR; } + b = cl->buf; + ngx_memcpy(b, buf, sizeof(ngx_buf_t)); b->shadow = buf; b->tag = p->tag; @@ -878,14 +871,6 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) b->recycled = 1; buf->shadow = b; - cl = ngx_alloc_chain_link(p->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); if (p->in) { diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c index 70a4262fccb..c553e46106b 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c @@ -26,11 +26,22 @@ typedef struct { #endif +#if (NGX_HAVE_UNIX_DOMAIN) + +typedef struct { + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_http_access_rule_un_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 +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_array_t *rules_un; /* array of ngx_http_access_rule_un_t */ +#endif } ngx_http_access_loc_conf_t; @@ -41,6 +52,10 @@ static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r, static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, u_char *p); #endif +#if (NGX_HAVE_UNIX_DOMAIN) +static ngx_int_t ngx_http_access_unix(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf); +#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); @@ -144,6 +159,19 @@ ngx_http_access_handler(ngx_http_request_t *r) return ngx_http_access_inet6(r, alcf, p); } + break; + +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + + case AF_UNIX: + if (alcf->rules_un) { + return ngx_http_access_unix(r, alcf); + } + + break; + #endif } @@ -221,6 +249,29 @@ ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, #endif +#if (NGX_HAVE_UNIX_DOMAIN) + +static ngx_int_t +ngx_http_access_unix(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf) +{ + ngx_uint_t i; + ngx_http_access_rule_un_t *rule_un; + + rule_un = alcf->rules_un->elts; + for (i = 0; i < alcf->rules_un->nelts; i++) { + + /* TODO: check path */ + if (1) { + return ngx_http_access_found(r, rule_un[i].deny); + } + } + + return NGX_DECLINED; +} + +#endif + + static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny) { @@ -246,13 +297,16 @@ 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_uint_t all; - 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; + ngx_http_access_rule6_t *rule6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_http_access_rule_un_t *rule_un; #endif ngx_memzero(&cidr, sizeof(ngx_cidr_t)); @@ -263,7 +317,19 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (!all) { +#if (NGX_HAVE_UNIX_DOMAIN) + + if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { + cidr.family = AF_UNIX; + rc = NGX_OK; + + } else { + rc = ngx_ptocidr(&value[1], &cidr); + } + +#else rc = ngx_ptocidr(&value[1], &cidr); +#endif if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -277,11 +343,28 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - switch (cidr.family) { + if (cidr.family == AF_INET || all) { + + 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; + } #if (NGX_HAVE_INET6) - case AF_INET6: - case 0: /* all */ + if (cidr.family == AF_INET6 || all) { if (alcf->rules6 == NULL) { alcf->rules6 = ngx_array_create(cf->pool, 4, @@ -299,33 +382,28 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) rule6->mask = cidr.u.in6.mask; rule6->addr = cidr.u.in6.addr; rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; - - if (!all) { - break; - } - - /* "all" passes through */ + } #endif - default: /* AF_INET */ +#if (NGX_HAVE_UNIX_DOMAIN) + if (cidr.family == AF_UNIX || all) { - if (alcf->rules == NULL) { - alcf->rules = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_access_rule_t)); - if (alcf->rules == NULL) { + if (alcf->rules_un == NULL) { + alcf->rules_un = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_access_rule_un_t)); + if (alcf->rules_un == NULL) { return NGX_CONF_ERROR; } } - rule = ngx_array_push(alcf->rules); - if (rule == NULL) { + rule_un = ngx_array_push(alcf->rules_un); + if (rule_un == 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_un->deny = (value[0].data[0] == 'd') ? 1 : 0; } +#endif return NGX_CONF_OK; } @@ -351,20 +429,22 @@ ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_access_loc_conf_t *prev = parent; ngx_http_access_loc_conf_t *conf = child; + if (conf->rules == NULL #if (NGX_HAVE_INET6) - - if (conf->rules == NULL && conf->rules6 == NULL) { + && conf->rules6 == NULL +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + && conf->rules_un == NULL +#endif + ) { conf->rules = prev->rules; +#if (NGX_HAVE_INET6) conf->rules6 = prev->rules6; - } - -#else - - if (conf->rules == NULL) { - conf->rules = prev->rules; - } - #endif +#if (NGX_HAVE_UNIX_DOMAIN) + conf->rules_un = prev->rules_un; +#endif + } return NGX_CONF_OK; } diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c index 8f158dd4f7b..38892c1063c 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c @@ -137,7 +137,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) if (rc == NGX_DECLINED) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "no user/password was provided for basic authentication"); return ngx_http_auth_basic_set_realm(r, &realm); diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c new file mode 100644 index 00000000000..b4307be2e7d --- /dev/null +++ b/usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c @@ -0,0 +1,444 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +typedef struct { + ngx_str_t uri; + ngx_array_t *vars; +} ngx_http_auth_request_conf_t; + + +typedef struct { + ngx_uint_t done; + ngx_uint_t status; + ngx_http_request_t *subrequest; +} ngx_http_auth_request_ctx_t; + + +typedef struct { + ngx_int_t index; + ngx_http_complex_value_t value; + ngx_http_set_variable_pt set_handler; +} ngx_http_auth_request_variable_t; + + +static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_auth_request_done(ngx_http_request_t *r, + void *data, ngx_int_t rc); +static ngx_int_t ngx_http_auth_request_set_variables(ngx_http_request_t *r, + ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx); +static ngx_int_t ngx_http_auth_request_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static void *ngx_http_auth_request_create_conf(ngx_conf_t *cf); +static char *ngx_http_auth_request_merge_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_auth_request_init(ngx_conf_t *cf); +static char *ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_auth_request_commands[] = { + + { ngx_string("auth_request"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_auth_request, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("auth_request_set"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_http_auth_request_set, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_auth_request_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_auth_request_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_auth_request_create_conf, /* create location configuration */ + ngx_http_auth_request_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_auth_request_module = { + NGX_MODULE_V1, + &ngx_http_auth_request_module_ctx, /* module context */ + ngx_http_auth_request_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_auth_request_handler(ngx_http_request_t *r) +{ + ngx_table_elt_t *h, *ho; + ngx_http_request_t *sr; + ngx_http_post_subrequest_t *ps; + ngx_http_auth_request_ctx_t *ctx; + ngx_http_auth_request_conf_t *arcf; + + arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module); + + if (arcf->uri.len == 0) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "auth request handler"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module); + + if (ctx != NULL) { + if (!ctx->done) { + return NGX_AGAIN; + } + + /* + * as soon as we are done - explicitly set variables to make + * sure they will be available after internal redirects + */ + + if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) { + return NGX_ERROR; + } + + /* return appropriate status */ + + if (ctx->status == NGX_HTTP_FORBIDDEN) { + return ctx->status; + } + + if (ctx->status == NGX_HTTP_UNAUTHORIZED) { + sr = ctx->subrequest; + + h = sr->headers_out.www_authenticate; + + if (!h && sr->upstream) { + h = sr->upstream->headers_in.www_authenticate; + } + + if (h) { + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + r->headers_out.www_authenticate = ho; + } + + return ctx->status; + } + + if (ctx->status >= NGX_HTTP_OK + && ctx->status < NGX_HTTP_SPECIAL_RESPONSE) + { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "auth request unexpected status: %d", ctx->status); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); + if (ps == NULL) { + return NGX_ERROR; + } + + ps->handler = ngx_http_auth_request_done; + ps->data = ctx; + + if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, + NGX_HTTP_SUBREQUEST_WAITED) + != NGX_OK) + { + return NGX_ERROR; + } + + /* + * allocate fake request body to avoid attempts to read it and to make + * sure real body file (if already read) won't be closed by upstream + */ + + sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (sr->request_body == NULL) { + return NGX_ERROR; + } + + sr->header_only = 1; + + ctx->subrequest = sr; + + ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module); + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc) +{ + ngx_http_auth_request_ctx_t *ctx = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "auth request done s:%d", r->headers_out.status); + + ctx->done = 1; + ctx->status = r->headers_out.status; + + return rc; +} + + +static ngx_int_t +ngx_http_auth_request_set_variables(ngx_http_request_t *r, + ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx) +{ + ngx_str_t val; + ngx_http_variable_t *v; + ngx_http_variable_value_t *vv; + ngx_http_auth_request_variable_t *av, *last; + ngx_http_core_main_conf_t *cmcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "auth request set variables"); + + if (arcf->vars == NULL) { + return NGX_OK; + } + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + v = cmcf->variables.elts; + + av = arcf->vars->elts; + last = av + arcf->vars->nelts; + + while (av < last) { + /* + * explicitly set new value to make sure it will be available after + * internal redirects + */ + + vv = &r->variables[av->index]; + + if (ngx_http_complex_value(ctx->subrequest, &av->value, &val) + != NGX_OK) + { + return NGX_ERROR; + } + + vv->valid = 1; + vv->not_found = 0; + vv->data = val.data; + vv->len = val.len; + + if (av->set_handler) { + /* + * set_handler only available in cmcf->variables_keys, so we store + * it explicitly + */ + + av->set_handler(r, vv, v[av->index].data); + } + + av++; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_auth_request_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "auth request variable"); + + v->not_found = 1; + + return NGX_OK; +} + + +static void * +ngx_http_auth_request_create_conf(ngx_conf_t *cf) +{ + ngx_http_auth_request_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_request_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->uri = { 0, NULL }; + */ + + conf->vars = NGX_CONF_UNSET_PTR; + + return conf; +} + + +static char * +ngx_http_auth_request_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_auth_request_conf_t *prev = parent; + ngx_http_auth_request_conf_t *conf = child; + + ngx_conf_merge_str_value(conf->uri, prev->uri, ""); + ngx_conf_merge_ptr_value(conf->vars, prev->vars, NULL); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_auth_request_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_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_auth_request_handler; + + return NGX_OK; +} + + +static char * +ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_auth_request_conf_t *arcf = conf; + + ngx_str_t *value; + + if (arcf->uri.data != NULL) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + arcf->uri.len = 0; + arcf->uri.data = (u_char *) ""; + + return NGX_CONF_OK; + } + + arcf->uri = value[1]; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_auth_request_conf_t *arcf = conf; + + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_http_auth_request_variable_t *av; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + if (value[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + value[1].len--; + value[1].data++; + + if (arcf->vars == NGX_CONF_UNSET_PTR) { + arcf->vars = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_auth_request_variable_t)); + if (arcf->vars == NULL) { + return NGX_CONF_ERROR; + } + } + + av = ngx_array_push(arcf->vars); + if (av == NULL) { + return NGX_CONF_ERROR; + } + + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + av->index = ngx_http_get_variable_index(cf, &value[1]); + if (av->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (v->get_handler == NULL) { + v->get_handler = ngx_http_auth_request_variable; + v->data = (uintptr_t) av; + } + + av->set_handler = v->set_handler; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &av->value; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c index 1eecfbe689c..f694df075db 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c @@ -233,6 +233,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type_len = sizeof("text/html") - 1; ngx_str_set(&r->headers_out.content_type, "text/html"); + r->headers_out.content_type_lowcase = NULL; rc = ngx_http_send_header(r); @@ -357,7 +358,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_dir_n " \"%s\" failed", &path); + ngx_close_dir_n " \"%V\" failed", &path); } escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len); diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c index 27a00d09aee..c9b7e9e8968 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c @@ -128,7 +128,7 @@ ngx_str_t ngx_http_charset_default_types[] = { ngx_string("text/xml"), ngx_string("text/plain"), ngx_string("text/vnd.wap.wml"), - ngx_string("application/x-javascript"), + ngx_string("application/javascript"), ngx_string("application/rss+xml"), ngx_null_string }; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c index a97c60e44de..e7f9e9ae3c8 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c @@ -10,8 +10,6 @@ #include <ngx_http.h> -#define NGX_HTTP_DAV_COPY_BLOCK 65536 - #define NGX_HTTP_DAV_OFF 2 @@ -606,7 +604,7 @@ destination_done: duri.len = last - p; duri.data = p; - flags = 0; + flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { goto invalid_destination; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c index e2427b4a885..80cd1a220a6 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c @@ -138,6 +138,8 @@ static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r); static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data); static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf); +static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data, + ssize_t bytes); static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, ngx_http_fastcgi_ctx_t *f); static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r); @@ -185,6 +187,7 @@ static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, + { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, @@ -232,6 +235,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access), NULL }, + { ngx_string("fastcgi_buffering"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering), + NULL }, + { ngx_string("fastcgi_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -395,6 +405,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("fastcgi_cache_revalidate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_revalidate), + NULL }, + #endif { ngx_string("fastcgi_temp_path"), @@ -553,7 +570,8 @@ static ngx_str_t ngx_http_fastcgi_hide_headers[] = { #if (NGX_HTTP_CACHE) static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = { - { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") }, + { ngx_string("HTTP_IF_MODIFIED_SINCE"), + ngx_string("$upstream_cache_last_modified") }, { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") }, { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, @@ -578,13 +596,6 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r) ngx_http_fastcgi_ctx_t *f; ngx_http_fastcgi_loc_conf_t *flcf; - if (r->subrequest_in_memory) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "ngx_http_fastcgi_module does not support " - "subrequest in memory"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -621,7 +632,7 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r) u->finalize_request = ngx_http_fastcgi_finalize_request; r->state = 0; - u->buffering = 1; + u->buffering = flcf->upstream.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { @@ -632,6 +643,8 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r) u->pipe->input_ctx = r; u->input_filter_init = ngx_http_fastcgi_input_filter_init; + u->input_filter = ngx_http_fastcgi_non_buffered_filter; + u->input_filter_ctx = r; rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); @@ -1582,7 +1595,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) ngx_str_set(&u->headers_in.status_line, "200 OK"); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } @@ -1825,19 +1838,13 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) break; } - if (p->free) { - cl = p->free; - b = cl->buf; - p->free = cl->next; - ngx_free_chain(p->pool, cl); - - } else { - b = ngx_alloc_buf(p->pool); - if (b == NULL) { - return NGX_ERROR; - } + cl = ngx_chain_get_free_buf(p->pool, &p->free); + if (cl == NULL) { + return NGX_ERROR; } + b = cl->buf; + ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = f->pos; @@ -1850,14 +1857,6 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) *prev = b; prev = &b->shadow; - cl = ngx_alloc_chain_link(p->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - if (p->in) { *p->last_in = cl; } else { @@ -1925,6 +1924,222 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) static ngx_int_t +ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes) +{ + u_char *m, *msg; + ngx_int_t rc; + ngx_buf_t *b, *buf; + ngx_chain_t *cl, **ll; + ngx_http_request_t *r; + ngx_http_upstream_t *u; + ngx_http_fastcgi_ctx_t *f; + + r = data; + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + u = r->upstream; + buf = &u->buffer; + + buf->pos = buf->last; + buf->last += bytes; + + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { + ll = &cl->next; + } + + f->pos = buf->pos; + f->last = buf->last; + + for ( ;; ) { + if (f->state < ngx_http_fastcgi_st_data) { + + rc = ngx_http_fastcgi_process_record(r, f); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { + f->state = ngx_http_fastcgi_st_padding; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi closed stdout"); + + continue; + } + } + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { + + if (f->pos + f->padding < f->last) { + u->length = 0; + break; + } + + if (f->pos + f->padding == f->last) { + u->length = 0; + u->keepalive = 1; + break; + } + + f->padding -= f->last - f->pos; + + break; + } + + if (f->pos + f->padding < f->last) { + f->state = ngx_http_fastcgi_st_version; + f->pos += f->padding; + + continue; + } + + if (f->pos + f->padding == f->last) { + f->state = ngx_http_fastcgi_st_version; + + break; + } + + f->padding -= f->last - f->pos; + + break; + } + + + /* f->state == ngx_http_fastcgi_st_data */ + + if (f->type == NGX_HTTP_FASTCGI_STDERR) { + + if (f->length) { + + if (f->pos == f->last) { + break; + } + + msg = f->pos; + + if (f->pos + f->length <= f->last) { + f->pos += f->length; + f->length = 0; + f->state = ngx_http_fastcgi_st_padding; + + } else { + f->length -= f->last - f->pos; + f->pos = f->last; + } + + for (m = f->pos - 1; msg < m; m--) { + if (*m != LF && *m != CR && *m != '.' && *m != ' ') { + break; + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "FastCGI sent in stderr: \"%*s\"", + m + 1 - msg, msg); + + } else { + f->state = ngx_http_fastcgi_st_padding; + } + + continue; + } + + if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { + + if (f->pos + f->length <= f->last) { + f->state = ngx_http_fastcgi_st_padding; + f->pos += f->length; + + continue; + } + + f->length -= f->last - f->pos; + + break; + } + + + /* f->type == NGX_HTTP_FASTCGI_STDOUT */ + + if (f->pos == f->last) { + break; + } + + cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); + if (cl == NULL) { + return NGX_ERROR; + } + + *ll = cl; + ll = &cl->next; + + b = cl->buf; + + b->flush = 1; + b->memory = 1; + + b->pos = f->pos; + b->tag = u->output.tag; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi output buf %p", b->pos); + + if (f->pos + f->length <= f->last) { + f->state = ngx_http_fastcgi_st_padding; + f->pos += f->length; + b->last = f->pos; + + continue; + } + + f->length -= f->last - f->pos; + b->last = f->last; + + break; + } + + /* provide continuous buffer for subrequests in memory */ + + if (r->subrequest_in_memory) { + + cl = u->out_bufs; + + if (cl) { + buf->pos = cl->buf->pos; + } + + buf->last = buf->pos; + + for (cl = u->out_bufs; cl; cl = cl->next) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi in memory %p-%p %uz", + cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf)); + + if (buf->last == cl->buf->pos) { + buf->last = cl->buf->last; + continue; + } + + buf->last = ngx_movemem(buf->last, cl->buf->pos, + cl->buf->last - cl->buf->pos); + + cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos); + cl->buf->last = buf->last; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, ngx_http_fastcgi_ctx_t *f) { @@ -2126,6 +2341,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; conf->upstream.cache_lock = NGX_CONF_UNSET; conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -2136,6 +2352,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) /* "fastcgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.change_buffering = 1; + conf->catch_stderr = NGX_CONF_UNSET_PTR; conf->keep_conn = NGX_CONF_UNSET; @@ -2357,12 +2575,6 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.no_cache, prev->upstream.no_cache, NULL); - if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) { - ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "\"fastcgi_no_cache\" functionality has been changed in 0.8.46, " - "now it should be used together with \"fastcgi_cache_bypass\""); - } - ngx_conf_merge_ptr_value(conf->upstream.cache_valid, prev->upstream.cache_valid, NULL); @@ -2376,6 +2588,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, prev->upstream.cache_lock_timeout, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, + prev->upstream.cache_revalidate, 0); + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, @@ -2551,7 +2766,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, s->key = h->key; s->value = h->value; - s->skip_empty = 0; + s->skip_empty = 1; next: diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c index d4e41e4a007..adadc9da6dd 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c @@ -199,7 +199,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } } - if (ctx->nomem) { + if (ctx->nomem || in == NULL) { /* flush busy buffers */ @@ -422,7 +422,7 @@ ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, rc = inflate(&ctx->zstream, ctx->flush); if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "inflate() failed: %d, %d", ctx->flush, rc); return NGX_ERROR; } @@ -500,9 +500,13 @@ ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, return NGX_OK; } - if (rc == Z_STREAM_END && ctx->flush == Z_FINISH - && ctx->zstream.avail_in == 0) - { + if (ctx->flush == Z_FINISH && ctx->zstream.avail_in == 0) { + + if (rc != Z_STREAM_END) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "inflate() returned %d on response end", rc); + return NGX_ERROR; + } if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) { return NGX_ERROR; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c index 35dd07ec473..ea1f1d0b9a2 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c @@ -368,9 +368,11 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { goto failed; } + + r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; } - if (ctx->nomem) { + if (ctx->nomem || in == NULL) { /* flush busy buffers */ @@ -620,8 +622,6 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, return NGX_ERROR; } - r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; - ctx->last_out = &ctx->out; ctx->crc32 = crc32(0L, Z_NULL, 0); ctx->flush = Z_NO_FLUSH; @@ -854,6 +854,8 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) *ctx->last_out = cl; ctx->last_out = &cl->next; + r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED; + return NGX_OK; } diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c index 6e777619b43..1746e550423 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c @@ -38,7 +38,7 @@ static ngx_conf_enum_t ngx_http_gzip_static[] = { static ngx_command_t ngx_http_gzip_static_commands[] = { { ngx_string("gzip_static"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_static_conf_t, enable), diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c index 0dfe8101ed6..e33e7ce5271 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c @@ -339,6 +339,10 @@ ngx_http_add_cache_control(ngx_http_request_t *r, ngx_http_header_val_t *hv, { ngx_table_elt_t *cc, **ccp; + if (value->len == 0) { + return NGX_OK; + } + ccp = r->headers_out.cache_control.elts; if (ccp == NULL) { diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c index c6c3b747a32..c983b973b46 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c @@ -478,7 +478,12 @@ ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in) "image buf: %uz", size); rest = ctx->image + ctx->length - p; - size = (rest < size) ? rest : size; + + if (size > rest) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "image filter: too big response"); + return NGX_ERROR; + } p = ngx_cpymem(p, b->pos, size); b->pos += size; @@ -567,7 +572,8 @@ ngx_http_image_json(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) ngx_http_clean_header(r); r->headers_out.status = NGX_HTTP_OK; - ngx_str_set(&r->headers_out.content_type, "text/plain"); + r->headers_out.content_type_len = sizeof("application/json") - 1; + ngx_str_set(&r->headers_out.content_type, "application/json"); r->headers_out.content_type_lowcase = NULL; if (ctx == NULL) { diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c index 90434c956a6..74f7fdaa75f 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c @@ -451,6 +451,8 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, node = ngx_slab_alloc_locked(ctx->shpool, size); if (node == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "could not allocate node%s", ctx->shpool->log_ctx); return NGX_ERROR; } } @@ -674,6 +676,8 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", &shm_zone->shm.name); + ctx->shpool->log_nomem = 0; + return NGX_OK; } @@ -912,7 +916,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) { + if (ngx_strcmp(value[i].data, "nodelay") == 0) { nodelay = 1; continue; } diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c index fe34fa5a92d..cd9afa7ac9e 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c @@ -13,11 +13,6 @@ #include <zlib.h> #endif -#if (NGX_ENABLE_SYSLOG) -#include <syslog.h> - -#define HTTP_SYSLOG_PRIORITY LOG_NOTICE -#endif typedef struct ngx_http_log_op_s ngx_http_log_op_t; @@ -71,12 +66,8 @@ typedef struct { ngx_http_log_script_t *script; time_t disk_full_time; time_t error_log_time; + ngx_syslog_peer_t *syslog_peer; ngx_http_log_fmt_t *format; - -#if (NGX_ENABLE_SYSLOG) - ngx_int_t priority; - unsigned syslog_on:1; /* unsigned :1 syslog_on */ -#endif } ngx_http_log_t; @@ -249,7 +240,8 @@ static ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { u_char *line, *p; - size_t len; + size_t len, size; + ssize_t n; ngx_uint_t i, l; ngx_http_log_t *log; ngx_http_log_op_t *op; @@ -292,6 +284,16 @@ ngx_http_log_handler(ngx_http_request_t *r) } } + if (log[l].syslog_peer) { + + /* length of syslog's PRI and HEADER message parts */ + len += sizeof("<255>Jan 01 00:00:00 ") - 1 + + ngx_cycle->hostname.len + 1 + + log[l].syslog_peer->tag.len + 2; + + goto alloc_line; + } + len += NGX_LINEFEED_SIZE; buffer = log[l].file ? log[l].file->data : NULL; @@ -330,6 +332,8 @@ ngx_http_log_handler(ngx_http_request_t *r) } } + alloc_line: + line = ngx_pnalloc(r->pool, len); if (line == NULL) { return NGX_ERROR; @@ -337,10 +341,33 @@ ngx_http_log_handler(ngx_http_request_t *r) p = line; + if (log[l].syslog_peer) { + p = ngx_syslog_add_header(log[l].syslog_peer, line); + } + for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } + if (log[l].syslog_peer) { + + size = p - line; + + n = ngx_syslog_send(log[l].syslog_peer, line, size); + + if (n < 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "send() to syslog failed"); + + } else if ((size_t) n != size) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "send() to syslog has written only %z of %uz", + n, size); + } + + continue; + } + ngx_linefeed(p); ngx_http_log_write(r, &log[l], line, p - line); @@ -358,24 +385,13 @@ ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, time_t now; ssize_t n; ngx_err_t err; - #if (NGX_ZLIB) ngx_http_log_buf_t *buffer; #endif -#if (NGX_ENABLE_SYSLOG) - n = 0; - if (log->syslog_on) { - syslog(log->priority, "%.*s", (int)len, buf); - } -#endif - if (log->script == NULL) { name = log->file->name.data; -#if (NGX_ENABLE_SYSLOG) - if (name != NULL) { -#endif #if (NGX_ZLIB) buffer = log->file->data; @@ -388,11 +404,7 @@ ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, #else n = ngx_write_fd(log->file->fd, buf, len); #endif -#if (NGX_ENABLE_SYSLOG) - } else { - n = len; - } -#endif + } else { name = NULL; n = ngx_http_log_script_write(r, log->script, &name, buf, len); @@ -1093,10 +1105,7 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) log->script = NULL; log->disk_full_time = 0; log->error_log_time = 0; -#if (NGX_ENABLE_SYSLOG) - log->priority = HTTP_SYSLOG_PRIORITY; - log->syslog_on = 0; -#endif + log->syslog_peer = NULL; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); fmt = lmcf->formats.elts; @@ -1120,18 +1129,12 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_msec_t flush; ngx_str_t *value, name, s; ngx_http_log_t *log; + ngx_syslog_peer_t *peer; ngx_http_log_buf_t *buffer; ngx_http_log_fmt_t *fmt; ngx_http_log_main_conf_t *lmcf; ngx_http_script_compile_t sc; -#if (NGX_ENABLE_SYSLOG) - u_char *off; - ngx_str_t priority; - ngx_uint_t syslog_on = 0; - name = priority = (ngx_str_t)ngx_null_string; -#endif - value = cf->args->elts; if (ngx_strcmp(value[1].data, "off") == 0) { @@ -1144,38 +1147,6 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) "invalid parameter \"%V\"", &value[2]); return NGX_CONF_ERROR; } -#if (NGX_ENABLE_SYSLOG) - else if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) { - if (!cf->cycle->new_log.syslog_set) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "You must set the syslog directive and enable it first."); - return NGX_CONF_ERROR; - } - - syslog_on = 1; - if (value[1].data[sizeof("syslog") - 1] == ':') { - priority.len = value[1].len - sizeof("syslog"); - priority.data = value[1].data + sizeof("syslog"); - - off = (u_char*) ngx_strchr(priority.data, '|'); - if (off != NULL) { - priority.len = off - priority.data; - - off++; - name.len = value[1].data + value[1].len - off; - name.data = off; - } - } - else { - if (value[1].len > sizeof("syslog")) { - name.len = value[1].len - sizeof("syslog"); - name.data = value[1].data + sizeof("syslog"); - } - } - } else { - name = value[1]; - } -#endif if (llcf->logs == NULL) { llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); @@ -1193,52 +1164,23 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(log, sizeof(ngx_http_log_t)); -#if (NGX_ENABLE_SYSLOG) - log->syslog_on = syslog_on; - - if (priority.len == 0) { - log->priority = HTTP_SYSLOG_PRIORITY; - } - else { - log->priority = ngx_log_get_priority(cf, &priority); - } - if (name.len != 0) { - n = ngx_http_script_variables_count(&name); + if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { - if (n == 0) { - log->file = ngx_conf_open_file(cf->cycle, &name); - if (log->file == NULL) { - return NGX_CONF_ERROR; - } - } else { - if (ngx_conf_full_name(cf->cycle, &name, 0) != NGX_OK) { - return NGX_CONF_ERROR; - } - log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t)); - if (log->script == NULL) { - return NGX_CONF_ERROR; - } - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - sc.cf = cf; - sc.source = &name; - sc.lengths = &log->script->lengths; - sc.values = &log->script->values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; - } + peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); + if (peer == NULL) { + return NGX_CONF_ERROR; } - } - else { - log->file = ngx_conf_open_file(cf->cycle, &name); - if (log->file == NULL) { + + if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { return NGX_CONF_ERROR; } + + log->syslog_peer = peer; + + goto process_formats; } -#else + n = ngx_http_script_variables_count(&value[1]); if (n == 0) { @@ -1271,7 +1213,8 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } } -#endif + +process_formats: if (cf->args->nelts >= 3) { name = value[2]; @@ -1301,6 +1244,17 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (log->syslog_peer != NULL) { + if (cf->args->nelts > 3) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "parameter \"%V\" is not supported by syslog", + &value[3]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + } + size = 0; flush = 0; gzip = 0; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c index 13c8b97ff66..3245e04132c 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c @@ -131,7 +131,7 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, } if (!value->valid) { - value = ngx_http_get_flushed_variable(r, (ngx_uint_t) value->data); + value = ngx_http_get_flushed_variable(r, (uintptr_t) value->data); if (value == NULL || value->not_found) { value = &ngx_http_variable_null_value; @@ -414,7 +414,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) var = ctx->var_values.elts; for (i = 0; i < ctx->var_values.nelts; i++) { - if (index == (ngx_int_t) var[i].data) { + if (index == (intptr_t) var[i].data) { var = &var[i]; goto found; } @@ -429,7 +429,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) var->no_cacheable = 0; var->not_found = 0; var->len = 0; - var->data = (u_char *) index; + var->data = (u_char *) (intptr_t) index; goto found; } diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c index 278b1ed8ad6..aaa047e8fb7 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c @@ -197,7 +197,6 @@ ngx_http_memcached_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - ctx->rest = NGX_HTTP_MEMCACHED_END; ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); @@ -309,10 +308,15 @@ ngx_http_memcached_process_header(ngx_http_request_t *r) found: - *p = '\0'; - - line.len = p - u->buffer.pos - 1; line.data = u->buffer.pos; + line.len = p - u->buffer.pos; + + if (line.len == 0 || *(p - 1) != CR) { + goto no_valid; + } + + *p = '\0'; + line.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "memcached: \"%V\"", &line); @@ -387,10 +391,9 @@ found: length: start = p; + p = line.data + line.len; - while (*p && *p++ != CR) { /* void */ } - - u->headers_in.content_length_n = ngx_atoof(start, p - start - 1); + u->headers_in.content_length_n = ngx_atoof(start, p - start); if (u->headers_in.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " @@ -401,7 +404,7 @@ found: u->headers_in.status_n = 200; u->state->status = 200; - u->buffer.pos = p + 1; + u->buffer.pos = p + sizeof(CRLF) - 1; return NGX_OK; } @@ -410,8 +413,10 @@ found: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); + u->headers_in.content_length_n = 0; u->headers_in.status_n = 404; u->state->status = 404; + u->buffer.pos = p + sizeof("END" CRLF) - 1; u->keepalive = 1; return NGX_OK; @@ -435,7 +440,13 @@ ngx_http_memcached_filter_init(void *data) u = ctx->request->upstream; - u->length += NGX_HTTP_MEMCACHED_END; + if (u->headers_in.status_n != 404) { + u->length = u->headers_in.content_length_n + NGX_HTTP_MEMCACHED_END; + ctx->rest = NGX_HTTP_MEMCACHED_END; + + } else { + u->length = 0; + } return NGX_OK; } @@ -509,7 +520,7 @@ ngx_http_memcached_filter(void *data, ssize_t bytes) return NGX_OK; } - last += u->length - NGX_HTTP_MEMCACHED_END; + last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END); if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c index 20ef51af2b6..8f439ba9239 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c @@ -27,14 +27,15 @@ #define NGX_HTTP_MP4_CTTS_ATOM 15 #define NGX_HTTP_MP4_CTTS_DATA 16 #define NGX_HTTP_MP4_STSC_ATOM 17 -#define NGX_HTTP_MP4_STSC_CHUNK 18 +#define NGX_HTTP_MP4_STSC_START 18 #define NGX_HTTP_MP4_STSC_DATA 19 -#define NGX_HTTP_MP4_STSZ_ATOM 20 -#define NGX_HTTP_MP4_STSZ_DATA 21 -#define NGX_HTTP_MP4_STCO_ATOM 22 -#define NGX_HTTP_MP4_STCO_DATA 23 -#define NGX_HTTP_MP4_CO64_ATOM 24 -#define NGX_HTTP_MP4_CO64_DATA 25 +#define NGX_HTTP_MP4_STSC_END 20 +#define NGX_HTTP_MP4_STSZ_ATOM 21 +#define NGX_HTTP_MP4_STSZ_DATA 22 +#define NGX_HTTP_MP4_STCO_ATOM 23 +#define NGX_HTTP_MP4_STCO_DATA 24 +#define NGX_HTTP_MP4_CO64_ATOM 25 +#define NGX_HTTP_MP4_CO64_DATA 26 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA @@ -62,10 +63,15 @@ typedef struct { uint32_t chunks; ngx_uint_t start_sample; + ngx_uint_t end_sample; ngx_uint_t start_chunk; - ngx_uint_t chunk_samples; - uint64_t chunk_samples_size; + ngx_uint_t end_chunk; + ngx_uint_t start_chunk_samples; + ngx_uint_t end_chunk_samples; + uint64_t start_chunk_samples_size; + uint64_t end_chunk_samples_size; off_t start_offset; + off_t end_offset; size_t tkhd_size; size_t mdhd_size; @@ -95,7 +101,8 @@ typedef struct { ngx_buf_t ctts_atom_buf; ngx_buf_t ctts_data_buf; ngx_buf_t stsc_atom_buf; - ngx_buf_t stsc_chunk_buf; + ngx_buf_t stsc_start_chunk_buf; + ngx_buf_t stsc_end_chunk_buf; ngx_buf_t stsc_data_buf; ngx_buf_t stsz_atom_buf; ngx_buf_t stsz_data_buf; @@ -104,7 +111,8 @@ typedef struct { ngx_buf_t co64_atom_buf; ngx_buf_t co64_data_buf; - ngx_mp4_stsc_entry_t stsc_chunk_entry; + ngx_mp4_stsc_entry_t stsc_start_chunk_entry; + ngx_mp4_stsc_entry_t stsc_end_chunk_entry; } ngx_http_mp4_trak_t; @@ -121,6 +129,7 @@ typedef struct { off_t end; off_t content_length; ngx_uint_t start; + ngx_uint_t length; uint32_t timescale; ngx_http_request_t *request; ngx_array_t trak; @@ -157,7 +166,11 @@ typedef struct { #define ngx_mp4_atom_header(mp4) (mp4->buffer_pos - 8) #define ngx_mp4_atom_data(mp4) mp4->buffer_pos #define ngx_mp4_atom_data_size(t) (uint64_t) (sizeof(t) - 8) -#define ngx_mp4_atom_next(mp4, n) mp4->buffer_pos += n; mp4->offset += n + + +#define ngx_mp4_atom_next(mp4, n) \ + mp4->buffer_pos += (size_t) n; \ + mp4->offset += n #define ngx_mp4_set_atom_name(p, n1, n2, n3, n4) \ @@ -202,6 +215,8 @@ typedef struct { &((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1] +static ngx_int_t ngx_http_mp4_handler(ngx_http_request_t *r); + static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4); static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size); @@ -213,7 +228,7 @@ static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, - off_t start_offset); + off_t start_offset, off_t end_offset); static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, @@ -252,18 +267,26 @@ static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); +static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start); static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); +static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start); static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); +static void ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start); static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); +static ngx_int_t ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start); static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, @@ -280,10 +303,12 @@ static ngx_int_t ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static void ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, off_t adjustment); + static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_mp4_create_conf(ngx_conf_t *cf); static char *ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child); + static ngx_command_t ngx_http_mp4_commands[] = { { ngx_string("mp4"), @@ -395,8 +420,8 @@ ngx_http_mp4_handler(ngx_http_request_t *r) { u_char *last; size_t root; - ngx_int_t rc, start; - ngx_uint_t level; + ngx_int_t rc, start, end; + ngx_uint_t level, length; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; @@ -501,6 +526,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r) r->allow_ranges = 1; start = -1; + length = 0; r->headers_out.content_length_n = of.size; mp4 = NULL; b = NULL; @@ -518,47 +544,72 @@ ngx_http_mp4_handler(ngx_http_request_t *r) ngx_set_errno(0); start = (int) (strtod((char *) value.data, NULL) * 1000); - if (ngx_errno == 0 && start >= 0) { - r->allow_ranges = 0; + if (ngx_errno != 0) { + start = -1; + } + } + + if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) { + + ngx_set_errno(0); + end = (int) (strtod((char *) value.data, NULL) * 1000); + + if (ngx_errno != 0) { + end = -1; + } + + if (end > 0) { + if (start < 0) { + start = 0; + } - mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); - if (mp4 == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (end > start) { + length = end - start; } + } + } + } - mp4->file.fd = of.fd; - mp4->file.name = path; - mp4->file.log = r->connection->log;; - mp4->end = of.size; - mp4->start = (ngx_uint_t) start; - mp4->request = r; + if (start >= 0) { + r->single_range = 1; - switch (ngx_http_mp4_process(mp4)) { + mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); + if (mp4 == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - case NGX_DECLINED: - if (mp4->buffer) { - ngx_pfree(r->pool, mp4->buffer); - } + mp4->file.fd = of.fd; + mp4->file.name = path; + mp4->file.log = r->connection->log; + mp4->end = of.size; + mp4->start = (ngx_uint_t) start; + mp4->length = length; + mp4->request = r; - ngx_pfree(r->pool, mp4); - mp4 = NULL; + switch (ngx_http_mp4_process(mp4)) { - break; + case NGX_DECLINED: + if (mp4->buffer) { + ngx_pfree(r->pool, mp4->buffer); + } - case NGX_OK: - r->headers_out.content_length_n = mp4->content_length; - break; + ngx_pfree(r->pool, mp4); + mp4 = NULL; - default: /* NGX_ERROR */ - if (mp4->buffer) { - ngx_pfree(r->pool, mp4->buffer); - } + break; - ngx_pfree(r->pool, mp4); + case NGX_OK: + r->headers_out.content_length_n = mp4->content_length; + break; - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + default: /* NGX_ERROR */ + if (mp4->buffer) { + ngx_pfree(r->pool, mp4->buffer); } + + ngx_pfree(r->pool, mp4); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; } } @@ -638,15 +689,15 @@ ngx_http_mp4_handler(ngx_http_request_t *r) static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) { - off_t start_offset, adjustment; + off_t start_offset, end_offset, adjustment; ngx_int_t rc; ngx_uint_t i, j; ngx_chain_t **prev; ngx_http_mp4_trak_t *trak; ngx_http_mp4_conf_t *conf; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "mp4 start:%ui", mp4->start); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 start:%ui, length:%ui", mp4->start, mp4->length); conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); @@ -688,6 +739,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) } start_offset = mp4->end; + end_offset = 0; trak = mp4->trak.elts; for (i = 0; i < mp4->trak.nelts; i++) { @@ -735,6 +787,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) start_offset = trak[i].start_offset; } + if (end_offset < trak[i].end_offset) { + end_offset = trak[i].end_offset; + } + *prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM]; prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next; @@ -746,6 +802,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) } } + if (end_offset < start_offset) { + end_offset = start_offset; + } + mp4->moov_size += 8; ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size); @@ -762,7 +822,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) } adjustment = mp4->ftyp_size + mp4->moov_size - + ngx_http_mp4_update_mdat_atom(mp4, start_offset) + + ngx_http_mp4_update_mdat_atom(mp4, start_offset, end_offset) - start_offset; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, @@ -948,7 +1008,7 @@ ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ftyp atom"); if (atom_data_size > 1024 - || ngx_mp4_atom_data(mp4) + atom_data_size > mp4->buffer_end) + || ngx_mp4_atom_data(mp4) + (size_t) atom_data_size > mp4->buffer_end) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 ftyp atom is too large:%uL", @@ -1006,7 +1066,7 @@ ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) no_mdat = (mp4->mdat_atom.buf == NULL); - if (no_mdat && mp4->start == 0) { + if (no_mdat && mp4->start == 0 && mp4->length == 0) { /* * send original file if moov atom resides before * mdat atom and client requests integral file @@ -1105,7 +1165,8 @@ ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) static size_t -ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset) +ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset, + off_t end_offset) { off_t atom_data_size; u_char *atom_header; @@ -1113,15 +1174,16 @@ ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset) uint64_t atom_size; ngx_buf_t *atom; - atom_data_size = mp4->mdat_data.buf->file_last - start_offset; + atom_data_size = end_offset - start_offset; mp4->mdat_data.buf->file_pos = start_offset; + mp4->mdat_data.buf->file_last = end_offset; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mdat new offset @%O:%O", start_offset, atom_data_size); atom_header = mp4->mdat_atom_header; - if ((uint64_t) atom_data_size > 0xffffffff) { + if ((uint64_t) atom_data_size > (uint64_t) 0xffffffff) { atom_size = 1; atom_header_size = sizeof(ngx_mp4_atom_header64_t); ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t), @@ -1196,7 +1258,7 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) u_char *atom_header; size_t atom_size; uint32_t timescale; - uint64_t duration; + uint64_t duration, start_time, length_time; ngx_buf_t *atom; ngx_mp4_mvhd_atom_t *mvhd_atom; ngx_mp4_mvhd64_atom_t *mvhd64_atom; @@ -1239,7 +1301,24 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) "mvhd timescale:%uD, duration:%uL, time:%.3fs", timescale, duration, (double) duration / timescale); - duration -= (uint64_t) mp4->start * timescale / 1000; + start_time = (uint64_t) mp4->start * timescale / 1000; + + if (duration < start_time) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 start time exceeds file duration", + mp4->file.name.data); + return NGX_ERROR; + } + + duration -= start_time; + + if (mp4->length) { + length_time = (uint64_t) mp4->length * timescale / 1000; + + if (duration > length_time) { + duration = length_time; + } + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mvhd new duration:%uL, time:%.3fs", @@ -1296,7 +1375,7 @@ ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak->out[NGX_HTTP_MP4_TRAK_ATOM].buf = atom; - atom_end = mp4->buffer_pos + atom_data_size; + atom_end = mp4->buffer_pos + (size_t) atom_data_size; atom_file_end = mp4->offset + atom_data_size; rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_trak_atoms, atom_data_size); @@ -1386,7 +1465,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) { u_char *atom_header; size_t atom_size; - uint64_t duration; + uint64_t duration, start_time, length_time; ngx_buf_t *atom; ngx_http_mp4_trak_t *trak; ngx_mp4_tkhd_atom_t *tkhd_atom; @@ -1426,7 +1505,23 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) "tkhd duration:%uL, time:%.3fs", duration, (double) duration / mp4->timescale); - duration -= (uint64_t) mp4->start * mp4->timescale / 1000; + start_time = (uint64_t) mp4->start * mp4->timescale / 1000; + + if (duration <= start_time) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "tkhd duration is less than start time"); + return NGX_DECLINED; + } + + duration -= start_time; + + if (mp4->length) { + length_time = (uint64_t) mp4->length * mp4->timescale / 1000; + + if (duration > length_time) { + duration = length_time; + } + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "tkhd new duration:%uL, time:%.3fs", @@ -1529,7 +1624,7 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) u_char *atom_header; size_t atom_size; uint32_t timescale; - uint64_t duration; + uint64_t duration, start_time, length_time; ngx_buf_t *atom; ngx_http_mp4_trak_t *trak; ngx_mp4_mdhd_atom_t *mdhd_atom; @@ -1571,7 +1666,23 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) "mdhd timescale:%uD, duration:%uL, time:%.3fs", timescale, duration, (double) duration / timescale); - duration -= (uint64_t) mp4->start * timescale / 1000; + start_time = (uint64_t) mp4->start * timescale / 1000; + + if (duration <= start_time) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mdhd duration is less than start time"); + return NGX_DECLINED; + } + + duration -= start_time; + + if (mp4->length) { + length_time = (uint64_t) mp4->length * timescale / 1000; + + if (duration > length_time) { + duration = length_time; + } + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mdhd new duration:%uL, time:%.3fs", @@ -1944,13 +2055,9 @@ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { - size_t atom_size; - uint32_t entries, count, duration; - uint64_t start_time; - ngx_buf_t *atom, *data; - ngx_uint_t start_sample; - ngx_mp4_stts_atom_t *stts_atom; - ngx_mp4_stts_entry_t *entry, *end; + size_t atom_size; + ngx_buf_t *atom, *data; + ngx_mp4_stts_atom_t *stts_atom; /* * mdia.minf.stbl.stts updating requires trak->timescale @@ -1969,12 +2076,60 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, return NGX_ERROR; } - entries = trak->time_to_sample_entries; - start_time = (uint64_t) mp4->start * trak->timescale / 1000; + if (ngx_http_mp4_crop_stts_data(mp4, trak, 1) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_mp4_crop_stts_data(mp4, trak, 0) != NGX_OK) { + return NGX_ERROR; + } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "time-to-sample start_time:%uL", start_time); + "time-to-sample entries:%uD", trak->time_to_sample_entries); + atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); + trak->size += atom_size; + + atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf; + stts_atom = (ngx_mp4_stts_atom_t *) atom->pos; + ngx_mp4_set_32value(stts_atom->size, atom_size); + ngx_mp4_set_32value(stts_atom->entries, trak->time_to_sample_entries); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start) +{ + uint32_t count, duration, rest; + uint64_t start_time; + ngx_buf_t *data; + ngx_uint_t start_sample, entries, start_sec; + ngx_mp4_stts_entry_t *entry, *end; + + if (start) { + start_sec = mp4->start; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stts crop start_time:%ui", start_sec); + + } else if (mp4->length) { + start_sec = mp4->length; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stts crop end_time:%ui", start_sec); + + } else { + return NGX_OK; + } + + data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; + + start_time = (uint64_t) start_sec * trak->timescale / 1000; + + entries = trak->time_to_sample_entries; start_sample = 0; entry = (ngx_mp4_stts_entry_t *) data->pos; end = (ngx_mp4_stts_entry_t *) data->last; @@ -1983,13 +2138,13 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, count = ngx_mp4_get_32value(entry->count); duration = ngx_mp4_get_32value(entry->duration); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "count:%uD, duration:%uD", count, duration); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "time:%uL, count:%uD, duration:%uD", + start_time, count, duration); if (start_time < (uint64_t) count * duration) { start_sample += (ngx_uint_t) (start_time / duration); - count -= (uint32_t) (start_time / duration); - ngx_mp4_set_32value(entry->count, count); + rest = (uint32_t) (start_time / duration); goto found; } @@ -1999,27 +2154,44 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, entry++; } - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "start time is out mp4 stts samples in \"%s\"", - mp4->file.name.data); + if (start) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "start time is out mp4 stts samples in \"%s\"", + mp4->file.name.data); - return NGX_ERROR; + return NGX_ERROR; + + } else { + trak->end_sample = trak->start_sample + start_sample; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "end_sample:%ui", trak->end_sample); + + return NGX_OK; + } found: - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start_sample:%ui, new count:%uD", start_sample, count); + if (start) { + ngx_mp4_set_32value(entry->count, count - rest); + data->pos = (u_char *) entry; + trak->time_to_sample_entries = entries; + trak->start_sample = start_sample; - trak->start_sample = start_sample; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "start_sample:%ui, new count:%uD", + trak->start_sample, count - rest); - data->pos = (u_char *) entry; - atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); - trak->size += atom_size; + } else { + ngx_mp4_set_32value(entry->count, rest); + data->last = (u_char *) (entry + 1); + trak->time_to_sample_entries -= entries - 1; + trak->end_sample = trak->start_sample + start_sample; - atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf; - stts_atom = (ngx_mp4_stts_atom_t *) atom->pos; - ngx_mp4_set_32value(stts_atom->size, atom_size); - ngx_mp4_set_32value(stts_atom->entries, entries); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "end_sample:%ui, new count:%uD", + trak->end_sample, rest); + } return NGX_OK; } @@ -2101,7 +2273,7 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { size_t atom_size; - uint32_t entries, sample, start_sample, *entry, *end; + uint32_t sample, start_sample, *entry, *end; ngx_buf_t *atom, *data; ngx_http_mp4_stss_atom_t *stss_atom; @@ -2120,18 +2292,79 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, return NGX_OK; } + ngx_http_mp4_crop_stss_data(mp4, trak, 1); + ngx_http_mp4_crop_stss_data(mp4, trak, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "sync sample entries:%uD", trak->sync_samples_entries); + + if (trak->sync_samples_entries) { + entry = (uint32_t *) data->pos; + end = (uint32_t *) data->last; + + start_sample = trak->start_sample; + + while (entry < end) { + sample = ngx_mp4_get_32value(entry); + sample -= start_sample; + ngx_mp4_set_32value(entry, sample); + entry++; + } + + } else { + trak->out[NGX_HTTP_MP4_STSS_DATA].buf = NULL; + } + + atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos); + trak->size += atom_size; + + atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf; + stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos; + + ngx_mp4_set_32value(stss_atom->size, atom_size); + ngx_mp4_set_32value(stss_atom->entries, trak->sync_samples_entries); + + return NGX_OK; +} + + +static void +ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start) +{ + uint32_t sample, start_sample, *entry, *end; + ngx_buf_t *data; + ngx_uint_t entries; + /* sync samples starts from 1 */ - start_sample = trak->start_sample + 1; - entries = trak->sync_samples_entries; + if (start) { + start_sample = trak->start_sample + 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stss crop start_sample:%uD", start_sample); + + } else if (mp4->length) { + start_sample = trak->end_sample + 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stss crop end_sample:%uD", start_sample); + + } else { + return; + } + + data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; + + entries = trak->sync_samples_entries; entry = (uint32_t *) data->pos; end = (uint32_t *) data->last; while (entry < end) { sample = ngx_mp4_get_32value(entry); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start:%uD, sync:%uD", start_sample, sample); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "sync:%uD", sample); if (sample >= start_sample) { goto found; @@ -2141,35 +2374,19 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, entry++; } - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "start sample is out of mp4 stss atom in \"%s\"", - mp4->file.name.data); - - return NGX_ERROR; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "sample is out of mp4 stss atom"); found: - data->pos = (u_char *) entry; - - start_sample = trak->start_sample; + if (start) { + data->pos = (u_char *) entry; + trak->sync_samples_entries = entries; - while (entry < end) { - sample = ngx_mp4_get_32value(entry); - sample -= start_sample; - ngx_mp4_set_32value(entry, sample); - entry++; + } else { + data->last = (u_char *) entry; + trak->sync_samples_entries -= entries; } - - atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos); - trak->size += atom_size; - - atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf; - stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos; - - ngx_mp4_set_32value(stss_atom->size, atom_size); - ngx_mp4_set_32value(stss_atom->entries, entries); - - return NGX_OK; } @@ -2253,11 +2470,9 @@ static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { - size_t atom_size; - uint32_t entries, count, start_sample; - ngx_buf_t *atom, *data; - ngx_mp4_ctts_atom_t *ctts_atom; - ngx_mp4_ctts_entry_t *entry, *end; + size_t atom_size; + ngx_buf_t *atom, *data; + ngx_mp4_ctts_atom_t *ctts_atom; /* * mdia.minf.stbl.ctts updating requires trak->start_sample @@ -2274,8 +2489,61 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, return; } + ngx_http_mp4_crop_ctts_data(mp4, trak, 1); + ngx_http_mp4_crop_ctts_data(mp4, trak, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "composition offset entries:%uD", + trak->composition_offset_entries); + + if (trak->composition_offset_entries == 0) { + trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; + trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; + return; + } + + atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos); + trak->size += atom_size; + + atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf; + ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos; + + ngx_mp4_set_32value(ctts_atom->size, atom_size); + ngx_mp4_set_32value(ctts_atom->entries, trak->composition_offset_entries); + + return; +} + + +static void +ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start) +{ + uint32_t count, start_sample, rest; + ngx_buf_t *data; + ngx_uint_t entries; + ngx_mp4_ctts_entry_t *entry, *end; + /* sync samples starts from 1 */ - start_sample = trak->start_sample + 1; + + if (start) { + start_sample = trak->start_sample + 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 ctts crop start_sample:%uD", start_sample); + + } else if (mp4->length) { + start_sample = trak->end_sample - trak->start_sample + 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 ctts crop end_sample:%uD", start_sample); + + } else { + return; + } + + data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; + entries = trak->composition_offset_entries; entry = (ngx_mp4_ctts_entry_t *) data->pos; end = (ngx_mp4_ctts_entry_t *) data->last; @@ -2284,12 +2552,11 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, count = ngx_mp4_get_32value(entry->count); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start:%uD, count:%uD, offset:%uD", + "sample:%uD, count:%uD, offset:%uD", start_sample, count, ngx_mp4_get_32value(entry->offset)); if (start_sample <= count) { - count -= (start_sample - 1); - ngx_mp4_set_32value(entry->count, count); + rest = start_sample - 1; goto found; } @@ -2298,24 +2565,25 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, entry++; } - trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; - trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; + if (start) { + data->pos = (u_char *) end; + trak->composition_offset_entries = 0; + } return; found: - data->pos = (u_char *) entry; - atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos); - trak->size += atom_size; - - atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf; - ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos; + if (start) { + ngx_mp4_set_32value(entry->count, count - rest); + data->pos = (u_char *) entry; + trak->composition_offset_entries = entries; - ngx_mp4_set_32value(ctts_atom->size, atom_size); - ngx_mp4_set_32value(ctts_atom->entries, entries); - - return; + } else { + ngx_mp4_set_32value(entry->count, rest); + data->last = (u_char *) (entry + 1); + trak->composition_offset_entries -= entries - 1; + } } @@ -2394,11 +2662,10 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { size_t atom_size; - uint32_t start_sample, entries, chunk, samples, id, - next_chunk, n; - ngx_buf_t *atom, *data, *buf; + uint32_t chunk; + ngx_buf_t *atom, *data; ngx_mp4_stsc_atom_t *stsc_atom; - ngx_mp4_stsc_entry_t *entry, *first, *end; + ngx_mp4_stsc_entry_t *entry, *end; /* * mdia.minf.stbl.stsc updating requires trak->start_sample @@ -2425,15 +2692,97 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, return NGX_ERROR; } - start_sample = (uint32_t) trak->start_sample; + if (ngx_http_mp4_crop_stsc_data(mp4, trak, 1) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_mp4_crop_stsc_data(mp4, trak, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "sample-to-chunk entries:%uD", + trak->sample_to_chunk_entries); + + entry = (ngx_mp4_stsc_entry_t *) data->pos; + end = (ngx_mp4_stsc_entry_t *) data->last; + + while (entry < end) { + chunk = ngx_mp4_get_32value(entry->chunk); + chunk -= trak->start_chunk; + ngx_mp4_set_32value(entry->chunk, chunk); + entry++; + } + + atom_size = sizeof(ngx_mp4_stsc_atom_t) + + trak->sample_to_chunk_entries * sizeof(ngx_mp4_stsc_entry_t); + + trak->size += atom_size; + + atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf; + stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos; + + ngx_mp4_set_32value(stsc_atom->size, atom_size); + ngx_mp4_set_32value(stsc_atom->entries, trak->sample_to_chunk_entries); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, ngx_uint_t start) +{ + uint32_t start_sample, chunk, samples, id, next_chunk, n, + prev_samples; + ngx_buf_t *data, *buf; + ngx_uint_t entries, target_chunk, chunk_samples; + ngx_mp4_stsc_entry_t *entry, *end, *first; + entries = trak->sample_to_chunk_entries - 1; + if (start) { + start_sample = (uint32_t) trak->start_sample; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stsc crop start_sample:%uD", start_sample); + + } else if (mp4->length) { + start_sample = (uint32_t) (trak->end_sample - trak->start_sample); + samples = 0; + + data = trak->out[NGX_HTTP_MP4_STSC_START].buf; + + if (data) { + entry = (ngx_mp4_stsc_entry_t *) data->pos; + samples = ngx_mp4_get_32value(entry->samples); + entries--; + + if (samples > start_sample) { + samples = start_sample; + ngx_mp4_set_32value(entry->samples, samples); + } + + start_sample -= samples; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stsc crop end_sample:%uD, ext_samples:%uD", + start_sample, samples); + + } else { + return NGX_OK; + } + + data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; + entry = (ngx_mp4_stsc_entry_t *) data->pos; end = (ngx_mp4_stsc_entry_t *) data->last; chunk = ngx_mp4_get_32value(entry->chunk); samples = ngx_mp4_get_32value(entry->samples); id = ngx_mp4_get_32value(entry->id); + prev_samples = 0; entry++; while (entry < end) { @@ -2441,18 +2790,19 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, next_chunk = ngx_mp4_get_32value(entry->chunk); ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start_sample:%uD, chunk:%uD, chunks:%uD, " + "sample:%uD, chunk:%uD, chunks:%uD, " "samples:%uD, id:%uD", start_sample, chunk, next_chunk - chunk, samples, id); n = (next_chunk - chunk) * samples; - if (start_sample <= n) { + if (start_sample < n) { goto found; } start_sample -= n; + prev_samples = samples; chunk = next_chunk; samples = ngx_mp4_get_32value(entry->samples); id = ngx_mp4_get_32value(entry->id); @@ -2460,18 +2810,18 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, entry++; } - next_chunk = trak->chunks; + next_chunk = trak->chunks + 1; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start_sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", + "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", start_sample, chunk, next_chunk - chunk, samples); n = (next_chunk - chunk) * samples; if (start_sample > n) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "start time is out mp4 stsc chunks in \"%s\"", - mp4->file.name.data); + "%s time is out mp4 stsc chunks in \"%s\"", + start ? "start" : "end", mp4->file.name.data); return NGX_ERROR; } @@ -2487,59 +2837,91 @@ found: return NGX_ERROR; } - trak->start_chunk = chunk - 1; + target_chunk = chunk - 1; + target_chunk += start_sample / samples; + chunk_samples = start_sample % samples; - trak->start_chunk += start_sample / samples; - trak->chunk_samples = start_sample % samples; + if (start) { + data->pos = (u_char *) entry; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start chunk:%ui, samples:%uD", - trak->start_chunk, trak->chunk_samples); + trak->sample_to_chunk_entries = entries; + trak->start_chunk = target_chunk; + trak->start_chunk_samples = chunk_samples; + + ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 1); + + samples -= chunk_samples; - data->pos = (u_char *) entry; - atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "start_chunk:%ui, start_chunk_samples:%ui", + trak->start_chunk, trak->start_chunk_samples); + + } else { + if (start_sample) { + data->last = (u_char *) (entry + 1); + trak->sample_to_chunk_entries -= entries - 1; + trak->end_chunk_samples = samples; - ngx_mp4_set_32value(entry->chunk, 1); + } else { + data->last = (u_char *) entry; + trak->sample_to_chunk_entries -= entries; + trak->end_chunk_samples = prev_samples; + } - if (trak->chunk_samples && next_chunk - trak->start_chunk == 2) { + if (chunk_samples) { + trak->end_chunk = target_chunk + 1; + trak->end_chunk_samples = chunk_samples; - /* last chunk in the entry */ + } else { + trak->end_chunk = target_chunk; + } - ngx_mp4_set_32value(entry->samples, samples - trak->chunk_samples); + samples = chunk_samples; + next_chunk = chunk + 1; - } else if (trak->chunk_samples) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "end_chunk:%ui, end_chunk_samples:%ui", + trak->end_chunk, trak->end_chunk_samples); + } - first = &trak->stsc_chunk_entry; + if (chunk_samples && next_chunk - target_chunk == 2) { + + ngx_mp4_set_32value(entry->samples, samples); + + } else if (chunk_samples && start) { + + first = &trak->stsc_start_chunk_entry; ngx_mp4_set_32value(first->chunk, 1); - ngx_mp4_set_32value(first->samples, samples - trak->chunk_samples); + ngx_mp4_set_32value(first->samples, samples); ngx_mp4_set_32value(first->id, id); - buf = &trak->stsc_chunk_buf; + buf = &trak->stsc_start_chunk_buf; buf->temporary = 1; buf->pos = (u_char *) first; buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t); - trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf; + trak->out[NGX_HTTP_MP4_STSC_START].buf = buf; - ngx_mp4_set_32value(entry->chunk, 2); + ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 2); - entries++; - atom_size += sizeof(ngx_mp4_stsc_entry_t); - } + trak->sample_to_chunk_entries++; - while (++entry < end) { - chunk = ngx_mp4_get_32value(entry->chunk); - chunk -= trak->start_chunk; - ngx_mp4_set_32value(entry->chunk, chunk); - } + } else if (chunk_samples) { - trak->size += atom_size; + first = &trak->stsc_end_chunk_entry; + ngx_mp4_set_32value(first->chunk, trak->end_chunk - trak->start_chunk); + ngx_mp4_set_32value(first->samples, samples); + ngx_mp4_set_32value(first->id, id); - atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf; - stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos; + buf = &trak->stsc_end_chunk_buf; + buf->temporary = 1; + buf->pos = (u_char *) first; + buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t); - ngx_mp4_set_32value(stsc_atom->size, atom_size); - ngx_mp4_set_32value(stsc_atom->entries, entries); + trak->out[NGX_HTTP_MP4_STSC_END].buf = buf; + + trak->sample_to_chunk_entries++; + } return NGX_OK; } @@ -2635,7 +3017,7 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { size_t atom_size; - uint32_t *pos, *end; + uint32_t *pos, *end, entries; ngx_buf_t *atom, *data; ngx_mp4_stsz_atom_t *stsz_atom; @@ -2651,22 +3033,47 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; if (data) { - if (trak->start_sample > trak->sample_sizes_entries) { + entries = trak->sample_sizes_entries; + + if (trak->start_sample > entries) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "start time is out mp4 stsz samples in \"%s\"", mp4->file.name.data); return NGX_ERROR; } + entries -= trak->start_sample; data->pos += trak->start_sample * sizeof(uint32_t); end = (uint32_t *) data->pos; - for (pos = end - trak->chunk_samples; pos < end; pos++) { - trak->chunk_samples_size += ngx_mp4_get_32value(pos); + for (pos = end - trak->start_chunk_samples; pos < end; pos++) { + trak->start_chunk_samples_size += ngx_mp4_get_32value(pos); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "chunk samples sizes:%uL", trak->chunk_samples_size); + "chunk samples sizes:%uL", + trak->start_chunk_samples_size); + + if (mp4->length) { + if (trak->end_sample - trak->start_sample > entries) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "end time is out mp4 stsz samples in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + + entries = trak->end_sample - trak->start_sample; + data->last = data->pos + entries * sizeof(uint32_t); + end = (uint32_t *) data->last; + + for (pos = end - trak->end_chunk_samples; pos < end; pos++) { + trak->end_chunk_samples_size += ngx_mp4_get_32value(pos); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 stsz end_chunk_samples_size:%uL", + trak->end_chunk_samples_size); + } atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); trak->size += atom_size; @@ -2675,8 +3082,7 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; ngx_mp4_set_32value(stsz_atom->size, atom_size); - ngx_mp4_set_32value(stsz_atom->entries, - trak->sample_sizes_entries - trak->start_sample); + ngx_mp4_set_32value(stsz_atom->entries, entries); } return NGX_OK; @@ -2757,6 +3163,7 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { size_t atom_size; + uint32_t entries; ngx_buf_t *atom, *data; ngx_mp4_stco_atom_t *stco_atom; @@ -2786,21 +3193,53 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, } data->pos += trak->start_chunk * sizeof(uint32_t); - atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); - trak->size += atom_size; trak->start_offset = ngx_mp4_get_32value(data->pos); - trak->start_offset += trak->chunk_samples_size; + trak->start_offset += trak->start_chunk_samples_size; ngx_mp4_set_32value(data->pos, trak->start_offset); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start chunk offset:%uD", trak->start_offset); + "start chunk offset:%O", trak->start_offset); + + if (mp4->length) { + + if (trak->end_chunk > trak->chunks) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "end time is out mp4 stco chunks in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + + entries = trak->end_chunk - trak->start_chunk; + data->last = data->pos + entries * sizeof(uint32_t); + + if (entries) { + trak->end_offset = + ngx_mp4_get_32value(data->last - sizeof(uint32_t)); + trak->end_offset += trak->end_chunk_samples_size; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "end chunk offset:%O", trak->end_offset); + } + + } else { + entries = trak->chunks - trak->start_chunk; + trak->end_offset = mp4->mdat_data.buf->file_last; + } + + if (entries == 0) { + trak->start_offset = mp4->end; + trak->end_offset = 0; + } + + atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); + trak->size += atom_size; atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; ngx_mp4_set_32value(stco_atom->size, atom_size); - ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk); + ngx_mp4_set_32value(stco_atom->entries, entries); return NGX_OK; } @@ -2908,6 +3347,7 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { size_t atom_size; + uint64_t entries; ngx_buf_t *atom, *data; ngx_mp4_co64_atom_t *co64_atom; @@ -2937,21 +3377,53 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, } data->pos += trak->start_chunk * sizeof(uint64_t); - atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); - trak->size += atom_size; trak->start_offset = ngx_mp4_get_64value(data->pos); - trak->start_offset += trak->chunk_samples_size; + trak->start_offset += trak->start_chunk_samples_size; ngx_mp4_set_64value(data->pos, trak->start_offset); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "start chunk offset:%uL", trak->start_offset); + "start chunk offset:%O", trak->start_offset); + + if (mp4->length) { + + if (trak->end_chunk > trak->chunks) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "end time is out mp4 co64 chunks in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + + entries = trak->end_chunk - trak->start_chunk; + data->last = data->pos + entries * sizeof(uint64_t); + + if (entries) { + trak->end_offset = + ngx_mp4_get_64value(data->last - sizeof(uint64_t)); + trak->end_offset += trak->end_chunk_samples_size; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "end chunk offset:%O", trak->end_offset); + } + + } else { + entries = trak->chunks - trak->start_chunk; + trak->end_offset = mp4->mdat_data.buf->file_last; + } + + if (entries == 0) { + trak->start_offset = mp4->end; + trak->end_offset = 0; + } + + atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); + trak->size += atom_size; atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; ngx_mp4_set_32value(co64_atom->size, atom_size); - ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); + ngx_mp4_set_32value(co64_atom->entries, entries); return NGX_OK; } diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c index 5e62caa30f4..8ee32f491a1 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c @@ -76,6 +76,12 @@ typedef struct { ngx_uint_t headers_hash_max_size; ngx_uint_t headers_hash_bucket_size; + +#if (NGX_HTTP_SSL) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +#endif } ngx_http_proxy_loc_conf_t; @@ -178,6 +184,7 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 }, + { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, @@ -185,6 +192,20 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { }; +#if (NGX_HTTP_SSL) + +static ngx_conf_bitmask_t ngx_http_proxy_ssl_protocols[] = { + { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, + { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, + { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, + { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, + { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, + { ngx_null_string, 0 } +}; + +#endif + + static ngx_conf_enum_t ngx_http_proxy_http_version[] = { { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, @@ -444,6 +465,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("proxy_cache_revalidate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate), + NULL }, + #endif { ngx_string("proxy_temp_path"), @@ -511,6 +539,20 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse), NULL }, + { ngx_string("proxy_ssl_protocols"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols), + &ngx_http_proxy_ssl_protocols }, + + { ngx_string("proxy_ssl_ciphers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers), + NULL }, + #endif ngx_null_command @@ -587,7 +629,8 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = { { ngx_string("Keep-Alive"), ngx_string("") }, { ngx_string("Expect"), ngx_string("") }, { ngx_string("Upgrade"), ngx_string("") }, - { ngx_string("If-Modified-Since"), ngx_string("") }, + { ngx_string("If-Modified-Since"), + ngx_string("$upstream_cache_last_modified") }, { ngx_string("If-Unmodified-Since"), ngx_string("") }, { ngx_string("If-None-Match"), ngx_string("") }, { ngx_string("If-Match"), ngx_string("") }, @@ -993,6 +1036,8 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) len += uri_len; + ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); + ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes); if (plcf->body_set_len) { @@ -1317,7 +1362,7 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r) return NGX_OK; } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = ctx->status.code; } @@ -1539,7 +1584,7 @@ ngx_http_proxy_input_filter_init(void *data) u->pipe->length = 3; /* "0" LF LF */ u->input_filter = ngx_http_proxy_non_buffered_chunked_filter; - u->length = -1; + u->length = 1; } else if (u->headers_in.content_length_n == 0) { /* empty body: special case as filter won't be called */ @@ -1570,19 +1615,13 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_OK; } - if (p->free) { - cl = p->free; - b = cl->buf; - p->free = cl->next; - ngx_free_chain(p->pool, cl); - - } else { - b = ngx_alloc_buf(p->pool); - if (b == NULL) { - return NGX_ERROR; - } + cl = ngx_chain_get_free_buf(p->pool, &p->free); + if (cl == NULL) { + return NGX_ERROR; } + b = cl->buf; + ngx_memcpy(b, buf, sizeof(ngx_buf_t)); b->shadow = buf; b->tag = p->tag; @@ -1590,14 +1629,6 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) b->recycled = 1; buf->shadow = b; - cl = ngx_alloc_chain_link(p->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); if (p->in) { @@ -1662,19 +1693,13 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) /* a chunk has been parsed successfully */ - if (p->free) { - cl = p->free; - b = cl->buf; - p->free = cl->next; - ngx_free_chain(p->pool, cl); - - } else { - b = ngx_alloc_buf(p->pool); - if (b == NULL) { - return NGX_ERROR; - } + cl = ngx_chain_get_free_buf(p->pool, &p->free); + if (cl == NULL) { + return NGX_ERROR; } + b = cl->buf; + ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = buf->pos; @@ -1687,14 +1712,6 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) *prev = b; prev = &b->shadow; - cl = ngx_alloc_chain_link(p->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - if (p->in) { *p->last_in = cl; } else { @@ -1709,7 +1726,7 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) if (buf->last - buf->pos >= ctx->chunked.size) { - buf->pos += ctx->chunked.size; + buf->pos += (size_t) ctx->chunked.size; b->last = buf->pos; ctx->chunked.size = 0; @@ -1872,7 +1889,7 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes) b->tag = u->output.tag; if (buf->last - buf->pos >= ctx->chunked.size) { - buf->pos += ctx->chunked.size; + buf->pos += (size_t) ctx->chunked.size; b->last = buf->pos; ctx->chunked.size = 0; @@ -2077,7 +2094,7 @@ ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, v->no_cacheable = 0; v->not_found = 0; - v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN); + v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN); if (v->data == NULL) { return NGX_ERROR; @@ -2383,6 +2400,9 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->body_set = NULL; * conf->body_source = { 0, NULL }; * conf->redirects = NULL; + * conf->ssl = 0; + * conf->ssl_protocols = 0; + * conf->ssl_ciphers = { 0, NULL }; */ conf->upstream.store = NGX_CONF_UNSET; @@ -2414,6 +2434,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; conf->upstream.cache_lock = NGX_CONF_UNSET; conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -2657,12 +2678,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.no_cache, prev->upstream.no_cache, NULL); - if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) { - ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "\"proxy_no_cache\" functionality has been changed in 0.8.46, " - "now it should be used together with \"proxy_cache_bypass\""); - } - ngx_conf_merge_ptr_value(conf->upstream.cache_valid, prev->upstream.cache_valid, NULL); @@ -2676,6 +2691,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, prev->upstream.cache_lock_timeout, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, + prev->upstream.cache_revalidate, 0); + #endif ngx_conf_merge_str_value(conf->method, prev->method, ""); @@ -2698,6 +2716,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) ngx_conf_merge_value(conf->upstream.ssl_session_reuse, prev->upstream.ssl_session_reuse, 1); + + ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, + (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2)); + + ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, + "DEFAULT"); + + if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) { + return NGX_CONF_ERROR; + } #endif ngx_conf_merge_value(conf->redirect, prev->redirect, 1); @@ -3143,9 +3173,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #if (NGX_HTTP_SSL) - if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) { - return NGX_CONF_ERROR; - } + plcf->ssl = 1; #endif return NGX_CONF_OK; @@ -3158,9 +3186,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) { #if (NGX_HTTP_SSL) - if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) { - return NGX_CONF_ERROR; - } + plcf->ssl = 1; add = 8; port = 443; @@ -3742,15 +3768,22 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) plcf->upstream.ssl->log = cf->log; - if (ngx_ssl_create(plcf->upstream.ssl, - NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2, - NULL) + if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL) != NGX_OK) { return NGX_ERROR; } + if (SSL_CTX_set_cipher_list(plcf->upstream.ssl->ctx, + (const char *) plcf->ssl_ciphers.data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &plcf->ssl_ciphers); + return NGX_ERROR; + } + cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_ERROR; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c index 82c202d33c5..6a65e48498d 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c @@ -22,7 +22,7 @@ * ... data ... * * - * the mutlipart format: + * the multipart format: * * "HTTP/1.0 206 Partial Content" CRLF * ... header ... @@ -148,6 +148,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) { time_t if_range_time; ngx_str_t *if_range, *etag; + ngx_uint_t ranges; ngx_http_core_loc_conf_t *clcf; ngx_http_range_filter_ctx_t *ctx; @@ -227,7 +228,9 @@ parse: return NGX_ERROR; } - switch (ngx_http_range_parse(r, ctx, clcf->max_ranges)) { + ranges = r->single_range ? 1 : clcf->max_ranges; + + switch (ngx_http_range_parse(r, ctx, ranges)) { case NGX_OK: ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); @@ -432,7 +435,9 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, + r->headers_out.content_type.len + sizeof(CRLF "Content-Range: bytes ") - 1; - if (r->headers_out.charset.len) { + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } @@ -451,7 +456,9 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, * "Content-Range: bytes " */ - if (r->headers_out.charset.len) { + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, CRLF "--%0muA" CRLF "Content-Type: %V; charset=%V" CRLF @@ -461,8 +468,6 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, &r->headers_out.charset) - ctx->boundary_header.data; - r->headers_out.charset.len = 0; - } else if (r->headers_out.content_type.len) { ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, CRLF "--%0muA" CRLF @@ -501,6 +506,8 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, r->headers_out.content_type_len = r->headers_out.content_type.len; + r->headers_out.charset.len = 0; + /* the size of the last boundary CRLF "--0123456789--" CRLF */ len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c index ed9c5f9e82c..7a621180379 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c @@ -13,6 +13,7 @@ #define NGX_HTTP_REALIP_XREALIP 0 #define NGX_HTTP_REALIP_XFWD 1 #define NGX_HTTP_REALIP_HEADER 2 +#define NGX_HTTP_REALIP_PROXY 3 typedef struct { @@ -156,6 +157,18 @@ ngx_http_realip_handler(ngx_http_request_t *r) break; + case NGX_HTTP_REALIP_PROXY: + + value = &r->connection->proxy_protocol_addr; + + if (value->len == 0) { + return NGX_DECLINED; + } + + xfwd = NULL; + + break; + default: /* NGX_HTTP_REALIP_HEADER */ part = &r->headers_in.headers.part; @@ -230,7 +243,8 @@ ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr) c = r->connection; - len = ngx_sock_ntop(addr->sockaddr, text, NGX_SOCKADDR_STRLEN, 0); + len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text, + NGX_SOCKADDR_STRLEN, 0); if (len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -342,6 +356,11 @@ ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } + if (ngx_strcmp(value[1].data, "proxy_protocol") == 0) { + rlcf->type = NGX_HTTP_REALIP_PROXY; + return NGX_CONF_OK; + } + rlcf->type = NGX_HTTP_REALIP_HEADER; rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len); rlcf->header = value[1]; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c index d8a014c5be6..b417eb227b0 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c @@ -12,22 +12,18 @@ #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) -#if !(NGX_PCRE) - -#define ngx_regex_t void - -#endif - typedef struct { ngx_hash_combined_t hash; #if (NGX_PCRE) ngx_array_t *regex; + ngx_array_t *server_name_regex; #endif ngx_flag_t no_referer; ngx_flag_t blocked_referer; + ngx_flag_t server_names; ngx_hash_keys_arrays_t *keys; @@ -41,10 +37,14 @@ static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, - ngx_str_t *value, ngx_str_t *uri); -static char *ngx_http_add_regex_referer(ngx_conf_t *cf, - ngx_http_referer_conf_t *rlcf, ngx_str_t *name, ngx_regex_t *regex); +static ngx_int_t ngx_http_add_referer(ngx_conf_t *cf, + ngx_hash_keys_arrays_t *keys, ngx_str_t *value, ngx_str_t *uri); +static ngx_int_t ngx_http_add_regex_referer(ngx_conf_t *cf, + ngx_http_referer_conf_t *rlcf, ngx_str_t *name); +#if (NGX_PCRE) +static ngx_int_t ngx_http_add_regex_server_name(ngx_conf_t *cf, + ngx_http_referer_conf_t *rlcf, ngx_http_regex_t *regex); +#endif static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, const void *two); @@ -117,6 +117,10 @@ ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_uint_t i, key; ngx_http_referer_conf_t *rlcf; u_char buf[256]; +#if (NGX_PCRE) + ngx_int_t rc; + ngx_str_t referer; +#endif rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); @@ -125,6 +129,7 @@ ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, && rlcf->hash.wc_tail == NULL #if (NGX_PCRE) && rlcf->regex == NULL + && rlcf->server_name_regex == NULL #endif ) { @@ -147,10 +152,12 @@ ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) { ref += 7; + len -= 7; goto valid_scheme; } else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) { ref += 8; + len -= 8; goto valid_scheme; } } @@ -171,12 +178,12 @@ valid_scheme: break; } - buf[i] = ngx_tolower(*p); - key = ngx_hash(key, buf[i++]); - if (i == 256) { goto invalid; } + + buf[i] = ngx_tolower(*p); + key = ngx_hash(key, buf[i++]); } uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref); @@ -187,11 +194,26 @@ valid_scheme: #if (NGX_PCRE) - if (rlcf->regex) { - ngx_int_t rc; - ngx_str_t referer; + if (rlcf->server_name_regex) { + referer.len = p - ref; + referer.data = buf; + + rc = ngx_regex_exec_array(rlcf->server_name_regex, &referer, + r->connection->log); + + if (rc == NGX_OK) { + goto valid; + } + + if (rc == NGX_ERROR) { + return rc; + } + + /* NGX_DECLINED */ + } - referer.len = len - 7; + if (rlcf->regex) { + referer.len = len; referer.data = ref; rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log); @@ -251,8 +273,17 @@ ngx_http_referer_create_conf(ngx_conf_t *cf) return NULL; } + /* + * set by ngx_pcalloc(): + * + * conf->hash = { NULL }; + * conf->server_names = 0; + * conf->keys = NULL; + */ + #if (NGX_PCRE) conf->regex = NGX_CONF_UNSET_PTR; + conf->server_name_regex = NGX_CONF_UNSET_PTR; #endif conf->no_referer = NGX_CONF_UNSET; @@ -270,13 +301,18 @@ ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_referer_conf_t *prev = parent; ngx_http_referer_conf_t *conf = child; - ngx_hash_init_t hash; + ngx_uint_t n; + ngx_hash_init_t hash; + ngx_http_server_name_t *sn; + ngx_http_core_srv_conf_t *cscf; if (conf->keys == NULL) { conf->hash = prev->hash; #if (NGX_PCRE) ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); + ngx_conf_merge_ptr_value(conf->server_name_regex, + prev->server_name_regex, NULL); #endif ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); @@ -288,6 +324,33 @@ ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_OK; } + if (conf->server_names == 1) { + cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); + + sn = cscf->server_names.elts; + for (n = 0; n < cscf->server_names.nelts; n++) { + +#if (NGX_PCRE) + if (sn[n].regex) { + + if (ngx_http_add_regex_server_name(cf, conf, sn[n].regex) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + continue; + } +#endif + + if (ngx_http_add_referer(cf, conf->keys, &sn[n].name, NULL) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + } + if ((conf->no_referer == 1 || conf->blocked_referer == 1) && conf->keys->keys.nelts == 0 && conf->keys->dns_wc_head.nelts == 0 @@ -366,6 +429,8 @@ ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_PCRE) ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); + ngx_conf_merge_ptr_value(conf->server_name_regex, prev->server_name_regex, + NULL); #endif if (conf->no_referer == NGX_CONF_UNSET) { @@ -389,15 +454,12 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) u_char *p; ngx_str_t *value, uri, name; - ngx_uint_t i, n; + ngx_uint_t i; ngx_http_variable_t *var; - ngx_http_server_name_t *sn; - ngx_http_core_srv_conf_t *cscf; ngx_str_set(&name, "invalid_referer"); - var = ngx_http_add_variable(cf, &name, - NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH); + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); if (var == NULL) { return NGX_CONF_ERROR; } @@ -437,48 +499,21 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - ngx_str_null(&uri); - if (ngx_strcmp(value[i].data, "server_names") == 0) { - - cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); - - sn = cscf->server_names.elts; - for (n = 0; n < cscf->server_names.nelts; n++) { - -#if (NGX_PCRE) - if (sn[n].regex) { - - if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name, - sn[n].regex->regex) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - continue; - } -#endif - - if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - } - + rlcf->server_names = 1; continue; } if (value[i].data[0] == '~') { - if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK) - { + if (ngx_http_add_regex_referer(cf, rlcf, &value[i]) != NGX_OK) { return NGX_CONF_ERROR; } continue; } + ngx_str_null(&uri); + p = (u_char *) ngx_strchr(value[i].data, '/'); if (p) { @@ -496,20 +531,20 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } -static char * +static ngx_int_t ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, ngx_str_t *value, ngx_str_t *uri) { ngx_int_t rc; ngx_str_t *u; - if (uri->len == 0) { + if (uri == NULL || uri->len == 0) { u = NGX_HTTP_REFERER_NO_URI_PART; } else { u = ngx_palloc(cf->pool, sizeof(ngx_str_t)); if (u == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *u = *uri; @@ -518,7 +553,7 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, rc = ngx_hash_add_key(keys, value, u, NGX_HASH_WILDCARD_KEY); if (rc == NGX_OK) { - return NGX_CONF_OK; + return NGX_OK; } if (rc == NGX_DECLINED) { @@ -531,13 +566,13 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, "conflicting parameter \"%V\"", value); } - return NGX_CONF_ERROR; + return NGX_ERROR; } -static char * +static ngx_int_t ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, - ngx_str_t *name, ngx_regex_t *regex) + ngx_str_t *name) { #if (NGX_PCRE) ngx_regex_elt_t *re; @@ -546,26 +581,19 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, if (name->len == 1) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name); - return NGX_CONF_ERROR; + return NGX_ERROR; } if (rlcf->regex == NGX_CONF_UNSET_PTR) { rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t)); if (rlcf->regex == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } } re = ngx_array_push(rlcf->regex); if (re == NULL) { - return NGX_CONF_ERROR; - } - - if (regex) { - re->regex = regex; - re->name = name->data; - - return NGX_CONF_OK; + return NGX_ERROR; } name->len--; @@ -581,13 +609,13 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, if (ngx_regex_compile(&rc) != NGX_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); - return NGX_CONF_ERROR; + return NGX_ERROR; } re->regex = rc.regex; re->name = name->data; - return NGX_CONF_OK; + return NGX_OK; #else @@ -595,12 +623,42 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, "the using of the regex \"%V\" requires PCRE library", name); - return NGX_CONF_ERROR; + return NGX_ERROR; #endif } +#if (NGX_PCRE) + +static ngx_int_t +ngx_http_add_regex_server_name(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, + ngx_http_regex_t *regex) +{ + ngx_regex_elt_t *re; + + if (rlcf->server_name_regex == NGX_CONF_UNSET_PTR) { + rlcf->server_name_regex = ngx_array_create(cf->pool, 2, + sizeof(ngx_regex_elt_t)); + if (rlcf->server_name_regex == NULL) { + return NGX_ERROR; + } + } + + re = ngx_array_push(rlcf->server_name_regex); + if (re == NULL) { + return NGX_ERROR; + } + + re->regex = regex->regex; + re->name = regex->name.data; + + return NGX_OK; +} + +#endif + + static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, const void *two) { diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c index 49cc96d248c..884cb500adf 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c @@ -65,6 +65,7 @@ static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = { { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, + { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, @@ -261,6 +262,13 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("scgi_cache_revalidate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_revalidate), + NULL }, + #endif { ngx_string("scgi_temp_path"), @@ -368,7 +376,8 @@ static ngx_str_t ngx_http_scgi_hide_headers[] = { #if (NGX_HTTP_CACHE) static ngx_keyval_t ngx_http_scgi_cache_headers[] = { - { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") }, + { ngx_string("HTTP_IF_MODIFIED_SINCE"), + ngx_string("$upstream_cache_last_modified") }, { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") }, { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, @@ -393,13 +402,6 @@ ngx_http_scgi_handler(ngx_http_request_t *r) ngx_http_upstream_t *u; ngx_http_scgi_loc_conf_t *scf; - if (r->subrequest_in_memory) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "ngx_http_scgi_module does not support " - "subrequests in memory"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -883,7 +885,7 @@ ngx_http_scgi_process_status_line(ngx_http_request_t *r) return ngx_http_scgi_process_header(r); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = status->code; } @@ -1011,7 +1013,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) ngx_str_set(&u->headers_in.status_line, "200 OK"); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } @@ -1099,6 +1101,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; conf->upstream.cache_lock = NGX_CONF_UNSET; conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -1339,6 +1342,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, prev->upstream.cache_lock_timeout, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, + prev->upstream.cache_revalidate, 0); + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, @@ -1500,7 +1506,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, s->key = h->key; s->value = h->value; - s->skip_empty = 0; + s->skip_empty = 1; next: @@ -1728,7 +1734,7 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) sc.source = &value[1]; sc.lengths = &scf->upstream.store_lengths; sc.values = &scf->upstream.store_values; - sc.variables = ngx_http_script_variables_count(&value[1]);; + sc.variables = ngx_http_script_variables_count(&value[1]); sc.complete_lengths = 1; sc.complete_values = 1; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c index eb286cc3475..aeb1376b7bb 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c @@ -21,6 +21,7 @@ typedef struct { ngx_flag_t enable; ngx_flag_t silent_errors; ngx_flag_t ignore_recycled_buffers; + ngx_flag_t last_modified; ngx_hash_t types; @@ -162,6 +163,13 @@ static ngx_command_t ngx_http_ssi_filter_commands[] = { offsetof(ngx_http_ssi_loc_conf_t, types_keys), &ngx_http_html_default_types[0] }, + { ngx_string("ssi_last_modified"), + 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_ssi_loc_conf_t, last_modified), + NULL }, + ngx_null_command }; @@ -205,6 +213,7 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static u_char ngx_http_ssi_string[] = "<!--"; static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); +static ngx_str_t ngx_http_ssi_timefmt = ngx_string("%A, %d-%b-%Y %H:%M:%S %Z"); static ngx_str_t ngx_http_ssi_null_string = ngx_null_string; @@ -351,7 +360,7 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N; ctx->params.pool = r->pool; - ngx_str_set(&ctx->timefmt, "%A, %d-%b-%Y %H:%M:%S %Z"); + ctx->timefmt = ngx_http_ssi_timefmt; ngx_str_set(&ctx->errmsg, "[an error occurred while processing the directive]"); @@ -359,9 +368,12 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) if (r == r->main) { ngx_http_clear_content_length(r); - ngx_http_clear_last_modified(r); ngx_http_clear_accept_ranges(r); ngx_http_clear_etag(r); + + if (!slcf->last_modified) { + ngx_http_clear_last_modified(r); + } } return ngx_http_next_header_filter(r); @@ -1971,8 +1983,6 @@ static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - u_char *dst, *src; - size_t len; ngx_int_t rc, key; ngx_str_t *uri, *file, *wait, *set, *stub, args; ngx_buf_t *b; @@ -2043,18 +2053,6 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, return rc; } - dst = uri->data; - src = uri->data; - - ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI); - - len = (uri->data + uri->len) - src; - if (len) { - dst = ngx_movemem(dst, src, len); - } - - uri->len = dst - uri->data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ssi include: \"%V\"", uri); @@ -2723,6 +2721,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, { ngx_http_ssi_ctx_t *ctx; ngx_time_t *tp; + ngx_str_t *timefmt; struct tm tm; char buf[NGX_HTTP_SSI_DATE_LEN]; @@ -2734,9 +2733,10 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); - if (ctx == NULL - || (ctx->timefmt.len == sizeof("%s") - 1 - && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's')) + timefmt = ctx ? &ctx->timefmt : &ngx_http_ssi_timefmt; + + if (timefmt->len == sizeof("%s") - 1 + && timefmt->data[0] == '%' && timefmt->data[1] == 's') { v->data = ngx_pnalloc(r->pool, NGX_TIME_T_LEN); if (v->data == NULL) { @@ -2755,7 +2755,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, } v->len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, - (char *) ctx->timefmt.data, &tm); + (char *) timefmt->data, &tm); if (v->len == 0) { return NGX_ERROR; } @@ -2878,6 +2878,7 @@ ngx_http_ssi_create_loc_conf(ngx_conf_t *cf) slcf->enable = NGX_CONF_UNSET; slcf->silent_errors = NGX_CONF_UNSET; slcf->ignore_recycled_buffers = NGX_CONF_UNSET; + slcf->last_modified = NGX_CONF_UNSET; slcf->min_file_chunk = NGX_CONF_UNSET_SIZE; slcf->value_len = NGX_CONF_UNSET_SIZE; @@ -2896,6 +2897,7 @@ ngx_http_ssi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0); ngx_conf_merge_value(conf->ignore_recycled_buffers, prev->ignore_recycled_buffers, 0); + ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0); 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, 255); diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c index a6c803da0dc..206f58d2537 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c @@ -17,6 +17,14 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "prime256v1" +#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" + + +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); +#endif #ifdef TLSEXT_TYPE_next_proto_neg static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, @@ -111,6 +119,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, ciphers), NULL }, + { ngx_string("ssl_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, buffer_size), + NULL }, + { ngx_string("ssl_verify_client"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, @@ -119,7 +134,7 @@ static ngx_command_t ngx_http_ssl_commands[] = { &ngx_http_ssl_verify }, { ngx_string("ssl_verify_depth"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, verify_depth), @@ -153,6 +168,20 @@ static ngx_command_t ngx_http_ssl_commands[] = { 0, NULL }, + { ngx_string("ssl_session_tickets"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, session_tickets), + NULL }, + + { ngx_string("ssl_session_ticket_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_array_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, session_ticket_keys), + NULL }, + { ngx_string("ssl_session_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_sec_slot, @@ -241,6 +270,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { 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_session_reused"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_session_reused, 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 }, @@ -267,9 +299,65 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP"); -#ifdef TLSEXT_TYPE_next_proto_neg +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation -#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" +static int +ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, unsigned int inlen, + void *arg) +{ + unsigned int srvlen; + unsigned char *srv; +#if (NGX_DEBUG) + unsigned int i; +#endif +#if (NGX_HTTP_SPDY) + ngx_http_connection_t *hc; +#endif +#if (NGX_HTTP_SPDY || NGX_DEBUG) + ngx_connection_t *c; + + c = ngx_ssl_get_connection(ssl_conn); +#endif + +#if (NGX_DEBUG) + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "SSL ALPN supported by client: %*s", in[i], &in[i + 1]); + } +#endif + +#if (NGX_HTTP_SPDY) + hc = c->data; + + if (hc->addr_conf->spdy) { + srv = (unsigned char *) NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; + srvlen = sizeof(NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; + + } else +#endif + { + srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; + srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; + } + + if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, + in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_NOACK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "SSL ALPN selected: %*s", *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + +#ifdef TLSEXT_TYPE_next_proto_neg static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, @@ -417,10 +505,13 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; + sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; + sscf->session_tickets = NGX_CONF_UNSET; + sscf->session_ticket_keys = NGX_CONF_UNSET_PTR; sscf->stapling = NGX_CONF_UNSET; sscf->stapling_verify = NGX_CONF_UNSET; @@ -457,6 +548,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, + NGX_SSL_BUFSIZE); + ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); @@ -534,6 +628,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL); +#endif + #ifdef TLSEXT_TYPE_next_proto_neg SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx, ngx_http_ssl_npn_advertised, NULL); @@ -561,8 +659,11 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "SSL_CTX_set_cipher_list(\"%V\") failed", &conf->ciphers); + return NGX_CONF_ERROR; } + conf->ssl.buffer_size = conf->buffer_size; + if (conf->verify) { if (conf->client_certificate.len == 0 && conf->verify != 3) { @@ -622,6 +723,23 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + ngx_conf_merge_value(conf->session_tickets, prev->session_tickets, 1); + +#ifdef SSL_OP_NO_TICKET + if (!conf->session_tickets) { + SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET); + } +#endif + + ngx_conf_merge_ptr_value(conf->session_ticket_keys, + prev->session_ticket_keys, NULL); + + if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (conf->stapling) { if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file, diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h index c4c576ef63b..ec2c62f6fb5 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h +++ b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h @@ -26,6 +26,8 @@ typedef struct { ngx_uint_t verify; ngx_uint_t verify_depth; + size_t buffer_size; + ssize_t builtin_session_cache; time_t session_timeout; @@ -42,6 +44,9 @@ typedef struct { ngx_shm_zone_t *shm_zone; + ngx_flag_t session_tickets; + ngx_array_t *session_ticket_keys; + ngx_flag_t stapling; ngx_flag_t stapling_verify; ngx_str_t stapling_file; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c index 83a35cda814..b5ecd6d9e2f 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c @@ -98,7 +98,9 @@ static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) return rc; } + r->headers_out.content_type_len = sizeof("text/plain") - 1; ngx_str_set(&r->headers_out.content_type, "text/plain"); + r->headers_out.content_type_lowcase = NULL; if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; @@ -145,6 +147,7 @@ static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) r->headers_out.content_length_n = b->last - b->pos; b->last_buf = (r == r->main) ? 1 : 0; + b->last_in_chain = 1; rc = ngx_http_send_header(r); diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c index 6ba57dfffc0..a4d666bed2b 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c @@ -17,6 +17,7 @@ typedef struct { ngx_hash_t types; ngx_flag_t once; + ngx_flag_t last_modified; ngx_array_t *types_keys; } ngx_http_sub_loc_conf_t; @@ -89,6 +90,13 @@ static ngx_command_t ngx_http_sub_filter_commands[] = { offsetof(ngx_http_sub_loc_conf_t, once), NULL }, + { ngx_string("sub_filter_last_modified"), + 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_sub_loc_conf_t, last_modified), + NULL }, + ngx_null_command }; @@ -167,8 +175,11 @@ ngx_http_sub_header_filter(ngx_http_request_t *r) if (r == r->main) { ngx_http_clear_content_length(r); - ngx_http_clear_last_modified(r); ngx_http_clear_etag(r); + + if (!slcf->last_modified) { + ngx_http_clear_last_modified(r); + } } return ngx_http_next_header_filter(r); @@ -250,66 +261,43 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return rc; } - if (ctx->copy_start != ctx->copy_end) { + if (ctx->saved.len) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "saved: \"%V\"", &ctx->saved); - if (ctx->saved.len) { + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } - if (ctx->free) { - cl = ctx->free; - ctx->free = ctx->free->next; - b = cl->buf; - ngx_memzero(b, sizeof(ngx_buf_t)); + b = cl->buf; - } else { - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } + ngx_memzero(b, sizeof(ngx_buf_t)); - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } + b->pos = ngx_pnalloc(r->pool, ctx->saved.len); + if (b->pos == NULL) { + return NGX_ERROR; + } - cl->buf = b; - } + ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len); + b->last = b->pos + ctx->saved.len; + b->memory = 1; - b->pos = ngx_pnalloc(r->pool, ctx->saved.len); - if (b->pos == NULL) { - return NGX_ERROR; - } + *ctx->last_out = cl; + ctx->last_out = &cl->next; - ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len); - b->last = b->pos + ctx->saved.len; - b->memory = 1; + ctx->saved.len = 0; + } - *ctx->last_out = cl; - ctx->last_out = &cl->next; + if (ctx->copy_start != ctx->copy_end) { - ctx->saved.len = 0; + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; } - if (ctx->free) { - cl = ctx->free; - ctx->free = ctx->free->next; - b = cl->buf; - - } else { - b = ngx_alloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - } + b = cl->buf; ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); @@ -324,7 +312,6 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) b->file_pos += b->pos - ctx->buf->pos; } - cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } @@ -338,6 +325,11 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->copy_end = NULL; } + if (ctx->looked.len > (size_t) (ctx->pos - ctx->buf->pos)) { + ctx->saved.len = ctx->looked.len - (ctx->pos - ctx->buf->pos); + ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len); + } + if (rc == NGX_AGAIN) { continue; } @@ -345,16 +337,15 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) /* rc == NGX_OK */ - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - cl = ngx_alloc_chain_link(r->pool); + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; } + b = cl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); if (ctx->sub.data == NULL) { @@ -375,8 +366,6 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) b->sync = 1; } - cl->buf = b; - cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; @@ -385,36 +374,47 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) continue; } - if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) { + if (ctx->buf->last_buf && ctx->looked.len) { + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + b = cl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->pos = ctx->looked.data; + b->last = b->pos + ctx->looked.len; + b->memory = 1; + + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + ctx->looked.len = 0; + } + + if (ctx->buf->last_buf || ctx->buf->flush + || ngx_buf_in_memory(ctx->buf)) + { if (b == NULL) { - if (ctx->free) { - cl = ctx->free; - ctx->free = ctx->free->next; - b = cl->buf; - ngx_memzero(b, sizeof(ngx_buf_t)); - - } else { - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; } + b = cl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + b->sync = 1; - cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } b->last_buf = ctx->buf->last_buf; + b->flush = ctx->buf->flush; b->shadow = ctx->buf; b->recycled = ctx->buf->recycled; @@ -507,7 +507,7 @@ static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) { u_char *p, *last, *copy_end, ch, match; - size_t looked; + size_t looked, i; ngx_http_sub_state_e state; if (ctx->once) { @@ -578,13 +578,11 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) looked++; if (looked == ctx->match.len) { - if ((size_t) (p - ctx->pos) < looked) { - ctx->saved.len = 0; - } ctx->state = sub_start_state; ctx->pos = p + 1; ctx->looked.len = 0; + ctx->saved.len = 0; ctx->copy_end = copy_end; if (ctx->copy_start == NULL && copy_end) { @@ -594,18 +592,53 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) return NGX_OK; } - } else if (ch == ctx->match.data[0]) { - copy_end = p; - ctx->looked.data[0] = *p; - looked = 1; - } else { - copy_end = p; - looked = 0; - state = sub_start_state; + /* + * check if there is another partial match in previously + * matched substring to catch cases like "aab" in "aaab" + */ + + ctx->looked.data[looked] = *p; + looked++; + + for (i = 1; i < looked; i++) { + if (ngx_strncasecmp(ctx->looked.data + i, + ctx->match.data, looked - i) + == 0) + { + break; + } + } + + if (i < looked) { + if (ctx->saved.len > i) { + ctx->saved.len = i; + } + + if ((size_t) (p + 1 - ctx->buf->pos) >= looked - i) { + copy_end = p + 1 - (looked - i); + } + + ngx_memmove(ctx->looked.data, ctx->looked.data + i, looked - i); + looked = looked - i; + + } else { + copy_end = p; + looked = 0; + state = sub_start_state; + } + + if (ctx->saved.len) { + p++; + goto out; + } } } + ctx->saved.len = 0; + +out: + ctx->state = state; ctx->pos = p; ctx->looked.len = looked; @@ -666,14 +699,12 @@ ngx_http_sub_create_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * conf->match = { 0, NULL }; - * conf->sub = { 0, NULL }; - * conf->sub_lengths = NULL; - * conf->sub_values = NULL; * conf->types = { NULL }; * conf->types_keys = NULL; */ slcf->once = NGX_CONF_UNSET; + slcf->last_modified = NGX_CONF_UNSET; return slcf; } @@ -687,6 +718,7 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->once, prev->once, 1); ngx_conf_merge_str_value(conf->match, prev->match, ""); + ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0); if (conf->value.value.data == NULL) { conf->value = prev->value; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c index 29c74fd54d0..041883fec82 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -174,7 +174,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) for ( ;; ) { - for (i = 0; i < iphp->addrlen; i++) { + for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) { hash = (hash * 113 + iphp->addr[i]) % 6271; } @@ -197,33 +197,39 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) n = p / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); - if (!(iphp->rrp.tried[n] & m)) { + if (iphp->rrp.tried[n] & m) { + goto next; + } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "get ip hash peer, hash: %ui %04XA", p, m); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get ip hash peer, hash: %ui %04XA", p, m); - peer = &iphp->rrp.peers->peer[p]; + peer = &iphp->rrp.peers->peer[p]; - /* ngx_lock_mutex(iphp->rrp.peers->mutex); */ + /* ngx_lock_mutex(iphp->rrp.peers->mutex); */ - if (!peer->down) { + if (peer->down) { + goto next_try; + } - if (peer->max_fails == 0 || peer->fails < peer->max_fails) { - break; - } + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + goto next_try; + } - if (now - peer->checked > peer->fail_timeout) { - peer->checked = now; - break; - } - } + break; - iphp->rrp.tried[n] |= m; + next_try: - /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ + iphp->rrp.tried[n] |= m; - pc->tries--; - } + /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ + + pc->tries--; + + next: if (++iphp->tries >= 20) { return iphp->get_rr_peer(pc, &iphp->rrp); @@ -236,6 +242,10 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) pc->socklen = peer->socklen; pc->name = &peer->name; + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ iphp->rrp.tried[n] |= m; diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c index eed117404f4..d07ed9edaf2 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -81,7 +81,7 @@ static ngx_command_t ngx_http_upstream_keepalive_commands[] = { { ngx_string("keepalive"), NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, ngx_http_upstream_keepalive, - 0, + NGX_HTTP_SRV_CONF_OFFSET, 0, NULL }, @@ -481,7 +481,7 @@ static char * ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_upstream_srv_conf_t *uscf; - ngx_http_upstream_keepalive_srv_conf_t *kcf; + ngx_http_upstream_keepalive_srv_conf_t *kcf = conf; ngx_int_t n; ngx_str_t *value; @@ -489,9 +489,6 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); - kcf = ngx_http_conf_upstream_srv_conf(uscf, - ngx_http_upstream_keepalive_module); - if (kcf->original_init_upstream) { return "is duplicate"; } diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c index 623ee495771..17dfc3b3ac7 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c @@ -34,6 +34,12 @@ typedef struct { ngx_uint_t modifier1; ngx_uint_t modifier2; + +#if (NGX_HTTP_SSL) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +#endif } ngx_http_uwsgi_loc_conf_t; @@ -66,6 +72,11 @@ static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif +#if (NGX_HTTP_SSL) +static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, + ngx_http_uwsgi_loc_conf_t *uwcf); +#endif + static ngx_conf_num_bounds_t ngx_http_uwsgi_modifier_bounds = { ngx_conf_check_num_bounds, 0, 255 @@ -78,6 +89,7 @@ static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = { { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, + { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, @@ -85,6 +97,20 @@ static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = { }; +#if (NGX_HTTP_SSL) + +static ngx_conf_bitmask_t ngx_http_uwsgi_ssl_protocols[] = { + { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, + { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, + { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, + { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, + { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, + { ngx_null_string, 0 } +}; + +#endif + + ngx_module_t ngx_http_uwsgi_module; @@ -288,6 +314,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("uwsgi_cache_revalidate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_revalidate), + NULL }, + #endif { ngx_string("uwsgi_temp_path"), @@ -353,6 +386,31 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_headers), &ngx_http_upstream_ignore_headers_masks }, +#if (NGX_HTTP_SSL) + + { ngx_string("uwsgi_ssl_session_reuse"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_session_reuse), + NULL }, + + { ngx_string("uwsgi_ssl_protocols"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_protocols), + &ngx_http_uwsgi_ssl_protocols }, + + { ngx_string("uwsgi_ssl_ciphers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphers), + NULL }, + +#endif + ngx_null_command }; @@ -401,7 +459,8 @@ static ngx_str_t ngx_http_uwsgi_hide_headers[] = { #if (NGX_HTTP_CACHE) static ngx_keyval_t ngx_http_uwsgi_cache_headers[] = { - { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") }, + { ngx_string("HTTP_IF_MODIFIED_SINCE"), + ngx_string("$upstream_cache_last_modified") }, { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") }, { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, @@ -426,13 +485,6 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) ngx_http_upstream_t *u; ngx_http_uwsgi_loc_conf_t *uwcf; - if (r->subrequest_in_memory) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "ngx_http_uwsgi_module does not support " - "subrequests in memory"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -446,15 +498,29 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); - if (uwcf->uwsgi_lengths) { + u = r->upstream; + + if (uwcf->uwsgi_lengths == NULL) { + +#if (NGX_HTTP_SSL) + u->ssl = (uwcf->upstream.ssl != NULL); + + if (u->ssl) { + ngx_str_set(&u->schema, "suwsgi://"); + + } else { + ngx_str_set(&u->schema, "uwsgi://"); + } +#else + ngx_str_set(&u->schema, "uwsgi://"); +#endif + + } else { if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } - u = r->upstream; - - ngx_str_set(&u->schema, "uwsgi://"); u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module; u->conf = &uwcf->upstream; @@ -492,6 +558,7 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) static ngx_int_t ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) { + size_t add; ngx_url_t url; ngx_http_upstream_t *u; @@ -504,6 +571,41 @@ ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) return NGX_ERROR; } + if (url.url.len > 8 + && ngx_strncasecmp(url.url.data, (u_char *) "uwsgi://", 8) == 0) + { + add = 8; + + } else if (url.url.len > 9 + && ngx_strncasecmp(url.url.data, (u_char *) "suwsgi://", 9) == 0) + { + +#if (NGX_HTTP_SSL) + add = 9; + r->upstream->ssl = 1; +#else + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "suwsgi protocol requires SSL support"); + return NGX_ERROR; +#endif + + } else { + add = 0; + } + + u = r->upstream; + + if (add) { + u->schema.len = add; + u->schema.data = url.url.data; + + url.url.data += add; + url.url.len -= add; + + } else { + ngx_str_set(&u->schema, "uwsgi://"); + } + url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { @@ -515,8 +617,6 @@ ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) return NGX_ERROR; } - u = r->upstream; - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); if (u->resolved == NULL) { return NGX_ERROR; @@ -917,7 +1017,7 @@ ngx_http_uwsgi_process_status_line(ngx_http_request_t *r) return ngx_http_uwsgi_process_header(r); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = status->code; } @@ -1045,7 +1145,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) ngx_str_set(&u->headers_in.status_line, "200 OK"); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } @@ -1136,12 +1236,16 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; conf->upstream.cache_lock = NGX_CONF_UNSET; conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; conf->upstream.intercept_errors = NGX_CONF_UNSET; +#if (NGX_HTTP_SSL) + conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; +#endif /* "uwsgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; @@ -1376,6 +1480,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, prev->upstream.cache_lock_timeout, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, + prev->upstream.cache_revalidate, 0); + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, @@ -1386,6 +1493,27 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->upstream.intercept_errors, prev->upstream.intercept_errors, 0); +#if (NGX_HTTP_SSL) + ngx_conf_merge_value(conf->upstream.ssl_session_reuse, + prev->upstream.ssl_session_reuse, 1); + + ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, + (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2)); + + ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, + "DEFAULT"); + + if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (conf->upstream.ssl == NULL) { + conf->upstream.ssl = prev->upstream.ssl; + } +#endif + ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, ""); hash.max_size = 512; @@ -1542,7 +1670,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, s->key = h->key; s->value = h->value; - s->skip_empty = 0; + s->skip_empty = 1; next: @@ -1664,6 +1792,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_uwsgi_loc_conf_t *uwcf = conf; + size_t add; ngx_url_t u; ngx_str_t *value, *url; ngx_uint_t n; @@ -1699,12 +1828,35 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } +#if (NGX_HTTP_SSL) + uwcf->ssl = 1; +#endif + return NGX_CONF_OK; } + if (ngx_strncasecmp(url->data, (u_char *) "uwsgi://", 8) == 0) { + add = 8; + + } else if (ngx_strncasecmp(url->data, (u_char *) "suwsgi://", 9) == 0) { + +#if (NGX_HTTP_SSL) + add = 9; + uwcf->ssl = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "suwsgi protocol requires SSL support"); + return NGX_CONF_ERROR; +#endif + + } else { + add = 0; + } + ngx_memzero(&u, sizeof(ngx_url_t)); - u.url = value[1]; + u.url.len = url->len - add; + u.url.data = url->data + add; u.no_resolve = 1; uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); @@ -1764,7 +1916,7 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) sc.source = &value[1]; sc.lengths = &uwcf->upstream.store_lengths; sc.values = &uwcf->upstream.store_values; - sc.variables = ngx_http_script_variables_count(&value[1]);; + sc.variables = ngx_http_script_variables_count(&value[1]); sc.complete_lengths = 1; sc.complete_values = 1; @@ -1838,3 +1990,47 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #endif + + +#if (NGX_HTTP_SSL) + +static ngx_int_t +ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) +{ + ngx_pool_cleanup_t *cln; + + uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (uwcf->upstream.ssl == NULL) { + return NGX_ERROR; + } + + uwcf->upstream.ssl->log = cf->log; + + if (ngx_ssl_create(uwcf->upstream.ssl, uwcf->ssl_protocols, NULL) + != NGX_OK) + { + return NGX_ERROR; + } + + if (SSL_CTX_set_cipher_list(uwcf->upstream.ssl->ctx, + (const char *) uwcf->ssl_ciphers.data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &uwcf->ssl_ciphers); + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = uwcf->upstream.ssl; + + return NGX_OK; +} + +#endif diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c index a6ae1ce02b8..9e85693bcc4 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c @@ -58,6 +58,7 @@ typedef struct { ngx_hash_t types; ngx_array_t *types_keys; ngx_array_t *params; /* ngx_http_xslt_param_t */ + ngx_flag_t last_modified; } ngx_http_xslt_filter_loc_conf_t; @@ -103,6 +104,7 @@ static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf); static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf); static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_xslt_filter_preconfiguration(ngx_conf_t *cf); static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf); static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle); @@ -150,12 +152,19 @@ static ngx_command_t ngx_http_xslt_filter_commands[] = { offsetof(ngx_http_xslt_filter_loc_conf_t, types_keys), &ngx_http_xslt_default_types[0] }, + { ngx_string("xslt_last_modified"), + 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_xslt_filter_loc_conf_t, last_modified), + NULL }, + ngx_null_command }; static ngx_http_module_t ngx_http_xslt_filter_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_xslt_filter_preconfiguration, /* preconfiguration */ ngx_http_xslt_filter_init, /* postconfiguration */ ngx_http_xslt_filter_create_main_conf, /* create main configuration */ @@ -300,9 +309,10 @@ static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b) { - ngx_int_t rc; - ngx_chain_t out; - ngx_pool_cleanup_t *cln; + ngx_int_t rc; + ngx_chain_t out; + ngx_pool_cleanup_t *cln; + ngx_http_xslt_filter_loc_conf_t *conf; ctx->done = 1; @@ -327,8 +337,13 @@ ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, r->headers_out.content_length = NULL; } - ngx_http_clear_last_modified(r); ngx_http_clear_etag(r); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); + + if (!conf->last_modified) { + ngx_http_clear_last_modified(r); + } } rc = ngx_http_next_header_filter(r); @@ -1058,6 +1073,8 @@ ngx_http_xslt_filter_create_conf(ngx_conf_t *cf) * conf->params = NULL; */ + conf->last_modified = NGX_CONF_UNSET; + return conf; } @@ -1088,12 +1105,14 @@ ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0); + return NGX_CONF_OK; } static ngx_int_t -ngx_http_xslt_filter_init(ngx_conf_t *cf) +ngx_http_xslt_filter_preconfiguration(ngx_conf_t *cf) { xmlInitParser(); @@ -1101,6 +1120,13 @@ ngx_http_xslt_filter_init(ngx_conf_t *cf) exsltRegisterAll(); #endif + return NGX_OK; +} + + +static ngx_int_t +ngx_http_xslt_filter_init(ngx_conf_t *cf) +{ ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_xslt_header_filter; diff --git a/usr.sbin/nginx/src/http/modules/perl/nginx.xs b/usr.sbin/nginx/src/http/modules/perl/nginx.xs index 77fb653739a..71f17a8bb45 100644 --- a/usr.sbin/nginx/src/http/modules/perl/nginx.xs +++ b/usr.sbin/nginx/src/http/modules/perl/nginx.xs @@ -261,13 +261,12 @@ header_in(r, key) sep = ';'; goto multi; } - - #if (NGX_HTTP_X_FORWARDED_FOR) +#if (NGX_HTTP_X_FORWARDED_FOR) if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) { sep = ','; goto multi; } - #endif +#endif if (hh->offset) { @@ -898,8 +897,7 @@ variable(r, name, value = NULL) var.len = len; var.data = lowcase; - - #if (NGX_DEBUG) +#if (NGX_DEBUG) if (value) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -908,8 +906,7 @@ variable(r, name, value = NULL) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl variable: \"%V\"", &var); } - - #endif +#endif vv = ngx_http_get_variable(r, &var, hash); if (vv == NULL) { diff --git a/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c b/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c index 90e32e80efa..bf4d1fe9ad7 100644 --- a/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c +++ b/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c @@ -421,7 +421,7 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, return NGX_ERROR; } - asv[0] = (SV *) i; + asv[0] = (SV *) (uintptr_t) i; for (i = 0; args[i]; i++) { asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len); @@ -692,7 +692,7 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, if (args) { EXTEND(sp, (intptr_t) args[0]); - for (i = 1; i <= (ngx_uint_t) args[0]; i++) { + for (i = 1; i <= (uintptr_t) args[0]; i++) { PUSHs(sv_2mortal(args[i])); } } diff --git a/usr.sbin/nginx/src/http/ngx_http.c b/usr.sbin/nginx/src/http/ngx_http.c index 987ae54df66..ce5adb7374a 100644 --- a/usr.sbin/nginx/src/http/ngx_http.c +++ b/usr.sbin/nginx/src/http/ngx_http.c @@ -949,7 +949,8 @@ ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two) #endif - rc = ngx_strcmp(first->name.data, second->name.data); + rc = ngx_filename_cmp(first->name.data, second->name.data, + ngx_min(first->name.len, second->name.len) + 1); if (rc == 0 && !first->exact_match && second->exact_match) { /* an exact match must be before the same inclusive one */ @@ -975,8 +976,10 @@ ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations) lq = (ngx_http_location_queue_t *) q; lx = (ngx_http_location_queue_t *) x; - if (ngx_strcmp(lq->name->data, lx->name->data) == 0) { - + if (lq->name->len == lx->name->len + && ngx_filename_cmp(lq->name->data, lx->name->data, lx->name->len) + == 0) + { if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "duplicate location \"%V\" in %s:%ui", @@ -1028,7 +1031,7 @@ ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q) lx = (ngx_http_location_queue_t *) x; if (len > lx->name->len - || (ngx_strncmp(name, lx->name->data, len) != 0)) + || ngx_filename_cmp(name, lx->name->data, len) != 0) { break; } @@ -1346,11 +1349,13 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } } -#if (NGX_HTTP_SPDY && NGX_HTTP_SSL && !defined TLSEXT_TYPE_next_proto_neg) +#if (NGX_HTTP_SPDY && NGX_HTTP_SSL \ + && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \ + && !defined TLSEXT_TYPE_next_proto_neg) if (lsopt->spdy && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "nginx was built without OpenSSL NPN support, " - "SPDY is not enabled for %s", lsopt->addr); + "nginx was built without OpenSSL ALPN or NPN " + "support, SPDY is not enabled for %s", lsopt->addr); } #endif @@ -1808,6 +1813,10 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->setfib = addr->opt.setfib; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = addr->opt.fastopen; +#endif + return ls; } @@ -1840,6 +1849,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, #if (NGX_HTTP_SPDY) addrs[i].conf.spdy = addr[i].opt.spdy; #endif + addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; if (addr[i].hash.buckets == NULL && (addr[i].wc_head == NULL diff --git a/usr.sbin/nginx/src/http/ngx_http_cache.h b/usr.sbin/nginx/src/http/ngx_http_cache.h index 2a2d7229153..193a35322b5 100644 --- a/usr.sbin/nginx/src/http/ngx_http_cache.h +++ b/usr.sbin/nginx/src/http/ngx_http_cache.h @@ -19,8 +19,9 @@ #define NGX_HTTP_CACHE_EXPIRED 3 #define NGX_HTTP_CACHE_STALE 4 #define NGX_HTTP_CACHE_UPDATING 5 -#define NGX_HTTP_CACHE_HIT 6 -#define NGX_HTTP_CACHE_SCARCE 7 +#define NGX_HTTP_CACHE_REVALIDATED 6 +#define NGX_HTTP_CACHE_HIT 7 +#define NGX_HTTP_CACHE_SCARCE 8 #define NGX_HTTP_CACHE_KEY_LEN 16 @@ -143,6 +144,7 @@ void ngx_http_file_cache_create_key(ngx_http_request_t *r); ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r); void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf); void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf); +void ngx_http_file_cache_update_header(ngx_http_request_t *r); ngx_int_t ngx_http_cache_send(ngx_http_request_t *); void ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf); time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status); diff --git a/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c index 95bc0b83564..3ad27b0425b 100644 --- a/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c @@ -169,13 +169,15 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) offset = c->busy_sendfile->file_pos; if (file->aio) { - c->aio_sendfile = (offset != file->aio->last_offset); + c->busy_count = (offset == file->aio->last_offset) ? + c->busy_count + 1 : 0; file->aio->last_offset = offset; - if (c->aio_sendfile == 0) { + if (c->busy_count > 2) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "sendfile(%V) returned busy again", &file->name); + c->aio_sendfile = 0; } } diff --git a/usr.sbin/nginx/src/http/ngx_http_core_module.c b/usr.sbin/nginx/src/http/ngx_http_core_module.c index fbb1467ce16..a77ac3b20e1 100644 --- a/usr.sbin/nginx/src/http/ngx_http_core_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_core_module.c @@ -1144,7 +1144,9 @@ ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) } if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) { - r->access_code = rc; + if (r->access_code != NGX_HTTP_UNAUTHORIZED) { + r->access_code = rc; + } r->phase_handler++; return NGX_AGAIN; @@ -1462,9 +1464,6 @@ ngx_http_update_location_config(ngx_http_request_t *r) if (r == r->main) { ngx_http_set_connection_log(r->connection, clcf->error_log); -#if (NGX_ENABLE_SYSLOG) - r->connection->log->priority = clcf->error_log->priority; -#endif } if ((ngx_io.flags & NGX_IO_SENDFILE) && clcf->sendfile) { @@ -1936,6 +1935,12 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_int_t ngx_http_send_header(ngx_http_request_t *r) { + if (r->header_sent) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "header already sent"); + return NGX_ERROR; + } + if (r->err_status) { r->headers_out.status = r->err_status; r->headers_out.status_line.len = 0; @@ -2019,7 +2024,9 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path, return NULL; } - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, path, 0) != NGX_OK) { + if (ngx_get_full_name(r->pool, (ngx_str_t *) &ngx_cycle->prefix, path) + != NGX_OK) + { return NULL; } @@ -2361,7 +2368,7 @@ equal: } -ngx_uint_t +static ngx_uint_t ngx_http_gzip_quantity(u_char *p, u_char *last) { u_char c; @@ -2625,6 +2632,14 @@ ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name) return NGX_DONE; } + if (r->uri.len == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "empty URI in redirect to named location \"%V\"", name); + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; + } + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); if (cscf->named_locations) { @@ -3034,9 +3049,12 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) #if (NGX_HAVE_SETFIB) lsopt.setfib = -1; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + lsopt.fastopen = -1; +#endif lsopt.wildcard = 1; - (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr, + (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr, NGX_SOCKADDR_STRLEN, 1); if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) { @@ -3214,9 +3232,9 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) #if (NGX_PCRE) if (clcf->regex == NULL - && ngx_strncmp(clcf->name.data, pclcf->name.data, len) != 0) + && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0) #else - if (ngx_strncmp(clcf->name.data, pclcf->name.data, len) != 0) + if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0) #endif { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3414,25 +3432,16 @@ ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_core_main_conf_t *cmcf = conf; - if (cmcf->server_names_hash_max_size == NGX_CONF_UNSET_UINT) { - cmcf->server_names_hash_max_size = 512; - } - - if (cmcf->server_names_hash_bucket_size == NGX_CONF_UNSET_UINT) { - cmcf->server_names_hash_bucket_size = ngx_cacheline_size; - } + ngx_conf_init_uint_value(cmcf->server_names_hash_max_size, 512); + ngx_conf_init_uint_value(cmcf->server_names_hash_bucket_size, + ngx_cacheline_size); cmcf->server_names_hash_bucket_size = ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size); - if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) { - cmcf->variables_hash_max_size = 512; - } - - if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) { - cmcf->variables_hash_bucket_size = 64; - } + ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024); + ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64); cmcf->variables_hash_bucket_size = ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size); @@ -3701,8 +3710,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->types_hash_max_size, 1024); ngx_conf_merge_uint_value(conf->types_hash_bucket_size, - prev->types_hash_bucket_size, - ngx_cacheline_size); + prev->types_hash_bucket_size, 64); conf->types_hash_bucket_size = ngx_align(conf->types_hash_bucket_size, ngx_cacheline_size); @@ -3982,12 +3990,15 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HAVE_SETFIB) lsopt.setfib = -1; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + lsopt.fastopen = -1; +#endif lsopt.wildcard = u.wildcard; #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) lsopt.ipv6only = 1; #endif - (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr, + (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr, NGX_SOCKADDR_STRLEN, 1); for (n = 2; n < cf->args->nelts; n++) { @@ -4008,6 +4019,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HAVE_SETFIB) if (ngx_strncmp(value[n].data, "setfib=", 7) == 0) { lsopt.setfib = ngx_atoi(value[n].data + 7, value[n].len - 7); + lsopt.set = 1; + lsopt.bind = 1; if (lsopt.setfib == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -4018,6 +4031,23 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } #endif + +#if (NGX_HAVE_TCP_FASTOPEN) + if (ngx_strncmp(value[n].data, "fastopen=", 9) == 0) { + lsopt.fastopen = ngx_atoi(value[n].data + 9, value[n].len - 9); + lsopt.set = 1; + lsopt.bind = 1; + + if (lsopt.fastopen == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid fastopen \"%V\"", &value[n]); + return NGX_CONF_ERROR; + } + + continue; + } +#endif + if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) { lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8); lsopt.set = 1; @@ -4247,6 +4277,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[n].data, "proxy_protocol") == 0) { + lsopt.proxy_protocol = 1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[n]); return NGX_CONF_ERROR; @@ -4476,7 +4511,7 @@ static ngx_http_method_name_t ngx_methods_names[] = { { (u_char *) "COPY", (uint32_t) ~NGX_HTTP_COPY }, { (u_char *) "MOVE", (uint32_t) ~NGX_HTTP_MOVE }, { (u_char *) "OPTIONS", (uint32_t) ~NGX_HTTP_OPTIONS }, - { (u_char *) "PROPFIND" , (uint32_t) ~NGX_HTTP_PROPFIND }, + { (u_char *) "PROPFIND", (uint32_t) ~NGX_HTTP_PROPFIND }, { (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH }, { (u_char *) "LOCK", (uint32_t) ~NGX_HTTP_LOCK }, { (u_char *) "UNLOCK", (uint32_t) ~NGX_HTTP_UNLOCK }, @@ -4897,82 +4932,7 @@ ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf = conf; - ngx_str_t *value, name; - -#if (NGX_ENABLE_SYSLOG) - u_char *off = NULL; - ngx_int_t syslog_on = 0; - ngx_str_t priority; - - name = priority = (ngx_str_t) ngx_null_string; -#endif - - - if (clcf->error_log) { - return "is duplicate"; - } - - value = cf->args->elts; - - if (ngx_strcmp(value[1].data, "stderr") == 0) { - ngx_str_null(&name); - -#if (NGX_ENABLE_SYSLOG) - } else if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) { - if (!cf->cycle->new_log.syslog_set) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "You must set the syslog directive and enable it first."); - return NGX_CONF_ERROR; - } - - syslog_on = 1; - - if (value[1].data[sizeof("syslog") - 1] == ':') { - priority.len = value[1].len - sizeof("syslog"); - priority.data = value[1].data + sizeof("syslog"); - - off = (u_char*) ngx_strchr(priority.data, '|'); - if (off != NULL) { - priority.len = off - priority.data; - - off++; - name.len = value[1].data + value[1].len - off; - name.data = off; - } - } - else { - if (value[1].len > sizeof("syslog")) { - name.len = value[1].len - sizeof("syslog"); - name.data = value[1].data + sizeof("syslog"); - } - } -#endif - } else { - name = value[1]; - } - - clcf->error_log = ngx_log_create(cf->cycle, &name); - if (clcf->error_log == NULL) { - return NGX_CONF_ERROR; - } - -#if (NGX_ENABLE_SYSLOG) - if (syslog_on) { - clcf->error_log->syslog_on = 1; - if (ngx_log_set_priority(cf, &priority, clcf->error_log) == NGX_CONF_ERROR) { - return NGX_CONF_ERROR; - } - } - - clcf->error_log->log_level = 0; -#endif - - if (cf->args->nelts == 2) { - clcf->error_log->log_level = NGX_LOG_ERR; - return NGX_CONF_OK; - } - - return ngx_log_set_levels(cf, clcf->error_log); + return ngx_log_set_log(cf, &clcf->error_log); } diff --git a/usr.sbin/nginx/src/http/ngx_http_core_module.h b/usr.sbin/nginx/src/http/ngx_http_core_module.h index 5b38000d8db..799d2fe0dd5 100644 --- a/usr.sbin/nginx/src/http/ngx_http_core_module.h +++ b/usr.sbin/nginx/src/http/ngx_http_core_module.h @@ -82,6 +82,7 @@ typedef struct { unsigned ipv6only:1; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; int backlog; int rcvbuf; @@ -89,6 +90,9 @@ typedef struct { #if (NGX_HAVE_SETFIB) int setfib; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + int fastopen; +#endif #if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; @@ -240,6 +244,7 @@ struct ngx_http_addr_conf_s { #if (NGX_HTTP_SPDY) unsigned spdy:1; #endif + unsigned proxy_protocol:1; }; diff --git a/usr.sbin/nginx/src/http/ngx_http_file_cache.c b/usr.sbin/nginx/src/http/ngx_http_file_cache.c index 6d94c503425..9e6be15844a 100644 --- a/usr.sbin/nginx/src/http/ngx_http_file_cache.c +++ b/usr.sbin/nginx/src/http/ngx_http_file_cache.c @@ -53,6 +53,7 @@ ngx_str_t ngx_http_cache_status[] = { ngx_string("EXPIRED"), ngx_string("STALE"), ngx_string("UPDATING"), + ngx_string("REVALIDATED"), ngx_string("HIT") }; @@ -445,8 +446,7 @@ ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev) timer = c->wait_time - ngx_current_msec; if ((ngx_msec_int_t) timer <= 0) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "http file cache lock timeout"); + ngx_log_error(NGX_LOG_INFO, ev->log, 0, "cache lock timeout"); c->lock = 0; goto wakeup; } @@ -504,7 +504,7 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) return NGX_DECLINED; } - if (h->body_start > c->body_start) { + if ((size_t) h->body_start > c->body_start) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has too long header", c->file.name.data); @@ -875,6 +875,8 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) c = r->cache; + ngx_memzero(h, sizeof(ngx_http_file_cache_header_t)); + h->valid_sec = c->valid_sec; h->last_modified = c->last_modified; h->date = c->date; @@ -970,6 +972,116 @@ ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) } +void +ngx_http_file_cache_update_header(ngx_http_request_t *r) +{ + ssize_t n; + ngx_err_t err; + ngx_file_t file; + ngx_file_info_t fi; + ngx_http_cache_t *c; + ngx_http_file_cache_header_t h; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache update header"); + + c = r->cache; + + ngx_memzero(&file, sizeof(ngx_file_t)); + + file.name = c->file.name; + file.log = r->connection->log; + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR, NGX_FILE_OPEN, 0); + + if (file.fd == NGX_INVALID_FILE) { + err = ngx_errno; + + /* cache file may have been deleted */ + + if (err == NGX_ENOENT) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache \"%s\" not found", + file.name.data); + return; + } + + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_open_file_n " \"%s\" failed", file.name.data); + return; + } + + /* + * make sure cache file wasn't replaced; + * if it was, do nothing + */ + + if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", file.name.data); + goto done; + } + + if (c->uniq != ngx_file_uniq(&fi) + || c->length != ngx_file_size(&fi)) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache \"%s\" changed", + file.name.data); + goto done; + } + + n = ngx_read_file(&file, (u_char *) &h, + sizeof(ngx_http_file_cache_header_t), 0); + + if (n == NGX_ERROR) { + goto done; + } + + if ((size_t) n != sizeof(ngx_http_file_cache_header_t)) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + ngx_read_file_n " read only %z of %z from \"%s\"", + n, sizeof(ngx_http_file_cache_header_t), file.name.data); + goto done; + } + + if (h.last_modified != c->last_modified + || h.crc32 != c->crc32 + || h.header_start != c->header_start + || h.body_start != c->body_start) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache \"%s\" content changed", + file.name.data); + goto done; + } + + /* + * update cache file header with new data, + * notably h.valid_sec and h.date + */ + + ngx_memzero(&h, sizeof(ngx_http_file_cache_header_t)); + + h.valid_sec = c->valid_sec; + h.last_modified = c->last_modified; + h.date = c->date; + h.crc32 = c->crc32; + h.valid_msec = (u_short) c->valid_msec; + h.header_start = (u_short) c->header_start; + h.body_start = (u_short) c->body_start; + + (void) ngx_write_file(&file, (u_char *) &h, + sizeof(ngx_http_file_cache_header_t), 0); + +done: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file.name.data); + } +} + + ngx_int_t ngx_http_cache_send(ngx_http_request_t *r) { diff --git a/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c index 707a8131353..507dc939c78 100644 --- a/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c @@ -92,10 +92,7 @@ static ngx_str_t ngx_http_status_lines[] = { ngx_string("411 Length Required"), ngx_string("412 Precondition Failed"), ngx_string("413 Request Entity Too Large"), - ngx_null_string, /* "414 Request-URI Too Large", but we never send it - * because we treat such requests as the HTTP/0.9 - * requests and send only a body without a header - */ + ngx_string("414 Request-URI Too Large"), ngx_string("415 Unsupported Media Type"), ngx_string("416 Requested Range Not Satisfiable"), @@ -267,7 +264,13 @@ ngx_http_header_filter(ngx_http_request_t *r) len += ngx_http_status_lines[status].len; } else { - len += NGX_INT_T_LEN; + len += NGX_INT_T_LEN + 1 /* SP */; + status_line = NULL; + } + + if (status_line && status_line->len == 0) { + status = r->headers_out.status; + len += NGX_INT_T_LEN + 1 /* SP */; status_line = NULL; } } @@ -448,7 +451,7 @@ ngx_http_header_filter(ngx_http_request_t *r) b->last = ngx_copy(b->last, status_line->data, status_line->len); } else { - b->last = ngx_sprintf(b->last, "%03ui", status); + b->last = ngx_sprintf(b->last, "%03ui ", status); } *b->last++ = CR; *b->last++ = LF; diff --git a/usr.sbin/nginx/src/http/ngx_http_parse.c b/usr.sbin/nginx/src/http/ngx_http_parse.c index f8d5910ddef..02b4a0fd109 100644 --- a/usr.sbin/nginx/src/http/ngx_http_parse.c +++ b/usr.sbin/nginx/src/http/ngx_http_parse.c @@ -212,14 +212,17 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case 5: if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) { r->method = NGX_HTTP_MKCOL; + break; } if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) { r->method = NGX_HTTP_PATCH; + break; } if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) { r->method = NGX_HTTP_TRACE; + break; } break; @@ -883,6 +886,19 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } + if (ch == '_') { + if (allow_underscores) { + hash = ngx_hash(0, ch); + r->lowcase_header[0] = ch; + i = 1; + + } else { + r->invalid_header = 1; + } + + break; + } + if (ch == '\0') { return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1258,8 +1274,8 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) * the line feed */ - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "s:%d in:'%Xd:%c'", state, ch, ch); switch (state) { @@ -1777,17 +1793,21 @@ ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_uint_t *flags) { - u_char ch, *p; - size_t len; + u_char ch, *p, *src, *dst; + size_t len; + ngx_uint_t quoted; len = uri->len; p = uri->data; + quoted = 0; if (len == 0 || p[0] == '?') { goto unsafe; } - if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) { + if (p[0] == '.' && len > 1 && p[1] == '.' + && (len == 2 || ngx_path_separator(p[2]))) + { goto unsafe; } @@ -1795,6 +1815,11 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, ch = *p++; + if (ch == '%') { + quoted = 1; + continue; + } + if (usual[ch >> 5] & (1 << (ch & 0x1f))) { continue; } @@ -1804,7 +1829,7 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, args->data = p; uri->len -= len; - return NGX_OK; + break; } if (ch == '\0') { @@ -1813,14 +1838,66 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, if (ngx_path_separator(ch) && len > 2) { - /* detect "/../" */ + /* detect "/../" and "/.." */ - if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) { + if (p[0] == '.' && p[1] == '.' + && (len == 3 || ngx_path_separator(p[2]))) + { goto unsafe; } } } + if (quoted) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "escaped URI: \"%V\"", uri); + + src = uri->data; + + dst = ngx_pnalloc(r->pool, uri->len); + if (dst == NULL) { + return NGX_ERROR; + } + + uri->data = dst; + + ngx_unescape_uri(&dst, &src, uri->len, 0); + + uri->len = dst - uri->data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "unescaped URI: \"%V\"", uri); + + len = uri->len; + p = uri->data; + + if (p[0] == '.' && len > 1 && p[1] == '.' + && (len == 2 || ngx_path_separator(p[2]))) + { + goto unsafe; + } + + for ( /* void */ ; len; len--) { + + ch = *p++; + + if (ch == '\0') { + goto unsafe; + } + + if (ngx_path_separator(ch) && len > 2) { + + /* detect "/../" and "/.." */ + + if (p[0] == '.' && p[1] == '.' + && (len == 3 || ngx_path_separator(p[2]))) + { + goto unsafe; + } + } + } + } + return NGX_OK; unsafe: @@ -2182,8 +2259,9 @@ data: ctx->length = 3 /* "0" LF LF */; break; case sw_chunk_size: - ctx->length = 2 /* LF LF */ - + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0); + ctx->length = 1 /* LF */ + + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ + : 1 /* LF */); break; case sw_chunk_extension: case sw_chunk_extension_almost_done: diff --git a/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c index 85c4b84d027..e893b836488 100644 --- a/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c @@ -70,8 +70,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) #if 0 /* TODO: SSI may pass NULL */ ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "http postpone filter NULL inactive request", - &r->uri, &r->args); + "http postpone filter NULL inactive request"); #endif return NGX_OK; @@ -108,8 +107,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) if (pr->out == NULL) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "http postpone filter NULL output", - &r->uri, &r->args); + "http postpone filter NULL output"); } else { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, diff --git a/usr.sbin/nginx/src/http/ngx_http_request.c b/usr.sbin/nginx/src/http/ngx_http_request.c index dcebc370862..4bf9d1fcf1c 100644 --- a/usr.sbin/nginx/src/http/ngx_http_request.c +++ b/usr.sbin/nginx/src/http/ngx_http_request.c @@ -343,6 +343,11 @@ ngx_http_init_connection(ngx_connection_t *c) } #endif + if (hc->addr_conf->proxy_protocol) { + hc->proxy_protocol = 1; + c->log->action = "reading PROXY protocol"; + } + if (rev->ready) { /* the deferred accept(), rtsig, aio, iocp */ @@ -368,6 +373,7 @@ ngx_http_init_connection(ngx_connection_t *c) static void ngx_http_wait_request_handler(ngx_event_t *rev) { + u_char *p; size_t size; ssize_t n; ngx_buf_t *b; @@ -458,6 +464,27 @@ ngx_http_wait_request_handler(ngx_event_t *rev) b->last += n; + if (hc->proxy_protocol) { + hc->proxy_protocol = 0; + + p = ngx_proxy_protocol_parse(c, b->pos, b->last); + + if (p == NULL) { + ngx_http_close_connection(c); + return; + } + + b->pos = p; + + if (b->pos == b->last) { + c->log->action = "waiting for request"; + b->pos = b->start; + b->last = b->start; + ngx_post_event(rev, &ngx_posted_events); + return; + } + } + c->log->action = "reading client request line"; ngx_reusable_connection(c, 0); @@ -517,9 +544,6 @@ ngx_http_create_request(ngx_connection_t *c) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_http_set_connection_log(r->connection, clcf->error_log); -#if (NGX_ENABLE_SYSLOG) - c->log->priority = clcf->error_log->priority; -#endif r->header_in = hc->nbusy ? hc->busy[0] : c->buffer; @@ -560,6 +584,7 @@ ngx_http_create_request(ngx_connection_t *c) r->start_msec = tp->msec; r->method = NGX_HTTP_UNKNOWN; + r->http_version = NGX_HTTP_VERSION_10; r->headers_in.content_length_n = -1; r->headers_in.keep_alive_n = -1; @@ -591,7 +616,8 @@ ngx_http_create_request(ngx_connection_t *c) static void ngx_http_ssl_handshake(ngx_event_t *rev) { - u_char buf[1]; + u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1]; + size_t size; ssize_t n; ngx_err_t err; ngx_int_t rc; @@ -600,6 +626,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_http_ssl_srv_conf_t *sscf; c = rev->data; + hc = c->data; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http check ssl handshake"); @@ -615,7 +642,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev) return; } - n = recv(c->fd, (char *) buf, 1, MSG_PEEK); + size = hc->proxy_protocol ? sizeof(buf) : 1; + + n = recv(c->fd, (char *) buf, size, MSG_PEEK); err = ngx_socket_errno; @@ -642,12 +671,39 @@ ngx_http_ssl_handshake(ngx_event_t *rev) return; } + if (hc->proxy_protocol) { + hc->proxy_protocol = 0; + + p = ngx_proxy_protocol_parse(c, buf, buf + n); + + if (p == NULL) { + ngx_http_close_connection(c); + return; + } + + size = p - buf; + + if (c->recv(c, buf, size) != (ssize_t) size) { + ngx_http_close_connection(c); + return; + } + + c->log->action = "SSL handshaking"; + + if (n == (ssize_t) size) { + ngx_post_event(rev, &ngx_posted_events); + return; + } + + n = 1; + buf[0] = *p; + } + if (n == 1) { if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "https ssl handshake: 0x%02Xd", buf[0]); - hc = c->data; sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -707,13 +763,26 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; -#if (NGX_HTTP_SPDY && defined TLSEXT_TYPE_next_proto_neg) +#if (NGX_HTTP_SPDY \ + && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ + || defined TLSEXT_TYPE_next_proto_neg)) { unsigned int len; const unsigned char *data; static const ngx_str_t spdy = ngx_string(NGX_SPDY_NPN_NEGOTIATED); +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + +#ifdef TLSEXT_TYPE_next_proto_neg + if (len == 0) { + SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); + } +#endif + +#else /* TLSEXT_TYPE_next_proto_neg */ SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); +#endif if (len == spdy.len && ngx_strncmp(data, spdy.data, spdy.len) == 0) { ngx_http_spdy_init(c->read); @@ -798,9 +867,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); ngx_http_set_connection_log(c, clcf->error_log); -#if (NGX_ENABLE_SYSLOG) - c->log->priority = clcf->error_log->priority; -#endif sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -1936,6 +2002,10 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; +#if (NGX_SUPPRESS_WARN) + cscf = NULL; +#endif + hc = r->http_connection; #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) @@ -2002,9 +2072,6 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_http_set_connection_log(r->connection, clcf->error_log); -#if (NGX_ENABLE_SYSLOG) - r->connection->log->priority = clcf->error_log->priority; -#endif return NGX_OK; } @@ -2679,6 +2746,33 @@ ngx_http_test_reading(ngx_http_request_t *r) #endif +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && rev->pending_eof) { + socklen_t len; + + rev->eof = 1; + c->error = 1; + + err = 0; + len = sizeof(ngx_err_t); + + /* + * BSDs and Linux return 0 and set a pending error in err + * Solaris returns -1 and sets errno + */ + + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) + == -1) + { + err = ngx_socket_errno; + } + + goto closed; + } + +#endif + n = recv(c->fd, buf, 1, MSG_PEEK); if (n == 0) { @@ -2719,7 +2813,7 @@ closed: ngx_log_error(NGX_LOG_INFO, c->log, err, "client prematurely closed connection"); - ngx_http_finalize_request(r, 0); + ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); } @@ -3152,8 +3246,8 @@ ngx_http_lingering_close_handler(ngx_event_t *rev) return; } - timer = (ngx_msec_t) (r->lingering_time - ngx_time()); - if (timer <= 0) { + timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); + if ((ngx_msec_int_t) timer <= 0) { ngx_http_close_request(r, 0); return; } @@ -3328,10 +3422,15 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) return; } - for (cln = r->cleanup; cln; cln = cln->next) { + cln = r->cleanup; + r->cleanup = NULL; + + while (cln) { if (cln->handler) { cln->handler(cln->data); } + + cln = cln->next; } #if (NGX_STAT_STUB) diff --git a/usr.sbin/nginx/src/http/ngx_http_request.h b/usr.sbin/nginx/src/http/ngx_http_request.h index bd842df7e3f..e4a4944fe44 100644 --- a/usr.sbin/nginx/src/http/ngx_http_request.h +++ b/usr.sbin/nginx/src/http/ngx_http_request.h @@ -309,8 +309,9 @@ typedef struct { ngx_int_t nfree; #if (NGX_HTTP_SSL) - ngx_uint_t ssl; /* unsigned ssl:1; */ + unsigned ssl:1; #endif + unsigned proxy_protocol:1; } ngx_http_connection_t; @@ -420,6 +421,7 @@ struct ngx_http_request_s { #endif size_t limit_rate; + size_t limit_rate_after; /* used to learn the Apache compatible response length without a header */ size_t header_size; @@ -526,6 +528,7 @@ struct ngx_http_request_s { unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; unsigned allow_ranges:1; + unsigned single_range:1; #if (NGX_STAT_STUB) unsigned stat_reading:1; @@ -584,6 +587,9 @@ extern ngx_http_header_out_t ngx_http_headers_out[]; #define ngx_http_set_connection_log(c, l) \ \ c->log->file = l->file; \ + c->log->next = l->next; \ + c->log->writer = l->writer; \ + c->log->wdata = l->wdata; \ if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \ c->log->log_level = l->log_level; \ } diff --git a/usr.sbin/nginx/src/http/ngx_http_request_body.c b/usr.sbin/nginx/src/http/ngx_http_request_body.c index e9cf3e93007..bbf16fd2576 100644 --- a/usr.sbin/nginx/src/http/ngx_http_request_body.c +++ b/usr.sbin/nginx/src/http/ngx_http_request_body.c @@ -43,7 +43,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, r->main->count++; #if (NGX_HTTP_SPDY) - if (r->spdy_stream) { + if (r->spdy_stream && r == r->main) { rc = ngx_http_spdy_read_request_body(r, post_handler); goto done; } @@ -582,9 +582,9 @@ ngx_http_discarded_request_body_handler(ngx_http_request_t *r) } if (r->lingering_time) { - timer = (ngx_msec_t) (r->lingering_time - ngx_time()); + timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); - if (timer <= 0) { + if ((ngx_msec_int_t) timer <= 0) { r->discard_body = 0; r->lingering_close = 0; ngx_http_finalize_request(r, NGX_ERROR); @@ -726,7 +726,7 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) size = b->last - b->pos; if ((off_t) size > rb->chunked->size) { - b->pos += rb->chunked->size; + b->pos += (size_t) rb->chunked->size; rb->chunked->size = 0; } else { @@ -765,7 +765,7 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) size = b->last - b->pos; if ((off_t) size > r->headers_in.content_length_n) { - b->pos += r->headers_in.content_length_n; + b->pos += (size_t) r->headers_in.content_length_n; r->headers_in.content_length_n = 0; } else { @@ -882,7 +882,7 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) rb->rest -= size; } else { - cl->buf->pos += rb->rest; + cl->buf->pos += (size_t) rb->rest; rb->rest = 0; b->last = cl->buf->pos; b->last_buf = 1; @@ -988,7 +988,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) size = cl->buf->last - cl->buf->pos; if ((off_t) size > rb->chunked->size) { - cl->buf->pos += rb->chunked->size; + cl->buf->pos += (size_t) rb->chunked->size; r->headers_in.content_length_n += rb->chunked->size; rb->chunked->size = 0; diff --git a/usr.sbin/nginx/src/http/ngx_http_script.c b/usr.sbin/nginx/src/http/ngx_http_script.c index 54d019589a9..02e2be3bb80 100644 --- a/usr.sbin/nginx/src/http/ngx_http_script.c +++ b/usr.sbin/nginx/src/http/ngx_http_script.c @@ -1327,16 +1327,17 @@ ngx_http_script_full_name_code(ngx_http_script_engine_t *e) { ngx_http_script_full_name_code_t *code; - ngx_str_t value; + ngx_str_t value, *prefix; code = (ngx_http_script_full_name_code_t *) e->ip; value.data = e->buf.data; value.len = e->pos - e->buf.data; - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix) - != NGX_OK) - { + prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix: + (ngx_str_t *) &ngx_cycle->prefix; + + if (ngx_get_full_name(e->request->pool, prefix, &value) != NGX_OK) { e->ip = ngx_http_script_exit; e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; return; @@ -1393,7 +1394,7 @@ ngx_http_script_if_code(ngx_http_script_engine_t *e) e->sp--; - if (e->sp->len && (e->sp->len !=1 || e->sp->data[0] != '0')) { + if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) { if (code->loc_conf) { e->request->loc_conf = code->loc_conf; ngx_http_update_location_config(e->request); diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy.c b/usr.sbin/nginx/src/http/ngx_http_spdy.c index 99afbfca180..9bd624c82bc 100644 --- a/usr.sbin/nginx/src/http/ngx_http_spdy.c +++ b/usr.sbin/nginx/src/http/ngx_http_spdy.c @@ -42,16 +42,19 @@ #define ngx_spdy_frame_parse_sid(p) \ (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff) +#define ngx_spdy_frame_parse_delta(p) \ + (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff) #define ngx_spdy_ctl_frame_check(h) \ - (((h) & 0xffffff00) == ngx_spdy_ctl_frame_head(0)) + (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0)) #define ngx_spdy_data_frame_check(h) \ (!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31)) -#define ngx_spdy_ctl_frame_type(h) ((h) & 0x000000ff) +#define ngx_spdy_ctl_frame_type(h) ((h) & 0x0000ffff) #define ngx_spdy_frame_flags(p) ((p) >> 24) #define ngx_spdy_frame_length(p) ((p) & 0x00ffffff) +#define ngx_spdy_frame_id(p) ((p) & 0x00ffffff) #define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE 4096 @@ -64,10 +67,21 @@ #define NGX_SPDY_CANCEL 5 #define NGX_SPDY_INTERNAL_ERROR 6 #define NGX_SPDY_FLOW_CONTROL_ERROR 7 +#define NGX_SPDY_STREAM_IN_USE 8 +#define NGX_SPDY_STREAM_ALREADY_CLOSED 9 +/* deprecated 10 */ +#define NGX_SPDY_FRAME_TOO_LARGE 11 #define NGX_SPDY_SETTINGS_MAX_STREAMS 4 +#define NGX_SPDY_SETTINGS_INIT_WINDOW 7 #define NGX_SPDY_SETTINGS_FLAG_PERSIST 0x01 +#define NGX_SPDY_SETTINGS_FLAG_PERSISTED 0x02 + +#define NGX_SPDY_MAX_WINDOW NGX_MAX_INT32_VALUE +#define NGX_SPDY_CONNECTION_WINDOW 65536 +#define NGX_SPDY_INIT_STREAM_WINDOW 65536 +#define NGX_SPDY_STREAM_WINDOW NGX_SPDY_MAX_WINDOW typedef struct { ngx_uint_t hash; @@ -81,8 +95,8 @@ static void ngx_http_spdy_read_handler(ngx_event_t *rev); static void ngx_http_spdy_write_handler(ngx_event_t *wev); static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc); -static u_char *ngx_http_spdy_state_detect_settings( - ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); +static u_char *ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, + u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, @@ -93,8 +107,12 @@ static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); +static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, + u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); +static u_char *ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, + u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, @@ -103,8 +121,6 @@ static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, @@ -114,6 +130,8 @@ static u_char *ngx_http_spdy_state_protocol_error( static u_char *ngx_http_spdy_state_internal_error( ngx_http_spdy_connection_t *sc); +static ngx_int_t ngx_http_spdy_send_window_update( + ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t delta); static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority); static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc); @@ -138,55 +156,220 @@ static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r); static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r); static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r); static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_parse_url(ngx_http_request_t *r); +static ngx_int_t ngx_http_spdy_parse_host(ngx_http_request_t *r); +static ngx_int_t ngx_http_spdy_parse_path(ngx_http_request_t *r); static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r); static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r); static void ngx_http_spdy_run_request(ngx_http_request_t *r); static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r); +static ngx_int_t ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc, + ngx_http_spdy_stream_t *stream, ngx_uint_t status); + +static void ngx_http_spdy_close_stream_handler(ngx_event_t *ev); + static void ngx_http_spdy_handle_connection_handler(ngx_event_t *rev); static void ngx_http_spdy_keepalive_handler(ngx_event_t *rev); static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc, ngx_int_t rc); +static ngx_int_t ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, + ssize_t delta); + static void ngx_http_spdy_pool_cleanup(void *data); static void *ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size); static void ngx_http_spdy_zfree(void *opaque, void *address); -static const u_char ngx_http_spdy_dict[] = - "options" "get" "head" "post" "put" "delete" "trace" - "accept" "accept-charset" "accept-encoding" "accept-language" - "authorization" "expect" "from" "host" - "if-modified-since" "if-match" "if-none-match" "if-range" - "if-unmodifiedsince" "max-forwards" "proxy-authorization" - "range" "referer" "te" "user-agent" - "100" "101" "200" "201" "202" "203" "204" "205" "206" - "300" "301" "302" "303" "304" "305" "306" "307" - "400" "401" "402" "403" "404" "405" "406" "407" "408" "409" "410" - "411" "412" "413" "414" "415" "416" "417" - "500" "501" "502" "503" "504" "505" - "accept-ranges" "age" "etag" "location" "proxy-authenticate" "public" - "retry-after" "server" "vary" "warning" "www-authenticate" "allow" - "content-base" "content-encoding" "cache-control" "connection" "date" - "trailer" "transfer-encoding" "upgrade" "via" "warning" - "content-language" "content-length" "content-location" - "content-md5" "content-range" "content-type" "etag" "expires" - "last-modified" "set-cookie" - "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday" - "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec" - "chunked" "text/html" "image/png" "image/jpg" "image/gif" - "application/xml" "application/xhtml" "text/plain" "public" "max-age" - "charset=iso-8859-1" "utf-8" "gzip" "deflate" "HTTP/1.1" "status" - "version" "url"; +static const u_char ngx_http_spdy_dict[] = { + 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, /* - - - - o p t i */ + 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, /* o n s - - - - h */ + 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, /* e a d - - - - p */ + 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, /* o s t - - - - p */ + 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, /* u t - - - - d e */ + 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, /* l e t e - - - - */ + 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, /* t r a c e - - - */ + 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, /* - a c c e p t - */ + 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */ + 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* t - c h a r s e */ + 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, /* t - - - - a c c */ + 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e p t - e n c o */ + 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, /* d i n g - - - - */ + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, /* a c c e p t - l */ + 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, /* a n g u a g e - */ + 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */ + 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, /* t - r a n g e s */ + 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, /* - - - - a g e - */ + 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, /* - - - a l l o w */ + 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, /* - - - - a u t h */ + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, /* o r i z a t i o */ + 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, /* n - - - - c a c */ + 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, /* h e - c o n t r */ + 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, /* o l - - - - c o */ + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, /* n n e c t i o n */ + 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */ + 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, /* e n t - b a s e */ + 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */ + 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e n t - e n c o */ + 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, /* d i n g - - - - */ + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, /* c o n t e n t - */ + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, /* l a n g u a g e */ + 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */ + 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, /* e n t - l e n g */ + 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, /* t h - - - - c o */ + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, /* n t e n t - l o */ + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* c a t i o n - - */ + 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */ + 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, /* t - m d 5 - - - */ + 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, /* - c o n t e n t */ + 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, /* - r a n g e - - */ + 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */ + 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, /* t - t y p e - - */ + 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, /* - - d a t e - - */ + 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, /* - - e t a g - - */ + 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, /* - - e x p e c t */ + 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, /* - - - - e x p i */ + 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, /* r e s - - - - f */ + 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, /* r o m - - - - h */ + 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, /* o s t - - - - i */ + 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, /* f - m a t c h - */ + 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, /* - - - i f - m o */ + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, /* d i f i e d - s */ + 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, /* i n c e - - - - */ + 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, /* i f - n o n e - */ + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, /* m a t c h - - - */ + 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, /* - i f - r a n g */ + 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, /* e - - - - i f - */ + 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, /* u n m o d i f i */ + 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, /* e d - s i n c e */ + 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, /* - - - - l a s t */ + 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, /* - m o d i f i e */ + 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, /* d - - - - l o c */ + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, /* a t i o n - - - */ + 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, /* - m a x - f o r */ + 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, /* w a r d s - - - */ + 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, /* - p r a g m a - */ + 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, /* - - - p r o x y */ + 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, /* - a u t h e n t */ + 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, /* i c a t e - - - */ + 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, /* - p r o x y - a */ + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, /* u t h o r i z a */ + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, /* t i o n - - - - */ + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, /* r a n g e - - - */ + 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, /* - r e f e r e r */ + 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, /* - - - - r e t r */ + 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, /* y - a f t e r - */ + 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, /* - - - s e r v e */ + 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, /* r - - - - t e - */ + 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, /* - - - t r a i l */ + 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, /* e r - - - - t r */ + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, /* a n s f e r - e */ + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, /* n c o d i n g - */ + 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, /* - - - u p g r a */ + 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, /* d e - - - - u s */ + 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, /* e r - a g e n t */ + 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, /* - - - - v a r y */ + 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, /* - - - - v i a - */ + 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, /* - - - w a r n i */ + 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, /* n g - - - - w w */ + 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, /* w - a u t h e n */ + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, /* t i c a t e - - */ + 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, /* - - m e t h o d */ + 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, /* - - - - g e t - */ + 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, /* - - - s t a t u */ + 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, /* s - - - - 2 0 0 */ + 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, /* - O K - - - - v */ + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* e r s i o n - - */ + 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, /* - - H T T P - 1 */ + 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, /* - 1 - - - - u r */ + 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, /* l - - - - p u b */ + 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, /* l i c - - - - s */ + 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, /* e t - c o o k i */ + 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, /* e - - - - k e e */ + 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, /* p - a l i v e - */ + 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, /* - - - o r i g i */ + 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, /* n 1 0 0 1 0 1 2 */ + 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, /* 0 1 2 0 2 2 0 5 */ + 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, /* 2 0 6 3 0 0 3 0 */ + 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, /* 2 3 0 3 3 0 4 3 */ + 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, /* 0 5 3 0 6 3 0 7 */ + 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, /* 4 0 2 4 0 5 4 0 */ + 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, /* 6 4 0 7 4 0 8 4 */ + 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, /* 0 9 4 1 0 4 1 1 */ + 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, /* 4 1 2 4 1 3 4 1 */ + 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, /* 4 4 1 5 4 1 6 4 */ + 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, /* 1 7 5 0 2 5 0 4 */ + 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, /* 5 0 5 2 0 3 - N */ + 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, /* o n - A u t h o */ + 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, /* r i t a t i v e */ + 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, /* - I n f o r m a */ + 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, /* t i o n 2 0 4 - */ + 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, /* N o - C o n t e */ + 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, /* n t 3 0 1 - M o */ + 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, /* v e d - P e r m */ + 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, /* a n e n t l y 4 */ + 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, /* 0 0 - B a d - R */ + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, /* e q u e s t 4 0 */ + 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, /* 1 - U n a u t h */ + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, /* o r i z e d 4 0 */ + 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, /* 3 - F o r b i d */ + 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, /* d e n 4 0 4 - N */ + 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, /* o t - F o u n d */ + 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, /* 5 0 0 - I n t e */ + 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, /* r n a l - S e r */ + 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, /* v e r - E r r o */ + 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, /* r 5 0 1 - N o t */ + 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, /* - I m p l e m e */ + 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, /* n t e d 5 0 3 - */ + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, /* S e r v i c e - */ + 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, /* U n a v a i l a */ + 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, /* b l e J a n - F */ + 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, /* e b - M a r - A */ + 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, /* p r - M a y - J */ + 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, /* u n - J u l - A */ + 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, /* u g - S e p t - */ + 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, /* O c t - N o v - */ + 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, /* D e c - 0 0 - 0 */ + 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, /* 0 - 0 0 - M o n */ + 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, /* - - T u e - - W */ + 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, /* e d - - T h u - */ + 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, /* - F r i - - S a */ + 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, /* t - - S u n - - */ + 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, /* G M T c h u n k */ + 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, /* e d - t e x t - */ + 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, /* h t m l - i m a */ + 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, /* g e - p n g - i */ + 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, /* m a g e - j p g */ + 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, /* - i m a g e - g */ + 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* i f - a p p l i */ + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */ + 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* m l - a p p l i */ + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */ + 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, /* h t m l - x m l */ + 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, /* - t e x t - p l */ + 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, /* a i n - t e x t */ + 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, /* - j a v a s c r */ + 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, /* i p t - p u b l */ + 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, /* i c p r i v a t */ + 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, /* e m a x - a g e */ + 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, /* - g z i p - d e */ + 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, /* f l a t e - s d */ + 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* c h c h a r s e */ + 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, /* t - u t f - 8 c */ + 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, /* h a r s e t - i */ + 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, /* s o - 8 8 5 9 - */ + 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, /* 1 - u t f - - - */ + 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e /* - e n q - 0 - */ +}; static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = { { 0, 6, "method", ngx_http_spdy_parse_method }, { 0, 6, "scheme", ngx_http_spdy_parse_scheme }, - { 0, 3, "url", ngx_http_spdy_parse_url }, + { 0, 4, "host", ngx_http_spdy_parse_host }, + { 0, 4, "path", ngx_http_spdy_parse_path }, { 0, 7, "version", ngx_http_spdy_parse_version }, }; @@ -233,7 +416,17 @@ ngx_http_spdy_init(ngx_event_t *rev) sc->connection = c; sc->http_connection = hc; - sc->handler = ngx_http_spdy_state_detect_settings; + sc->send_window = NGX_SPDY_CONNECTION_WINDOW; + sc->recv_window = NGX_SPDY_CONNECTION_WINDOW; + + sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW; + + sc->handler = ngx_http_spdy_state_head; + + if (hc->proxy_protocol) { + c->log->action = "reading PROXY protocol"; + sc->handler = ngx_http_spdy_proxy_protocol; + } sc->zstream_in.zalloc = ngx_http_spdy_zalloc; sc->zstream_in.zfree = ngx_http_spdy_zfree; @@ -295,6 +488,24 @@ ngx_http_spdy_init(ngx_event_t *rev) return; } + if (ngx_http_spdy_send_settings(sc) == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (ngx_http_spdy_send_window_update(sc, 0, NGX_SPDY_MAX_WINDOW + - sc->recv_window) + == NGX_ERROR) + { + ngx_http_close_connection(c); + return; + } + + sc->recv_window = NGX_SPDY_MAX_WINDOW; + + ngx_queue_init(&sc->waiting); + ngx_queue_init(&sc->posted); + c->data = sc; rev->handler = ngx_http_spdy_read_handler; @@ -344,7 +555,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev) break; } - if (n == 0 && (sc->waiting || sc->processing)) { + if (n == 0 && (sc->incomplete || sc->processing)) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed prematurely connection"); } @@ -358,7 +569,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev) end += n; sc->buffer_used = 0; - sc->waiting = 0; + sc->incomplete = 0; do { p = sc->handler(sc, p, end); @@ -376,6 +587,11 @@ ngx_http_spdy_read_handler(ngx_event_t *rev) return; } + if (sc->last_out && ngx_http_spdy_send_output_queue(sc) == NGX_ERROR) { + ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + sc->blocked = 0; if (sc->processing) { @@ -393,8 +609,9 @@ static void ngx_http_spdy_write_handler(ngx_event_t *wev) { ngx_int_t rc; + ngx_queue_t *q; ngx_connection_t *c; - ngx_http_spdy_stream_t *stream, *s, *sn; + ngx_http_spdy_stream_t *stream; ngx_http_spdy_connection_t *sc; c = wev->data; @@ -409,7 +626,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler"); - sc->blocked = 2; + sc->blocked = 1; rc = ngx_http_spdy_send_output_queue(sc); @@ -418,20 +635,13 @@ ngx_http_spdy_write_handler(ngx_event_t *wev) return; } - stream = NULL; + while (!ngx_queue_empty(&sc->posted)) { + q = ngx_queue_head(&sc->posted); - for (s = sc->last_stream; s; s = sn) { - sn = s->next; - s->next = stream; - stream = s; - } + ngx_queue_remove(q); - sc->last_stream = NULL; + stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); - sc->blocked = 1; - - for ( /* void */ ; stream; stream = sn) { - sn = stream->next; stream->handled = 0; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -484,9 +694,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) out = frame; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy frame out: %p sid:%ui prio:%ui bl:%ui size:%uz", + "spdy frame out: %p sid:%ui prio:%ui bl:%d len:%uz", out, out->stream ? out->stream->id : 0, out->priority, - out->blocked, out->size); + out->blocked, out->length); } cl = c->send_chain(c, cl, 0); @@ -517,7 +727,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) } } - for ( /* void */ ; out; out = out->next) { + for ( /* void */ ; out; out = fn) { + fn = out->next; + if (out->handler(sc, out) != NGX_OK) { out->blocked = 1; out->priority = NGX_SPDY_HIGHEST_PRIORITY; @@ -525,9 +737,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy frame sent: %p sid:%ui bl:%ui size:%uz", + "spdy frame sent: %p sid:%ui bl:%d len:%uz", out, out->stream ? out->stream->id : 0, - out->blocked, out->size); + out->blocked, out->length); } frame = NULL; @@ -567,7 +779,7 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc) sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, ngx_http_spdy_module); - if (sc->waiting) { + if (sc->incomplete) { ngx_add_timer(c->read, sscf->recv_timeout); return; } @@ -605,34 +817,18 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc) static u_char * -ngx_http_spdy_state_detect_settings(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end) +ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos, + u_char *end) { - if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_detect_settings); - } - - /* - * Since this is the first frame in a buffer, - * then it is properly aligned - */ - - if (*(uint32_t *) pos == htonl(ngx_spdy_ctl_frame_head(NGX_SPDY_SETTINGS))) - { - sc->length = ngx_spdy_frame_length(htonl(((uint32_t *) pos)[1])); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy SETTINGS frame received, size: %uz", sc->length); - - pos += NGX_SPDY_FRAME_HEADER_SIZE; + pos = ngx_proxy_protocol_parse(sc->connection, pos, end); - return ngx_http_spdy_state_settings(sc, pos, end); + if (pos == NULL) { + return ngx_http_spdy_state_protocol_error(sc); } - ngx_http_spdy_send_settings(sc); + sc->connection->log->action = "processing SPDY"; - return ngx_http_spdy_state_head(sc, pos, end); + return ngx_http_spdy_state_complete(sc, pos, end); } @@ -640,7 +836,8 @@ static u_char * ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) { - uint32_t head, flen; + uint32_t head, flen; + ngx_uint_t type; if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) { return ngx_http_spdy_state_save(sc, pos, end, @@ -659,11 +856,13 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, pos += sizeof(uint32_t); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy process frame head:%08Xd f:%ui l:%ui", + "spdy process frame head:%08XD f:%Xd l:%uz", head, sc->flags, sc->length); if (ngx_spdy_ctl_frame_check(head)) { - switch (ngx_spdy_ctl_frame_type(head)) { + type = ngx_spdy_ctl_frame_type(head); + + switch (type) { case NGX_SPDY_SYN_STREAM: return ngx_http_spdy_state_syn_stream(sc, pos, end); @@ -675,10 +874,7 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, return ngx_http_spdy_state_rst_stream(sc, pos, end); case NGX_SPDY_SETTINGS: - return ngx_http_spdy_state_skip(sc, pos, end); - - case NGX_SPDY_NOOP: - return ngx_http_spdy_state_noop(sc, pos, end); + return ngx_http_spdy_state_settings(sc, pos, end); case NGX_SPDY_PING: return ngx_http_spdy_state_ping(sc, pos, end); @@ -689,7 +885,12 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, case NGX_SPDY_HEADERS: return ngx_http_spdy_state_protocol_error(sc); - default: /* TODO logging */ + case NGX_SPDY_WINDOW_UPDATE: + return ngx_http_spdy_state_window_update(sc, pos, end); + + default: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy control frame with unknown type %ui", type); return ngx_http_spdy_state_skip(sc, pos, end); } } @@ -729,7 +930,7 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, sc->length -= NGX_SPDY_SYN_STREAM_SIZE; sid = ngx_spdy_frame_parse_sid(pos); - prio = pos[8] >> 6; + prio = pos[8] >> 5; pos += NGX_SPDY_SYN_STREAM_SIZE; @@ -742,7 +943,7 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, if (sc->processing >= sscf->concurrent_streams) { ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "spdy concurrent streams excessed %ui", sc->processing); + "spdy concurrent streams exceeded %ui", sc->processing); if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM, prio) @@ -809,6 +1010,8 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, sc->zstream_in.next_in = pos; sc->zstream_in.avail_in = size; sc->zstream_in.next_out = buf->last; + + /* one byte is reserved for null-termination of the last header value */ sc->zstream_in.avail_out = buf->end - buf->last - 1; z = inflate(&sc->zstream_in, Z_NO_FLUSH); @@ -851,18 +1054,28 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, if (r->headers_in.headers.part.elts == NULL) { if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) { + + if (complete) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent SYN_STREAM frame " + "with invalid HEADERS block"); + ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); + return ngx_http_spdy_state_protocol_error(sc); + } + return ngx_http_spdy_state_save(sc, pos, end, ngx_http_spdy_state_headers); } - sc->headers = ngx_spdy_frame_parse_uint16(buf->pos); + sc->entries = ngx_spdy_frame_parse_uint32(buf->pos); buf->pos += NGX_SPDY_NV_NUM_SIZE; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy headers count: %ui", sc->headers); + "spdy HEADERS block consists of %ui entries", + sc->entries); - if (ngx_list_init(&r->headers_in.headers, r->pool, sc->headers + 3, + if (ngx_list_init(&r->headers_in.headers, r->pool, 20, sizeof(ngx_table_elt_t)) != NGX_OK) { @@ -881,14 +1094,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, } } - while (sc->headers) { + while (sc->entries) { rc = ngx_http_spdy_parse_header(r); switch (rc) { case NGX_DONE: - sc->headers--; + sc->entries--; case NGX_OK: break; @@ -912,9 +1125,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, return ngx_http_spdy_state_headers_error(sc, pos, end); } + /* null-terminate the last processed header name or value */ + *buf->pos = '\0'; + buf = r->header_in; sc->zstream_in.next_out = buf->last; + + /* one byte is reserved for null-termination */ sc->zstream_in.avail_out = buf->end - buf->last - 1; z = inflate(&sc->zstream_in, Z_NO_FLUSH); @@ -983,10 +1201,10 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, } } - if (buf->pos != buf->last) { - /* TODO: improve error message */ - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "end %ui %p %p", complete, buf->pos, buf->last); + if (buf->pos != buf->last || sc->zstream_in.avail_in) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent SYN_STREAM frame " + "with invalid HEADERS block"); ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); return ngx_http_spdy_state_protocol_error(sc); } @@ -996,6 +1214,9 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_http_spdy_state_headers); } + /* null-terminate the last header value */ + *buf->pos = '\0'; + ngx_http_spdy_run_request(r); return ngx_http_spdy_state_complete(sc, pos, end); @@ -1064,14 +1285,224 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, static u_char * +ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, + u_char *end) +{ + size_t delta; + ngx_uint_t sid; + ngx_event_t *wev; + ngx_queue_t *q; + ngx_http_spdy_stream_t *stream; + + if (end - pos < NGX_SPDY_WINDOW_UPDATE_SIZE) { + return ngx_http_spdy_state_save(sc, pos, end, + ngx_http_spdy_state_window_update); + } + + if (sc->length != NGX_SPDY_WINDOW_UPDATE_SIZE) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent WINDOW_UPDATE frame " + "with incorrect length %uz", sc->length); + + return ngx_http_spdy_state_protocol_error(sc); + } + + sid = ngx_spdy_frame_parse_sid(pos); + + pos += NGX_SPDY_SID_SIZE; + + delta = ngx_spdy_frame_parse_delta(pos); + + pos += NGX_SPDY_DELTA_SIZE; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy WINDOW_UPDATE sid:%ui delta:%ui", sid, delta); + + if (sid) { + stream = ngx_http_spdy_get_stream_by_id(sc, sid); + + if (stream == NULL) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent WINDOW_UPDATE frame " + "for unknown stream %ui", sid); + + if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_INVALID_STREAM, + NGX_SPDY_LOWEST_PRIORITY) + == NGX_ERROR) + { + return ngx_http_spdy_state_internal_error(sc); + } + + return ngx_http_spdy_state_complete(sc, pos, end); + } + + if (stream->send_window > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) { + + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client violated flow control for stream %ui: " + "received WINDOW_UPDATE frame with delta %uz " + "that is not allowed for window %z", + sid, delta, stream->send_window); + + if (ngx_http_spdy_terminate_stream(sc, stream, + NGX_SPDY_FLOW_CONTROL_ERROR) + == NGX_ERROR) + { + return ngx_http_spdy_state_internal_error(sc); + } + + return ngx_http_spdy_state_complete(sc, pos, end); + } + + stream->send_window += delta; + + if (stream->exhausted) { + stream->exhausted = 0; + + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; + wev->handler(wev); + } + } + + } else { + sc->send_window += delta; + + if (sc->send_window > NGX_SPDY_MAX_WINDOW) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client violated connection flow control: " + "received WINDOW_UPDATE frame with delta %uz " + "that is not allowed for window %uz", + delta, sc->send_window); + + return ngx_http_spdy_state_protocol_error(sc); + } + + while (!ngx_queue_empty(&sc->waiting)) { + q = ngx_queue_head(&sc->waiting); + + ngx_queue_remove(q); + + stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); + + stream->handled = 0; + + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; + wev->handler(wev); + + if (sc->send_window == 0) { + break; + } + } + } + } + + return ngx_http_spdy_state_complete(sc, pos, end); +} + + +static u_char * ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) { + ngx_http_spdy_stream_t *stream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy DATA frame"); + + if (sc->length > sc->recv_window) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client violated connection flow control: length of " + "received DATA frame %uz, while available window %uz", + sc->length, sc->recv_window); + + return ngx_http_spdy_state_protocol_error(sc); + } + + sc->recv_window -= sc->length; + + if (sc->recv_window < NGX_SPDY_MAX_WINDOW / 4) { + + if (ngx_http_spdy_send_window_update(sc, 0, + NGX_SPDY_MAX_WINDOW + - sc->recv_window) + == NGX_ERROR) + { + return ngx_http_spdy_state_internal_error(sc); + } + + sc->recv_window = NGX_SPDY_MAX_WINDOW; + } + + stream = sc->stream; + + if (stream == NULL) { + return ngx_http_spdy_state_skip(sc, pos, end); + } + + if (sc->length > stream->recv_window) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client violated flow control for stream %ui: length of " + "received DATA frame %uz, while available window %uz", + stream->id, sc->length, stream->recv_window); + + if (ngx_http_spdy_terminate_stream(sc, stream, + NGX_SPDY_FLOW_CONTROL_ERROR) + == NGX_ERROR) + { + return ngx_http_spdy_state_internal_error(sc); + } + + return ngx_http_spdy_state_skip(sc, pos, end); + } + + stream->recv_window -= sc->length; + + if (stream->recv_window < NGX_SPDY_STREAM_WINDOW / 4) { + + if (ngx_http_spdy_send_window_update(sc, stream->id, + NGX_SPDY_STREAM_WINDOW + - stream->recv_window) + == NGX_ERROR) + { + return ngx_http_spdy_state_internal_error(sc); + } + + stream->recv_window = NGX_SPDY_STREAM_WINDOW; + } + + if (stream->in_closed) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent DATA frame for half closed stream %ui", + stream->id); + + if (ngx_http_spdy_terminate_stream(sc, stream, + NGX_SPDY_STREAM_ALREADY_CLOSED) + == NGX_ERROR) + { + return ngx_http_spdy_state_internal_error(sc); + } + + return ngx_http_spdy_state_skip(sc, pos, end); + } + + return ngx_http_spdy_state_read_data(sc, pos, end); +} + + +static u_char * +ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos, + u_char *end) +{ size_t size; ssize_t n; ngx_buf_t *buf; ngx_int_t rc; - ngx_uint_t complete; ngx_temp_file_t *tf; ngx_http_request_t *r; ngx_http_spdy_stream_t *stream; @@ -1080,18 +1511,10 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, stream = sc->stream; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy DATA frame"); - if (stream == NULL) { return ngx_http_spdy_state_skip(sc, pos, end); } - if (stream->in_closed) { - /* TODO log */ - return ngx_http_spdy_state_protocol_error(sc); - } - if (stream->skip_data) { if (sc->flags & NGX_SPDY_FLAG_FIN) { @@ -1104,13 +1527,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, size = end - pos; - if (size >= sc->length) { + if (size > sc->length) { size = sc->length; - complete = 1; - - } else { - sc->length -= size; - complete = 0; } r = stream->request; @@ -1152,6 +1570,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, } } + sc->length -= size; + if (tf) { buf->start = pos; buf->pos = pos; @@ -1180,15 +1600,28 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, r->request_length += size; } - if (!complete) { + if (sc->length) { return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_data); + ngx_http_spdy_state_read_data); } if (sc->flags & NGX_SPDY_FLAG_FIN) { stream->in_closed = 1; + if (r->headers_in.content_length_n < 0) { + r->headers_in.content_length_n = rb->rest; + + } else if (r->headers_in.content_length_n != rb->rest) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client prematurely closed stream: " + "%O of %O bytes of request body received", + rb->rest, r->headers_in.content_length_n); + + stream->skip_data = NGX_SPDY_DATA_ERROR; + goto error; + } + if (tf) { ngx_memzero(buf, sizeof(ngx_buf_t)); @@ -1199,11 +1632,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, rb->buf = NULL; } - if (r->headers_in.content_length_n < 0) { - r->headers_in.content_length_n = rb->rest; - } - if (rb->post_handler) { + r->read_event_handler = ngx_http_block_reading; rb->post_handler(r); } } @@ -1237,7 +1667,6 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_uint_t sid, status; ngx_event_t *ev; ngx_connection_t *fc; - ngx_http_request_t *r; ngx_http_spdy_stream_t *stream; if (end - pos < NGX_SPDY_RST_STREAM_SIZE) { @@ -1246,7 +1675,10 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, } if (sc->length != NGX_SPDY_RST_STREAM_SIZE) { - /* TODO logging */ + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent RST_STREAM frame with incorrect length %uz", + sc->length); + return ngx_http_spdy_state_protocol_error(sc); } @@ -1261,55 +1693,42 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, "spdy RST_STREAM sid:%ui st:%ui", sid, status); + stream = ngx_http_spdy_get_stream_by_id(sc, sid); + if (stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "unknown stream, probably it has been closed already"); + return ngx_http_spdy_state_complete(sc, pos, end); + } - switch (status) { + stream->in_closed = 1; + stream->out_closed = 1; - case NGX_SPDY_PROTOCOL_ERROR: - /* TODO logging */ - return ngx_http_spdy_state_protocol_error(sc); + fc = stream->request->connection; + fc->error = 1; - case NGX_SPDY_INVALID_STREAM: - /* TODO */ - break; + switch (status) { - case NGX_SPDY_REFUSED_STREAM: - /* TODO */ + case NGX_SPDY_CANCEL: + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client canceled stream %ui", sid); break; - case NGX_SPDY_UNSUPPORTED_VERSION: - /* TODO logging */ - return ngx_http_spdy_state_protocol_error(sc); - - case NGX_SPDY_CANCEL: case NGX_SPDY_INTERNAL_ERROR: - stream = ngx_http_spdy_get_stream_by_id(sc, sid); - if (stream == NULL) { - /* TODO false cancel */ - break; - } - - stream->in_closed = 1; - stream->out_closed = 1; - - r = stream->request; - - fc = r->connection; - fc->error = 1; - - ev = fc->read; - ev->handler(ev); - + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client terminated stream %ui because of internal error", + sid); break; - case NGX_SPDY_FLOW_CONTROL_ERROR: - /* TODO logging */ - return ngx_http_spdy_state_protocol_error(sc); - default: - /* TODO */ - return ngx_http_spdy_state_protocol_error(sc); + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client terminated stream %ui with status %ui", + sid, status); + break; } + ev = fc->read; + ev->handler(ev); + return ngx_http_spdy_state_complete(sc, pos, end); } @@ -1382,70 +1801,77 @@ static u_char * ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) { - ngx_uint_t v; - ngx_http_spdy_srv_conf_t *sscf; + ngx_uint_t fid, val; - if (sc->headers == 0) { + if (sc->entries == 0) { if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) { return ngx_http_spdy_state_save(sc, pos, end, ngx_http_spdy_state_settings); } - sc->headers = ngx_spdy_frame_parse_uint32(pos); + sc->entries = ngx_spdy_frame_parse_uint32(pos); pos += NGX_SPDY_SETTINGS_NUM_SIZE; sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE; - if (sc->length < sc->headers * NGX_SPDY_SETTINGS_PAIR_SIZE) { + if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) { /* TODO logging */ return ngx_http_spdy_state_protocol_error(sc); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, "spdy SETTINGS frame consists of %ui entries", - sc->headers); + sc->entries); } - while (sc->headers) { + while (sc->entries) { if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) { return ngx_http_spdy_state_save(sc, pos, end, ngx_http_spdy_state_settings); } - sc->headers--; + sc->entries--; + sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE; - if (pos[0] != NGX_SPDY_SETTINGS_MAX_STREAMS) { - pos += NGX_SPDY_SETTINGS_PAIR_SIZE; - sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE; - continue; - } + fid = ngx_spdy_frame_parse_uint32(pos); + + pos += NGX_SPDY_SETTINGS_FID_SIZE; + + val = ngx_spdy_frame_parse_uint32(pos); - v = ngx_spdy_frame_parse_uint32(pos + NGX_SPDY_SETTINGS_IDF_SIZE); + pos += NGX_SPDY_SETTINGS_VAL_SIZE; - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy SETTINGS entry fl:%ui id:%ui val:%ui", + ngx_spdy_frame_flags(fid), ngx_spdy_frame_id(fid), val); - if (v != sscf->concurrent_streams) { - ngx_http_spdy_send_settings(sc); + if (ngx_spdy_frame_flags(fid) == NGX_SPDY_SETTINGS_FLAG_PERSISTED) { + continue; } - return ngx_http_spdy_state_skip(sc, pos, end); - } + switch (ngx_spdy_frame_id(fid)) { - ngx_http_spdy_send_settings(sc); + case NGX_SPDY_SETTINGS_INIT_WINDOW: - return ngx_http_spdy_state_complete(sc, pos, end); -} + if (val > NGX_SPDY_MAX_WINDOW) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent SETTINGS frame with " + "incorrect INIT_WINDOW value: %ui", val); + + return ngx_http_spdy_state_protocol_error(sc); + } + if (ngx_http_spdy_adjust_windows(sc, val - sc->init_window) + != NGX_OK) + { + return ngx_http_spdy_state_internal_error(sc); + } -static u_char * -ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - if (sc->length) { - /* TODO logging */ - return ngx_http_spdy_state_protocol_error(sc); + sc->init_window = val; + + continue; + } } return ngx_http_spdy_state_complete(sc, pos, end); @@ -1465,20 +1891,22 @@ static u_char * ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler) { -#if 1 - if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) { + size_t size; + + size = end - pos; + + if (size > NGX_SPDY_STATE_BUFFER_SIZE) { ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, "spdy state buffer overflow: " - "%i bytes required", end - pos); + "%uz bytes required", size); return ngx_http_spdy_state_internal_error(sc); } -#endif ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE); - sc->buffer_used = end - pos; + sc->buffer_used = size; sc->handler = handler; - sc->waiting = 1; + sc->incomplete = 1; return end; } @@ -1509,6 +1937,41 @@ ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc) static ngx_int_t +ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, + ngx_uint_t delta) +{ + u_char *p; + ngx_buf_t *buf; + ngx_http_spdy_out_frame_t *frame; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy write WINDOW_UPDATE sid:%ui delta:%ui", sid, delta); + + frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE, + NGX_SPDY_HIGHEST_PRIORITY); + if (frame == NULL) { + return NGX_ERROR; + } + + buf = frame->first->buf; + + p = buf->pos; + + p = ngx_spdy_frame_write_head(p, NGX_SPDY_WINDOW_UPDATE); + p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_WINDOW_UPDATE_SIZE); + + p = ngx_spdy_frame_write_sid(p, sid); + p = ngx_spdy_frame_aligned_write_uint32(p, delta); + + buf->last = p; + + ngx_http_spdy_queue_frame(sc, frame); + + return NGX_OK; +} + + +static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority) { @@ -1587,7 +2050,6 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc) { u_char *p; ngx_buf_t *buf; - ngx_pool_t *pool; ngx_chain_t *cl; ngx_http_spdy_srv_conf_t *sscf; ngx_http_spdy_out_frame_t *frame; @@ -1595,21 +2057,19 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, "spdy create SETTINGS frame"); - pool = sc->connection->pool; - - frame = ngx_palloc(pool, sizeof(ngx_http_spdy_out_frame_t)); + frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t)); if (frame == NULL) { return NGX_ERROR; } - cl = ngx_alloc_chain_link(pool); + cl = ngx_alloc_chain_link(sc->pool); if (cl == NULL) { return NGX_ERROR; } - buf = ngx_create_temp_buf(pool, NGX_SPDY_FRAME_HEADER_SIZE - + NGX_SPDY_SETTINGS_NUM_SIZE - + NGX_SPDY_SETTINGS_PAIR_SIZE); + buf = ngx_create_temp_buf(sc->pool, NGX_SPDY_FRAME_HEADER_SIZE + + NGX_SPDY_SETTINGS_NUM_SIZE + + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE); if (buf == NULL) { return NGX_ERROR; } @@ -1622,11 +2082,10 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc) frame->first = cl; frame->last = cl; frame->handler = ngx_http_spdy_settings_frame_handler; -#if (NGX_DEBUG) frame->stream = NULL; - frame->size = NGX_SPDY_FRAME_HEADER_SIZE - + NGX_SPDY_SETTINGS_NUM_SIZE - + NGX_SPDY_SETTINGS_PAIR_SIZE; +#if (NGX_DEBUG) + frame->length = NGX_SPDY_SETTINGS_NUM_SIZE + + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE; #endif frame->priority = NGX_SPDY_HIGHEST_PRIORITY; frame->blocked = 0; @@ -1635,19 +2094,20 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc) p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS); p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS, - NGX_SPDY_SETTINGS_NUM_SIZE - + NGX_SPDY_SETTINGS_PAIR_SIZE); + NGX_SPDY_SETTINGS_NUM_SIZE + + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE); - p = ngx_spdy_frame_aligned_write_uint32(p, 1); - p = ngx_spdy_frame_aligned_write_uint32(p, - NGX_SPDY_SETTINGS_MAX_STREAMS << 24 - | NGX_SPDY_SETTINGS_FLAG_PERSIST); + p = ngx_spdy_frame_aligned_write_uint32(p, 2); sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, ngx_http_spdy_module); + p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_MAX_STREAMS); p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams); + p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_INIT_WINDOW); + p = ngx_spdy_frame_aligned_write_uint32(p, NGX_SPDY_STREAM_WINDOW); + buf->last = p; ngx_http_spdy_queue_frame(sc, frame); @@ -1675,7 +2135,7 @@ ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc, static ngx_http_spdy_out_frame_t * -ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size, +ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length, ngx_uint_t priority) { ngx_chain_t *cl; @@ -1684,7 +2144,7 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size, frame = sc->free_ctl_frames; if (frame) { - sc->free_ctl_frames = frame->free; + sc->free_ctl_frames = frame->next; cl = frame->first; cl->buf->pos = cl->buf->start; @@ -1711,19 +2171,17 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size, frame->first = cl; frame->last = cl; frame->handler = ngx_http_spdy_ctl_frame_handler; + frame->stream = NULL; } - frame->free = NULL; - #if (NGX_DEBUG) - if (size > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) { + if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) { ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0, - "requested control frame is too big: %z", size); + "requested control frame is too big: %uz", length); return NULL; } - frame->stream = NULL; - frame->size = size; + frame->length = length; #endif frame->priority = priority; @@ -1745,7 +2203,7 @@ ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc, return NGX_AGAIN; } - frame->free = sc->free_ctl_frames; + frame->next = sc->free_ctl_frames; sc->free_ctl_frames = frame; return NGX_OK; @@ -1814,7 +2272,7 @@ ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id, rev->data = fc; rev->ready = 1; - rev->handler = ngx_http_empty_handler; + rev->handler = ngx_http_spdy_close_stream_handler; rev->log = log; ngx_memcpy(wev, rev, sizeof(ngx_event_t)); @@ -1864,6 +2322,10 @@ ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id, stream->id = id; stream->request = r; stream->connection = sc; + + stream->send_window = sc->init_window; + stream->recv_window = NGX_SPDY_STREAM_WINDOW; + stream->priority = priority; sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module); @@ -1907,7 +2369,7 @@ static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r) { u_char *p, *end, ch; - ngx_uint_t len, hash; + ngx_uint_t hash; ngx_http_core_srv_conf_t *cscf; enum { @@ -1930,16 +2392,17 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) return NGX_AGAIN; } - len = ngx_spdy_frame_parse_uint16(p); + r->lowcase_index = ngx_spdy_frame_parse_uint32(p); - if (!len) { + if (r->lowcase_index == 0) { return NGX_HTTP_PARSE_INVALID_HEADER; } + /* null-terminate the previous header value */ + *p = '\0'; + p += NGX_SPDY_NV_NLEN_SIZE; - r->header_name_end = p + len; - r->lowcase_index = len; r->invalid_header = 0; state = sw_name; @@ -1948,13 +2411,18 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) case sw_name: - if (r->header_name_end > end) { + if ((ngx_uint_t) (end - p) < r->lowcase_index) { break; } cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); r->header_name_start = p; + r->header_name_end = p + r->lowcase_index; + + if (p[0] == ':') { + p++; + } hash = 0; @@ -1999,30 +2467,26 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) break; } - len = ngx_spdy_frame_parse_uint16(p); + r->lowcase_index = ngx_spdy_frame_parse_uint32(p); - if (!len) { - return NGX_ERROR; - } + /* null-terminate header name */ + *p = '\0'; p += NGX_SPDY_NV_VLEN_SIZE; - r->header_end = p + len; - state = sw_value; /* fall through */ case sw_value: - if (r->header_end > end) { + if ((ngx_uint_t) (end - p) < r->lowcase_index) { break; } r->header_start = p; - for ( /* void */ ; p != r->header_end; p++) { - + while (r->lowcase_index--) { ch = *p; if (ch == '\0') { @@ -2031,7 +2495,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) return NGX_ERROR; } - r->header_size = p - r->header_start; + r->header_end = p; r->header_in->pos = p + 1; return NGX_OK; @@ -2040,9 +2504,11 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) if (ch == CR || ch == LF) { return NGX_HTTP_PARSE_INVALID_HEADER; } + + p++; } - r->header_size = p - r->header_start; + r->header_end = p; r->header_in->pos = p; r->state = 0; @@ -2091,7 +2557,7 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy large header alloc: %p %uz", + "spdy large header alloc: %p %z", buf->pos, buf->end - buf->last); old = r->header_in->pos; @@ -2101,13 +2567,6 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) buf->last = ngx_cpymem(new, old, rest); } - if (r->header_name_end > old) { - r->header_name_end = new + (r->header_name_end - old); - - } else if (r->header_end > old) { - r->header_end = new + (r->header_end - old); - } - r->header_in = buf; stream->header_buffers++; @@ -2135,21 +2594,25 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r) return NGX_OK; } - } else { + } + + if (r->header_name_start[0] == ':') { + r->header_name_start++; + for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) { sh = &ngx_http_spdy_request_headers[i]; if (sh->hash != r->header_hash - || sh->len != r->lowcase_index - || ngx_strncmp(sh->header, r->header_name_start, - r->lowcase_index) - != 0) + || sh->len != r->header_name_end - r->header_name_start + || ngx_strncmp(sh->header, r->header_name_start, sh->len) != 0) { continue; } return sh->handler(r); } + + return NGX_HTTP_PARSE_INVALID_REQUEST; } h = ngx_list_push(&r->headers_in.headers); @@ -2161,13 +2624,11 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r) h->hash = r->header_hash; - h->key.len = r->lowcase_index; + h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; - h->key.data[h->key.len] = '\0'; - h->value.len = r->header_size; + h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; - h->value.data[h->value.len] = '\0'; h->lowcase_key = h->key.data; @@ -2176,7 +2637,7 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r) void -ngx_http_spdy_request_headers_init() +ngx_http_spdy_request_headers_init(void) { ngx_uint_t i; ngx_http_spdy_request_header_t *h; @@ -2226,7 +2687,7 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r) return NGX_HTTP_PARSE_INVALID_HEADER; } - len = r->header_size; + len = r->header_end - r->header_start; r->method_name.len = len; r->method_name.data = r->header_start; @@ -2287,7 +2748,39 @@ ngx_http_spdy_parse_scheme(ngx_http_request_t *r) static ngx_int_t -ngx_http_spdy_parse_url(ngx_http_request_t *r) +ngx_http_spdy_parse_host(ngx_http_request_t *r) +{ + ngx_table_elt_t *h; + + if (r->headers_in.host) { + return NGX_HTTP_PARSE_INVALID_HEADER; + } + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + ngx_http_spdy_close_stream(r->spdy_stream, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + r->headers_in.host = h; + + h->hash = r->header_hash; + + h->key.len = r->header_name_end - r->header_name_start; + h->key.data = r->header_name_start; + + h->value.len = r->header_end - r->header_start; + h->value.data = r->header_start; + + h->lowcase_key = h->key.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_spdy_parse_path(ngx_http_request_t *r) { if (r->unparsed_uri.len) { return NGX_HTTP_PARSE_INVALID_HEADER; @@ -2319,7 +2812,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) p = r->header_start; - if (r->header_size < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) { + if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) { return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -2335,6 +2828,10 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) ch = *p; + if (ch == '.') { + break; + } + if (ch < '0' || ch > '9') { return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -2365,7 +2862,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) r->http_minor = r->http_minor * 10 + ch - '0'; } - r->http_protocol.len = r->header_size; + r->http_protocol.len = r->header_end - r->header_start; r->http_protocol.data = r->header_start; r->http_version = r->http_major * 1000 + r->http_minor; @@ -2465,6 +2962,16 @@ ngx_http_spdy_run_request(ngx_http_request_t *r) return; } + if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client prematurely closed stream"); + + r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR; + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; + } + ngx_http_process_request(r); } @@ -2597,10 +3104,55 @@ ngx_http_spdy_read_request_body(ngx_http_request_t *r, r->request_body->post_handler = post_handler; + r->read_event_handler = ngx_http_test_reading; + r->write_event_handler = ngx_http_request_empty_handler; + return NGX_AGAIN; } +static ngx_int_t +ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc, + ngx_http_spdy_stream_t *stream, ngx_uint_t status) +{ + ngx_event_t *rev; + ngx_connection_t *fc; + + if (ngx_http_spdy_send_rst_stream(sc, stream->id, status, + NGX_SPDY_HIGHEST_PRIORITY) + == NGX_ERROR) + { + return NGX_ERROR; + } + + stream->out_closed = 1; + + fc = stream->request->connection; + fc->error = 1; + + rev = fc->read; + rev->handler(rev); + + return NGX_OK; +} + + +static void +ngx_http_spdy_close_stream_handler(ngx_event_t *ev) +{ + ngx_connection_t *fc; + ngx_http_request_t *r; + + fc = ev->data; + r = fc->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "spdy close stream handler"); + + ngx_http_spdy_close_stream(r->spdy_stream, 0); +} + + void ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) { @@ -2612,9 +3164,16 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) sc = stream->connection; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy close stream %ui, processing %ui", - stream->id, sc->processing); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy close stream %ui, queued %ui, processing %ui", + stream->id, stream->queued, sc->processing); + + fc = stream->request->connection; + + if (stream->queued) { + fc->write->handler = ngx_http_spdy_close_stream_handler; + return; + } if (!stream->out_closed) { if (ngx_http_spdy_send_rst_stream(sc, stream->id, @@ -2650,14 +3209,13 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) index = &s->index; } - fc = stream->request->connection; - ngx_http_free_request(stream->request, rc); ev = fc->read; if (ev->active || ev->disabled) { - ngx_del_event(ev, NGX_READ_EVENT, 0); + ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, + "spdy fake read event was activated"); } if (ev->timer_set) { @@ -2671,7 +3229,8 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) ev = fc->write; if (ev->active || ev->disabled) { - ngx_del_event(ev, NGX_WRITE_EVENT, 0); + ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, + "spdy fake write event was activated"); } if (ev->timer_set) { @@ -2802,6 +3361,7 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc, c->error = 1; c->read->handler = ngx_http_empty_handler; + c->write->handler = ngx_http_empty_handler; sc->last_out = NULL; @@ -2816,15 +3376,18 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc, stream = sc->streams_index[i]; while (stream) { - r = stream->request; + stream->handled = 0; + r = stream->request; fc = r->connection; + fc->error = 1; - if (stream->waiting) { - r->blocked -= stream->waiting; - stream->waiting = 0; + if (stream->queued) { + stream->queued = 0; + ev = fc->write; + ev->delayed = 0; } else { ev = fc->read; @@ -2847,6 +3410,61 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc, } +static ngx_int_t +ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, ssize_t delta) +{ + ngx_uint_t i, size; + ngx_event_t *wev; + ngx_http_spdy_stream_t *stream, *sn; + ngx_http_spdy_srv_conf_t *sscf; + + sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, + ngx_http_spdy_module); + + size = ngx_http_spdy_streams_index_size(sscf); + + for (i = 0; i < size; i++) { + + for (stream = sc->streams_index[i]; stream; stream = sn) { + sn = stream->index; + + if (delta > 0 + && stream->send_window + > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) + { + if (ngx_http_spdy_terminate_stream(sc, stream, + NGX_SPDY_FLOW_CONTROL_ERROR) + == NGX_ERROR) + { + return NGX_ERROR; + } + + continue; + } + + stream->send_window += delta; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy:%ui adjust window:%z", + stream->id, stream->send_window); + + if (stream->send_window > 0 && stream->exhausted) { + stream->exhausted = 0; + + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; + wev->handler(wev); + } + } + } + } + + return NGX_OK; +} + + static void ngx_http_spdy_pool_cleanup(void *data) { diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy.h b/usr.sbin/nginx/src/http/ngx_http_spdy.h index 4294e3d5078..55aceda8999 100644 --- a/usr.sbin/nginx/src/http/ngx_http_spdy.h +++ b/usr.sbin/nginx/src/http/ngx_http_spdy.h @@ -15,12 +15,10 @@ #include <zlib.h> -#define NGX_SPDY_VERSION 2 +#define NGX_SPDY_VERSION 3 -#ifdef TLSEXT_TYPE_next_proto_neg -#define NGX_SPDY_NPN_ADVERTISE "\x06spdy/2" -#define NGX_SPDY_NPN_NEGOTIATED "spdy/2" -#endif +#define NGX_SPDY_NPN_ADVERTISE "\x08spdy/3.1" +#define NGX_SPDY_NPN_NEGOTIATED "spdy/3.1" #define NGX_SPDY_STATE_BUFFER_SIZE 16 @@ -30,32 +28,34 @@ #define NGX_SPDY_SYN_REPLY 2 #define NGX_SPDY_RST_STREAM 3 #define NGX_SPDY_SETTINGS 4 -#define NGX_SPDY_NOOP 5 #define NGX_SPDY_PING 6 #define NGX_SPDY_GOAWAY 7 #define NGX_SPDY_HEADERS 8 +#define NGX_SPDY_WINDOW_UPDATE 9 #define NGX_SPDY_FRAME_HEADER_SIZE 8 #define NGX_SPDY_SID_SIZE 4 +#define NGX_SPDY_DELTA_SIZE 4 #define NGX_SPDY_SYN_STREAM_SIZE 10 -#define NGX_SPDY_SYN_REPLY_SIZE 6 +#define NGX_SPDY_SYN_REPLY_SIZE 4 #define NGX_SPDY_RST_STREAM_SIZE 8 #define NGX_SPDY_PING_SIZE 4 -#define NGX_SPDY_GOAWAY_SIZE 4 -#define NGX_SPDY_NV_NUM_SIZE 2 -#define NGX_SPDY_NV_NLEN_SIZE 2 -#define NGX_SPDY_NV_VLEN_SIZE 2 +#define NGX_SPDY_GOAWAY_SIZE 8 +#define NGX_SPDY_WINDOW_UPDATE_SIZE 8 +#define NGX_SPDY_NV_NUM_SIZE 4 +#define NGX_SPDY_NV_NLEN_SIZE 4 +#define NGX_SPDY_NV_VLEN_SIZE 4 #define NGX_SPDY_SETTINGS_NUM_SIZE 4 -#define NGX_SPDY_SETTINGS_IDF_SIZE 4 +#define NGX_SPDY_SETTINGS_FID_SIZE 4 #define NGX_SPDY_SETTINGS_VAL_SIZE 4 #define NGX_SPDY_SETTINGS_PAIR_SIZE \ - (NGX_SPDY_SETTINGS_IDF_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE) + (NGX_SPDY_SETTINGS_FID_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE) #define NGX_SPDY_HIGHEST_PRIORITY 0 -#define NGX_SPDY_LOWEST_PRIORITY 3 +#define NGX_SPDY_LOWEST_PRIORITY 7 #define NGX_SPDY_FLAG_FIN 0x01 #define NGX_SPDY_FLAG_UNIDIRECTIONAL 0x02 @@ -81,6 +81,12 @@ struct ngx_http_spdy_connection_s { ngx_uint_t processing; + size_t send_window; + size_t recv_window; + size_t init_window; + + ngx_queue_t waiting; + u_char buffer[NGX_SPDY_STATE_BUFFER_SIZE]; size_t buffer_used; ngx_http_spdy_handler_pt handler; @@ -96,18 +102,19 @@ struct ngx_http_spdy_connection_s { ngx_http_spdy_stream_t **streams_index; ngx_http_spdy_out_frame_t *last_out; - ngx_http_spdy_stream_t *last_stream; + + ngx_queue_t posted; ngx_http_spdy_stream_t *stream; - ngx_uint_t headers; + ngx_uint_t entries; size_t length; u_char flags; ngx_uint_t last_sid; - unsigned blocked:2; - unsigned waiting:1; /* FIXME better name */ + unsigned blocked:1; + unsigned incomplete:1; }; @@ -116,15 +123,27 @@ struct ngx_http_spdy_stream_s { ngx_http_request_t *request; ngx_http_spdy_connection_t *connection; ngx_http_spdy_stream_t *index; - ngx_http_spdy_stream_t *next; ngx_uint_t header_buffers; - ngx_uint_t waiting; + ngx_uint_t queued; + + /* + * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the + * send_window to become negative, hence it's signed. + */ + ssize_t send_window; + size_t recv_window; + ngx_http_spdy_out_frame_t *free_frames; ngx_chain_t *free_data_headers; + ngx_chain_t *free_bufs; - unsigned priority:2; + ngx_queue_t queue; + + unsigned priority:3; unsigned handled:1; + unsigned blocked:1; + unsigned exhausted:1; unsigned in_closed:1; unsigned out_closed:1; unsigned skip_data:2; @@ -138,10 +157,8 @@ struct ngx_http_spdy_out_frame_s { ngx_int_t (*handler)(ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); - ngx_http_spdy_out_frame_t *free; - ngx_http_spdy_stream_t *stream; - size_t size; + size_t length; ngx_uint_t priority; unsigned blocked:1; @@ -157,6 +174,9 @@ ngx_http_spdy_queue_frame(ngx_http_spdy_connection_t *sc, for (out = &sc->last_out; *out; out = &(*out)->next) { + /* + * NB: higher values represent lower priorities. + */ if (frame->priority >= (*out)->priority) { break; } @@ -173,9 +193,9 @@ ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc, { ngx_http_spdy_out_frame_t **out; - for (out = &sc->last_out; *out && !(*out)->blocked; out = &(*out)->next) + for (out = &sc->last_out; *out; out = &(*out)->next) { - if (frame->priority >= (*out)->priority) { + if ((*out)->blocked) { break; } } @@ -186,7 +206,7 @@ ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc, void ngx_http_spdy_init(ngx_event_t *rev); -void ngx_http_spdy_request_headers_init(); +void ngx_http_spdy_request_headers_init(void); ngx_int_t ngx_http_spdy_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler); @@ -229,7 +249,10 @@ ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc); #define ngx_spdy_frame_write_flags_and_len(p, f, l) \ ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (l)) +#define ngx_spdy_frame_write_flags_and_id(p, f, i) \ + ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (i)) -#define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32 +#define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32 +#define ngx_spdy_frame_write_window ngx_spdy_frame_aligned_write_uint32 #endif /* _NGX_HTTP_SPDY_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c index 8fe46b2e954..559fb4aab9a 100644 --- a/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c @@ -14,14 +14,12 @@ #include <zlib.h> -#define NGX_SPDY_WRITE_BUFFERED NGX_HTTP_WRITE_BUFFERED - #define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1) #define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1) -#define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint16 -#define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint16 -#define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint16 +#define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint32 +#define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint32 +#define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint32 #define ngx_http_spdy_nv_write_name(p, h) \ ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1) @@ -29,12 +27,22 @@ #define ngx_http_spdy_nv_write_val(p, h) \ ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1) + +static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc, + ngx_chain_t *in, off_t limit); + static ngx_inline ngx_int_t ngx_http_spdy_filter_send( ngx_connection_t *fc, ngx_http_spdy_stream_t *stream); +static ngx_inline ngx_int_t ngx_http_spdy_flow_control( + ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream); +static void ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, + ngx_http_spdy_stream_t *stream); +static ngx_chain_t *ngx_http_spdy_filter_get_shadow( + ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size); static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame( - ngx_http_spdy_stream_t *stream, size_t len, ngx_uint_t flags, - ngx_chain_t *first, ngx_chain_t *last); + ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first, + ngx_chain_t *last); static ngx_int_t ngx_http_spdy_syn_frame_handler( ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); @@ -82,7 +90,6 @@ ngx_module_t ngx_http_spdy_filter_module = { static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t @@ -159,10 +166,12 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) } len = NGX_SPDY_NV_NUM_SIZE - + ngx_http_spdy_nv_nsize("version") + + ngx_http_spdy_nv_nsize(":version") + ngx_http_spdy_nv_vsize("HTTP/1.1") - + ngx_http_spdy_nv_nsize("status") - + ngx_http_spdy_nv_vsize("418"); + + ngx_http_spdy_nv_nsize(":status") + + (r->headers_out.status_line.len + ? NGX_SPDY_NV_VLEN_SIZE + r->headers_out.status_line.len + : ngx_http_spdy_nv_vsize("418")); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -300,12 +309,20 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) last = buf + NGX_SPDY_NV_NUM_SIZE; - last = ngx_http_spdy_nv_write_name(last, "version"); + last = ngx_http_spdy_nv_write_name(last, ":version"); last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1"); - last = ngx_http_spdy_nv_write_name(last, "status"); - last = ngx_spdy_frame_write_uint16(last, 3); - last = ngx_sprintf(last, "%03ui", r->headers_out.status); + last = ngx_http_spdy_nv_write_name(last, ":status"); + + if (r->headers_out.status_line.len) { + last = ngx_http_spdy_nv_write_vlen(last, + r->headers_out.status_line.len); + last = ngx_cpymem(last, r->headers_out.status_line.data, + r->headers_out.status_line.len); + } else { + last = ngx_http_spdy_nv_write_vlen(last, 3); + last = ngx_sprintf(last, "%03ui", r->headers_out.status); + } count = 2; @@ -444,17 +461,6 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) continue; } - if ((header[i].key.len == 6 - && ngx_strncasecmp(header[i].key.data, - (u_char *) "status", 6) == 0) - || (header[i].key.len == 7 - && ngx_strncasecmp(header[i].key.data, - (u_char *) "version", 7) == 0)) - { - header[i].hash = 0; - continue; - } - last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len); ngx_strlow(last, header[i].key.data, header[i].key.len); @@ -500,7 +506,7 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) count++; } - (void) ngx_spdy_frame_write_uint16(buf, count); + (void) ngx_http_spdy_nv_write_num(buf, count); stream = r->spdy_stream; sc = stream->connection; @@ -547,13 +553,14 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) r->header_size = len; + len -= NGX_SPDY_FRAME_HEADER_SIZE; + if (r->header_only) { b->last_buf = 1; - p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN, - len - NGX_SPDY_FRAME_HEADER_SIZE); + p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN, len); + } else { - p = ngx_spdy_frame_write_flags_and_len(p, 0, - len - NGX_SPDY_FRAME_HEADER_SIZE); + p = ngx_spdy_frame_write_flags_and_len(p, 0, len); } (void) ngx_spdy_frame_write_sid(p, stream->id); @@ -574,21 +581,18 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) frame->first = cl; frame->last = cl; frame->handler = ngx_http_spdy_syn_frame_handler; - frame->free = NULL; frame->stream = stream; - frame->size = len; + frame->length = len; frame->priority = stream->priority; frame->blocked = 1; frame->fin = r->header_only; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, - "spdy:%ui create SYN_REPLY frame %p: size:%uz", - stream->id, frame, frame->size); + "spdy:%ui create SYN_REPLY frame %p: len:%uz", + stream->id, frame, frame->length); ngx_http_spdy_queue_blocked_frame(sc, frame); - r->blocked++; - cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; @@ -597,109 +601,240 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) cln->handler = ngx_http_spdy_filter_cleanup; cln->data = stream; - stream->waiting = 1; + stream->queued = 1; + + c->send_chain = ngx_http_spdy_send_chain; + c->need_last_buf = 1; return ngx_http_spdy_filter_send(c, stream); } -static ngx_int_t -ngx_http_spdy_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +static ngx_chain_t * +ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) { - off_t size; - ngx_buf_t *b; - ngx_chain_t *cl, *ll, *out, **ln; - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_out_frame_t *frame; - + off_t size, offset; + size_t rest, frame_size; + ngx_chain_t *cl, *out, **ln; + ngx_http_request_t *r; + ngx_http_spdy_stream_t *stream; + ngx_http_spdy_loc_conf_t *slcf; + ngx_http_spdy_out_frame_t *frame; + ngx_http_spdy_connection_t *sc; + + r = fc->data; stream = r->spdy_stream; - if (stream == NULL) { - return ngx_http_next_body_filter(r, in); +#if (NGX_SUPPRESS_WARN) + size = 0; +#endif + + while (in) { + size = ngx_buf_size(in->buf); + + if (size || in->buf->last_buf) { + break; + } + + in = in->next; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy body filter \"%V?%V\"", &r->uri, &r->args); + if (in == NULL) { - if (in == NULL || r->header_only) { + if (stream->queued) { + fc->write->delayed = 1; + } else { + fc->buffered &= ~NGX_SPDY_BUFFERED; + } - if (stream->waiting) { - return NGX_AGAIN; + return NULL; + } + + sc = stream->connection; + + if (size && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) { + fc->write->delayed = 1; + return in; + } + + if (limit == 0 || limit > (off_t) sc->send_window) { + limit = sc->send_window; + } + + if (limit > stream->send_window) { + limit = (stream->send_window > 0) ? stream->send_window : 0; + } + + if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_CHAIN_ERROR; } - r->connection->buffered &= ~NGX_SPDY_WRITE_BUFFERED; + cl->buf = in->buf; + in->buf = cl->buf->shadow; - return NGX_OK; + offset = ngx_buf_in_memory(in->buf) + ? (cl->buf->pos - in->buf->pos) + : (cl->buf->file_pos - in->buf->file_pos); + + cl->next = stream->free_bufs; + stream->free_bufs = cl; + + } else { + offset = 0; } - size = 0; - ln = &out; - ll = in; +#if (NGX_SUPPRESS_WARN) + cl = NULL; +#endif + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_spdy_module); + + frame_size = (limit <= (off_t) slcf->chunk_size) ? (size_t) limit + : slcf->chunk_size; for ( ;; ) { - b = ll->buf; -#if 1 - if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "zero size buf in spdy body filter " - "t:%d r:%d f:%d %p %p-%p %p %O-%O", - b->temporary, - b->recycled, - b->in_file, - b->start, - b->pos, - b->last, - b->file, - b->file_pos, - b->file_last); - - ngx_debug_point(); - return NGX_ERROR; + ln = &out; + rest = frame_size; + + while ((off_t) rest >= size) { + + if (offset) { + cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, + offset, size); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + offset = 0; + + } else { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + cl->buf = in->buf; + } + + *ln = cl; + ln = &cl->next; + + rest -= (size_t) size; + in = in->next; + + if (in == NULL) { + frame_size -= rest; + rest = 0; + break; + } + + size = ngx_buf_size(in->buf); } -#endif - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; + + if (rest) { + cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, + offset, rest); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + cl->buf->flush = 0; + cl->buf->last_buf = 0; + + *ln = cl; + + offset += rest; + size -= rest; } - size += ngx_buf_size(b); - cl->buf = b; + frame = ngx_http_spdy_filter_get_data_frame(stream, frame_size, + out, cl); + if (frame == NULL) { + return NGX_CHAIN_ERROR; + } + + ngx_http_spdy_queue_frame(sc, frame); + + sc->send_window -= frame_size; + + stream->send_window -= frame_size; + stream->queued++; + + if (in == NULL) { + break; + } - *ln = cl; - ln = &cl->next; + limit -= frame_size; - if (ll->next == NULL) { + if (limit == 0) { break; } - ll = ll->next; + if (limit < (off_t) slcf->chunk_size) { + frame_size = (size_t) limit; + } } - if (size > NGX_SPDY_MAX_FRAME_SIZE) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "FIXME: chain too big in spdy filter: %O", size); - return NGX_ERROR; + if (offset) { + cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + in->buf = cl->buf; + ngx_free_chain(r->pool, cl); } - frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size, - b->last_buf, out, cl); - if (frame == NULL) { - return NGX_ERROR; + if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (in && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) { + fc->write->delayed = 1; } - ngx_http_spdy_queue_frame(stream->connection, frame); + return in; +} + + +static ngx_chain_t * +ngx_http_spdy_filter_get_shadow(ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, + off_t offset, off_t size) +{ + ngx_buf_t *chunk; + ngx_chain_t *cl; + + cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs); + if (cl == NULL) { + return NULL; + } + + chunk = cl->buf; + + ngx_memcpy(chunk, buf, sizeof(ngx_buf_t)); - stream->waiting++; + chunk->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow; + chunk->shadow = buf; - r->main->blocked++; + if (ngx_buf_in_memory(chunk)) { + chunk->pos += offset; + chunk->last = chunk->pos + size; + } + + if (chunk->in_file) { + chunk->file_pos += offset; + chunk->file_last = chunk->file_pos + size; + } - return ngx_http_spdy_filter_send(r->connection, stream); + return cl; } static ngx_http_spdy_out_frame_t * ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream, - size_t len, ngx_uint_t fin, ngx_chain_t *first, ngx_chain_t *last) + size_t len, ngx_chain_t *first, ngx_chain_t *last) { u_char *p; ngx_buf_t *buf; @@ -711,7 +846,7 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream, frame = stream->free_frames; if (frame) { - stream->free_frames = frame->free; + stream->free_frames = frame->next; } else { frame = ngx_palloc(stream->request->pool, @@ -721,62 +856,60 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream, } } + flags = last->buf->last_buf ? NGX_SPDY_FLAG_FIN : 0; + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, - "spdy:%ui create DATA frame %p: len:%uz fin:%ui", - stream->id, frame, len, fin); + "spdy:%ui create DATA frame %p: len:%uz flags:%ui", + stream->id, frame, len, flags); - if (len || fin) { + cl = ngx_chain_get_free_buf(stream->request->pool, + &stream->free_data_headers); + if (cl == NULL) { + return NULL; + } - flags = fin ? NGX_SPDY_FLAG_FIN : 0; + buf = cl->buf; - cl = ngx_chain_get_free_buf(stream->request->pool, - &stream->free_data_headers); - if (cl == NULL) { - return NULL; - } + if (buf->start) { + p = buf->start; + buf->pos = p; - buf = cl->buf; + p += NGX_SPDY_SID_SIZE; - if (buf->start) { - p = buf->start; - buf->pos = p; + (void) ngx_spdy_frame_write_flags_and_len(p, flags, len); - p += sizeof(uint32_t); + } else { + p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE); + if (p == NULL) { + return NULL; + } - (void) ngx_spdy_frame_write_flags_and_len(p, flags, len); + buf->pos = p; + buf->start = p; - } else { - p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE); - if (p == NULL) { - return NULL; - } + p = ngx_spdy_frame_write_sid(p, stream->id); + p = ngx_spdy_frame_write_flags_and_len(p, flags, len); - buf->pos = p; - buf->start = p; + buf->last = p; + buf->end = p; - p = ngx_spdy_frame_write_sid(p, stream->id); - p = ngx_spdy_frame_write_flags_and_len(p, flags, len); - - buf->last = p; - buf->end = p; + buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame; + buf->memory = 1; + } - buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_module; - buf->memory = 1; - } + cl->next = first; + first = cl; - cl->next = first; - first = cl; - } + last->buf->flush = 1; frame->first = first; frame->last = last; frame->handler = ngx_http_spdy_data_frame_handler; - frame->free = NULL; frame->stream = stream; - frame->size = NGX_SPDY_FRAME_HEADER_SIZE + len; + frame->length = len; frame->priority = stream->priority; frame->blocked = 0; - frame->fin = fin; + frame->fin = last->buf->last_buf; return frame; } @@ -785,23 +918,76 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream, static ngx_inline ngx_int_t ngx_http_spdy_filter_send(ngx_connection_t *fc, ngx_http_spdy_stream_t *stream) { + stream->blocked = 1; + if (ngx_http_spdy_send_output_queue(stream->connection) == NGX_ERROR) { fc->error = 1; return NGX_ERROR; } - if (stream->waiting) { - fc->buffered |= NGX_SPDY_WRITE_BUFFERED; + stream->blocked = 0; + + if (stream->queued) { + fc->buffered |= NGX_SPDY_BUFFERED; fc->write->delayed = 1; return NGX_AGAIN; } - fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED; + fc->buffered &= ~NGX_SPDY_BUFFERED; + + return NGX_OK; +} + + +static ngx_inline ngx_int_t +ngx_http_spdy_flow_control(ngx_http_spdy_connection_t *sc, + ngx_http_spdy_stream_t *stream) +{ + if (stream->send_window <= 0) { + stream->exhausted = 1; + return NGX_DECLINED; + } + + if (sc->send_window == 0) { + ngx_http_spdy_waiting_queue(sc, stream); + return NGX_DECLINED; + } return NGX_OK; } +static void +ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, + ngx_http_spdy_stream_t *stream) +{ + ngx_queue_t *q; + ngx_http_spdy_stream_t *s; + + if (stream->handled) { + return; + } + + stream->handled = 1; + + for (q = ngx_queue_last(&sc->waiting); + q != ngx_queue_sentinel(&sc->waiting); + q = ngx_queue_prev(q)) + { + s = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); + + /* + * NB: higher values represent lower priorities. + */ + if (stream->priority >= s->priority) { + break; + } + } + + ngx_queue_insert_after(q, &stream->queue); +} + + static ngx_int_t ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame) @@ -834,6 +1020,7 @@ static ngx_int_t ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame) { + ngx_buf_t *buf; ngx_chain_t *cl, *ln; ngx_http_spdy_stream_t *stream; @@ -841,7 +1028,7 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc, cl = frame->first; - if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_module) { + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame) { if (cl->buf->pos != cl->buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, @@ -864,6 +1051,18 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc, } for ( ;; ) { + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { + buf = cl->buf->shadow; + + if (ngx_buf_in_memory(buf)) { + buf->pos = cl->buf->pos; + } + + if (buf->in_file) { + buf->file_pos = cl->buf->file_pos; + } + } + if (ngx_buf_size(cl->buf) != 0) { if (cl != frame->first) { @@ -880,7 +1079,13 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc, ln = cl->next; - ngx_free_chain(stream->request->pool, cl); + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { + cl->next = stream->free_bufs; + stream->free_bufs = cl; + + } else { + ngx_free_chain(stream->request->pool, cl); + } if (cl == frame->last) { goto done; @@ -912,17 +1117,16 @@ ngx_http_spdy_handle_frame(ngx_http_spdy_stream_t *stream, r = stream->request; - r->connection->sent += frame->size; - r->blocked--; + r->connection->sent += NGX_SPDY_FRAME_HEADER_SIZE + frame->length; if (frame->fin) { stream->out_closed = 1; } - frame->free = stream->free_frames; + frame->next = stream->free_frames; stream->free_frames = frame; - stream->waiting--; + stream->queued--; } @@ -930,21 +1134,19 @@ static ngx_inline void ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream) { - ngx_connection_t *fc; - - fc = stream->request->connection; - - fc->write->delayed = 0; + ngx_event_t *wev; - if (stream->handled) { + if (stream->handled || stream->blocked || stream->exhausted) { return; } - if (sc->blocked == 2) { - stream->handled = 1; + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; - stream->next = sc->last_stream; - sc->last_stream = stream; + stream->handled = 1; + ngx_queue_insert_tail(&sc->posted, &stream->queue); } } @@ -954,16 +1156,22 @@ ngx_http_spdy_filter_cleanup(void *data) { ngx_http_spdy_stream_t *stream = data; - ngx_http_request_t *r; - ngx_http_spdy_out_frame_t *frame, **fn; + size_t delta; + ngx_http_spdy_out_frame_t *frame, **fn; + ngx_http_spdy_connection_t *sc; - if (stream->waiting == 0) { - return; + if (stream->handled) { + stream->handled = 0; + ngx_queue_remove(&stream->queue); } - r = stream->request; + if (stream->queued == 0) { + return; + } - fn = &stream->connection->last_out; + delta = 0; + sc = stream->connection; + fn = &sc->last_out; for ( ;; ) { frame = *fn; @@ -973,16 +1181,26 @@ ngx_http_spdy_filter_cleanup(void *data) } if (frame->stream == stream && !frame->blocked) { + *fn = frame->next; - stream->waiting--; - r->blocked--; + delta += frame->length; + + if (--stream->queued == 0) { + break; + } - *fn = frame->next; continue; } fn = &frame->next; } + + if (sc->send_window == 0 && delta && !ngx_queue_empty(&sc->waiting)) { + ngx_queue_add(&sc->posted, &sc->waiting); + ngx_queue_init(&sc->waiting); + } + + sc->send_window += delta; } @@ -992,8 +1210,5 @@ ngx_http_spdy_filter_init(ngx_conf_t *cf) ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_spdy_header_filter; - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_spdy_body_filter; - return NGX_OK; } diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy_module.c b/usr.sbin/nginx/src/http/ngx_http_spdy_module.c index 7f02a18ca0c..5178a36f239 100644 --- a/usr.sbin/nginx/src/http/ngx_http_spdy_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_spdy_module.c @@ -22,16 +22,19 @@ static ngx_int_t ngx_http_spdy_module_init(ngx_cycle_t *cycle); static void *ngx_http_spdy_create_main_conf(ngx_conf_t *cf); static char *ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf); - static void *ngx_http_spdy_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static void *ngx_http_spdy_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); static char *ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data); static ngx_conf_num_bounds_t ngx_http_spdy_headers_comp_bounds = { @@ -44,6 +47,8 @@ static ngx_conf_post_t ngx_http_spdy_pool_size_post = { ngx_http_spdy_pool_size }; static ngx_conf_post_t ngx_http_spdy_streams_index_mask_post = { ngx_http_spdy_streams_index_mask }; +static ngx_conf_post_t ngx_http_spdy_chunk_size_post = + { ngx_http_spdy_chunk_size }; static ngx_command_t ngx_http_spdy_commands[] = { @@ -97,6 +102,13 @@ static ngx_command_t ngx_http_spdy_commands[] = { offsetof(ngx_http_spdy_srv_conf_t, headers_comp), &ngx_http_spdy_headers_comp_bounds }, + { ngx_string("spdy_chunk_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_spdy_loc_conf_t, chunk_size), + &ngx_http_spdy_chunk_size_post }, + ngx_null_command }; @@ -111,8 +123,8 @@ static ngx_http_module_t ngx_http_spdy_module_ctx = { ngx_http_spdy_create_srv_conf, /* create server configuration */ ngx_http_spdy_merge_srv_conf, /* merge server configuration */ - NULL, /* create location configuration */ - NULL /* merge location configuration */ + ngx_http_spdy_create_loc_conf, /* create location configuration */ + ngx_http_spdy_merge_loc_conf /* merge location configuration */ }; @@ -168,11 +180,11 @@ ngx_http_spdy_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { if (r->spdy_stream) { - v->len = 1; + v->len = sizeof("3.1") - 1; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = (u_char *) "2"; + v->data = (u_char *) "3.1"; return NGX_OK; } @@ -239,9 +251,7 @@ ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_spdy_main_conf_t *smcf = conf; - if (smcf->recv_buffer_size == NGX_CONF_UNSET_SIZE) { - smcf->recv_buffer_size = 256 * 1024; - } + ngx_conf_init_size_value(smcf->recv_buffer_size, 256 * 1024); return NGX_CONF_OK; } @@ -296,6 +306,34 @@ ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } +static void * +ngx_http_spdy_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_spdy_loc_conf_t *slcf; + + slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_loc_conf_t)); + if (slcf == NULL) { + return NULL; + } + + slcf->chunk_size = NGX_CONF_UNSET_SIZE; + + return slcf; +} + + +static char * +ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_spdy_loc_conf_t *prev = parent; + ngx_http_spdy_loc_conf_t *conf = child; + + ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024); + + return NGX_CONF_OK; +} + + static char * ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, void *data) { @@ -349,3 +387,22 @@ ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } + + +static char * +ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the spdy chunk size cannot be zero"); + return NGX_CONF_ERROR; + } + + if (*sp > NGX_SPDY_MAX_FRAME_SIZE) { + *sp = NGX_SPDY_MAX_FRAME_SIZE; + } + + return NGX_CONF_OK; +} diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy_module.h b/usr.sbin/nginx/src/http/ngx_http_spdy_module.h index 97a7a13a6fc..5242322b3d6 100644 --- a/usr.sbin/nginx/src/http/ngx_http_spdy_module.h +++ b/usr.sbin/nginx/src/http/ngx_http_spdy_module.h @@ -30,6 +30,11 @@ typedef struct { } ngx_http_spdy_srv_conf_t; +typedef struct { + size_t chunk_size; +} ngx_http_spdy_loc_conf_t; + + extern ngx_module_t ngx_http_spdy_module; diff --git a/usr.sbin/nginx/src/http/ngx_http_special_response.c b/usr.sbin/nginx/src/http/ngx_http_special_response.c index 875c24d9c75..546400539ba 100644 --- a/usr.sbin/nginx/src/http/ngx_http_special_response.c +++ b/usr.sbin/nginx/src/http/ngx_http_special_response.c @@ -370,7 +370,7 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) ngx_http_core_loc_conf_t *clcf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http special response: %d, \"%V?%V\"", + "http special response: %i, \"%V?%V\"", error, &r->uri, &r->args); r->err_status = error; diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.c b/usr.sbin/nginx/src/http/ngx_http_upstream.c index d99d8545488..040bda10623 100644 --- a/usr.sbin/nginx/src/http/ngx_http_upstream.c +++ b/usr.sbin/nginx/src/http/ngx_http_upstream.c @@ -17,6 +17,8 @@ static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); #endif static void ngx_http_upstream_init_request(ngx_http_request_t *r); @@ -358,6 +360,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_cache_status, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_cache_last_modified"), NULL, + ngx_http_upstream_cache_last_modified, 0, + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + #endif { ngx_null_string, NULL, NULL, 0, 0, 0 } @@ -369,6 +375,7 @@ static ngx_http_upstream_next_t ngx_http_upstream_next_errors[] = { { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 }, { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 }, + { 403, NGX_HTTP_UPSTREAM_FT_HTTP_403 }, { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 }, { 0, 0 } }; @@ -605,7 +612,7 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) if (uscf->host.len == host->len && ((uscf->port == 0 && u->resolved->no_port) || uscf->port == u->resolved->port) - && ngx_memcmp(uscf->host.data, host->data, host->len) == 0) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) { goto found; } @@ -637,7 +644,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) } ctx->name = *host; - ctx->type = NGX_RESOLVE_A; ctx->handler = ngx_http_upstream_resolve_handler; ctx->data = r; ctx->timeout = clcf->resolver_timeout; @@ -709,7 +715,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->cache->header_start + 256 >= u->conf->buffer_size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V_buffer_size %uz is not enough for cache key, " - "it should increased at least to %uz", + "it should be increased to at least %uz", &u->conf->module, u->conf->buffer_size, ngx_align(r->cache->header_start + 256, 1024)); @@ -911,16 +917,18 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) #if (NGX_DEBUG) { - in_addr_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; ngx_uint_t i; + addr.data = text; + for (i = 0; i < ctx->naddrs; i++) { - addr = ntohl(ur->addrs[i]); + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "name was resolved to %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "name was resolved to %V", &addr); } } #endif @@ -1069,6 +1077,55 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, #endif +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) { + socklen_t len; + + ev->eof = 1; + c->error = 1; + + err = 0; + len = sizeof(ngx_err_t); + + /* + * BSDs and Linux return 0 and set a pending error in err + * Solaris returns -1 and sets errno + */ + + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) + == -1) + { + err = ngx_socket_errno; + } + + if (err) { + ev->error = 1; + } + + if (!u->cacheable && u->peer.connection) { + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "epoll_wait() reported that client prematurely closed " + "connection, so upstream connection is closed too"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "epoll_wait() reported that client prematurely closed " + "connection"); + + if (u->peer.connection == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + } + + return; + } + +#endif + n = recv(c->fd, buf, 1, MSG_PEEK); err = ngx_socket_errno; @@ -1180,7 +1237,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } - /* rc == NGX_OK || rc == NGX_AGAIN */ + /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */ c = u->peer.connection; @@ -1281,6 +1338,11 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, { ngx_int_t rc; + if (ngx_http_upstream_test_connect(c) != NGX_OK) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + if (ngx_ssl_create_connection(u->conf->ssl, c, NGX_SSL_BUFFER|NGX_SSL_CLIENT) != NGX_OK) @@ -1332,13 +1394,19 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; + c = r->connection; + ngx_http_upstream_send_request(r, u); + ngx_http_run_posted_requests(c); return; } + c = r->connection; + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + ngx_http_run_posted_requests(c); } #endif @@ -1471,22 +1539,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_add_timer(c->read, u->conf->read_timeout); -#if 1 if (c->read->ready) { - - /* post aio operation */ - - /* - * TODO comment - * although we can post aio operation just in the end - * of ngx_http_upstream_connect() CHECK IT !!! - * it's better to do here because we postpone header buffer allocation - */ - ngx_http_upstream_process_header(r, u); return; } -#endif u->write_event_handler = ngx_http_upstream_dummy_handler; @@ -1660,11 +1716,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) /* rc == NGX_OK */ - if (u->headers_in.status_n > NGX_HTTP_SPECIAL_RESPONSE) { - - if (r->subrequest_in_memory) { - u->buffer.last = u->buffer.pos; - } + if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { if (ngx_http_upstream_test_next(r, u) == NGX_OK) { return; @@ -1693,15 +1745,14 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) } if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } n = u->buffer.last - u->buffer.pos; if (n) { - u->buffer.last -= n; + u->buffer.last = u->buffer.pos; u->state->response_length += n; @@ -1709,11 +1760,11 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } + } - if (u->length == 0) { - ngx_http_upstream_finalize_request(r, u, 0); - return; - } + if (u->length == 0) { + ngx_http_upstream_finalize_request(r, u, 0); + return; } u->read_event_handler = ngx_http_upstream_process_body_in_memory; @@ -1762,6 +1813,56 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) #endif } +#if (NGX_HTTP_CACHE) + + if (status == NGX_HTTP_NOT_MODIFIED + && u->cache_status == NGX_HTTP_CACHE_EXPIRED + && u->conf->cache_revalidate) + { + time_t now, valid; + ngx_int_t rc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream not modified"); + + now = ngx_time(); + valid = r->cache->valid_sec; + + rc = u->reinit_request(r); + + if (rc != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, rc); + return NGX_OK; + } + + u->cache_status = NGX_HTTP_CACHE_REVALIDATED; + rc = ngx_http_upstream_cache_send(r, u); + + if (valid == 0) { + valid = r->cache->valid_sec; + } + + if (valid == 0) { + valid = ngx_http_file_cache_valid(u->conf->cache_valid, + u->headers_in.status_n); + if (valid) { + valid = now + valid; + } + } + + if (valid) { + r->cache->valid_sec = valid; + r->cache->date = now; + + ngx_http_file_cache_update_header(r); + } + + ngx_http_upstream_finalize_request(r, u, rc); + return NGX_OK; + } + +#endif + return NGX_DECLINED; } @@ -1876,7 +1977,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c) if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1) { - err = ngx_errno; + err = ngx_socket_errno; } if (err) { @@ -1893,7 +1994,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c) static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_str_t *uri, args; + ngx_str_t uri, args; ngx_uint_t i, flags; ngx_list_part_t *part; ngx_table_elt_t *h; @@ -1934,11 +2035,11 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) } } - uri = &u->headers_in.x_accel_redirect->value; + uri = u->headers_in.x_accel_redirect->value; ngx_str_null(&args); flags = NGX_HTTP_LOG_UNSAFE; - if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); return NGX_DONE; } @@ -1947,7 +2048,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) r->method = NGX_HTTP_GET; } - ngx_http_internal_redirect(r, uri, &args); + ngx_http_internal_redirect(r, &uri, &args); ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } @@ -2006,7 +2107,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) r->headers_out.content_length_n = u->headers_in.content_length_n; - u->length = u->headers_in.content_length_n; + u->length = -1; return NGX_OK; } @@ -2030,7 +2131,7 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, if (rev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } @@ -2106,6 +2207,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } + u->header_sent = 1; + if (u->upgrade) { ngx_http_upstream_upgrade(r, u); return; @@ -2132,8 +2235,6 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) } } - u->header_sent = 1; - if (r->request_body && r->request_body->temp_file) { ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd); r->request_body->temp_file->file.fd = NGX_INVALID_FILE; @@ -2156,7 +2257,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) r->limit_rate = 0; if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2170,7 +2271,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2185,7 +2286,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2196,7 +2297,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->buffer.last = u->buffer.start; if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2220,7 +2321,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) switch (ngx_http_test_predicates(r, u->conf->no_cache)) { case NGX_ERROR: - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; case NGX_DECLINED: @@ -2236,7 +2337,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) r->cache->file_cache = u->conf->cache->data; if (ngx_http_file_cache_create(r) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2297,7 +2398,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (p->temp_file == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2320,7 +2421,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->preread_bufs = ngx_alloc_chain_link(r->pool); if (p->preread_bufs == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2334,7 +2435,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->buf_to_file = ngx_calloc_buf(r->pool); if (p->buf_to_file == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2382,7 +2483,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (u->input_filter_init && u->input_filter_init(p->input_ctx) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2424,7 +2525,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2440,7 +2541,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_connection_error(u->peer.connection, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2449,7 +2550,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) } if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2524,7 +2625,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (upstream->read->timedout || upstream->write->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } @@ -2547,7 +2648,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (b->start == NULL) { b->start = ngx_palloc(r->pool, u->conf->buffer_size); if (b->start == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2570,7 +2671,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, n = dst->send(dst, b->pos, size); if (n == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2625,7 +2726,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (ngx_handle_write_event(upstream->write, u->conf->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2637,7 +2738,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, } if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2651,12 +2752,12 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (ngx_handle_write_event(downstream->write, clcf->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2711,7 +2812,7 @@ ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r, if (c->read->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } @@ -2747,7 +2848,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, rc = ngx_http_output_filter(r, u->out_bufs); if (rc == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2758,13 +2859,27 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, if (u->busy_bufs == NULL) { if (u->length == 0 - || upstream->read->eof - || upstream->read->error) + || (upstream->read->eof && u->length == -1)) { ngx_http_upstream_finalize_request(r, u, 0); return; } + if (upstream->read->eof) { + ngx_log_error(NGX_LOG_ERR, upstream->log, 0, + "upstream prematurely closed connection"); + + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_BAD_GATEWAY); + return; + } + + if (upstream->read->error) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_BAD_GATEWAY); + return; + } + b->pos = b->start; b->last = b->start; } @@ -2784,7 +2899,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2803,7 +2918,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, if (ngx_handle_write_event(downstream->write, clcf->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2816,7 +2931,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, } if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2907,14 +3022,14 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r) ngx_add_timer(wev, p->send_timeout); if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); } return; } if (ngx_event_pipe(p, wev->write) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2932,14 +3047,14 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r) "http downstream delayed"); if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); } return; } if (ngx_event_pipe(p, 1) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2967,7 +3082,7 @@ ngx_http_upstream_process_upstream(ngx_http_request_t *r, } else { if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2992,11 +3107,12 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) if (p->upstream_eof || p->upstream_done) { - tf = u->pipe->temp_file; + tf = p->temp_file; if (u->headers_in.status_n == NGX_HTTP_OK + && (p->upstream_done || p->length == -1) && (u->headers_in.content_length_n == -1 - || (u->headers_in.content_length_n == tf->offset))) + || u->headers_in.content_length_n == tf->offset)) { ngx_http_upstream_store(r, u); u->store = 0; @@ -3009,15 +3125,16 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) if (u->cacheable) { if (p->upstream_done) { - ngx_http_file_cache_update(r, u->pipe->temp_file); + ngx_http_file_cache_update(r, p->temp_file); } else if (p->upstream_eof) { - tf = u->pipe->temp_file; + tf = p->temp_file; - if (u->headers_in.content_length_n == -1 - || u->headers_in.content_length_n - == tf->offset - (off_t) r->cache->body_start) + if (p->length == -1 + && (u->headers_in.content_length_n == -1 + || u->headers_in.content_length_n + == tf->offset - (off_t) r->cache->body_start)) { ngx_http_file_cache_update(r, tf); @@ -3026,7 +3143,7 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) } } else if (p->upstream_error) { - ngx_http_file_cache_free(r->cache, u->pipe->temp_file); + ngx_http_file_cache_free(r->cache, p->temp_file); } } @@ -3035,10 +3152,20 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) if (p->upstream_done || p->upstream_eof || p->upstream_error) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream exit: %p", p->out); -#if 0 - ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); -#endif - ngx_http_upstream_finalize_request(r, u, 0); + + if (p->upstream_done + || (p->upstream_eof && p->length == -1)) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (p->upstream_eof) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream prematurely closed connection"); + } + + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); return; } } @@ -3048,7 +3175,7 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) "http upstream downstream error"); if (!u->cacheable && !u->store && u->peer.connection) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); } } } @@ -3148,14 +3275,13 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http next upstream, %xi", ft_type); -#if 0 - ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); -#endif - if (u->peer.sockaddr) { - if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { + if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 + || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) + { state = NGX_PEER_NEXT; + } else { state = NGX_PEER_FAILED; } @@ -3187,6 +3313,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; + case NGX_HTTP_UPSTREAM_FT_HTTP_403: + status = NGX_HTTP_FORBIDDEN; + break; + case NGX_HTTP_UPSTREAM_FT_HTTP_404: status = NGX_HTTP_NOT_FOUND; break; @@ -3258,13 +3388,6 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, u->peer.connection = NULL; } -#if 0 - if (u->conf->busy_lock && !u->busy_locked) { - ngx_http_upstream_busy_lock(p); - return; - } -#endif - ngx_http_upstream_connect(r, u); } @@ -3285,6 +3408,7 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc) { + ngx_uint_t flush; ngx_time_t *tp; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -3391,11 +3515,10 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, #endif - if (u->header_sent - && rc != NGX_HTTP_REQUEST_TIME_OUT - && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) + if (r->subrequest_in_memory + && u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { - rc = 0; + u->buffer.last = u->buffer.pos; } if (rc == NGX_DECLINED) { @@ -3404,14 +3527,32 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, r->connection->log->action = "sending to client"; - if (rc == 0 - && !r->header_only -#if (NGX_HTTP_CACHE) - && !r->cached -#endif - ) + if (!u->header_sent + || rc == NGX_HTTP_REQUEST_TIME_OUT + || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) { + ngx_http_finalize_request(r, rc); + return; + } + + flush = 0; + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + rc = NGX_ERROR; + flush = 1; + } + + if (r->header_only) { + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == 0) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); + + } else if (flush) { + r->keepalive = 0; + rc = ngx_http_send_special(r, NGX_HTTP_FLUSH); } ngx_http_finalize_request(r, rc); @@ -3513,7 +3654,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, return NGX_OK; } - if (r->cache->valid_sec != 0) { + if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) { return NGX_OK; } @@ -4042,7 +4183,12 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, if (r->cached) { r->allow_ranges = 1; return NGX_OK; + } + if (r->upstream->cacheable) { + r->allow_ranges = 1; + r->single_range = 1; + return NGX_OK; } #endif @@ -4274,7 +4420,7 @@ ngx_http_upstream_response_time_variable(ngx_http_request_t *r, ms = (ngx_msec_int_t) (state[i].response_sec * 1000 + state[i].response_msec); ms = ngx_max(ms, 0); - p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000); + p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); } else { *p++ = '-'; @@ -4406,6 +4552,36 @@ ngx_http_upstream_cache_status(ngx_http_request_t *r, return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + if (r->upstream == NULL + || !r->upstream->conf->cache_revalidate + || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED + || r->cache->last_modified == -1) + { + v->not_found = 1; + return NGX_OK; + } + + p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_http_time(p, r->cache->last_modified) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + #endif @@ -4615,7 +4791,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - if (ngx_strncmp(value[i].data, "backup", 6) == 0) { + if (ngx_strcmp(value[i].data, "backup") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) { goto invalid; @@ -4626,7 +4802,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - if (ngx_strncmp(value[i].data, "down", 4) == 0) { + if (ngx_strcmp(value[i].data, "down") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) { goto invalid; diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.h b/usr.sbin/nginx/src/http/ngx_http_upstream.h index 29ebf9bd92d..9f96c50f309 100644 --- a/usr.sbin/nginx/src/http/ngx_http_upstream.h +++ b/usr.sbin/nginx/src/http/ngx_http_upstream.h @@ -24,10 +24,11 @@ #define NGX_HTTP_UPSTREAM_FT_HTTP_502 0x00000020 #define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040 #define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080 -#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000100 -#define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000200 -#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000400 -#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000800 +#define NGX_HTTP_UPSTREAM_FT_HTTP_403 0x00000100 +#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000200 +#define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000400 +#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000800 +#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00001000 #define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000 #define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000 @@ -35,6 +36,7 @@ |NGX_HTTP_UPSTREAM_FT_HTTP_502 \ |NGX_HTTP_UPSTREAM_FT_HTTP_503 \ |NGX_HTTP_UPSTREAM_FT_HTTP_504 \ + |NGX_HTTP_UPSTREAM_FT_HTTP_403 \ |NGX_HTTP_UPSTREAM_FT_HTTP_404) #define NGX_HTTP_UPSTREAM_INVALID_HEADER 40 @@ -176,6 +178,8 @@ typedef struct { ngx_flag_t cache_lock; ngx_msec_t cache_lock_timeout; + ngx_flag_t cache_revalidate; + ngx_array_t *cache_valid; ngx_array_t *cache_bypass; ngx_array_t *no_cache; @@ -252,7 +256,7 @@ typedef struct { ngx_uint_t no_port; /* unsigned no_port:1 */ ngx_uint_t naddrs; - in_addr_t *addrs; + ngx_addr_t *addrs; struct sockaddr *sockaddr; socklen_t socklen; diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c b/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c index e0c6c58c747..85ff5581baf 100644 --- a/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c +++ b/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c @@ -71,20 +71,20 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n = 0; for (i = 0; i < us->servers->nelts; i++) { - for (j = 0; j < server[i].naddrs; j++) { - if (server[i].backup) { - continue; - } + if (server[i].backup) { + continue; + } + for (j = 0; j < server[i].naddrs; j++) { peers->peer[n].sockaddr = server[i].addrs[j].sockaddr; peers->peer[n].socklen = server[i].addrs[j].socklen; peers->peer[n].name = server[i].addrs[j].name; - peers->peer[n].max_fails = server[i].max_fails; - peers->peer[n].fail_timeout = server[i].fail_timeout; - peers->peer[n].down = server[i].down; peers->peer[n].weight = server[i].weight; peers->peer[n].effective_weight = server[i].weight; peers->peer[n].current_weight = 0; + peers->peer[n].max_fails = server[i].max_fails; + peers->peer[n].fail_timeout = server[i].fail_timeout; + peers->peer[n].down = server[i].down; n++; } } @@ -125,11 +125,11 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n = 0; for (i = 0; i < us->servers->nelts; i++) { - for (j = 0; j < server[i].naddrs; j++) { - if (!server[i].backup) { - continue; - } + if (!server[i].backup) { + continue; + } + for (j = 0; j < server[i].naddrs; j++) { backup->peer[n].sockaddr = server[i].addrs[j].sockaddr; backup->peer[n].socklen = server[i].addrs[j].socklen; backup->peer[n].name = server[i].addrs[j].name; @@ -266,8 +266,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, { u_char *p; size_t len; + socklen_t socklen; ngx_uint_t i, n; - struct sockaddr_in *sin; + struct sockaddr *sockaddr; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peer_data_t *rrp; @@ -306,27 +307,34 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, for (i = 0; i < ur->naddrs; i++) { - len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1; + socklen = ur->addrs[i].socklen; - p = ngx_pnalloc(r->pool, len); - if (p == NULL) { + sockaddr = ngx_palloc(r->pool, socklen); + if (sockaddr == NULL) { return NGX_ERROR; } - len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN); - len = ngx_sprintf(&p[len], ":%d", ur->port) - p; + ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen); - sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { + switch (sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port); + break; +#endif + default: /* AF_INET */ + ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port); + } + + p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN); + if (p == NULL) { return NGX_ERROR; } - sin->sin_family = AF_INET; - sin->sin_port = htons(ur->port); - sin->sin_addr.s_addr = ur->addrs[i]; + len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); - peers->peer[i].sockaddr = (struct sockaddr *) sin; - peers->peer[i].socklen = sizeof(struct sockaddr_in); + peers->peer[i].sockaddr = sockaddr; + peers->peer[i].socklen = socklen; peers->peer[i].name.len = len; peers->peer[i].name.data = p; peers->peer[i].weight = 1; diff --git a/usr.sbin/nginx/src/http/ngx_http_variables.c b/usr.sbin/nginx/src/http/ngx_http_variables.c index 7a7d15c1e0d..f618622976f 100644 --- a/usr.sbin/nginx/src/http/ngx_http_variables.c +++ b/usr.sbin/nginx/src/http/ngx_http_variables.c @@ -54,6 +54,8 @@ static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, @@ -183,6 +185,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 }, + { ngx_string("proxy_protocol_addr"), NULL, + ngx_http_variable_proxy_protocol_addr, 0, 0, 0 }, + { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 }, { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 }, @@ -487,7 +492,7 @@ ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index) if (cmcf->variables.nelts <= index) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "unknown variable index: %d", index); + "unknown variable index: %ui", index); return NULL; } @@ -1185,6 +1190,12 @@ ngx_http_variable_remote_port(ngx_http_request_t *r, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + port = 0; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->sockaddr; port = ntohs(sin->sin_port); @@ -1200,6 +1211,20 @@ ngx_http_variable_remote_port(ngx_http_request_t *r, static ngx_int_t +ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + v->len = r->connection->proxy_protocol_addr.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->connection->proxy_protocol_addr.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { @@ -1263,6 +1288,12 @@ ngx_http_variable_server_port(ngx_http_request_t *r, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + port = 0; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->local_sockaddr; port = ntohs(sin->sin_port); @@ -1374,7 +1405,9 @@ ngx_http_variable_document_root(ngx_http_request_t *r, return NGX_ERROR; } - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) { + if (ngx_get_full_name(r->pool, (ngx_str_t *) &ngx_cycle->prefix, &path) + != NGX_OK) + { return NGX_ERROR; } @@ -1416,7 +1449,9 @@ ngx_http_variable_realpath_root(ngx_http_request_t *r, path.data[path.len - 1] = '\0'; - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) { + if (ngx_get_full_name(r->pool, (ngx_str_t *) &ngx_cycle->prefix, &path) + != NGX_OK) + { return NGX_ERROR; } } @@ -1740,8 +1775,7 @@ ngx_http_variable_sent_last_modified(ngx_http_request_t *r, } if (r->headers_out.last_modified_time >= 0) { - p = ngx_pnalloc(r->pool, - sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1); + p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1); if (p == NULL) { return NGX_ERROR; } @@ -2257,6 +2291,7 @@ ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) re->regex = rc->regex; re->ncaptures = rc->captures; + re->name = rc->pattern; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures); @@ -2274,7 +2309,6 @@ ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) re->variables = rv; re->nvariables = n; - re->name = rc->pattern; size = rc->name_size; p = rc->names; diff --git a/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c index 5594c7faaad..83cb1fa1e98 100644 --- a/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c +++ b/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c @@ -184,7 +184,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_AGAIN; } - if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) { + if (size == 0 + && !(c->buffered & NGX_LOWLEVEL_BUFFERED) + && !(last && c->need_last_buf)) + { if (last || flush) { for (cl = r->out; cl; /* void */) { ln = cl; @@ -207,8 +210,12 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (r->limit_rate) { + if (r->limit_rate_after == 0) { + r->limit_rate_after = clcf->limit_rate_after; + } + limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) - - (c->sent - clcf->limit_rate_after); + - (c->sent - r->limit_rate_after); if (limit <= 0) { c->write->delayed = 1; @@ -249,14 +256,14 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) nsent = c->sent; - if (clcf->limit_rate_after) { + if (r->limit_rate_after) { - sent -= clcf->limit_rate_after; + sent -= r->limit_rate_after; if (sent < 0) { sent = 0; } - nsent -= clcf->limit_rate_after; + nsent -= r->limit_rate_after; if (nsent < 0) { nsent = 0; } diff --git a/usr.sbin/nginx/src/mail/ngx_mail.c b/usr.sbin/nginx/src/mail/ngx_mail.c index 3812e15179e..350d2cdf90b 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail.c +++ b/usr.sbin/nginx/src/mail/ngx_mail.c @@ -465,7 +465,8 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, addrs[i].conf.ssl = addr[i].ssl; #endif - len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); if (p == NULL) { @@ -513,7 +514,8 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, addrs6[i].conf.ssl = addr[i].ssl; #endif - len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); if (p == NULL) { diff --git a/usr.sbin/nginx/src/mail/ngx_mail.h b/usr.sbin/nginx/src/mail/ngx_mail.h index ccdfb8c6f10..dc39f1e1375 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail.h +++ b/usr.sbin/nginx/src/mail/ngx_mail.h @@ -234,6 +234,8 @@ typedef struct { ngx_str_t smtp_from; ngx_str_t smtp_to; + ngx_str_t cmd; + ngx_uint_t command; ngx_array_t args; diff --git a/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c b/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c index 2e9b9f24da8..8094bbc5cc7 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c @@ -699,7 +699,6 @@ ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, p = ngx_pnalloc(s->connection->pool, ctx->err.len); if (p == NULL) { - ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; diff --git a/usr.sbin/nginx/src/mail/ngx_mail_core_module.c b/usr.sbin/nginx/src/mail/ngx_mail_core_module.c index be8673c299f..4ee7c8dc3d7 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_core_module.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_core_module.c @@ -439,7 +439,8 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->bind = 1; } else { - len = ngx_sock_ntop(sa, buf, NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(sa, ls->socklen, buf, + NGX_SOCKADDR_STRLEN, 1); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "ipv6only is not supported " diff --git a/usr.sbin/nginx/src/mail/ngx_mail_handler.c b/usr.sbin/nginx/src/mail/ngx_mail_handler.c index ae955f9c6ae..47ddb0dcf05 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_handler.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_handler.c @@ -127,7 +127,7 @@ ngx_mail_init_connection(ngx_connection_t *c) c->data = s; s->connection = c; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V", + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %V connected to %V", c->number, &c->addr_text, s->addr_text); ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t)); @@ -559,8 +559,13 @@ ngx_mail_send(ngx_event_t *wev) n = c->send(c, s->out.data, s->out.len); if (n > 0) { + s->out.data += n; s->out.len -= n; + if (s->out.len != 0) { + goto again; + } + if (wev->timer_set) { ngx_del_timer(wev); } @@ -584,6 +589,8 @@ ngx_mail_send(ngx_event_t *wev) /* n == NGX_AGAIN */ +again: + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); ngx_add_timer(c->write, cscf->timeout); @@ -620,7 +627,9 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_ERROR; } - return NGX_AGAIN; + if (s->buffer->pos == s->buffer->last) { + return NGX_AGAIN; + } } cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); @@ -661,8 +670,12 @@ void ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c) { s->args.nelts = 0; - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } + s->state = 0; if (c->read->timer_set) { diff --git a/usr.sbin/nginx/src/mail/ngx_mail_parse.c b/usr.sbin/nginx/src/mail/ngx_mail_parse.c index eb16d5b4fe9..b158f5a0fba 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_parse.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_parse.c @@ -626,6 +626,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) ngx_str_t *arg; enum { sw_start = 0, + sw_command, + sw_invalid, sw_spaces_before_argument, sw_argument, sw_almost_done @@ -640,8 +642,14 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) /* SMTP command */ case sw_start: + s->cmd_start = p; + state = sw_command; + + /* fall through */ + + case sw_command: if (ch == ' ' || ch == CR || ch == LF) { - c = s->buffer->start; + c = s->cmd_start; if (p - c == 4) { @@ -719,6 +727,9 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -738,6 +749,9 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) break; + case sw_invalid: + goto invalid; + case sw_spaces_before_argument: switch (ch) { case ' ': @@ -824,9 +838,21 @@ done: invalid: - s->state = sw_start; + s->state = sw_invalid; s->arg_start = NULL; + /* skip invalid command till LF */ + + for (p = s->buffer->pos; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + p++; + break; + } + } + + s->buffer->pos = p; + return NGX_MAIL_PARSE_INVALID_COMMAND; } @@ -842,6 +868,10 @@ ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c) } #endif + if (s->args.nelts == 0) { + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + arg = s->args.elts; if (arg[0].len == 5) { diff --git a/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c b/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c index 4ea608ceafa..41cbcf6e312 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c @@ -542,17 +542,40 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) CRLF) - 1 + s->connection->addr_text.len + s->login.len + s->host.len; +#if (NGX_HAVE_INET6) + if (s->connection->sockaddr->sa_family == AF_INET6) { + line.len += sizeof("IPV6:") - 1; + } +#endif + line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } - line.len = ngx_sprintf(line.data, - "XCLIENT ADDR=%V%s%V NAME=%V" CRLF, - &s->connection->addr_text, - (s->login.len ? " LOGIN=" : ""), &s->login, &s->host) - - line.data; + p = ngx_cpymem(line.data, "XCLIENT ADDR=", sizeof("XCLIENT ADDR=") - 1); + +#if (NGX_HAVE_INET6) + if (s->connection->sockaddr->sa_family == AF_INET6) { + p = ngx_cpymem(p, "IPV6:", sizeof("IPV6:") - 1); + } +#endif + + p = ngx_copy(p, s->connection->addr_text.data, + s->connection->addr_text.len); + + if (s->login.len) { + p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1); + p = ngx_copy(p, s->login.data, s->login.len); + } + + p = ngx_cpymem(p, " NAME=", sizeof(" NAME=") - 1); + p = ngx_copy(p, s->host.data, s->host.len); + + *p++ = CR; *p++ = LF; + + line.len = p - line.data; if (s->smtp_helo.len) { s->mail_state = ngx_smtp_xclient_helo; @@ -657,7 +680,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - ngx_mail_proxy_handler(s->connection->write); + if (s->buffer->pos == s->buffer->last) { + ngx_mail_proxy_handler(s->connection->write); + + } else { + ngx_mail_proxy_handler(c->write); + } return; @@ -702,7 +730,7 @@ ngx_mail_proxy_dummy_handler(ngx_event_t *wev) static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state) { - u_char *p; + u_char *p, *m; ssize_t n; ngx_buf_t *b; ngx_mail_proxy_conf_t *pcf; @@ -779,6 +807,25 @@ ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state) break; default: /* NGX_MAIL_SMTP_PROTOCOL */ + + if (p[3] == '-') { + /* multiline reply, check if we got last line */ + + m = b->last - (sizeof(CRLF "200" CRLF) - 1); + + while (m > p) { + if (m[0] == CR && m[1] == LF) { + break; + } + + m--; + } + + if (m <= p || m[5] == '-') { + return NGX_AGAIN; + } + } + switch (state) { case ngx_smtp_start: diff --git a/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c b/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c index 21714239fcc..52fe475234a 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c @@ -55,7 +55,6 @@ static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]"); void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) { - struct sockaddr_in *sin; ngx_resolver_ctx_t *ctx; ngx_mail_core_srv_conf_t *cscf; @@ -67,11 +66,13 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) return; } - if (c->sockaddr->sa_family != AF_INET) { +#if (NGX_HAVE_UNIX_DOMAIN) + if (c->sockaddr->sa_family == AF_UNIX) { s->host = smtp_tempunavail; ngx_mail_smtp_greeting(s, c); return; } +#endif c->log->action = "in resolving client address"; @@ -81,11 +82,8 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) return; } - /* AF_INET only */ - - sin = (struct sockaddr_in *) c->sockaddr; - - ctx->addr = sin->sin_addr.s_addr; + ctx->addr.sockaddr = c->sockaddr; + ctx->addr.socklen = c->socklen; ctx->handler = ngx_mail_smtp_resolve_addr_handler; ctx->data = s; ctx->timeout = cscf->resolver_timeout; @@ -167,7 +165,6 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev) } ctx->name = s->host; - ctx->type = NGX_RESOLVE_A; ctx->handler = ngx_mail_smtp_resolve_name_handler; ctx->data = s; ctx->timeout = cscf->resolver_timeout; @@ -181,10 +178,8 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev) static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx) { - in_addr_t addr; ngx_uint_t i; ngx_connection_t *c; - struct sockaddr_in *sin; ngx_mail_session_t *s; s = ctx->data; @@ -205,22 +200,29 @@ ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx) } else { - /* AF_INET only */ +#if (NGX_DEBUG) + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; - sin = (struct sockaddr_in *) c->sockaddr; + addr.data = text; for (i = 0; i < ctx->naddrs; i++) { + addr.len = ngx_sock_ntop(ctx->addrs[i].sockaddr, + ctx->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); - addr = ctx->addrs[i]; - - ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, - "name was resolved to %ud.%ud.%ud.%ud", - (ntohl(addr) >> 24) & 0xff, - (ntohl(addr) >> 16) & 0xff, - (ntohl(addr) >> 8) & 0xff, - ntohl(addr) & 0xff); + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "name was resolved to %V", &addr); + } + } +#endif - if (addr == sin->sin_addr.s_addr) { + for (i = 0; i < ctx->naddrs; i++) { + if (ngx_cmp_sockaddr(ctx->addrs[i].sockaddr, ctx->addrs[i].socklen, + c->sockaddr, c->socklen, 0) + == NGX_OK) + { goto found; } } @@ -321,6 +323,7 @@ ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev) } ngx_str_set(&s->out, smtp_invalid_pipelining); + s->quit = 1; } ngx_mail_send(c->write); @@ -485,6 +488,10 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) } } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -504,11 +511,14 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) case NGX_OK: s->args.nelts = 0; - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } if (s->state) { - s->arg_start = s->buffer->start; + s->arg_start = s->buffer->pos; } ngx_mail_send(c->write); @@ -651,9 +661,7 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c) static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) { - u_char ch; - ngx_str_t l; - ngx_uint_t i; + ngx_str_t *arg, cmd; ngx_mail_smtp_srv_conf_t *sscf; sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); @@ -671,37 +679,20 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_OK; } - l.len = s->buffer->last - s->buffer->start; - l.data = s->buffer->start; - - for (i = 0; i < l.len; i++) { - ch = l.data[i]; - - if (ch != CR && ch != LF) { - continue; - } - - l.data[i] = ' '; - } - - while (i) { - if (l.data[i - 1] != ' ') { - break; - } - - i--; - } + arg = s->args.elts; + arg += s->args.nelts - 1; - l.len = i; + cmd.len = arg->data + arg->len - s->cmd.data; + cmd.data = s->cmd.data; - s->smtp_from.len = l.len; + s->smtp_from.len = cmd.len; - s->smtp_from.data = ngx_pnalloc(c->pool, l.len); + s->smtp_from.data = ngx_pnalloc(c->pool, cmd.len); if (s->smtp_from.data == NULL) { return NGX_ERROR; } - ngx_memcpy(s->smtp_from.data, l.data, l.len); + ngx_memcpy(s->smtp_from.data, cmd.data, cmd.len); ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp mail from:\"%V\"", &s->smtp_from); @@ -715,46 +706,27 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) static ngx_int_t ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c) { - u_char ch; - ngx_str_t l; - ngx_uint_t i; + ngx_str_t *arg, cmd; if (s->smtp_from.len == 0) { ngx_str_set(&s->out, smtp_bad_sequence); return NGX_OK; } - l.len = s->buffer->last - s->buffer->start; - l.data = s->buffer->start; - - for (i = 0; i < l.len; i++) { - ch = l.data[i]; - - if (ch != CR && ch != LF) { - continue; - } - - l.data[i] = ' '; - } - - while (i) { - if (l.data[i - 1] != ' ') { - break; - } - - i--; - } + arg = s->args.elts; + arg += s->args.nelts - 1; - l.len = i; + cmd.len = arg->data + arg->len - s->cmd.data; + cmd.data = s->cmd.data; - s->smtp_to.len = l.len; + s->smtp_to.len = cmd.len; - s->smtp_to.data = ngx_pnalloc(c->pool, l.len); + s->smtp_to.data = ngx_pnalloc(c->pool, cmd.len); if (s->smtp_to.data == NULL) { return NGX_ERROR; } - ngx_memcpy(s->smtp_to.data, l.data, l.len); + ngx_memcpy(s->smtp_to.data, cmd.data, cmd.len); ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp rcpt to:\"%V\"", &s->smtp_to); diff --git a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c index 60e7a9a883a..fe88f48e43b 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c +++ b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c @@ -25,7 +25,7 @@ static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_conf_enum_t ngx_http_starttls_state[] = { +static ngx_conf_enum_t ngx_mail_starttls_state[] = { { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, { ngx_string("on"), NGX_MAIL_STARTTLS_ON }, { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY }, @@ -58,7 +58,7 @@ static ngx_command_t ngx_mail_ssl_commands[] = { ngx_mail_ssl_starttls, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, starttls), - ngx_http_starttls_state }, + ngx_mail_starttls_state }, { ngx_string("ssl_certificate"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, @@ -116,6 +116,20 @@ static ngx_command_t ngx_mail_ssl_commands[] = { 0, NULL }, + { ngx_string("ssl_session_tickets"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, session_tickets), + NULL }, + + { ngx_string("ssl_session_ticket_key"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_array_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, session_ticket_keys), + NULL }, + { ngx_string("ssl_session_timeout"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_sec_slot, @@ -184,6 +198,8 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->builtin_session_cache = NGX_CONF_UNSET; scf->session_timeout = NGX_CONF_UNSET; + scf->session_tickets = NGX_CONF_UNSET; + scf->session_ticket_keys = NGX_CONF_UNSET_PTR; return scf; } @@ -292,15 +308,14 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->ciphers.len) { - if (SSL_CTX_set_cipher_list(conf->ssl.ctx, - (const char *) conf->ciphers.data) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &conf->ciphers); - } + if (SSL_CTX_set_cipher_list(conf->ssl.ctx, + (const char *) conf->ciphers.data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &conf->ciphers); + return NGX_CONF_ERROR; } if (conf->prefer_server_ciphers) { @@ -313,6 +328,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) { + return NGX_CONF_ERROR; + } + ngx_conf_merge_value(conf->builtin_session_cache, prev->builtin_session_cache, NGX_SSL_NONE_SCACHE); @@ -328,6 +347,24 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + ngx_conf_merge_value(conf->session_tickets, + prev->session_tickets, 1); + +#ifdef SSL_OP_NO_TICKET + if (!conf->session_tickets) { + SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET); + } +#endif + + ngx_conf_merge_ptr_value(conf->session_ticket_keys, + prev->session_ticket_keys, NULL); + + if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } diff --git a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h index 7f59b38ae39..bef0e515a02 100644 --- a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h +++ b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h @@ -41,6 +41,9 @@ typedef struct { ngx_shm_zone_t *shm_zone; + ngx_flag_t session_tickets; + ngx_array_t *session_ticket_keys; + u_char *file; ngx_uint_t line; } ngx_mail_ssl_conf_t; diff --git a/usr.sbin/nginx/src/os/unix/ngx_channel.c b/usr.sbin/nginx/src/os/unix/ngx_channel.c index 29c69da4065..8e9069660f4 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_channel.c +++ b/usr.sbin/nginx/src/os/unix/ngx_channel.c @@ -34,6 +34,8 @@ ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = sizeof(cmsg); + ngx_memzero(&cmsg, sizeof(cmsg)); + cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.cm.cmsg_level = SOL_SOCKET; cmsg.cm.cmsg_type = SCM_RIGHTS; @@ -142,7 +144,7 @@ ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log) if ((size_t) n < sizeof(ngx_channel_t)) { ngx_log_error(NGX_LOG_ALERT, log, 0, - "recvmsg() returned not enough data: %uz", n); + "recvmsg() returned not enough data: %z", n); return NGX_ERROR; } diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h b/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h index 149778c29ad..7ac86c73e82 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h +++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h @@ -20,6 +20,7 @@ #include <stddef.h> /* offsetof() */ #include <stdio.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <string.h> #include <signal.h> diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c b/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c index e3cc5fe3eec..1bc7520cade 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c +++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c @@ -59,7 +59,7 @@ sysctl_t sysctls[] = { void -ngx_debug_init() +ngx_debug_init(void) { #if (NGX_DEBUG_MALLOC) diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c b/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c index 078d10b2429..76c4a3a4dad 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c +++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c @@ -317,9 +317,9 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) c->sent += sent; - for (cl = in; cl; cl = cl->next) { + for ( /* void */ ; in; in = in->next) { - if (ngx_buf_special(cl->buf)) { + if (ngx_buf_special(in->buf)) { continue; } @@ -327,28 +327,28 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) break; } - size = ngx_buf_size(cl->buf); + size = ngx_buf_size(in->buf); if (sent >= size) { sent -= size; - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos = cl->buf->last; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos = in->buf->last; } - if (cl->buf->in_file) { - cl->buf->file_pos = cl->buf->file_last; + if (in->buf->in_file) { + in->buf->file_pos = in->buf->file_last; } continue; } - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos += (size_t) sent; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos += (size_t) sent; } - if (cl->buf->in_file) { - cl->buf->file_pos += sent; + if (in->buf->in_file) { + in->buf->file_pos += sent; } break; @@ -360,13 +360,11 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (!complete) { wev->ready = 0; - return cl; + return in; } - if (send >= limit || cl == NULL) { - return cl; + if (send >= limit || in == NULL) { + return in; } - - in = cl; } } diff --git a/usr.sbin/nginx/src/os/unix/ngx_errno.h b/usr.sbin/nginx/src/os/unix/ngx_errno.h index 1497c5f2f35..16cafda3107 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_errno.h +++ b/usr.sbin/nginx/src/os/unix/ngx_errno.h @@ -34,6 +34,8 @@ typedef int ngx_err_t; #define NGX_ENOSPC ENOSPC #define NGX_EPIPE EPIPE #define NGX_EINPROGRESS EINPROGRESS +#define NGX_ENOPROTOOPT ENOPROTOOPT +#define NGX_EOPNOTSUPP EOPNOTSUPP #define NGX_EADDRINUSE EADDRINUSE #define NGX_ECONNABORTED ECONNABORTED #define NGX_ECONNRESET ECONNRESET @@ -50,6 +52,7 @@ typedef int ngx_err_t; #define NGX_EILSEQ EILSEQ #define NGX_ENOMOREFILES 0 #define NGX_ELOOP ELOOP +#define NGX_EBADF EBADF #if (NGX_HAVE_OPENAT) #define NGX_EMLINK EMLINK diff --git a/usr.sbin/nginx/src/os/unix/ngx_files.h b/usr.sbin/nginx/src/os/unix/ngx_files.h index 9c97e2bb789..a78ec961365 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_files.h +++ b/usr.sbin/nginx/src/os/unix/ngx_files.h @@ -53,7 +53,9 @@ typedef struct { #ifdef __CYGWIN__ +#ifndef NGX_HAVE_CASELESS_FILESYSTEM #define NGX_HAVE_CASELESS_FILESYSTEM 1 +#endif #define ngx_open_file(name, mode, create, access) \ open((const char *) name, mode|create|O_BINARY, access) @@ -72,8 +74,8 @@ typedef struct { #define NGX_FILE_RDWR O_RDWR #define NGX_FILE_CREATE_OR_OPEN O_CREAT #define NGX_FILE_OPEN 0 -#define NGX_FILE_TRUNCATE O_CREAT|O_TRUNC -#define NGX_FILE_APPEND O_WRONLY|O_APPEND +#define NGX_FILE_TRUNCATE (O_CREAT|O_TRUNC) +#define NGX_FILE_APPEND (O_WRONLY|O_APPEND) #define NGX_FILE_NONBLOCK O_NONBLOCK #if (NGX_HAVE_OPENAT) @@ -86,13 +88,16 @@ typedef struct { #endif #if defined(O_SEARCH) -#define NGX_FILE_SEARCH O_SEARCH|NGX_FILE_DIRECTORY +#define NGX_FILE_SEARCH (O_SEARCH|NGX_FILE_DIRECTORY) #elif defined(O_EXEC) -#define NGX_FILE_SEARCH O_EXEC|NGX_FILE_DIRECTORY +#define NGX_FILE_SEARCH (O_EXEC|NGX_FILE_DIRECTORY) + +#elif (NGX_HAVE_O_PATH) +#define NGX_FILE_SEARCH (O_PATH|O_RDONLY|NGX_FILE_DIRECTORY) #else -#define NGX_FILE_SEARCH O_RDONLY|NGX_FILE_DIRECTORY +#define NGX_FILE_SEARCH (O_RDONLY|NGX_FILE_DIRECTORY) #endif #endif /* NGX_HAVE_OPENAT */ @@ -189,17 +194,6 @@ ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm); void ngx_close_file_mapping(ngx_file_mapping_t *fm); -#if (NGX_HAVE_CASELESS_FILESYSTEM) - -#define ngx_filename_cmp(s1, s2, n) strncasecmp((char *) s1, (char *) s2, n) - -#else - -#define ngx_filename_cmp ngx_memcmp - -#endif - - #define ngx_realpath(p, r) (u_char *) realpath((char *) p, (char *) r) #define ngx_realpath_n "realpath()" #define ngx_getcwd(buf, size) (getcwd((char *) buf, size) != NULL) diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h b/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h index 5b3ff278c01..92b2928c8b5 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h +++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h @@ -16,6 +16,7 @@ #include <stddef.h> /* offsetof() */ #include <stdio.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <string.h> #include <signal.h> @@ -94,6 +95,11 @@ typedef struct aiocb ngx_aiocb_t; #define NGX_LISTEN_BACKLOG -1 +#ifdef __DragonFly__ +#define NGX_KEEPALIVE_FACTOR 1000 +#endif + + #if (__FreeBSD_version < 430000 || __FreeBSD_version < 500012) pid_t rfork_thread(int flags, void *stack, int (*func)(void *arg), void *arg); diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c b/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c index aeeceaf2565..c4c12dd741c 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c +++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c @@ -72,7 +72,7 @@ sysctl_t sysctls[] = { void -ngx_debug_init() +ngx_debug_init(void) { #if (NGX_DEBUG_MALLOC) diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c index 530ec4a53bb..e92f9a9fdd7 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c +++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c @@ -271,7 +271,7 @@ ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle) ngx_tid_t -ngx_thread_self() +ngx_thread_self(void) { ngx_int_t tid; diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h index 2c238f79ca6..ff160449dad 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h +++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h @@ -57,7 +57,7 @@ extern size_t ngx_thread_stack_size; static ngx_inline ngx_int_t -ngx_gettid() +ngx_gettid(void) { char *sp; @@ -83,7 +83,7 @@ ngx_gettid() } -ngx_tid_t ngx_thread_self(); +ngx_tid_t ngx_thread_self(void); typedef ngx_uint_t ngx_tls_key_t; diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c b/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c index f58b5c20fe1..11cec82269a 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -231,7 +231,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET) { if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { - err = ngx_errno; + err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, @@ -368,9 +368,9 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) c->sent += sent; - for (cl = in; cl; cl = cl->next) { + for ( /* void */ ; in; in = in->next) { - if (ngx_buf_special(cl->buf)) { + if (ngx_buf_special(in->buf)) { continue; } @@ -378,28 +378,28 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) break; } - size = ngx_buf_size(cl->buf); + size = ngx_buf_size(in->buf); if (sent >= size) { sent -= size; - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos = cl->buf->last; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos = in->buf->last; } - if (cl->buf->in_file) { - cl->buf->file_pos = cl->buf->file_last; + if (in->buf->in_file) { + in->buf->file_pos = in->buf->file_last; } continue; } - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos += (size_t) sent; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos += (size_t) sent; } - if (cl->buf->in_file) { - cl->buf->file_pos += sent; + if (in->buf->in_file) { + in->buf->file_pos += sent; } break; @@ -407,7 +407,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) #if (NGX_HAVE_AIO_SENDFILE) if (c->busy_sendfile) { - return cl; + return in; } #endif @@ -421,7 +421,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) */ wev->ready = 0; - return cl; + return in; } if (eintr) { @@ -430,13 +430,11 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (!complete) { wev->ready = 0; - return cl; + return in; } - if (send >= limit || cl == NULL) { - return cl; + if (send >= limit || in == NULL) { + return in; } - - in = cl; } } diff --git a/usr.sbin/nginx/src/os/unix/ngx_linux_config.h b/usr.sbin/nginx/src/os/unix/ngx_linux_config.h index 2834032dea0..72594bac0ea 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_linux_config.h +++ b/usr.sbin/nginx/src/os/unix/ngx_linux_config.h @@ -22,6 +22,7 @@ #include <stddef.h> /* offsetof() */ #include <stdio.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <string.h> #include <signal.h> @@ -51,7 +52,6 @@ #include <malloc.h> /* memalign() */ #include <limits.h> /* IOV_MAX */ #include <sys/ioctl.h> -#include <sys/sysctl.h> #include <crypt.h> #include <sys/utsname.h> /* uname() */ @@ -77,8 +77,14 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size); #endif -#if (NGX_HAVE_POLL || NGX_HAVE_RTSIG) +#if (NGX_HAVE_POLL) +#include <poll.h> +#endif + + +#if (NGX_HAVE_RTSIG) #include <poll.h> +#include <sys/sysctl.h> #endif diff --git a/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c b/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c index e8f3d5a894e..16395f94337 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c +++ b/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c @@ -24,7 +24,7 @@ * so we limit it to 2G-1 bytes. */ -#define NGX_SENDFILE_LIMIT 2147483647L +#define NGX_SENDFILE_MAXSIZE 2147483647L #if (IOV_MAX > 64) @@ -63,8 +63,8 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) /* the maximum limit size is 2G-1 - the page size */ - if (limit == 0 || limit > (off_t) (NGX_SENDFILE_LIMIT - ngx_pagesize)) { - limit = NGX_SENDFILE_LIMIT - ngx_pagesize; + if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) { + limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize; } @@ -163,7 +163,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { - err = ngx_errno; + err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, @@ -181,7 +181,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } else { c->tcp_nodelay = NGX_TCP_NODELAY_UNSET; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "no tcp_nodelay"); } } @@ -189,7 +189,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { - err = ngx_errno; + err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, @@ -325,9 +325,9 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) c->sent += sent; - for (cl = in; cl; cl = cl->next) { + for ( /* void */ ; in; in = in->next) { - if (ngx_buf_special(cl->buf)) { + if (ngx_buf_special(in->buf)) { continue; } @@ -335,28 +335,28 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) break; } - size = ngx_buf_size(cl->buf); + size = ngx_buf_size(in->buf); if (sent >= size) { sent -= size; - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos = cl->buf->last; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos = in->buf->last; } - if (cl->buf->in_file) { - cl->buf->file_pos = cl->buf->file_last; + if (in->buf->in_file) { + in->buf->file_pos = in->buf->file_last; } continue; } - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos += (size_t) sent; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos += (size_t) sent; } - if (cl->buf->in_file) { - cl->buf->file_pos += sent; + if (in->buf->in_file) { + in->buf->file_pos += sent; } break; @@ -368,13 +368,11 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (!complete) { wev->ready = 0; - return cl; + return in; } - if (send >= limit || cl == NULL) { - return cl; + if (send >= limit || in == NULL) { + return in; } - - in = cl; } } diff --git a/usr.sbin/nginx/src/os/unix/ngx_posix_config.h b/usr.sbin/nginx/src/os/unix/ngx_posix_config.h index 4cf90cc9897..d725659dfac 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_posix_config.h +++ b/usr.sbin/nginx/src/os/unix/ngx_posix_config.h @@ -39,6 +39,7 @@ #include <stddef.h> /* offsetof() */ #include <stdio.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <string.h> #include <signal.h> diff --git a/usr.sbin/nginx/src/os/unix/ngx_process.c b/usr.sbin/nginx/src/os/unix/ngx_process.c index 4ef3582e8a2..6f3f38556ab 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_process.c +++ b/usr.sbin/nginx/src/os/unix/ngx_process.c @@ -291,9 +291,14 @@ ngx_init_signals(ngx_log_t *log) sa.sa_handler = sig->handler; sigemptyset(&sa.sa_mask); if (sigaction(sig->signo, &sa, NULL) == -1) { +#if (NGX_VALGRIND) + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sigaction(%s) failed, ignored", sig->signame); +#else ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "sigaction(%s) failed", sig->signame); return NGX_ERROR; +#endif } } diff --git a/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c b/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c index 77fdcf21fe5..078b1251e90 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c +++ b/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c @@ -356,6 +356,8 @@ ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); + ngx_memzero(&ch, sizeof(ngx_channel_t)); + ch.command = NGX_CMD_OPEN_CHANNEL; for (i = 0; i < n; i++) { @@ -402,6 +404,8 @@ ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) &ngx_cache_manager_ctx, "cache manager process", respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN); + ngx_memzero(&ch, sizeof(ngx_channel_t)); + ch.command = NGX_CMD_OPEN_CHANNEL; ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; @@ -461,6 +465,8 @@ ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) ngx_err_t err; ngx_channel_t ch; + ngx_memzero(&ch, sizeof(ngx_channel_t)); + #if (NGX_BROKEN_SCM_RIGHTS) ch.command = 0; @@ -531,7 +537,7 @@ ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) } ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "kill (%P, %d)" , ngx_processes[i].pid, signo); + "kill (%P, %d)", ngx_processes[i].pid, signo); if (kill(ngx_processes[i].pid, signo) == -1) { err = ngx_errno; @@ -562,6 +568,8 @@ ngx_reap_children(ngx_cycle_t *cycle) ngx_channel_t ch; ngx_core_conf_t *ccf; + ngx_memzero(&ch, sizeof(ngx_channel_t)); + ch.command = NGX_CMD_CLOSE_CHANNEL; ch.fd = -1; @@ -703,10 +711,13 @@ ngx_master_process_exit(ngx_cycle_t *cycle) * ngx_cycle->pool is already destroyed. */ - ngx_exit_log_file.fd = ngx_cycle->log->file->fd; - ngx_exit_log = *ngx_cycle->log; + ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log); + + ngx_exit_log_file.fd = ngx_exit_log.file->fd; ngx_exit_log.file = &ngx_exit_log_file; + ngx_exit_log.next = NULL; + ngx_exit_log.writer = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; @@ -1000,6 +1011,8 @@ nochroot: "sigprocmask() failed"); } + srandom((ngx_pid << 16) ^ ngx_time()); + /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point @@ -1085,8 +1098,8 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) && !c[i].read->resolver) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in connection %ui", - c[i].fd, i); + "*%uA open socket #%d left in connection %ui", + c[i].number, c[i].fd, i); ngx_debug_quit = 1; } } @@ -1104,10 +1117,12 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) * ngx_cycle->pool is already destroyed. */ - ngx_exit_log_file.fd = ngx_cycle->log->file->fd; + ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log); - ngx_exit_log = *ngx_cycle->log; + ngx_exit_log_file.fd = ngx_exit_log.file->fd; ngx_exit_log.file = &ngx_exit_log_file; + ngx_exit_log.next = NULL; + ngx_exit_log.writer = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; diff --git a/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c index 7b6badfa825..8836c817dad 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c +++ b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c @@ -129,6 +129,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) "%d available bytes", rev->available); #endif + rev->ready = 0; rev->eof = 1; rev->available = 0; } @@ -136,7 +137,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) return n; } - if (n < size) { + if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { rev->ready = 0; } diff --git a/usr.sbin/nginx/src/os/unix/ngx_recv.c b/usr.sbin/nginx/src/os/unix/ngx_recv.c index 6a4a0996624..86675dfdd8f 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_recv.c +++ b/usr.sbin/nginx/src/os/unix/ngx_recv.c @@ -80,6 +80,7 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) * even if kqueue reported about available data */ + rev->ready = 0; rev->eof = 1; rev->available = 0; } @@ -87,7 +88,9 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) return n; } - if ((size_t) n < size) { + if ((size_t) n < size + && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) + { rev->ready = 0; } diff --git a/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h b/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h index e664ba826c0..ddfd984577e 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h +++ b/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h @@ -22,6 +22,7 @@ #include <stddef.h> /* offsetof() */ #include <stdio.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <string.h> #include <signal.h> diff --git a/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c b/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c index 520eaaab4c7..37bb09d961a 100644 --- a/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -207,9 +207,9 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) c->sent += sent; - for (cl = in; cl; cl = cl->next) { + for ( /* void */ ; in; in = in->next) { - if (ngx_buf_special(cl->buf)) { + if (ngx_buf_special(in->buf)) { continue; } @@ -217,28 +217,28 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) break; } - size = ngx_buf_size(cl->buf); + size = ngx_buf_size(in->buf); if ((off_t) sent >= size) { sent = (size_t) ((off_t) sent - size); - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos = cl->buf->last; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos = in->buf->last; } - if (cl->buf->in_file) { - cl->buf->file_pos = cl->buf->file_last; + if (in->buf->in_file) { + in->buf->file_pos = in->buf->file_last; } continue; } - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos += sent; + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos += sent; } - if (cl->buf->in_file) { - cl->buf->file_pos += sent; + if (in->buf->in_file) { + in->buf->file_pos += sent; } break; @@ -250,13 +250,11 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (!complete) { wev->ready = 0; - return cl; + return in; } - if (send >= limit || cl == NULL) { - return cl; + if (send >= limit || in == NULL) { + return in; } - - in = cl; } } |