From 8094197df9eb5095582095edb9147142ae59c387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 25 Apr 2023 22:36:23 +0200 Subject: [PATCH 01/89] New upstream version 1.24.0 --- CHANGES | 148 +- CHANGES.ru | 150 +- auto/cc/conf | 2 +- auto/cc/msvc | 19 +- auto/lib/openssl/make | 15 +- auto/lib/openssl/makefile.msvc | 2 +- auto/os/conf | 2 +- auto/os/linux | 15 + auto/sources | 3 +- configure | 1 + contrib/vim/syntax/nginx.vim | 1004 +++--------- src/core/nginx.h | 4 +- src/core/ngx_conf_file.c | 4 +- src/core/ngx_connection.c | 2 +- src/core/ngx_connection.h | 2 + src/core/ngx_hash.h | 7 +- src/core/ngx_proxy_protocol.c | 212 ++- src/core/ngx_proxy_protocol.h | 6 +- src/core/ngx_resolver.c | 61 +- src/core/ngx_resolver.h | 4 +- src/core/ngx_string.c | 7 +- src/core/ngx_string.h | 6 +- src/core/ngx_syslog.c | 52 +- src/core/ngx_syslog.h | 20 +- src/event/modules/ngx_iocp_module.c | 379 +++++ src/event/modules/ngx_iocp_module.h | 22 + src/event/ngx_event.c | 9 +- src/event/ngx_event.h | 7 +- src/event/ngx_event_acceptex.c | 229 +++ src/event/ngx_event_connect.c | 2 + src/event/ngx_event_connectex.c | 206 +++ src/event/ngx_event_openssl.c | 539 ++++-- src/event/ngx_event_openssl.h | 37 +- src/event/ngx_event_udp.c | 92 +- src/event/ngx_event_udp.h | 58 + src/http/modules/ngx_http_auth_basic_module.c | 1 + .../modules/ngx_http_auth_request_module.c | 12 +- src/http/modules/ngx_http_dav_module.c | 1 + src/http/modules/ngx_http_fastcgi_module.c | 78 +- src/http/modules/ngx_http_flv_module.c | 3 +- src/http/modules/ngx_http_geo_module.c | 6 +- src/http/modules/ngx_http_geoip_module.c | 12 +- src/http/modules/ngx_http_grpc_module.c | 84 +- .../modules/ngx_http_gzip_filter_module.c | 19 +- .../modules/ngx_http_gzip_static_module.c | 4 + .../modules/ngx_http_headers_filter_module.c | 55 +- src/http/modules/ngx_http_memcached_module.c | 1 + src/http/modules/ngx_http_mp4_module.c | 3 +- src/http/modules/ngx_http_proxy_module.c | 104 +- .../modules/ngx_http_range_filter_module.c | 16 + src/http/modules/ngx_http_realip_module.c | 7 +- src/http/modules/ngx_http_scgi_module.c | 58 +- src/http/modules/ngx_http_ssi_filter_module.c | 29 +- src/http/modules/ngx_http_ssi_filter_module.h | 1 + src/http/modules/ngx_http_ssl_module.c | 9 +- src/http/modules/ngx_http_static_module.c | 10 +- .../modules/ngx_http_userid_filter_module.c | 19 +- src/http/modules/ngx_http_uwsgi_module.c | 141 +- src/http/modules/perl/nginx.xs | 116 +- src/http/ngx_http.c | 65 +- src/http/ngx_http.h | 8 +- src/http/ngx_http_core_module.c | 154 +- src/http/ngx_http_core_module.h | 10 +- src/http/ngx_http_file_cache.c | 14 +- src/http/ngx_http_parse.c | 60 +- src/http/ngx_http_request.c | 60 +- src/http/ngx_http_request.h | 14 +- src/http/ngx_http_script.c | 1 + src/http/ngx_http_special_response.c | 1 + src/http/ngx_http_upstream.c | 410 +++-- src/http/ngx_http_upstream.h | 12 +- src/http/ngx_http_variables.c | 199 ++- src/http/ngx_http_variables.h | 5 +- src/http/ngx_http_write_filter_module.c | 3 +- src/http/v2/ngx_http_v2.c | 13 +- src/http/v2/ngx_http_v2.h | 2 +- src/http/v2/ngx_http_v2_filter_module.c | 33 +- src/mail/ngx_mail_core_module.c | 47 +- src/mail/ngx_mail_proxy_module.c | 16 +- src/mail/ngx_mail_ssl_module.c | 7 +- src/os/unix/ngx_linux_config.h | 4 + src/os/unix/ngx_process_cycle.c | 11 +- src/os/unix/ngx_readv_chain.c | 6 +- src/os/unix/ngx_recv.c | 4 +- src/os/unix/ngx_udp_sendmsg_chain.c | 240 ++- src/os/win32/nginx.ico | Bin 0 -> 1350 bytes src/os/win32/nginx.rc | 6 + src/os/win32/nginx_icon16.xpm | 24 + src/os/win32/nginx_icon32.xpm | 39 + src/os/win32/nginx_icon48.xpm | 55 + src/os/win32/ngx_alloc.c | 44 + src/os/win32/ngx_alloc.h | 27 + src/os/win32/ngx_atomic.h | 69 + src/os/win32/ngx_dlopen.c | 22 + src/os/win32/ngx_dlopen.h | 32 + src/os/win32/ngx_errno.c | 60 + src/os/win32/ngx_errno.h | 71 + src/os/win32/ngx_event_log.c | 99 ++ src/os/win32/ngx_files.c | 1459 +++++++++++++++++ src/os/win32/ngx_files.h | 271 +++ src/os/win32/ngx_os.h | 68 + src/os/win32/ngx_process.c | 238 +++ src/os/win32/ngx_process.h | 80 + src/os/win32/ngx_process_cycle.c | 1044 ++++++++++++ src/os/win32/ngx_process_cycle.h | 44 + src/os/win32/ngx_service.c | 134 ++ src/os/win32/ngx_shmem.c | 161 ++ src/os/win32/ngx_shmem.h | 33 + src/os/win32/ngx_socket.c | 49 + src/os/win32/ngx_socket.h | 253 +++ src/os/win32/ngx_stat.c | 34 + src/os/win32/ngx_thread.c | 30 + src/os/win32/ngx_thread.h | 27 + src/os/win32/ngx_time.c | 83 + src/os/win32/ngx_time.h | 51 + src/os/win32/ngx_udp_wsarecv.c | 149 ++ src/os/win32/ngx_user.c | 23 + src/os/win32/ngx_user.h | 25 + src/os/win32/ngx_win32_config.h | 287 ++++ src/os/win32/ngx_win32_init.c | 329 ++++ src/os/win32/ngx_wsarecv.c | 215 +++ src/os/win32/ngx_wsarecv_chain.c | 147 ++ src/os/win32/ngx_wsasend.c | 185 +++ src/os/win32/ngx_wsasend_chain.c | 296 ++++ src/stream/ngx_stream_core_module.c | 49 +- src/stream/ngx_stream_proxy_module.c | 97 +- src/stream/ngx_stream_ssl_module.c | 7 +- src/stream/ngx_stream_variables.c | 39 + src/stream/ngx_stream_write_filter_module.c | 2 +- 129 files changed, 10228 insertions(+), 1745 deletions(-) create mode 100644 src/event/modules/ngx_iocp_module.c create mode 100644 src/event/modules/ngx_iocp_module.h create mode 100644 src/event/ngx_event_acceptex.c create mode 100644 src/event/ngx_event_connectex.c create mode 100644 src/event/ngx_event_udp.h create mode 100644 src/os/win32/nginx.ico create mode 100644 src/os/win32/nginx.rc create mode 100644 src/os/win32/nginx_icon16.xpm create mode 100644 src/os/win32/nginx_icon32.xpm create mode 100644 src/os/win32/nginx_icon48.xpm create mode 100644 src/os/win32/ngx_alloc.c create mode 100644 src/os/win32/ngx_alloc.h create mode 100644 src/os/win32/ngx_atomic.h create mode 100644 src/os/win32/ngx_dlopen.c create mode 100644 src/os/win32/ngx_dlopen.h create mode 100644 src/os/win32/ngx_errno.c create mode 100644 src/os/win32/ngx_errno.h create mode 100644 src/os/win32/ngx_event_log.c create mode 100644 src/os/win32/ngx_files.c create mode 100644 src/os/win32/ngx_files.h create mode 100644 src/os/win32/ngx_os.h create mode 100644 src/os/win32/ngx_process.c create mode 100644 src/os/win32/ngx_process.h create mode 100644 src/os/win32/ngx_process_cycle.c create mode 100644 src/os/win32/ngx_process_cycle.h create mode 100644 src/os/win32/ngx_service.c create mode 100644 src/os/win32/ngx_shmem.c create mode 100644 src/os/win32/ngx_shmem.h create mode 100644 src/os/win32/ngx_socket.c create mode 100644 src/os/win32/ngx_socket.h create mode 100644 src/os/win32/ngx_stat.c create mode 100644 src/os/win32/ngx_thread.c create mode 100644 src/os/win32/ngx_thread.h create mode 100644 src/os/win32/ngx_time.c create mode 100644 src/os/win32/ngx_time.h create mode 100644 src/os/win32/ngx_udp_wsarecv.c create mode 100644 src/os/win32/ngx_user.c create mode 100644 src/os/win32/ngx_user.h create mode 100644 src/os/win32/ngx_win32_config.h create mode 100644 src/os/win32/ngx_win32_init.c create mode 100644 src/os/win32/ngx_wsarecv.c create mode 100644 src/os/win32/ngx_wsarecv_chain.c create mode 100644 src/os/win32/ngx_wsasend.c create mode 100644 src/os/win32/ngx_wsasend_chain.c diff --git a/CHANGES b/CHANGES index c356ba7..6774b29 100644 --- a/CHANGES +++ b/CHANGES @@ -1,15 +1,157 @@ -Changes with nginx 1.22.1 19 Oct 2022 +Changes with nginx 1.24.0 11 Apr 2023 + + *) 1.24.x stable branch. + + +Changes with nginx 1.23.4 28 Mar 2023 + + *) Change: now TLSv1.3 protocol is enabled by default. + + *) Change: now nginx issues a warning if protocol parameters of a + listening socket are redefined. + + *) Change: now nginx closes connections with lingering if pipelining was + used by the client. + + *) Feature: byte ranges support in the ngx_http_gzip_static_module. + + *) Bugfix: port ranges in the "listen" directive did not work; the bug + had appeared in 1.23.3. + Thanks to Valentin Bartenev. + + *) Bugfix: incorrect location might be chosen to process a request if a + prefix location longer than 255 characters was used in the + configuration. + + *) Bugfix: non-ASCII characters in file names on Windows were not + supported by the ngx_http_autoindex_module, the ngx_http_dav_module, + and the "include" directive. + + *) Change: the logging level of the "data length too long", "length too + short", "bad legacy version", "no shared signature algorithms", "bad + digest length", "missing sigalgs extension", "encrypted length too + long", "bad length", "bad key update", "mixed handshake and non + handshake data", "ccs received early", "data between ccs and + finished", "packet length too long", "too many warn alerts", "record + too small", and "got a fin before a ccs" SSL errors has been lowered + from "crit" to "info". + + *) Bugfix: a socket leak might occur when using HTTP/2 and the + "error_page" directive to redirect errors with code 400. + + *) Bugfix: messages about logging to syslog errors did not contain + information that the errors happened while logging to syslog. + Thanks to Safar Safarly. + + *) Workaround: "gzip filter failed to use preallocated memory" alerts + appeared in logs when using zlib-ng. + + *) Bugfix: in the mail proxy server. + + +Changes with nginx 1.23.3 13 Dec 2022 + + *) Bugfix: an error might occur when reading PROXY protocol version 2 + header with large number of TLVs. + + *) Bugfix: a segmentation fault might occur in a worker process if SSI + was used to process subrequests created by other modules. + Thanks to Ciel Zhao. + + *) Workaround: when a hostname used in the "listen" directive resolves + to multiple addresses, nginx now ignores duplicates within these + addresses. + + *) Bugfix: nginx might hog CPU during unbuffered proxying if SSL + connections to backends were used. + + +Changes with nginx 1.23.2 19 Oct 2022 *) Security: processing of a specially crafted mp4 file by the ngx_http_mp4_module might cause a worker process crash, worker process memory disclosure, or might have potential other impact (CVE-2022-41741, CVE-2022-41742). + *) Feature: the "$proxy_protocol_tlv_..." variables. -Changes with nginx 1.22.0 24 May 2022 + *) Feature: TLS session tickets encryption keys are now automatically + rotated when using shared memory in the "ssl_session_cache" + directive. - *) 1.22.x stable branch. + *) Change: the logging level of the "bad record type" SSL errors has + been lowered from "crit" to "info". + Thanks to Murilo Andrade. + + *) Change: now when using shared memory in the "ssl_session_cache" + directive the "could not allocate new session" errors are logged at + the "warn" level instead of "alert" and not more often than once per + second. + + *) Bugfix: nginx/Windows could not be built with OpenSSL 3.0.x. + + *) Bugfix: in logging of the PROXY protocol errors. + Thanks to Sergey Brester. + + *) Workaround: shared memory from the "ssl_session_cache" directive was + spent on sessions using TLS session tickets when using TLSv1.3 with + OpenSSL. + + *) Workaround: timeout specified with the "ssl_session_timeout" + directive did not work when using TLSv1.3 with OpenSSL or BoringSSL. + + +Changes with nginx 1.23.1 19 Jul 2022 + + *) Feature: memory usage optimization in configurations with SSL + proxying. + + *) Feature: looking up of IPv4 addresses while resolving now can be + disabled with the "ipv4=off" parameter of the "resolver" directive. + + *) Change: the logging level of the "bad key share", "bad extension", + "bad cipher", and "bad ecpoint" SSL errors has been lowered from + "crit" to "info". + + *) Bugfix: while returning byte ranges nginx did not remove the + "Content-Range" header line if it was present in the original backend + response. + + *) Bugfix: a proxied response might be truncated during reconfiguration + on Linux; the bug had appeared in 1.17.5. + + +Changes with nginx 1.23.0 21 Jun 2022 + + *) Change in internal API: now header lines are represented as linked + lists. + + *) Change: now nginx combines arbitrary header lines with identical + names when sending to FastCGI, SCGI, and uwsgi backends, in the + $r->header_in() method of the ngx_http_perl_module, and during lookup + of the "$http_...", "$sent_http_...", "$sent_trailer_...", + "$upstream_http_...", and "$upstream_trailer_..." variables. + + *) Bugfix: if there were multiple "Vary" header lines in the backend + response, nginx only used the last of them when caching. + + *) Bugfix: if there were multiple "WWW-Authenticate" header lines in the + backend response and errors with code 401 were intercepted or the + "auth_request" directive was used, nginx only sent the first of the + header lines to the client. + + *) Change: the logging level of the "application data after close + notify" SSL errors has been lowered from "crit" to "info". + + *) Bugfix: connections might hang if nginx was built on Linux 2.6.17 or + newer, but was used on systems without EPOLLRDHUP support, notably + with epoll emulation layers; the bug had appeared in 1.17.5. + Thanks to Marcus Ball. + + *) Bugfix: nginx did not cache the response if the "Expires" response + header line disabled caching, but following "Cache-Control" header + line enabled caching. Changes with nginx 1.21.6 25 Jan 2022 diff --git a/CHANGES.ru b/CHANGES.ru index 9ee9e11..544f15b 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,5 +1,75 @@ -Изменения в nginx 1.22.1 19.10.2022 +Изменения в nginx 1.24.0 11.04.2023 + + *) Стабильная ветка 1.24.x. + + +Изменения в nginx 1.23.4 28.03.2023 + + *) Изменение: теперь протокол TLSv1.3 разрешён по умолчанию. + + *) Изменение: теперь nginx выдаёт предупреждение при переопределении + параметров listen-сокета, задающих используемые протоколы. + + *) Изменение: теперь, если клиент использует pipelining, nginx закрывает + соединения с ожиданием дополнительных данных (lingering close). + + *) Добавление: поддержка byte ranges для ответов модуля + ngx_http_gzip_static_module. + + *) Исправление: диапазоны портов в директиве listen не работали; ошибка + появилась в 1.23.3. + Спасибо Валентину Бартеневу. + + *) Исправление: для обработки запроса мог быть выбран неверный location, + если в конфигурации использовался префиксный location длиннее 255 + символов. + + *) Исправление: не-ASCII символы в именах файлов на Windows не + поддерживались модулями ngx_http_autoindex_module и + ngx_http_dav_module, а также директивой include. + + *) Изменение: уровень логгирования ошибок SSL "data length too long", + "length too short", "bad legacy version", "no shared signature + algorithms", "bad digest length", "missing sigalgs extension", + "encrypted length too long", "bad length", "bad key update", "mixed + handshake and non handshake data", "ccs received early", "data + between ccs and finished", "packet length too long", "too many warn + alerts", "record too small", и "got a fin before a ccs" понижен с + уровня crit до info. + + *) Исправление: при использовании HTTP/2 и директивы error_page для + перенаправления ошибок с кодом 400 могла происходить утечка сокетов. + + *) Исправление: сообщения об ошибках записи в syslog не содержали + информации о том, что ошибки происходили в процессе записи в syslog. + Спасибо Safar Safarly. + + *) Изменение: при использовании zlib-ng в логах появлялись сообщения + "gzip filter failed to use preallocated memory". + + *) Исправление: в почтовом прокси-сервере. + + +Изменения в nginx 1.23.3 13.12.2022 + + *) Исправление: при чтении заголовка протокола PROXY версии 2, + содержащего большое количество TLV, могла возникать ошибка. + + *) Исправление: при использовании SSI для обработки подзапросов, + созданных другими модулями, в рабочем процессе мог произойти + segmentation fault. + Спасибо Ciel Zhao. + + *) Изменение: теперь, если при преобразовании в адреса имени хоста, + указанного в директиве listen, возвращается несколько адресов, nginx + игнорирует дубликаты среди этих адресов. + + *) Исправление: nginx мог нагружать процессор при небуферизированном + проксировании, если использовались SSL-соединения с бэкендами. + + +Изменения в nginx 1.23.2 19.10.2022 *) Безопасность: обработка специально созданного mp4-файла модулем ngx_http_mp4_module могла приводить к падению рабочего процесса, @@ -7,10 +77,84 @@ потенциально могла иметь другие последствия (CVE-2022-41741, CVE-2022-41742). + *) Добавление: переменные "$proxy_protocol_tlv_...". -Изменения в nginx 1.22.0 24.05.2022 + *) Добавление: ключи шифрования TLS session tickets теперь автоматически + меняются при использовании разделяемой памяти в ssl_session_cache. - *) Стабильная ветка 1.22.x. + *) Изменение: уровень логгирования ошибок SSL "bad record type" понижен + с уровня crit до info. + Спасибо Murilo Andrade. + + *) Изменение: теперь при использовании разделяемой памяти в + ssl_session_cache сообщения "could not allocate new session" + логгируются на уровне warn вместо alert и не чаще одного раза в + секунду. + + *) Исправление: nginx/Windows не собирался с OpenSSL 3.0.x. + + *) Исправление: в логгировании ошибок протокола PROXY. + Спасибо Сергею Брестеру. + + *) Изменение: при использовании TLSv1.3 с OpenSSL разделяемая память из + ssl_session_cache расходовалась в том числе на сессии, использующие + TLS session tickets. + + *) Изменение: таймаут, заданный с помощью директивы ssl_session_timeout, + не работал при использовании TLSv1.3 с OpenSSL или BoringSSL. + + +Изменения в nginx 1.23.1 19.07.2022 + + *) Добавление: оптимизация использования памяти в конфигурациях с + SSL-проксированием. + + *) Добавление: теперь с помощью параметра "ipv4=off" директивы + "resolver" можно запретить поиск IPv4-адресов при преобразовании имён + в адреса. + + *) Изменение: уровень логгирования ошибок SSL "bad key share", "bad + extension", "bad cipher" и "bad ecpoint" понижен с уровня crit до + info. + + *) Исправление: при возврате диапазонов nginx не удалял строку заголовка + "Content-Range", если она присутствовала в исходном ответе бэкенда. + + *) Исправление: проксированный ответ мог быть отправлен не полностью при + переконфигурации на Linux; ошибка появилась в 1.17.5. + + +Изменения в nginx 1.23.0 21.06.2022 + + *) Изменение во внутреннем API: теперь строки заголовков представлены + связными списками. + + *) Изменение: теперь nginx объединяет произвольные строки заголовков с + одинаковыми именами при отправке на FastCGI-, SCGI- и uwsgi-бэкенды, + в методе $r->header_in() модуля ngx_http_perl_module, и при доступе + через переменные "$http_...", "$sent_http_...", "$sent_trailer_...", + "$upstream_http_..." и "$upstream_trailer_...". + + *) Исправление: если в заголовке ответа бэкенда было несколько строк + "Vary", при кэшировании nginx учитывал только последнюю из них. + + *) Исправление: если в заголовке ответа бэкенда было несколько строк + "WWW-Authenticate" и использовался перехват ошибок с кодом 401 от + бэкенда или директива auth_request, nginx пересылал клиенту только + первую из этих строк. + + *) Изменение: уровень логгирования ошибок SSL "application data after + close notify" понижен с уровня crit до info. + + *) Исправление: соединения могли зависать, если nginx был собран на + Linux 2.6.17 и новее, а использовался на системах без поддержки + EPOLLRDHUP, в частности, на системах с эмуляцией epoll; ошибка + появилась в 1.17.5. + Спасибо Marcus Ball. + + *) Исправление: nginx не кэшировал ответ, если строка заголовка ответа + "Expires" запрещала кэширование, а последующая строка заголовка + "Cache-Control" разрешала кэширование. Изменения в nginx 1.21.6 25.01.2022 diff --git a/auto/cc/conf b/auto/cc/conf index afbca62..ba31cb8 100644 --- a/auto/cc/conf +++ b/auto/cc/conf @@ -117,7 +117,7 @@ else . auto/cc/acc ;; - msvc*) + msvc) # MSVC++ 6.0 SP2, MSVC++ Toolkit 2003 . auto/cc/msvc diff --git a/auto/cc/msvc b/auto/cc/msvc index 68435ff..567bac7 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -11,8 +11,8 @@ # MSVC 2015 (14.0) cl 19.00 -NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'Compiler Version' 2>&1 \ - | sed -e 's/^.* Version \(.*\)/\1/'` +NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'C/C++.* [0-9][0-9]*\.[0-9]' 2>&1 \ + | sed -e 's/^.* \([0-9][0-9]*\.[0-9].*\)/\1/'` echo " + cl version: $NGX_MSVC_VER" @@ -22,6 +22,21 @@ have=NGX_COMPILER value="\"cl $NGX_MSVC_VER\"" . auto/define ngx_msvc_ver=`echo $NGX_MSVC_VER | sed -e 's/^\([0-9]*\).*/\1/'` +# detect x64 builds + +case "$NGX_MSVC_VER" in + + *x64) + NGX_MACHINE=amd64 + ;; + + *) + NGX_MACHINE=i386 + ;; + +esac + + # optimizations # maximize speed, equivalent to -Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make index 126a238..a7e9369 100644 --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -7,11 +7,24 @@ case "$CC" in cl) + case "$NGX_MACHINE" in + + amd64) + OPENSSL_TARGET=VC-WIN64A + ;; + + *) + OPENSSL_TARGET=VC-WIN32 + ;; + + esac + cat << END >> $NGX_MAKEFILE $OPENSSL/openssl/include/openssl/ssl.h: $NGX_MAKEFILE \$(MAKE) -f auto/lib/openssl/makefile.msvc \ - OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT" + OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT" \ + OPENSSL_TARGET="$OPENSSL_TARGET" END diff --git a/auto/lib/openssl/makefile.msvc b/auto/lib/openssl/makefile.msvc index 5b90dcb..ed17cde 100644 --- a/auto/lib/openssl/makefile.msvc +++ b/auto/lib/openssl/makefile.msvc @@ -6,7 +6,7 @@ all: cd $(OPENSSL) - perl Configure VC-WIN32 no-shared \ + perl Configure $(OPENSSL_TARGET) no-shared no-threads \ --prefix="%cd%/openssl" \ --openssldir="%cd%/openssl/ssl" \ $(OPENSSL_OPT) diff --git a/auto/os/conf b/auto/os/conf index 7c6cb69..d7f6e03 100644 --- a/auto/os/conf +++ b/auto/os/conf @@ -110,7 +110,7 @@ case "$NGX_MACHINE" in NGX_MACH_CACHE_LINE=64 ;; - aarch64 ) + aarch64 | arm64) have=NGX_ALIGNMENT value=16 . auto/define NGX_MACH_CACHE_LINE=64 ;; diff --git a/auto/os/linux b/auto/os/linux index 74b5870..eb67026 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -232,4 +232,19 @@ ngx_feature_test="struct crypt_data cd; ngx_include="sys/vfs.h"; . auto/include +# UDP segmentation offloading + +ngx_feature="UDP_SEGMENT" +ngx_feature_name="NGX_HAVE_UDP_SEGMENT" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="socklen_t optlen = sizeof(int); + int val; + getsockopt(0, SOL_UDP, UDP_SEGMENT, &val, &optlen)" +. auto/feature + + CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" diff --git a/auto/sources b/auto/sources index 156f797..a539093 100644 --- a/auto/sources +++ b/auto/sources @@ -89,7 +89,8 @@ EVENT_DEPS="src/event/ngx_event.h \ src/event/ngx_event_timer.h \ src/event/ngx_event_posted.h \ src/event/ngx_event_connect.h \ - src/event/ngx_event_pipe.h" + src/event/ngx_event_pipe.h \ + src/event/ngx_event_udp.h" EVENT_SRCS="src/event/ngx_event.c \ src/event/ngx_event_timer.c \ diff --git a/configure b/configure index 474d69e..5b88ebb 100755 --- a/configure +++ b/configure @@ -44,6 +44,7 @@ if test -z "$NGX_PLATFORM"; then else echo "building for $NGX_PLATFORM" NGX_SYSTEM=$NGX_PLATFORM + NGX_MACHINE=i386 fi . auto/cc/conf diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 6828cd3..7d587fc 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -111,19 +111,14 @@ syn keyword ngxDirectiveControl contained set syn keyword ngxDirectiveError contained error_page syn keyword ngxDirectiveError contained post_action -syn keyword ngxDirectiveDeprecated contained limit_zone syn keyword ngxDirectiveDeprecated contained proxy_downstream_buffer syn keyword ngxDirectiveDeprecated contained proxy_upstream_buffer -syn keyword ngxDirectiveDeprecated contained spdy_chunk_size -syn keyword ngxDirectiveDeprecated contained spdy_headers_comp -syn keyword ngxDirectiveDeprecated contained spdy_keepalive_timeout -syn keyword ngxDirectiveDeprecated contained spdy_max_concurrent_streams -syn keyword ngxDirectiveDeprecated contained spdy_pool_size -syn keyword ngxDirectiveDeprecated contained spdy_recv_buffer_size -syn keyword ngxDirectiveDeprecated contained spdy_recv_timeout -syn keyword ngxDirectiveDeprecated contained spdy_streams_index_size syn keyword ngxDirectiveDeprecated contained ssl -syn keyword ngxDirectiveDeprecated contained upstream_conf +syn keyword ngxDirectiveDeprecated contained http2_idle_timeout +syn keyword ngxDirectiveDeprecated contained http2_max_field_size +syn keyword ngxDirectiveDeprecated contained http2_max_header_size +syn keyword ngxDirectiveDeprecated contained http2_max_requests +syn keyword ngxDirectiveDeprecated contained http2_recv_timeout syn keyword ngxDirective contained absolute_redirect syn keyword ngxDirective contained accept_mutex @@ -152,6 +147,7 @@ syn keyword ngxDirective contained auth_http_timeout syn keyword ngxDirective contained auth_jwt syn keyword ngxDirective contained auth_jwt_claim_set syn keyword ngxDirective contained auth_jwt_header_set +syn keyword ngxDirective contained auth_jwt_key_cache syn keyword ngxDirective contained auth_jwt_key_file syn keyword ngxDirective contained auth_jwt_key_request syn keyword ngxDirective contained auth_jwt_leeway @@ -309,17 +305,12 @@ syn keyword ngxDirective contained hls_mp4_buffer_size syn keyword ngxDirective contained hls_mp4_max_buffer_size syn keyword ngxDirective contained http2_body_preread_size syn keyword ngxDirective contained http2_chunk_size -syn keyword ngxDirective contained http2_idle_timeout syn keyword ngxDirective contained http2_max_concurrent_pushes syn keyword ngxDirective contained http2_max_concurrent_streams -syn keyword ngxDirective contained http2_max_field_size -syn keyword ngxDirective contained http2_max_header_size -syn keyword ngxDirective contained http2_max_requests syn keyword ngxDirective contained http2_pool_size syn keyword ngxDirective contained http2_push syn keyword ngxDirective contained http2_push_preload syn keyword ngxDirective contained http2_recv_buffer_size -syn keyword ngxDirective contained http2_recv_timeout syn keyword ngxDirective contained http2_streams_index_size syn keyword ngxDirective contained if_modified_since syn keyword ngxDirective contained ignore_invalid_headers @@ -339,14 +330,17 @@ syn keyword ngxDirective contained ip_hash syn keyword ngxDirective contained js_access syn keyword ngxDirective contained js_body_filter syn keyword ngxDirective contained js_content +syn keyword ngxDirective contained js_fetch_buffer_size syn keyword ngxDirective contained js_fetch_ciphers +syn keyword ngxDirective contained js_fetch_max_response_buffer_size syn keyword ngxDirective contained js_fetch_protocols +syn keyword ngxDirective contained js_fetch_timeout syn keyword ngxDirective contained js_fetch_trusted_certificate +syn keyword ngxDirective contained js_fetch_verify syn keyword ngxDirective contained js_fetch_verify_depth syn keyword ngxDirective contained js_filter syn keyword ngxDirective contained js_header_filter syn keyword ngxDirective contained js_import -syn keyword ngxDirective contained js_include syn keyword ngxDirective contained js_path syn keyword ngxDirective contained js_preread syn keyword ngxDirective contained js_set @@ -391,7 +385,6 @@ syn keyword ngxDirective contained max_ranges syn keyword ngxDirective contained memcached_bind syn keyword ngxDirective contained memcached_buffer_size syn keyword ngxDirective contained memcached_connect_timeout -syn keyword ngxDirective contained memcached_force_ranges syn keyword ngxDirective contained memcached_gzip_flag syn keyword ngxDirective contained memcached_next_upstream syn keyword ngxDirective contained memcached_next_upstream_timeout @@ -645,7 +638,6 @@ syn keyword ngxDirective contained status syn keyword ngxDirective contained status_format syn keyword ngxDirective contained status_zone syn keyword ngxDirective contained sticky -syn keyword ngxDirective contained sticky_cookie_insert syn keyword ngxDirective contained stub_status syn keyword ngxDirective contained sub_filter syn keyword ngxDirective contained sub_filter_last_modified @@ -774,62 +766,14 @@ syn keyword ngxDirective contained zone_sync_ssl_verify syn keyword ngxDirective contained zone_sync_ssl_verify_depth syn keyword ngxDirective contained zone_sync_timeout + " 3rd party modules list taken from -" https://github.com/freebsd/freebsd-ports/blob/master/www/nginx-devel/Makefile -" ----------------------------------------------------------------------------- +" https://github.com/freebsd/freebsd-ports/blob/main/www/nginx-devel/Makefile.extmod +" ---------------------------------------------------------------------------------- -" Accept Language -" https://github.com/giom/nginx_accept_language_module -syn keyword ngxDirectiveThirdParty contained set_from_accept_language - -" Digest Authentication -" https://github.com/atomx/nginx-http-auth-digest -syn keyword ngxDirectiveThirdParty contained auth_digest -syn keyword ngxDirectiveThirdParty contained auth_digest_drop_time -syn keyword ngxDirectiveThirdParty contained auth_digest_evasion_time -syn keyword ngxDirectiveThirdParty contained auth_digest_expires -syn keyword ngxDirectiveThirdParty contained auth_digest_maxtries -syn keyword ngxDirectiveThirdParty contained auth_digest_replays -syn keyword ngxDirectiveThirdParty contained auth_digest_shm_size -syn keyword ngxDirectiveThirdParty contained auth_digest_timeout -syn keyword ngxDirectiveThirdParty contained auth_digest_user_file - -" SPNEGO Authentication -" https://github.com/stnoonan/spnego-http-auth-nginx-module -syn keyword ngxDirectiveThirdParty contained auth_gss -syn keyword ngxDirectiveThirdParty contained auth_gss_allow_basic_fallback -syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal -syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal_regex -syn keyword ngxDirectiveThirdParty contained auth_gss_constrained_delegation -syn keyword ngxDirectiveThirdParty contained auth_gss_delegate_credentials -syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm -syn keyword ngxDirectiveThirdParty contained auth_gss_format_full -syn keyword ngxDirectiveThirdParty contained auth_gss_keytab -syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local -syn keyword ngxDirectiveThirdParty contained auth_gss_realm -syn keyword ngxDirectiveThirdParty contained auth_gss_service_ccache -syn keyword ngxDirectiveThirdParty contained auth_gss_service_name - -" LDAP Authentication -" https://github.com/kvspb/nginx-auth-ldap -syn keyword ngxDirectiveThirdParty contained auth_ldap -syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_enabled -syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_expiration_time -syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_size -syn keyword ngxDirectiveThirdParty contained auth_ldap_servers -syn keyword ngxDirectiveThirdParty contained auth_ldap_servers_size -syn keyword ngxDirectiveThirdParty contained ldap_server - -" PAM Authentication -" https://github.com/sto/ngx_http_auth_pam_module -syn keyword ngxDirectiveThirdParty contained auth_pam -syn keyword ngxDirectiveThirdParty contained auth_pam_service_name -syn keyword ngxDirectiveThirdParty contained auth_pam_set_pam_env - -" AJP protocol proxy -" https://github.com/yaoweibin/nginx_ajp_module -syn keyword ngxDirectiveThirdParty contained ajp_buffers +" https://github.com/msva/nginx_ajp_module syn keyword ngxDirectiveThirdParty contained ajp_buffer_size +syn keyword ngxDirectiveThirdParty contained ajp_buffers syn keyword ngxDirectiveThirdParty contained ajp_busy_buffers_size syn keyword ngxDirectiveThirdParty contained ajp_cache syn keyword ngxDirectiveThirdParty contained ajp_cache_key @@ -850,11 +794,13 @@ syn keyword ngxDirectiveThirdParty contained ajp_keep_conn syn keyword ngxDirectiveThirdParty contained ajp_max_data_packet_size syn keyword ngxDirectiveThirdParty contained ajp_max_temp_file_size syn keyword ngxDirectiveThirdParty contained ajp_next_upstream +syn keyword ngxDirectiveThirdParty contained ajp_param syn keyword ngxDirectiveThirdParty contained ajp_pass syn keyword ngxDirectiveThirdParty contained ajp_pass_header syn keyword ngxDirectiveThirdParty contained ajp_pass_request_body syn keyword ngxDirectiveThirdParty contained ajp_pass_request_headers syn keyword ngxDirectiveThirdParty contained ajp_read_timeout +syn keyword ngxDirectiveThirdParty contained ajp_script_url syn keyword ngxDirectiveThirdParty contained ajp_secret syn keyword ngxDirectiveThirdParty contained ajp_send_lowat syn keyword ngxDirectiveThirdParty contained ajp_send_timeout @@ -865,7 +811,12 @@ syn keyword ngxDirectiveThirdParty contained ajp_temp_path syn keyword ngxDirectiveThirdParty contained ajp_upstream_fail_timeout syn keyword ngxDirectiveThirdParty contained ajp_upstream_max_fails -" AWS proxy +" https://github.com/openresty/array-var-nginx-module +syn keyword ngxDirectiveThirdParty contained array_join +syn keyword ngxDirectiveThirdParty contained array_map +syn keyword ngxDirectiveThirdParty contained array_map_op +syn keyword ngxDirectiveThirdParty contained array_split + " https://github.com/anomalizer/ngx_aws_auth syn keyword ngxDirectiveThirdParty contained aws_access_key syn keyword ngxDirectiveThirdParty contained aws_endpoint @@ -874,7 +825,18 @@ syn keyword ngxDirectiveThirdParty contained aws_s3_bucket syn keyword ngxDirectiveThirdParty contained aws_sign syn keyword ngxDirectiveThirdParty contained aws_signing_key -" embedding Clojure or Java or Groovy programs +" https://github.com/google/ngx_brotli +syn keyword ngxDirectiveThirdParty contained brotli +syn keyword ngxDirectiveThirdParty contained brotli_buffers +syn keyword ngxDirectiveThirdParty contained brotli_comp_level +syn keyword ngxDirectiveThirdParty contained brotli_min_length +syn keyword ngxDirectiveThirdParty contained brotli_static +syn keyword ngxDirectiveThirdParty contained brotli_types +syn keyword ngxDirectiveThirdParty contained brotli_window + +" https://github.com/torden/ngx_cache_purge +syn keyword ngxDirectiveThirdParty contained cache_purge_response_type + " https://github.com/nginx-clojure/nginx-clojure syn keyword ngxDirectiveThirdParty contained access_handler_code syn keyword ngxDirectiveThirdParty contained access_handler_name @@ -892,8 +854,8 @@ syn keyword ngxDirectiveThirdParty contained content_handler_property syn keyword ngxDirectiveThirdParty contained content_handler_type syn keyword ngxDirectiveThirdParty contained handler_code syn keyword ngxDirectiveThirdParty contained handler_name -syn keyword ngxDirectiveThirdParty contained handlers_lazy_init syn keyword ngxDirectiveThirdParty contained handler_type +syn keyword ngxDirectiveThirdParty contained handlers_lazy_init syn keyword ngxDirectiveThirdParty contained header_filter_code syn keyword ngxDirectiveThirdParty contained header_filter_name syn keyword ngxDirectiveThirdParty contained header_filter_property @@ -921,18 +883,20 @@ syn keyword ngxDirectiveThirdParty contained rewrite_handler_type syn keyword ngxDirectiveThirdParty contained shared_map syn keyword ngxDirectiveThirdParty contained write_page_size +" https://github.com/AirisX/nginx_cookie_flag_module +syn keyword ngxDirectiveThirdParty contained set_cookie_flag -" Certificate Transparency " https://github.com/grahamedgecombe/nginx-ct syn keyword ngxDirectiveThirdParty contained ssl_ct syn keyword ngxDirectiveThirdParty contained ssl_ct_static_scts -" ngx_echo " https://github.com/openresty/echo-nginx-module +syn keyword ngxDirectiveThirdParty contained echo syn keyword ngxDirectiveThirdParty contained echo_abort_parent syn keyword ngxDirectiveThirdParty contained echo_after_body syn keyword ngxDirectiveThirdParty contained echo_before_body syn keyword ngxDirectiveThirdParty contained echo_blocking_sleep +syn keyword ngxDirectiveThirdParty contained echo_duplicate syn keyword ngxDirectiveThirdParty contained echo_end syn keyword ngxDirectiveThirdParty contained echo_exec syn keyword ngxDirectiveThirdParty contained echo_flush @@ -942,28 +906,124 @@ syn keyword ngxDirectiveThirdParty contained echo_location_async syn keyword ngxDirectiveThirdParty contained echo_read_request_body syn keyword ngxDirectiveThirdParty contained echo_request_body syn keyword ngxDirectiveThirdParty contained echo_reset_timer +syn keyword ngxDirectiveThirdParty contained echo_sleep syn keyword ngxDirectiveThirdParty contained echo_status syn keyword ngxDirectiveThirdParty contained echo_subrequest syn keyword ngxDirectiveThirdParty contained echo_subrequest_async -" FastDFS -" https://github.com/happyfish100/fastdfs-nginx-module -syn keyword ngxDirectiveThirdParty contained ngx_fastdfs_module +" https://github.com/openresty/drizzle-nginx-module +syn keyword ngxDirectiveThirdParty contained drizzle_buffer_size +syn keyword ngxDirectiveThirdParty contained drizzle_connect_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_dbname +syn keyword ngxDirectiveThirdParty contained drizzle_keepalive +syn keyword ngxDirectiveThirdParty contained drizzle_module_header +syn keyword ngxDirectiveThirdParty contained drizzle_pass +syn keyword ngxDirectiveThirdParty contained drizzle_query +syn keyword ngxDirectiveThirdParty contained drizzle_recv_cols_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_recv_rows_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_send_query_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_server +syn keyword ngxDirectiveThirdParty contained drizzle_status + +" https://github.com/ZigzagAK/ngx_dynamic_upstream +syn keyword ngxDirectiveThirdParty contained dns_add_down +syn keyword ngxDirectiveThirdParty contained dns_ipv6 +syn keyword ngxDirectiveThirdParty contained dns_update +syn keyword ngxDirectiveThirdParty contained dynamic_state_file +syn keyword ngxDirectiveThirdParty contained dynamic_upstream + +" https://github.com/ZigzagAK/ngx_dynamic_healthcheck +syn keyword ngxDirectiveThirdParty contained check +syn keyword ngxDirectiveThirdParty contained check_disable_host +syn keyword ngxDirectiveThirdParty contained check_exclude_host +syn keyword ngxDirectiveThirdParty contained check_persistent +syn keyword ngxDirectiveThirdParty contained check_request_body +syn keyword ngxDirectiveThirdParty contained check_request_headers +syn keyword ngxDirectiveThirdParty contained check_request_uri +syn keyword ngxDirectiveThirdParty contained check_response_body +syn keyword ngxDirectiveThirdParty contained check_response_codes +syn keyword ngxDirectiveThirdParty contained healthcheck +syn keyword ngxDirectiveThirdParty contained healthcheck_buffer_size +syn keyword ngxDirectiveThirdParty contained healthcheck_disable_host +syn keyword ngxDirectiveThirdParty contained healthcheck_get +syn keyword ngxDirectiveThirdParty contained healthcheck_persistent +syn keyword ngxDirectiveThirdParty contained healthcheck_request_body +syn keyword ngxDirectiveThirdParty contained healthcheck_request_headers +syn keyword ngxDirectiveThirdParty contained healthcheck_request_uri +syn keyword ngxDirectiveThirdParty contained healthcheck_response_body +syn keyword ngxDirectiveThirdParty contained healthcheck_response_codes +syn keyword ngxDirectiveThirdParty contained healthcheck_status +syn keyword ngxDirectiveThirdParty contained healthcheck_update + +" https://github.com/openresty/encrypted-session-nginx-module +syn keyword ngxDirectiveThirdParty contained encrypted_session_expires +syn keyword ngxDirectiveThirdParty contained encrypted_session_iv +syn keyword ngxDirectiveThirdParty contained encrypted_session_key +syn keyword ngxDirectiveThirdParty contained set_decrypt_session +syn keyword ngxDirectiveThirdParty contained set_encrypt_session + +" https://github.com/calio/form-input-nginx-module +syn keyword ngxDirectiveThirdParty contained set_form_input +syn keyword ngxDirectiveThirdParty contained set_form_input_multi + +" https://github.com/nieoding/nginx-gridfs +syn keyword ngxDirectiveThirdParty contained gridfs +syn keyword ngxDirectiveThirdParty contained mongo -" ngx_headers_more " https://github.com/openresty/headers-more-nginx-module syn keyword ngxDirectiveThirdParty contained more_clear_headers syn keyword ngxDirectiveThirdParty contained more_clear_input_headers syn keyword ngxDirectiveThirdParty contained more_set_headers syn keyword ngxDirectiveThirdParty contained more_set_input_headers -" NGINX WebDAV missing commands support (PROPFIND & OPTIONS) +" https://github.com/dvershinin/nginx_accept_language_module +syn keyword ngxDirectiveThirdParty contained set_from_accept_language + +" https://github.com/atomx/nginx-http-auth-digest +syn keyword ngxDirectiveThirdParty contained auth_digest +syn keyword ngxDirectiveThirdParty contained auth_digest_drop_time +syn keyword ngxDirectiveThirdParty contained auth_digest_evasion_time +syn keyword ngxDirectiveThirdParty contained auth_digest_expires +syn keyword ngxDirectiveThirdParty contained auth_digest_maxtries +syn keyword ngxDirectiveThirdParty contained auth_digest_replays +syn keyword ngxDirectiveThirdParty contained auth_digest_shm_size +syn keyword ngxDirectiveThirdParty contained auth_digest_timeout +syn keyword ngxDirectiveThirdParty contained auth_digest_user_file + +" https://github.com/stnoonan/spnego-http-auth-nginx-module +syn keyword ngxDirectiveThirdParty contained auth_gss +syn keyword ngxDirectiveThirdParty contained auth_gss_allow_basic_fallback +syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal +syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal_regex +syn keyword ngxDirectiveThirdParty contained auth_gss_constrained_delegation +syn keyword ngxDirectiveThirdParty contained auth_gss_delegate_credentials +syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm +syn keyword ngxDirectiveThirdParty contained auth_gss_format_full +syn keyword ngxDirectiveThirdParty contained auth_gss_keytab +syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local +syn keyword ngxDirectiveThirdParty contained auth_gss_realm +syn keyword ngxDirectiveThirdParty contained auth_gss_service_ccache +syn keyword ngxDirectiveThirdParty contained auth_gss_service_name + +" https://github.com/kvspb/nginx-auth-ldap +syn keyword ngxDirectiveThirdParty contained auth_ldap +syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_enabled +syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_expiration_time +syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_size +syn keyword ngxDirectiveThirdParty contained auth_ldap_servers +syn keyword ngxDirectiveThirdParty contained auth_ldap_servers_size +syn keyword ngxDirectiveThirdParty contained ldap_server + +" https://github.com/sto/ngx_http_auth_pam_module +syn keyword ngxDirectiveThirdParty contained auth_pam +syn keyword ngxDirectiveThirdParty contained auth_pam_service_name +syn keyword ngxDirectiveThirdParty contained auth_pam_set_pam_env + " https://github.com/arut/nginx-dav-ext-module syn keyword ngxDirectiveThirdParty contained dav_ext_lock syn keyword ngxDirectiveThirdParty contained dav_ext_lock_zone syn keyword ngxDirectiveThirdParty contained dav_ext_methods -" ngx_eval " https://github.com/openresty/nginx-eval-module syn keyword ngxDirectiveThirdParty contained eval syn keyword ngxDirectiveThirdParty contained eval_buffer_size @@ -971,7 +1031,6 @@ syn keyword ngxDirectiveThirdParty contained eval_escalate syn keyword ngxDirectiveThirdParty contained eval_override_content_type syn keyword ngxDirectiveThirdParty contained eval_subrequest_in_memory -" Fancy Index " https://github.com/aperezdc/ngx-fancyindex syn keyword ngxDirectiveThirdParty contained fancyindex syn keyword ngxDirectiveThirdParty contained fancyindex_css_href @@ -988,40 +1047,29 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_show_dotfiles syn keyword ngxDirectiveThirdParty contained fancyindex_show_path syn keyword ngxDirectiveThirdParty contained fancyindex_time_format -" Footer filter " https://github.com/alibaba/nginx-http-footer-filter syn keyword ngxDirectiveThirdParty contained footer syn keyword ngxDirectiveThirdParty contained footer_types -" ngx_http_geoip2_module " https://github.com/leev/ngx_http_geoip2_module syn keyword ngxDirectiveThirdParty contained geoip2 syn keyword ngxDirectiveThirdParty contained geoip2_proxy syn keyword ngxDirectiveThirdParty contained geoip2_proxy_recursive -" A version of the Nginx HTTP stub status module that outputs in JSON format -" https://github.com/nginx-modules/nginx-json-status-module -syn keyword ngxDirectiveThirdParty contained json_status -syn keyword ngxDirectiveThirdParty contained json_status_type +" https://github.com/ip2location/ip2location-nginx +syn keyword ngxDirectiveThirdParty contained ip2location_database +syn keyword ngxDirectiveThirdParty contained ip2location_proxy +syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive -" MogileFS client for nginx -" https://github.com/vkholodkov/nginx-mogilefs-module -syn keyword ngxDirectiveThirdParty contained mogilefs_class -syn keyword ngxDirectiveThirdParty contained mogilefs_connect_timeout -syn keyword ngxDirectiveThirdParty contained mogilefs_domain -syn keyword ngxDirectiveThirdParty contained mogilefs_methods -syn keyword ngxDirectiveThirdParty contained mogilefs_noverify -syn keyword ngxDirectiveThirdParty contained mogilefs_pass -syn keyword ngxDirectiveThirdParty contained mogilefs_read_timeout -syn keyword ngxDirectiveThirdParty contained mogilefs_send_timeout -syn keyword ngxDirectiveThirdParty contained mogilefs_tracker +" https://github.com/ip2location/ip2proxy-nginx +syn keyword ngxDirectiveThirdParty contained ip2proxy_database +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive -" Ancient nginx plugin; probably not useful to anyone " https://github.com/kr/nginx-notice syn keyword ngxDirectiveThirdParty contained notice syn keyword ngxDirectiveThirdParty contained notice_type -" nchan " https://github.com/slact/nchan syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_credentials syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_origin @@ -1034,8 +1082,8 @@ syn keyword ngxDirectiveThirdParty contained nchan_benchmark_publisher_distribut syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time -syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string +syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id syn keyword ngxDirectiveThirdParty contained nchan_channel_group syn keyword ngxDirectiveThirdParty contained nchan_channel_group_accounting syn keyword ngxDirectiveThirdParty contained nchan_channel_id @@ -1074,11 +1122,25 @@ syn keyword ngxDirectiveThirdParty contained nchan_pubsub syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_backoff +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_jitter +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_max +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_min +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_connect_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_max_failing_time +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_backoff +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_jitter +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_max +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_min +syn keyword ngxDirectiveThirdParty contained nchan_redis_command_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_discovered_ip_range_blacklist syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_load_scripts_unconditionally syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace +syn keyword ngxDirectiveThirdParty contained nchan_redis_node_connect_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_nostore_fastpublish syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target syn keyword ngxDirectiveThirdParty contained nchan_redis_pass @@ -1086,6 +1148,13 @@ syn keyword ngxDirectiveThirdParty contained nchan_redis_pass_inheritable syn keyword ngxDirectiveThirdParty contained nchan_redis_password syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_publish_msgpacked_max_size +syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay +syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_backoff +syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_jitter +syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_max +syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_min +syn keyword ngxDirectiveThirdParty contained nchan_redis_retry_commands +syn keyword ngxDirectiveThirdParty contained nchan_redis_retry_commands_max_wait syn keyword ngxDirectiveThirdParty contained nchan_redis_server syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_ciphers @@ -1113,10 +1182,10 @@ syn keyword ngxDirectiveThirdParty contained nchan_store_messages syn keyword ngxDirectiveThirdParty contained nchan_stub_status syn keyword ngxDirectiveThirdParty contained nchan_sub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_subscribe_existing_channels_only +syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request syn keyword ngxDirectiveThirdParty contained nchan_subscriber syn keyword ngxDirectiveThirdParty contained nchan_subscriber_channel_id syn keyword ngxDirectiveThirdParty contained nchan_subscriber_compound_etag_message_id -syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator syn keyword ngxDirectiveThirdParty contained nchan_subscriber_info @@ -1145,7 +1214,6 @@ syn keyword ngxDirectiveThirdParty contained push_subscriber syn keyword ngxDirectiveThirdParty contained push_subscriber_concurrency syn keyword ngxDirectiveThirdParty contained push_subscriber_timeout -" Push Stream " https://github.com/wandenberg/nginx-push-stream-module syn keyword ngxDirectiveThirdParty contained push_stream_allow_connections_to_events_channel syn keyword ngxDirectiveThirdParty contained push_stream_allowed_origins @@ -1184,23 +1252,6 @@ syn keyword ngxDirectiveThirdParty contained push_stream_websocket_allow_publish syn keyword ngxDirectiveThirdParty contained push_stream_wildcard_channel_max_qtd syn keyword ngxDirectiveThirdParty contained push_stream_wildcard_channel_prefix -" redis module -" https://www.nginx.com/resources/wiki/modules/redis/ -syn keyword ngxDirectiveThirdParty contained redis_bind -syn keyword ngxDirectiveThirdParty contained redis_buffer_size -syn keyword ngxDirectiveThirdParty contained redis_connect_timeout -syn keyword ngxDirectiveThirdParty contained redis_gzip_flag -syn keyword ngxDirectiveThirdParty contained redis_next_upstream -syn keyword ngxDirectiveThirdParty contained redis_pass -syn keyword ngxDirectiveThirdParty contained redis_read_timeout -syn keyword ngxDirectiveThirdParty contained redis_send_timeout - -" ngx_http_response -" http://catap.ru/downloads/nginx/ -syn keyword ngxDirectiveThirdParty contained response -syn keyword ngxDirectiveThirdParty contained response_type - -" nginx_substitutions_filter " https://github.com/yaoweibin/ngx_http_substitutions_filter_module syn keyword ngxDirectiveThirdParty contained subs_buffers syn keyword ngxDirectiveThirdParty contained subs_filter @@ -1208,7 +1259,6 @@ syn keyword ngxDirectiveThirdParty contained subs_filter_bypass syn keyword ngxDirectiveThirdParty contained subs_filter_types syn keyword ngxDirectiveThirdParty contained subs_line_buffer_size -" Tarantool nginx upstream module " https://github.com/tarantool/nginx_upstream_module syn keyword ngxDirectiveThirdParty contained tnt_allowed_indexes syn keyword ngxDirectiveThirdParty contained tnt_allowed_spaces @@ -1238,44 +1288,28 @@ syn keyword ngxDirectiveThirdParty contained tnt_set_header syn keyword ngxDirectiveThirdParty contained tnt_update syn keyword ngxDirectiveThirdParty contained tnt_upsert -" A module for nginx web server for handling file uploads using multipart/form-data encoding (RFC 1867) -" https://github.com/Austinb/nginx-upload-module +" https://github.com/fdintino/nginx-upload-module +syn keyword ngxDirectiveThirdParty contained upload_add_header syn keyword ngxDirectiveThirdParty contained upload_aggregate_form_field -syn keyword ngxDirectiveThirdParty contained upload_archive_elm -syn keyword ngxDirectiveThirdParty contained upload_archive_elm_separator -syn keyword ngxDirectiveThirdParty contained upload_archive_path -syn keyword ngxDirectiveThirdParty contained upload_archive_path_separator syn keyword ngxDirectiveThirdParty contained upload_buffer_size syn keyword ngxDirectiveThirdParty contained upload_cleanup -syn keyword ngxDirectiveThirdParty contained upload_content_type -syn keyword ngxDirectiveThirdParty contained upload_discard -syn keyword ngxDirectiveThirdParty contained upload_field_name -syn keyword ngxDirectiveThirdParty contained upload_file_crc32 -syn keyword ngxDirectiveThirdParty contained upload_file_md5 -syn keyword ngxDirectiveThirdParty contained upload_file_md5_uc -syn keyword ngxDirectiveThirdParty contained upload_file_name -syn keyword ngxDirectiveThirdParty contained upload_file_sha1 -syn keyword ngxDirectiveThirdParty contained upload_file_sha1_uc -syn keyword ngxDirectiveThirdParty contained upload_file_size -syn keyword ngxDirectiveThirdParty contained upload_filter +syn keyword ngxDirectiveThirdParty contained upload_empty_fiels_names +syn keyword ngxDirectiveThirdParty contained upload_limit_rate syn keyword ngxDirectiveThirdParty contained upload_max_file_size syn keyword ngxDirectiveThirdParty contained upload_max_output_body_len syn keyword ngxDirectiveThirdParty contained upload_max_part_header_len +syn keyword ngxDirectiveThirdParty contained upload_merge_buffer_size syn keyword ngxDirectiveThirdParty contained upload_pass syn keyword ngxDirectiveThirdParty contained upload_pass_args syn keyword ngxDirectiveThirdParty contained upload_pass_form_field +syn keyword ngxDirectiveThirdParty contained upload_range_header_buffer_size +syn keyword ngxDirectiveThirdParty contained upload_resumable syn keyword ngxDirectiveThirdParty contained upload_set_form_field +syn keyword ngxDirectiveThirdParty contained upload_state_store syn keyword ngxDirectiveThirdParty contained upload_store syn keyword ngxDirectiveThirdParty contained upload_store_access -syn keyword ngxDirectiveThirdParty contained upload_tmp_path -syn keyword ngxDirectiveThirdParty contained upload_unzip -syn keyword ngxDirectiveThirdParty contained upload_unzip_buffers -syn keyword ngxDirectiveThirdParty contained upload_unzip_hash -syn keyword ngxDirectiveThirdParty contained upload_unzip_max_file_name_len -syn keyword ngxDirectiveThirdParty contained upload_unzip_window -syn keyword ngxDirectiveThirdParty contained upload_void_content_type +syn keyword ngxDirectiveThirdParty contained upload_tame_arrays -" nginx-upload-progress-module " https://github.com/masterzen/nginx-upload-progress-module syn keyword ngxDirectiveThirdParty contained report_uploads syn keyword ngxDirectiveThirdParty contained track_uploads @@ -1288,9 +1322,7 @@ syn keyword ngxDirectiveThirdParty contained upload_progress_jsonp_output syn keyword ngxDirectiveThirdParty contained upload_progress_jsonp_parameter syn keyword ngxDirectiveThirdParty contained upload_progress_template -" Health checks upstreams for nginx " https://github.com/yaoweibin/nginx_upstream_check_module -syn keyword ngxDirectiveThirdParty contained check syn keyword ngxDirectiveThirdParty contained check_fastcgi_param syn keyword ngxDirectiveThirdParty contained check_http_expect_alive syn keyword ngxDirectiveThirdParty contained check_http_send @@ -1298,13 +1330,14 @@ syn keyword ngxDirectiveThirdParty contained check_keepalive_requests syn keyword ngxDirectiveThirdParty contained check_shm_size syn keyword ngxDirectiveThirdParty contained check_status -" The fair load balancer module for nginx -" https://github.com/cryptofuture/nginx-upstream-fair +" https://github.com/jaygooby/nginx-upstream-fair syn keyword ngxDirectiveThirdParty contained fair syn keyword ngxDirectiveThirdParty contained upstream_fair_shm_size -" Nginx Video Thumb Extractor Module -" https://github.com/wandenberg/nginx-video-thumbextractor-module +" https://github.com/ayty-adrianomartins/nginx-sticky-module-ng +syn keyword ngxDirectiveThirdParty contained sticky_no_fallback + +" https://github.com/Novetta/nginx-video-thumbextractor-module syn keyword ngxDirectiveThirdParty contained video_thumbextractor syn keyword ngxDirectiveThirdParty contained video_thumbextractor_image_height syn keyword ngxDirectiveThirdParty contained video_thumbextractor_image_width @@ -1329,43 +1362,14 @@ syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_sample_in syn keyword ngxDirectiveThirdParty contained video_thumbextractor_video_filename syn keyword ngxDirectiveThirdParty contained video_thumbextractor_video_second -" drizzle-nginx-module - Upstream module for talking to MySQL and Drizzle directly -" https://github.com/openresty/drizzle-nginx-module -syn keyword ngxDirectiveThirdParty contained drizzle_buffer_size -syn keyword ngxDirectiveThirdParty contained drizzle_connect_timeout -syn keyword ngxDirectiveThirdParty contained drizzle_dbname -syn keyword ngxDirectiveThirdParty contained drizzle_keepalive -syn keyword ngxDirectiveThirdParty contained drizzle_module_header -syn keyword ngxDirectiveThirdParty contained drizzle_pass -syn keyword ngxDirectiveThirdParty contained drizzle_query -syn keyword ngxDirectiveThirdParty contained drizzle_recv_cols_timeout -syn keyword ngxDirectiveThirdParty contained drizzle_recv_rows_timeout -syn keyword ngxDirectiveThirdParty contained drizzle_send_query_timeout -syn keyword ngxDirectiveThirdParty contained drizzle_server -syn keyword ngxDirectiveThirdParty contained drizzle_status +" https://github.com/calio/iconv-nginx-module +syn keyword ngxDirectiveThirdParty contained iconv_buffer_size +syn keyword ngxDirectiveThirdParty contained iconv_filter +syn keyword ngxDirectiveThirdParty contained set_iconv -" ngx_dynamic_upstream -" https://github.com/cubicdaiya/ngx_dynamic_upstream -syn keyword ngxDirectiveThirdParty contained dynamic_upstream - -" encrypt and decrypt nginx variable values -" https://github.com/openresty/encrypted-session-nginx-module -syn keyword ngxDirectiveThirdParty contained encrypted_session_expires -syn keyword ngxDirectiveThirdParty contained encrypted_session_iv -syn keyword ngxDirectiveThirdParty contained encrypted_session_key -syn keyword ngxDirectiveThirdParty contained set_decrypt_session -syn keyword ngxDirectiveThirdParty contained set_encrypt_session - -" serve content directly from MongoDB's GridFS -" https://github.com/mdirolf/nginx-gridfs -syn keyword ngxDirectiveThirdParty contained gridfs -syn keyword ngxDirectiveThirdParty contained mongo - -" Adds support for arithmetic operations to NGINX config -" https://github.com/arut/nginx-let-module +" https://github.com/baysao/nginx-let-module syn keyword ngxDirectiveThirdParty contained let -" ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers " https://github.com/openresty/lua-nginx-module syn keyword ngxDirectiveThirdParty contained access_by_lua syn keyword ngxDirectiveThirdParty contained access_by_lua_block @@ -1431,6 +1435,8 @@ syn keyword ngxDirectiveThirdParty contained rewrite_by_lua syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_block syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_file syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_no_postpone +syn keyword ngxDirectiveThirdParty contained server_rewrite_by_lua_block +syn keyword ngxDirectiveThirdParty contained server_rewrite_by_lua_file syn keyword ngxDirectiveThirdParty contained set_by_lua syn keyword ngxDirectiveThirdParty contained set_by_lua_block syn keyword ngxDirectiveThirdParty contained set_by_lua_file @@ -1443,7 +1449,16 @@ syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_block syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_file -" ngx_memc - An extended version of the standard memcached module +" https://github.com/Taymindis/nginx-link-function +syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_prop +syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_req_header +syn keyword ngxDirectiveThirdParty contained ngx_link_func_ca_cert +syn keyword ngxDirectiveThirdParty contained ngx_link_func_call +syn keyword ngxDirectiveThirdParty contained ngx_link_func_download_link_lib +syn keyword ngxDirectiveThirdParty contained ngx_link_func_lib +syn keyword ngxDirectiveThirdParty contained ngx_link_func_shm_size +syn keyword ngxDirectiveThirdParty contained ngx_link_func_subrequest + " https://github.com/openresty/memc-nginx-module syn keyword ngxDirectiveThirdParty contained memc_buffer_size syn keyword ngxDirectiveThirdParty contained memc_cmds_allowed @@ -1457,21 +1472,24 @@ syn keyword ngxDirectiveThirdParty contained memc_send_timeout syn keyword ngxDirectiveThirdParty contained memc_upstream_fail_timeout syn keyword ngxDirectiveThirdParty contained memc_upstream_max_fails -" ModSecurity web application firewall -" https://github.com/SpiderLabs/ModSecurity/tree/master -syn keyword ngxDirectiveThirdParty contained ModSecurityConfig -syn keyword ngxDirectiveThirdParty contained ModSecurityEnabled -syn keyword ngxDirectiveThirdParty contained pool_context_hash_size +" https://github.com/SpiderLabs/ModSecurity-nginx +syn keyword ngxDirectiveThirdParty contained modsecurity +syn keyword ngxDirectiveThirdParty contained modsecurity_rules +syn keyword ngxDirectiveThirdParty contained modsecurity_rules_file +syn keyword ngxDirectiveThirdParty contained modsecurity_rules_remote +syn keyword ngxDirectiveThirdParty contained modsecurity_transaction_id -" NAXSI is an open-source, high performance, low rules maintenance WAF for NGINX " https://github.com/nbs-system/naxsi syn keyword ngxDirectiveThirdParty contained BasicRule syn keyword ngxDirectiveThirdParty contained CheckRule syn keyword ngxDirectiveThirdParty contained DeniedUrl +syn keyword ngxDirectiveThirdParty contained IgnoreCIDR +syn keyword ngxDirectiveThirdParty contained IgnoreIP syn keyword ngxDirectiveThirdParty contained LearningMode syn keyword ngxDirectiveThirdParty contained LibInjectionSql syn keyword ngxDirectiveThirdParty contained LibInjectionXss syn keyword ngxDirectiveThirdParty contained MainRule +syn keyword ngxDirectiveThirdParty contained NaxsiLogFile syn keyword ngxDirectiveThirdParty contained SecRulesDisabled syn keyword ngxDirectiveThirdParty contained SecRulesEnabled syn keyword ngxDirectiveThirdParty contained basic_rule @@ -1481,17 +1499,31 @@ syn keyword ngxDirectiveThirdParty contained learning_mode syn keyword ngxDirectiveThirdParty contained libinjection_sql syn keyword ngxDirectiveThirdParty contained libinjection_xss syn keyword ngxDirectiveThirdParty contained main_rule +syn keyword ngxDirectiveThirdParty contained naxsi_log syn keyword ngxDirectiveThirdParty contained rules_disabled syn keyword ngxDirectiveThirdParty contained rules_enabled -" Phusion Passenger -" https://www.phusionpassenger.com/library/config/nginx/reference/ +" https://github.com/opentracing-contrib/nginx-opentracing +syn keyword ngxDirectiveThirdParty contained opentracing +syn keyword ngxDirectiveThirdParty contained opentracing_fastcgi_propagate_context +syn keyword ngxDirectiveThirdParty contained opentracing_grpc_propagate_context +syn keyword ngxDirectiveThirdParty contained opentracing_load_tracer +syn keyword ngxDirectiveThirdParty contained opentracing_location_operation_name +syn keyword ngxDirectiveThirdParty contained opentracing_operation_name +syn keyword ngxDirectiveThirdParty contained opentracing_propagate_context +syn keyword ngxDirectiveThirdParty contained opentracing_tag +syn keyword ngxDirectiveThirdParty contained opentracing_trace_locations +syn keyword ngxDirectiveThirdParty contained opentracing_trust_incoming_span + +" https://github.com/phusion/passenger syn keyword ngxDirectiveThirdParty contained passenger_abort_on_startup_error syn keyword ngxDirectiveThirdParty contained passenger_abort_websockets_on_process_shutdown syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_auth_type syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_password syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_url syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_username +syn keyword ngxDirectiveThirdParty contained passenger_analytics_log_group +syn keyword ngxDirectiveThirdParty contained passenger_analytics_log_user syn keyword ngxDirectiveThirdParty contained passenger_anonymous_telemetry_proxy syn keyword ngxDirectiveThirdParty contained passenger_app_env syn keyword ngxDirectiveThirdParty contained passenger_app_file_descriptor_ulimit @@ -1499,20 +1531,25 @@ syn keyword ngxDirectiveThirdParty contained passenger_app_group_name syn keyword ngxDirectiveThirdParty contained passenger_app_log_file syn keyword ngxDirectiveThirdParty contained passenger_app_rights syn keyword ngxDirectiveThirdParty contained passenger_app_root +syn keyword ngxDirectiveThirdParty contained passenger_app_start_command syn keyword ngxDirectiveThirdParty contained passenger_app_type syn keyword ngxDirectiveThirdParty contained passenger_base_uri syn keyword ngxDirectiveThirdParty contained passenger_buffer_response syn keyword ngxDirectiveThirdParty contained passenger_buffer_size +syn keyword ngxDirectiveThirdParty contained passenger_buffer_upload syn keyword ngxDirectiveThirdParty contained passenger_buffers syn keyword ngxDirectiveThirdParty contained passenger_busy_buffers_size syn keyword ngxDirectiveThirdParty contained passenger_concurrency_model syn keyword ngxDirectiveThirdParty contained passenger_core_file_descriptor_ulimit syn keyword ngxDirectiveThirdParty contained passenger_ctl syn keyword ngxDirectiveThirdParty contained passenger_data_buffer_dir +syn keyword ngxDirectiveThirdParty contained passenger_debug_log_file syn keyword ngxDirectiveThirdParty contained passenger_debugger syn keyword ngxDirectiveThirdParty contained passenger_default_group syn keyword ngxDirectiveThirdParty contained passenger_default_user +syn keyword ngxDirectiveThirdParty contained passenger_direct_instance_request_address syn keyword ngxDirectiveThirdParty contained passenger_disable_anonymous_telemetry +syn keyword ngxDirectiveThirdParty contained passenger_disable_log_prefix syn keyword ngxDirectiveThirdParty contained passenger_disable_security_update_check syn keyword ngxDirectiveThirdParty contained passenger_document_root syn keyword ngxDirectiveThirdParty contained passenger_dump_config_manifest @@ -1548,8 +1585,10 @@ syn keyword ngxDirectiveThirdParty contained passenger_nodejs syn keyword ngxDirectiveThirdParty contained passenger_pass_header syn keyword ngxDirectiveThirdParty contained passenger_pool_idle_time syn keyword ngxDirectiveThirdParty contained passenger_pre_start +syn keyword ngxDirectiveThirdParty contained passenger_preload_bundler syn keyword ngxDirectiveThirdParty contained passenger_python syn keyword ngxDirectiveThirdParty contained passenger_read_timeout +syn keyword ngxDirectiveThirdParty contained passenger_request_buffering syn keyword ngxDirectiveThirdParty contained passenger_request_queue_overflow_status_code syn keyword ngxDirectiveThirdParty contained passenger_resist_deployment_errors syn keyword ngxDirectiveThirdParty contained passenger_response_buffer_high_watermark @@ -1561,36 +1600,36 @@ syn keyword ngxDirectiveThirdParty contained passenger_security_update_check_pro syn keyword ngxDirectiveThirdParty contained passenger_set_header syn keyword ngxDirectiveThirdParty contained passenger_show_version_in_header syn keyword ngxDirectiveThirdParty contained passenger_socket_backlog +syn keyword ngxDirectiveThirdParty contained passenger_spawn_dir +syn keyword ngxDirectiveThirdParty contained passenger_spawn_exception_status_code syn keyword ngxDirectiveThirdParty contained passenger_spawn_method syn keyword ngxDirectiveThirdParty contained passenger_start_timeout syn keyword ngxDirectiveThirdParty contained passenger_startup_file syn keyword ngxDirectiveThirdParty contained passenger_stat_throttle_rate syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions +syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions_cookie_attributes syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions_cookie_name +syn keyword ngxDirectiveThirdParty contained passenger_temp_path syn keyword ngxDirectiveThirdParty contained passenger_thread_count syn keyword ngxDirectiveThirdParty contained passenger_turbocaching +syn keyword ngxDirectiveThirdParty contained passenger_use_global_queue syn keyword ngxDirectiveThirdParty contained passenger_user syn keyword ngxDirectiveThirdParty contained passenger_user_switching syn keyword ngxDirectiveThirdParty contained passenger_vary_turbocache_by_cookie -syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_analytics_log_group -syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_analytics_log_user -syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_debug_log_file -syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_use_global_queue -syn keyword ngxDirectiveThirdPartyDeprecated contained rack_env -syn keyword ngxDirectiveThirdPartyDeprecated contained rails_app_spawner_idle_time -syn keyword ngxDirectiveThirdPartyDeprecated contained rails_env -syn keyword ngxDirectiveThirdPartyDeprecated contained rails_framework_spawner_idle_time -syn keyword ngxDirectiveThirdPartyDeprecated contained rails_spawn_method -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_filter -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_address -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_cert -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_port -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_key -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_proxy_address -syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_support +syn keyword ngxDirectiveThirdParty contained rack_env +syn keyword ngxDirectiveThirdParty contained rails_app_spawner_idle_time +syn keyword ngxDirectiveThirdParty contained rails_env +syn keyword ngxDirectiveThirdParty contained rails_framework_spawner_idle_time +syn keyword ngxDirectiveThirdParty contained rails_spawn_method +syn keyword ngxDirectiveThirdParty contained union_station_filter +syn keyword ngxDirectiveThirdParty contained union_station_gateway_address +syn keyword ngxDirectiveThirdParty contained union_station_gateway_cert +syn keyword ngxDirectiveThirdParty contained union_station_gateway_port +syn keyword ngxDirectiveThirdParty contained union_station_key +syn keyword ngxDirectiveThirdParty contained union_station_proxy_address +syn keyword ngxDirectiveThirdParty contained union_station_support -" ngx_postgres is an upstream module that allows nginx to communicate directly with PostgreSQL database -" https://github.com/FRiCKLE/ngx_postgres +" https://github.com/konstruxi/ngx_postgres syn keyword ngxDirectiveThirdParty contained postgres_connect_timeout syn keyword ngxDirectiveThirdParty contained postgres_escape syn keyword ngxDirectiveThirdParty contained postgres_keepalive @@ -1602,7 +1641,6 @@ syn keyword ngxDirectiveThirdParty contained postgres_rewrite syn keyword ngxDirectiveThirdParty contained postgres_server syn keyword ngxDirectiveThirdParty contained postgres_set -" ngx_rds_csv - Nginx output filter module to convert Resty-DBD-Streams (RDS) to Comma-Separated Values (CSV) " https://github.com/openresty/rds-csv-nginx-module syn keyword ngxDirectiveThirdParty contained rds_csv syn keyword ngxDirectiveThirdParty contained rds_csv_buffer_size @@ -1611,7 +1649,6 @@ syn keyword ngxDirectiveThirdParty contained rds_csv_field_name_header syn keyword ngxDirectiveThirdParty contained rds_csv_field_separator syn keyword ngxDirectiveThirdParty contained rds_csv_row_terminator -" ngx_rds_json - an output filter that formats Resty DBD Streams generated by ngx_drizzle and others to JSON " https://github.com/openresty/rds-json-nginx-module syn keyword ngxDirectiveThirdParty contained rds_json syn keyword ngxDirectiveThirdParty contained rds_json_buffer_size @@ -1624,7 +1661,6 @@ syn keyword ngxDirectiveThirdParty contained rds_json_root syn keyword ngxDirectiveThirdParty contained rds_json_success_property syn keyword ngxDirectiveThirdParty contained rds_json_user_property -" ngx_redis2 - Nginx upstream module for the Redis 2.0 protocol " https://github.com/openresty/redis2-nginx-module syn keyword ngxDirectiveThirdParty contained redis2_bind syn keyword ngxDirectiveThirdParty contained redis2_buffer_size @@ -1638,7 +1674,6 @@ syn keyword ngxDirectiveThirdParty contained redis2_raw_query syn keyword ngxDirectiveThirdParty contained redis2_read_timeout syn keyword ngxDirectiveThirdParty contained redis2_send_timeout -" NGINX-based Media Streaming Server " https://github.com/arut/nginx-rtmp-module syn keyword ngxDirectiveThirdParty contained ack_window syn keyword ngxDirectiveThirdParty contained application @@ -1750,7 +1785,6 @@ syn keyword ngxDirectiveThirdParty contained sync syn keyword ngxDirectiveThirdParty contained wait_key syn keyword ngxDirectiveThirdParty contained wait_video -" ngx_set_misc - Various set_xxx directives added to nginx's rewrite module (md5/sha1, sql/json quoting, and many more) " https://github.com/openresty/set-misc-nginx-module syn keyword ngxDirectiveThirdParty contained set_base32_alphabet syn keyword ngxDirectiveThirdParty contained set_base32_padding @@ -1770,6 +1804,7 @@ syn keyword ngxDirectiveThirdParty contained set_hmac_sha1 syn keyword ngxDirectiveThirdParty contained set_hmac_sha256 syn keyword ngxDirectiveThirdParty contained set_if_empty syn keyword ngxDirectiveThirdParty contained set_local_today +syn keyword ngxDirectiveThirdParty contained set_md5 syn keyword ngxDirectiveThirdParty contained set_misc_base32_padding syn keyword ngxDirectiveThirdParty contained set_quote_json_str syn keyword ngxDirectiveThirdParty contained set_quote_pgsql_str @@ -1778,20 +1813,18 @@ syn keyword ngxDirectiveThirdParty contained set_random syn keyword ngxDirectiveThirdParty contained set_rotate syn keyword ngxDirectiveThirdParty contained set_secure_random_alphanum syn keyword ngxDirectiveThirdParty contained set_secure_random_lcalpha +syn keyword ngxDirectiveThirdParty contained set_sha1 syn keyword ngxDirectiveThirdParty contained set_unescape_uri -" nginx-sflow-module " https://github.com/sflow/nginx-sflow-module syn keyword ngxDirectiveThirdParty contained sflow -" Shibboleth auth request module for Nginx " https://github.com/nginx-shib/nginx-http-shibboleth syn keyword ngxDirectiveThirdParty contained shib_request syn keyword ngxDirectiveThirdParty contained shib_request_set syn keyword ngxDirectiveThirdParty contained shib_request_use_headers -" nginx module which adds ability to cache static files -" https://github.com/FRiCKLE/ngx_slowfs_cache +" https://github.com/baysao/ngx_slowfs_cache syn keyword ngxDirectiveThirdParty contained slowfs_big_file_size syn keyword ngxDirectiveThirdParty contained slowfs_cache syn keyword ngxDirectiveThirdParty contained slowfs_cache_key @@ -1801,8 +1834,7 @@ syn keyword ngxDirectiveThirdParty contained slowfs_cache_purge syn keyword ngxDirectiveThirdParty contained slowfs_cache_valid syn keyword ngxDirectiveThirdParty contained slowfs_temp_path -" Dynamic Image Transformation Module For nginx -" https://github.com/cubicdaiya/ngx_small_light +" https://github.com/kawakibi/ngx_small_light syn keyword ngxDirectiveThirdParty contained small_light syn keyword ngxDirectiveThirdParty contained small_light_buffer syn keyword ngxDirectiveThirdParty contained small_light_getparam_mode @@ -1812,7 +1844,6 @@ syn keyword ngxDirectiveThirdParty contained small_light_pattern_define syn keyword ngxDirectiveThirdParty contained small_light_radius_max syn keyword ngxDirectiveThirdParty contained small_light_sigma_max -" ngx_srcache - Transparent subrequest-based caching layout for arbitrary nginx locations " https://github.com/openresty/srcache-nginx-module syn keyword ngxDirectiveThirdParty contained srcache_buffer syn keyword ngxDirectiveThirdParty contained srcache_default_expire @@ -1835,7 +1866,6 @@ syn keyword ngxDirectiveThirdParty contained srcache_store_ranges syn keyword ngxDirectiveThirdParty contained srcache_store_skip syn keyword ngxDirectiveThirdParty contained srcache_store_statuses -" NGINX-based VOD Packager " https://github.com/kaltura/nginx-vod-module syn keyword ngxDirectiveThirdParty contained vod syn keyword ngxDirectiveThirdParty contained vod_align_segments_to_key_frames @@ -1875,6 +1905,7 @@ syn keyword ngxDirectiveThirdParty contained vod_live_window_duration syn keyword ngxDirectiveThirdParty contained vod_manifest_duration_policy syn keyword ngxDirectiveThirdParty contained vod_manifest_segment_durations_mode syn keyword ngxDirectiveThirdParty contained vod_mapping_cache +syn keyword ngxDirectiveThirdParty contained vod_max_frame_count syn keyword ngxDirectiveThirdParty contained vod_max_frames_size syn keyword ngxDirectiveThirdParty contained vod_max_mapping_response_size syn keyword ngxDirectiveThirdParty contained vod_max_metadata_size @@ -1901,6 +1932,7 @@ syn keyword ngxDirectiveThirdParty contained vod_response_cache syn keyword ngxDirectiveThirdParty contained vod_secret_key syn keyword ngxDirectiveThirdParty contained vod_segment_count_policy syn keyword ngxDirectiveThirdParty contained vod_segment_duration +syn keyword ngxDirectiveThirdParty contained vod_segment_max_frame_count syn keyword ngxDirectiveThirdParty contained vod_segments_base_url syn keyword ngxDirectiveThirdParty contained vod_source_clip_map_uri syn keyword ngxDirectiveThirdParty contained vod_speed_param_name @@ -1910,7 +1942,6 @@ syn keyword ngxDirectiveThirdParty contained vod_tracks_param_name syn keyword ngxDirectiveThirdParty contained vod_upstream_extra_args syn keyword ngxDirectiveThirdParty contained vod_upstream_location -" Nginx virtual host traffic status module " https://github.com/vozlt/nginx-module-vts syn keyword ngxDirectiveThirdParty contained vhost_traffic_status syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_average_method @@ -1934,7 +1965,6 @@ syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_traffic_ syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_set_by_filter syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_zone -" xss-nginx-module - Native cross-site scripting support in nginx " https://github.com/openresty/xss-nginx-module syn keyword ngxDirectiveThirdParty contained xss_callback_arg syn keyword ngxDirectiveThirdParty contained xss_check_status @@ -1943,471 +1973,6 @@ syn keyword ngxDirectiveThirdParty contained xss_input_types syn keyword ngxDirectiveThirdParty contained xss_output_type syn keyword ngxDirectiveThirdParty contained xss_override_status -" Add support for array-typed variables to nginx config files -" https://github.com/openresty/array-var-nginx-module -syn keyword ngxDirectiveThirdParty contained array_join -syn keyword ngxDirectiveThirdParty contained array_map -syn keyword ngxDirectiveThirdParty contained array_map_op -syn keyword ngxDirectiveThirdParty contained array_split - -" NGINX module for Brotli compression -" https://github.com/eustas/ngx_brotli -syn keyword ngxDirectiveThirdParty contained brotli -syn keyword ngxDirectiveThirdParty contained brotli_buffers -syn keyword ngxDirectiveThirdParty contained brotli_comp_level -syn keyword ngxDirectiveThirdParty contained brotli_min_length -syn keyword ngxDirectiveThirdParty contained brotli_static -syn keyword ngxDirectiveThirdParty contained brotli_types -syn keyword ngxDirectiveThirdParty contained brotli_window - -" form-input-nginx-module -" https://github.com/calio/form-input-nginx-module -syn keyword ngxDirectiveThirdParty contained set_form_input -syn keyword ngxDirectiveThirdParty contained set_form_input_multi - -" character conversion nginx module using libiconv -" https://github.com/calio/iconv-nginx-module -syn keyword ngxDirectiveThirdParty contained iconv_buffer_size -syn keyword ngxDirectiveThirdParty contained iconv_filter -syn keyword ngxDirectiveThirdParty contained set_iconv - -" 3rd party modules list taken from -" https://www.nginx.com/resources/wiki/modules/ -" --------------------------------------------- - -" Nginx Module for Authenticating Akamai G2O requests -" https://github.com/kaltura/nginx_mod_akamai_g2o -syn keyword ngxDirectiveThirdParty contained g2o -syn keyword ngxDirectiveThirdParty contained g2o_data_header -syn keyword ngxDirectiveThirdParty contained g2o_hash_function -syn keyword ngxDirectiveThirdParty contained g2o_key -syn keyword ngxDirectiveThirdParty contained g2o_log_level -syn keyword ngxDirectiveThirdParty contained g2o_nonce -syn keyword ngxDirectiveThirdParty contained g2o_sign_header -syn keyword ngxDirectiveThirdParty contained g2o_time_window -syn keyword ngxDirectiveThirdParty contained g2o_version - -" nginx_lua_module -" https://github.com/alacner/nginx_lua_module -syn keyword ngxDirectiveThirdParty contained lua_file - -" Nginx Audio Track for HTTP Live Streaming -" https://github.com/flavioribeiro/nginx-audio-track-for-hls-module -syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track -syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_output_format -syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_output_header -syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_rootpath - -" A Nginx module to dump backtrace when a worker process exits abnormally -" https://github.com/alibaba/nginx-backtrace -syn keyword ngxDirectiveThirdParty contained backtrace_log -syn keyword ngxDirectiveThirdParty contained backtrace_max_stack_size - -" circle_gif module -" https://github.com/evanmiller/nginx_circle_gif -syn keyword ngxDirectiveThirdParty contained circle_gif -syn keyword ngxDirectiveThirdParty contained circle_gif_max_radius -syn keyword ngxDirectiveThirdParty contained circle_gif_min_radius -syn keyword ngxDirectiveThirdParty contained circle_gif_step_radius - -" Upstream Consistent Hash -" https://github.com/replay/ngx_http_consistent_hash -syn keyword ngxDirectiveThirdParty contained consistent_hash - -" Nginx module for etags on dynamic content -" https://github.com/kali/nginx-dynamic-etags -syn keyword ngxDirectiveThirdParty contained dynamic_etags - -" Enhanced Nginx Memcached Module -" https://github.com/bpaquet/ngx_http_enhanced_memcached_module -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_allow_delete -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_allow_put -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_bind -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_buffer_size -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_connect_timeout -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_flush -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_flush_namespace -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_hash_keys_with_md5 -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_pass -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_read_timeout -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_send_timeout -syn keyword ngxDirectiveThirdParty contained enhanced_memcached_stats - -" nginx max connections queue -" https://github.com/ezmobius/nginx-ey-balancer -syn keyword ngxDirectiveThirdParty contained max_connections_max_queue_length -syn keyword ngxDirectiveThirdParty contained max_connections_queue_timeout - -" Nginx module for POST authentication and authorization -" https://github.com/veruu/ngx_form_auth -syn keyword ngxDirectiveThirdParty contained form_auth -syn keyword ngxDirectiveThirdParty contained form_auth_login -syn keyword ngxDirectiveThirdParty contained form_auth_pam_service -syn keyword ngxDirectiveThirdParty contained form_auth_password -syn keyword ngxDirectiveThirdParty contained form_auth_remote_user - -" ngx_http_accounting_module -" https://github.com/Lax/ngx_http_accounting_module -syn keyword ngxDirectiveThirdParty contained accounting -syn keyword ngxDirectiveThirdParty contained accounting_id -syn keyword ngxDirectiveThirdParty contained accounting_interval -syn keyword ngxDirectiveThirdParty contained accounting_log -syn keyword ngxDirectiveThirdParty contained accounting_perturb - -" concatenating files in a given context: CSS and JS files usually -" https://github.com/alibaba/nginx-http-concat -syn keyword ngxDirectiveThirdParty contained concat -syn keyword ngxDirectiveThirdParty contained concat_delimiter -syn keyword ngxDirectiveThirdParty contained concat_ignore_file_error -syn keyword ngxDirectiveThirdParty contained concat_max_files -syn keyword ngxDirectiveThirdParty contained concat_types -syn keyword ngxDirectiveThirdParty contained concat_unique - -" update upstreams' config by restful interface -" https://github.com/yzprofile/ngx_http_dyups_module -syn keyword ngxDirectiveThirdParty contained dyups_interface -syn keyword ngxDirectiveThirdParty contained dyups_shm_zone_size - -" add given content to the end of the response according to the condition specified -" https://github.com/flygoast/ngx_http_footer_if_filter -syn keyword ngxDirectiveThirdParty contained footer_if - -" NGINX HTTP Internal Redirect Module -" https://github.com/flygoast/ngx_http_internal_redirect -syn keyword ngxDirectiveThirdParty contained internal_redirect_if -syn keyword ngxDirectiveThirdParty contained internal_redirect_if_no_postpone - -" nginx-ip-blocker -" https://github.com/tmthrgd/nginx-ip-blocker -syn keyword ngxDirectiveThirdParty contained ip_blocker - -" IP2Location Nginx -" https://github.com/chrislim2888/ip2location-nginx -syn keyword ngxDirectiveThirdParty contained ip2location_database - -" Limit upload rate -" https://github.com/cfsego/limit_upload_rate -syn keyword ngxDirectiveThirdParty contained limit_upload_rate -syn keyword ngxDirectiveThirdParty contained limit_upload_rate_after -syn keyword ngxDirectiveThirdParty contained limit_upload_rate_log_level - -" limit the number of connections to upstream -" https://github.com/cfsego/nginx-limit-upstream -syn keyword ngxDirectiveThirdParty contained limit_upstream_conn -syn keyword ngxDirectiveThirdParty contained limit_upstream_log_level -syn keyword ngxDirectiveThirdParty contained limit_upstream_zone - -" conditional accesslog for nginx -" https://github.com/cfsego/ngx_log_if -syn keyword ngxDirectiveThirdParty contained access_log_bypass_if - -" log messages over ZeroMQ -" https://github.com/alticelabs/nginx-log-zmq -syn keyword ngxDirectiveThirdParty contained log_zmq_endpoint -syn keyword ngxDirectiveThirdParty contained log_zmq_format -syn keyword ngxDirectiveThirdParty contained log_zmq_off -syn keyword ngxDirectiveThirdParty contained log_zmq_server - -" simple module to uppercase/lowercase strings in the nginx config -" https://github.com/replay/ngx_http_lower_upper_case -syn keyword ngxDirectiveThirdParty contained lower -syn keyword ngxDirectiveThirdParty contained upper - -" content filter for nginx, which returns the md5 hash of the content otherwise returned -" https://github.com/kainswor/nginx_md5_filter -syn keyword ngxDirectiveThirdParty contained md5_filter - -" Non-blocking upstream module for Nginx to connect to MongoDB -" https://github.com/simpl/ngx_mongo -syn keyword ngxDirectiveThirdParty contained mongo_auth -syn keyword ngxDirectiveThirdParty contained mongo_bind -syn keyword ngxDirectiveThirdParty contained mongo_buffer_size -syn keyword ngxDirectiveThirdParty contained mongo_buffering -syn keyword ngxDirectiveThirdParty contained mongo_buffers -syn keyword ngxDirectiveThirdParty contained mongo_busy_buffers_size -syn keyword ngxDirectiveThirdParty contained mongo_connect_timeout -syn keyword ngxDirectiveThirdParty contained mongo_json -syn keyword ngxDirectiveThirdParty contained mongo_next_upstream -syn keyword ngxDirectiveThirdParty contained mongo_pass -syn keyword ngxDirectiveThirdParty contained mongo_query -syn keyword ngxDirectiveThirdParty contained mongo_read_timeout -syn keyword ngxDirectiveThirdParty contained mongo_send_timeout - -" Nginx OCSP processing module designed for response caching -" https://github.com/kyprizel/nginx_ocsp_proxy-module -syn keyword ngxDirectiveThirdParty contained ocsp_cache_timeout -syn keyword ngxDirectiveThirdParty contained ocsp_proxy - -" Nginx OpenSSL version check at startup -" https://github.com/apcera/nginx-openssl-version -syn keyword ngxDirectiveThirdParty contained openssl_builddate_minimum -syn keyword ngxDirectiveThirdParty contained openssl_version_minimum - -" Automatic PageSpeed optimization module for Nginx -" https://github.com/pagespeed/ngx_pagespeed -syn keyword ngxDirectiveThirdParty contained pagespeed - -" PECL Memcache standard hashing compatible loadbalancer for Nginx -" https://github.com/replay/ngx_http_php_memcache_standard_balancer -syn keyword ngxDirectiveThirdParty contained hash_key - -" nginx module to parse php sessions -" https://github.com/replay/ngx_http_php_session -syn keyword ngxDirectiveThirdParty contained php_session_parse -syn keyword ngxDirectiveThirdParty contained php_session_strip_formatting - -" Nginx HTTP rDNS module -" https://github.com/flant/nginx-http-rdns -syn keyword ngxDirectiveThirdParty contained rdns -syn keyword ngxDirectiveThirdParty contained rdns_allow -syn keyword ngxDirectiveThirdParty contained rdns_deny - -" Streaming regular expression replacement in response bodies -" https://github.com/openresty/replace-filter-nginx-module -syn keyword ngxDirectiveThirdParty contained replace_filter -syn keyword ngxDirectiveThirdParty contained replace_filter_last_modified -syn keyword ngxDirectiveThirdParty contained replace_filter_max_buffered_size -syn keyword ngxDirectiveThirdParty contained replace_filter_skip -syn keyword ngxDirectiveThirdParty contained replace_filter_types - -" Link RRDtool's graphing facilities directly into nginx -" https://github.com/evanmiller/mod_rrd_graph -syn keyword ngxDirectiveThirdParty contained rrd_graph -syn keyword ngxDirectiveThirdParty contained rrd_graph_root - -" Module for nginx to proxy rtmp using http protocol -" https://github.com/kwojtek/nginx-rtmpt-proxy-module -syn keyword ngxDirectiveThirdParty contained rtmpt_proxy -syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_http_timeout -syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_rtmp_timeout -syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_stat -syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_stylesheet -syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_target - -" Syntactically Awesome NGINX Module -" https://github.com/mneudert/sass-nginx-module -syn keyword ngxDirectiveThirdParty contained sass_compile -syn keyword ngxDirectiveThirdParty contained sass_error_log -syn keyword ngxDirectiveThirdParty contained sass_include_path -syn keyword ngxDirectiveThirdParty contained sass_indent -syn keyword ngxDirectiveThirdParty contained sass_is_indented_syntax -syn keyword ngxDirectiveThirdParty contained sass_linefeed -syn keyword ngxDirectiveThirdParty contained sass_output_style -syn keyword ngxDirectiveThirdParty contained sass_precision -syn keyword ngxDirectiveThirdParty contained sass_source_comments -syn keyword ngxDirectiveThirdParty contained sass_source_map_embed - -" Nginx Selective Cache Purge Module -" https://github.com/wandenberg/nginx-selective-cache-purge-module -syn keyword ngxDirectiveThirdParty contained selective_cache_purge_query -syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_database -syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_host -syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_password -syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_port -syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_unix_socket - -" cconv nginx module -" https://github.com/liseen/set-cconv-nginx-module -syn keyword ngxDirectiveThirdParty contained set_cconv_to_simp -syn keyword ngxDirectiveThirdParty contained set_cconv_to_trad -syn keyword ngxDirectiveThirdParty contained set_pinyin_to_normal - -" Nginx module that allows the setting of variables to the value of a variety of hashes -" https://github.com/simpl/ngx_http_set_hash -syn keyword ngxDirectiveThirdParty contained set_md5 -syn keyword ngxDirectiveThirdParty contained set_md5_upper -syn keyword ngxDirectiveThirdParty contained set_murmur2 -syn keyword ngxDirectiveThirdParty contained set_murmur2_upper -syn keyword ngxDirectiveThirdParty contained set_sha1 -syn keyword ngxDirectiveThirdParty contained set_sha1_upper - -" Nginx module to set the language of a request based on a number of options -" https://github.com/simpl/ngx_http_set_lang -syn keyword ngxDirectiveThirdParty contained lang_cookie -syn keyword ngxDirectiveThirdParty contained lang_get_var -syn keyword ngxDirectiveThirdParty contained lang_host -syn keyword ngxDirectiveThirdParty contained lang_list -syn keyword ngxDirectiveThirdParty contained lang_post_var -syn keyword ngxDirectiveThirdParty contained lang_referer -syn keyword ngxDirectiveThirdParty contained set_lang -syn keyword ngxDirectiveThirdParty contained set_lang_method - -" Nginx Sorted Querystring Module -" https://github.com/wandenberg/nginx-sorted-querystring-module -syn keyword ngxDirectiveThirdParty contained sorted_querysting_filter_parameter - -" Nginx upstream module for Sphinx 2.x search daemon -" https://github.com/reeteshranjan/sphinx2-nginx-module -syn keyword ngxDirectiveThirdParty contained sphinx2_bind -syn keyword ngxDirectiveThirdParty contained sphinx2_buffer_size -syn keyword ngxDirectiveThirdParty contained sphinx2_connect_timeout -syn keyword ngxDirectiveThirdParty contained sphinx2_next_upstream -syn keyword ngxDirectiveThirdParty contained sphinx2_pass -syn keyword ngxDirectiveThirdParty contained sphinx2_read_timeout -syn keyword ngxDirectiveThirdParty contained sphinx2_send_timeout - -" Nginx module for retrieving user attributes and groups from SSSD -" https://github.com/veruu/ngx_sssd_info -syn keyword ngxDirectiveThirdParty contained sssd_info -syn keyword ngxDirectiveThirdParty contained sssd_info_attribute -syn keyword ngxDirectiveThirdParty contained sssd_info_attribute_separator -syn keyword ngxDirectiveThirdParty contained sssd_info_attributes -syn keyword ngxDirectiveThirdParty contained sssd_info_group -syn keyword ngxDirectiveThirdParty contained sssd_info_group_separator -syn keyword ngxDirectiveThirdParty contained sssd_info_groups -syn keyword ngxDirectiveThirdParty contained sssd_info_output_to - -" An nginx module for sending statistics to statsd -" https://github.com/zebrafishlabs/nginx-statsd -syn keyword ngxDirectiveThirdParty contained statsd_count -syn keyword ngxDirectiveThirdParty contained statsd_sample_rate -syn keyword ngxDirectiveThirdParty contained statsd_server -syn keyword ngxDirectiveThirdParty contained statsd_timing - -" ngx_stream_echo - TCP/stream echo module for NGINX (a port of the ngx_http_echo module) -" https://github.com/openresty/stream-echo-nginx-module -syn keyword ngxDirectiveThirdParty contained echo -syn keyword ngxDirectiveThirdParty contained echo_client_error_log_level -syn keyword ngxDirectiveThirdParty contained echo_discard_request -syn keyword ngxDirectiveThirdParty contained echo_duplicate -syn keyword ngxDirectiveThirdParty contained echo_flush_wait -syn keyword ngxDirectiveThirdParty contained echo_lingering_close -syn keyword ngxDirectiveThirdParty contained echo_lingering_time -syn keyword ngxDirectiveThirdParty contained echo_lingering_timeout -syn keyword ngxDirectiveThirdParty contained echo_read_buffer_size -syn keyword ngxDirectiveThirdParty contained echo_read_bytes -syn keyword ngxDirectiveThirdParty contained echo_read_line -syn keyword ngxDirectiveThirdParty contained echo_read_timeout -syn keyword ngxDirectiveThirdParty contained echo_request_data -syn keyword ngxDirectiveThirdParty contained echo_send_timeout -syn keyword ngxDirectiveThirdParty contained echo_sleep - -" Embed the power of Lua into NGINX TCP/UDP servers -" https://github.com/openresty/stream-lua-nginx-module -syn keyword ngxDirectiveThirdParty contained lua_add_variable -syn keyword ngxDirectiveThirdParty contained preread_by_lua_block -syn keyword ngxDirectiveThirdParty contained preread_by_lua_file -syn keyword ngxDirectiveThirdParty contained preread_by_lua_no_postpone - -" nginx-upsync-module -" https://github.com/weibocom/nginx-upsync-module -syn keyword ngxDirectiveThirdParty contained upstream_show -syn keyword ngxDirectiveThirdParty contained upsync -syn keyword ngxDirectiveThirdParty contained upsync_dump_path -syn keyword ngxDirectiveThirdParty contained upsync_lb - -" Whitespace stripper for nginx -" https://github.com/evanmiller/mod_strip -syn keyword ngxDirectiveThirdParty contained strip - -" Split one big HTTP/Range request to multiple subrange requesets -" https://github.com/Qihoo360/ngx_http_subrange_module -syn keyword ngxDirectiveThirdParty contained subrange - -" summarizer-nginx-module -" https://github.com/reeteshranjan/summarizer-nginx-module -syn keyword ngxDirectiveThirdParty contained summarizer_bind -syn keyword ngxDirectiveThirdParty contained summarizer_buffer_size -syn keyword ngxDirectiveThirdParty contained summarizer_connect_timeout -syn keyword ngxDirectiveThirdParty contained summarizer_next_upstream -syn keyword ngxDirectiveThirdParty contained summarizer_pass -syn keyword ngxDirectiveThirdParty contained summarizer_read_timeout -syn keyword ngxDirectiveThirdParty contained summarizer_send_timeout - -" nginx module providing API to communicate with supervisord and manage (start/stop) backends on-demand -" https://github.com/FRiCKLE/ngx_supervisord -syn keyword ngxDirectiveThirdParty contained supervisord -syn keyword ngxDirectiveThirdParty contained supervisord_inherit_backend_status -syn keyword ngxDirectiveThirdParty contained supervisord_name -syn keyword ngxDirectiveThirdParty contained supervisord_start -syn keyword ngxDirectiveThirdParty contained supervisord_stop - -" simple robot mitigation module using cookie based challenge/response technique. Not supported any more. -" https://github.com/kyprizel/testcookie-nginx-module -syn keyword ngxDirectiveThirdParty contained testcookie -syn keyword ngxDirectiveThirdParty contained testcookie_arg -syn keyword ngxDirectiveThirdParty contained testcookie_deny_keepalive -syn keyword ngxDirectiveThirdParty contained testcookie_domain -syn keyword ngxDirectiveThirdParty contained testcookie_expires -syn keyword ngxDirectiveThirdParty contained testcookie_fallback -syn keyword ngxDirectiveThirdParty contained testcookie_get_only -syn keyword ngxDirectiveThirdParty contained testcookie_httponly_flag -syn keyword ngxDirectiveThirdParty contained testcookie_https_location -syn keyword ngxDirectiveThirdParty contained testcookie_internal -syn keyword ngxDirectiveThirdParty contained testcookie_max_attempts -syn keyword ngxDirectiveThirdParty contained testcookie_name -syn keyword ngxDirectiveThirdParty contained testcookie_p3p -syn keyword ngxDirectiveThirdParty contained testcookie_pass -syn keyword ngxDirectiveThirdParty contained testcookie_path -syn keyword ngxDirectiveThirdParty contained testcookie_port_in_redirect -syn keyword ngxDirectiveThirdParty contained testcookie_redirect_via_refresh -syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie -syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_iv -syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_key -syn keyword ngxDirectiveThirdParty contained testcookie_refresh_status -syn keyword ngxDirectiveThirdParty contained testcookie_refresh_template -syn keyword ngxDirectiveThirdParty contained testcookie_samesite -syn keyword ngxDirectiveThirdParty contained testcookie_secret -syn keyword ngxDirectiveThirdParty contained testcookie_secure_flag -syn keyword ngxDirectiveThirdParty contained testcookie_session -syn keyword ngxDirectiveThirdParty contained testcookie_whitelist - -" ngx_http_types_filter_module -" https://github.com/flygoast/ngx_http_types_filter -syn keyword ngxDirectiveThirdParty contained types_filter -syn keyword ngxDirectiveThirdParty contained types_filter_use_default - -" A module allowing the nginx to use files embedded in a zip file -" https://github.com/youzee/nginx-unzip-module -syn keyword ngxDirectiveThirdParty contained file_in_unzip -syn keyword ngxDirectiveThirdParty contained file_in_unzip_archivefile -syn keyword ngxDirectiveThirdParty contained file_in_unzip_extract - -" An asynchronous domain name resolve module for nginx upstream -" https://github.com/wdaike/ngx_upstream_jdomain -syn keyword ngxDirectiveThirdParty contained jdomain - -" Nginx url encoding converting module -" https://github.com/vozlt/nginx-module-url -syn keyword ngxDirectiveThirdParty contained url_encoding_convert -syn keyword ngxDirectiveThirdParty contained url_encoding_convert_alloc_size -syn keyword ngxDirectiveThirdParty contained url_encoding_convert_alloc_size_x -syn keyword ngxDirectiveThirdParty contained url_encoding_convert_from -syn keyword ngxDirectiveThirdParty contained url_encoding_convert_phase -syn keyword ngxDirectiveThirdParty contained url_encoding_convert_to - -" A nginx module to match browsers and crawlers -" https://github.com/alibaba/nginx-http-user-agent -syn keyword ngxDirectiveThirdParty contained user_agent - -" nginx load-balancer module implementing ketama consistent hashing -" https://github.com/flygoast/ngx_http_upstream_ketama_chash -syn keyword ngxDirectiveThirdParty contained ketama_chash - -" nginx-sticky-module-ng -" https://github.com/ayty-adrianomartins/nginx-sticky-module-ng -syn keyword ngxDirectiveThirdParty contained sticky_no_fallback - -" dynamic linking and call the function of your application -" https://github.com/Taymindis/nginx-link-function -syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_prop -syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_req_header -syn keyword ngxDirectiveThirdParty contained ngx_link_func_ca_cert -syn keyword ngxDirectiveThirdParty contained ngx_link_func_call -syn keyword ngxDirectiveThirdParty contained ngx_link_func_download_link_lib -syn keyword ngxDirectiveThirdParty contained ngx_link_func_lib -syn keyword ngxDirectiveThirdParty contained ngx_link_func_shm_size -syn keyword ngxDirectiveThirdParty contained ngx_link_func_subrequest - -" purge content from FastCGI, proxy, SCGI and uWSGI caches -" https://github.com/torden/ngx_cache_purge -syn keyword ngxDirectiveThirdParty contained cache_purge_response_type - -" set the flags "HttpOnly", "secure" and "SameSite" for cookies -" https://github.com/AirisX/nginx_cookie_flag_module -syn keyword ngxDirectiveThirdParty contained set_cookie_flag - -" Embed websockify into Nginx (convert any tcp connection into websocket) " https://github.com/tg123/websockify-nginx-module syn keyword ngxDirectiveThirdParty contained websockify_buffer_size syn keyword ngxDirectiveThirdParty contained websockify_connect_timeout @@ -2415,55 +1980,6 @@ syn keyword ngxDirectiveThirdParty contained websockify_pass syn keyword ngxDirectiveThirdParty contained websockify_read_timeout syn keyword ngxDirectiveThirdParty contained websockify_send_timeout -" IP2Location Nginx -" https://github.com/ip2location/ip2location-nginx -syn keyword ngxDirectiveThirdParty contained ip2location_addresstype -syn keyword ngxDirectiveThirdParty contained ip2location_areacode -syn keyword ngxDirectiveThirdParty contained ip2location_category -syn keyword ngxDirectiveThirdParty contained ip2location_city -syn keyword ngxDirectiveThirdParty contained ip2location_country_long -syn keyword ngxDirectiveThirdParty contained ip2location_country_short -syn keyword ngxDirectiveThirdParty contained ip2location_domain -syn keyword ngxDirectiveThirdParty contained ip2location_elevation -syn keyword ngxDirectiveThirdParty contained ip2location_iddcode -syn keyword ngxDirectiveThirdParty contained ip2location_isp -syn keyword ngxDirectiveThirdParty contained ip2location_latitude -syn keyword ngxDirectiveThirdParty contained ip2location_longitude -syn keyword ngxDirectiveThirdParty contained ip2location_mcc -syn keyword ngxDirectiveThirdParty contained ip2location_mnc -syn keyword ngxDirectiveThirdParty contained ip2location_mobilebrand -syn keyword ngxDirectiveThirdParty contained ip2location_netspeed -syn keyword ngxDirectiveThirdParty contained ip2location_proxy -syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive -syn keyword ngxDirectiveThirdParty contained ip2location_region -syn keyword ngxDirectiveThirdParty contained ip2location_timezone -syn keyword ngxDirectiveThirdParty contained ip2location_usagetype -syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationcode -syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationname -syn keyword ngxDirectiveThirdParty contained ip2location_zipcode - -" IP2Proxy module for Nginx -" https://github.com/ip2location/ip2proxy-nginx -syn keyword ngxDirectiveThirdParty contained ip2proxy_as -syn keyword ngxDirectiveThirdParty contained ip2proxy_asn -syn keyword ngxDirectiveThirdParty contained ip2proxy_city -syn keyword ngxDirectiveThirdParty contained ip2proxy_country_long -syn keyword ngxDirectiveThirdParty contained ip2proxy_country_short -syn keyword ngxDirectiveThirdParty contained ip2proxy_database -syn keyword ngxDirectiveThirdParty contained ip2proxy_domain -syn keyword ngxDirectiveThirdParty contained ip2proxy_isp -syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy -syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen -syn keyword ngxDirectiveThirdParty contained ip2proxy_provider -syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy -syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive -syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type -syn keyword ngxDirectiveThirdParty contained ip2proxy_region -syn keyword ngxDirectiveThirdParty contained ip2proxy_threat -syn keyword ngxDirectiveThirdParty contained ip2proxy_usage_type - - - " highlight hi def link ngxComment Comment diff --git a/src/core/nginx.h b/src/core/nginx.h index 9f8756b..832baaa 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1022001 -#define NGINX_VERSION "1.22.1" +#define nginx_version 1024000 +#define NGINX_VERSION "1.24.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index fec7bb8..197704b 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -544,8 +544,8 @@ ngx_conf_read_token(ngx_conf_t *cf) } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unexpected end of file, " - "expecting \";\" or \"}\""); + "unexpected end of file, " + "expecting \";\" or \"}\""); return NGX_ERROR; } diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index fe729a7..3682345 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -660,7 +660,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) /* * on OpenVZ after suspend/resume EADDRINUSE * may be returned by listen() instead of bind(), see - * https://bugzilla.openvz.org/show_bug.cgi?id=2470 + * https://bugs.openvz.org/browse/OVZ-5587 */ if (err != NGX_EADDRINUSE || !ngx_test_config) { diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 8cc1475..36e1be2 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -172,6 +172,7 @@ struct ngx_connection_s { unsigned timedout:1; unsigned error:1; unsigned destroyed:1; + unsigned pipeline:1; unsigned idle:1; unsigned reusable:1; @@ -184,6 +185,7 @@ struct ngx_connection_s { unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ unsigned need_last_buf:1; + unsigned need_flush_buf:1; #if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) unsigned busy_count:2; diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h index abc3cbe..3b57099 100644 --- a/src/core/ngx_hash.h +++ b/src/core/ngx_hash.h @@ -89,12 +89,15 @@ typedef struct { } ngx_hash_keys_arrays_t; -typedef struct { +typedef struct ngx_table_elt_s ngx_table_elt_t; + +struct ngx_table_elt_s { ngx_uint_t hash; ngx_str_t key; ngx_str_t value; u_char *lowcase_key; -} ngx_table_elt_t; + ngx_table_elt_t *next; +}; void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len); diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c index 7a9e7f9..49888b9 100644 --- a/src/core/ngx_proxy_protocol.c +++ b/src/core/ngx_proxy_protocol.c @@ -13,7 +13,15 @@ #define NGX_PROXY_PROTOCOL_AF_INET6 2 -#define ngx_proxy_protocol_parse_uint16(p) ((p)[0] << 8 | (p)[1]) +#define ngx_proxy_protocol_parse_uint16(p) \ + ( ((uint16_t) (p)[0] << 8) \ + + ( (p)[1]) ) + +#define ngx_proxy_protocol_parse_uint32(p) \ + ( ((uint32_t) (p)[0] << 24) \ + + ( (p)[1] << 16) \ + + ( (p)[2] << 8) \ + + ( (p)[3]) ) typedef struct { @@ -40,12 +48,52 @@ typedef struct { } ngx_proxy_protocol_inet6_addrs_t; +typedef struct { + u_char type; + u_char len[2]; +} ngx_proxy_protocol_tlv_t; + + +typedef struct { + u_char client; + u_char verify[4]; +} ngx_proxy_protocol_tlv_ssl_t; + + +typedef struct { + ngx_str_t name; + ngx_uint_t type; +} ngx_proxy_protocol_tlv_entry_t; + + static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last, ngx_str_t *addr); static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port, u_char sep); static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last); +static ngx_int_t ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, + ngx_str_t *tlvs, ngx_uint_t type, ngx_str_t *value); + + +static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_entries[] = { + { ngx_string("alpn"), 0x01 }, + { ngx_string("authority"), 0x02 }, + { ngx_string("unique_id"), 0x05 }, + { ngx_string("ssl"), 0x20 }, + { ngx_string("netns"), 0x30 }, + { ngx_null_string, 0x00 } +}; + + +static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_ssl_entries[] = { + { ngx_string("version"), 0x21 }, + { ngx_string("cn"), 0x22 }, + { ngx_string("cipher"), 0x23 }, + { ngx_string("sig_alg"), 0x24 }, + { ngx_string("key_alg"), 0x25 }, + { ngx_null_string, 0x00 } +}; u_char * @@ -61,7 +109,7 @@ ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) len = last - buf; if (len >= sizeof(ngx_proxy_protocol_header_t) - && memcmp(p, signature, sizeof(signature) - 1) == 0) + && ngx_memcmp(p, signature, sizeof(signature) - 1) == 0) { return ngx_proxy_protocol_v2_read(c, buf, last); } @@ -139,8 +187,14 @@ skip: invalid: + for (p = buf; p < last; p++) { + if (*p == CR || *p == LF) { + break; + } + } + ngx_log_error(NGX_LOG_ERR, c->log, 0, - "broken header: \"%*s\"", (size_t) (last - buf), buf); + "broken header: \"%*s\"", (size_t) (p - buf), buf); return NULL; } @@ -227,7 +281,9 @@ ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last) { ngx_uint_t port, lport; - if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) { + if (last - buf < NGX_PROXY_PROTOCOL_V1_MAX_HEADER) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "too small buffer for PROXY protocol"); return NULL; } @@ -340,11 +396,11 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last) src_sockaddr.sockaddr_in.sin_family = AF_INET; src_sockaddr.sockaddr_in.sin_port = 0; - memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4); + ngx_memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4); dst_sockaddr.sockaddr_in.sin_family = AF_INET; dst_sockaddr.sockaddr_in.sin_port = 0; - memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4); + ngx_memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4); pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port); pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port); @@ -367,11 +423,11 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last) src_sockaddr.sockaddr_in6.sin6_family = AF_INET6; src_sockaddr.sockaddr_in6.sin6_port = 0; - memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16); + ngx_memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16); dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6; dst_sockaddr.sockaddr_in6.sin6_port = 0; - memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16); + ngx_memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16); pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port); pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port); @@ -412,11 +468,147 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last) &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port); if (buf < end) { - ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol v2 %z bytes of tlv ignored", end - buf); + pp->tlvs.data = ngx_pnalloc(c->pool, end - buf); + if (pp->tlvs.data == NULL) { + return NULL; + } + + ngx_memcpy(pp->tlvs.data, buf, end - buf); + pp->tlvs.len = end - buf; } c->proxy_protocol = pp; return end; } + + +ngx_int_t +ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name, + ngx_str_t *value) +{ + u_char *p; + size_t n; + uint32_t verify; + ngx_str_t ssl, *tlvs; + ngx_int_t rc, type; + ngx_proxy_protocol_tlv_ssl_t *tlv_ssl; + ngx_proxy_protocol_tlv_entry_t *te; + + if (c->proxy_protocol == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol v2 get tlv \"%V\"", name); + + te = ngx_proxy_protocol_tlv_entries; + tlvs = &c->proxy_protocol->tlvs; + + p = name->data; + n = name->len; + + if (n >= 4 && p[0] == 's' && p[1] == 's' && p[2] == 'l' && p[3] == '_') { + + rc = ngx_proxy_protocol_lookup_tlv(c, tlvs, 0x20, &ssl); + if (rc != NGX_OK) { + return rc; + } + + if (ssl.len < sizeof(ngx_proxy_protocol_tlv_ssl_t)) { + return NGX_ERROR; + } + + p += 4; + n -= 4; + + if (n == 6 && ngx_strncmp(p, "verify", 6) == 0) { + + tlv_ssl = (ngx_proxy_protocol_tlv_ssl_t *) ssl.data; + verify = ngx_proxy_protocol_parse_uint32(tlv_ssl->verify); + + value->data = ngx_pnalloc(c->pool, NGX_INT32_LEN); + if (value->data == NULL) { + return NGX_ERROR; + } + + value->len = ngx_sprintf(value->data, "%uD", verify) + - value->data; + return NGX_OK; + } + + ssl.data += sizeof(ngx_proxy_protocol_tlv_ssl_t); + ssl.len -= sizeof(ngx_proxy_protocol_tlv_ssl_t); + + te = ngx_proxy_protocol_tlv_ssl_entries; + tlvs = &ssl; + } + + if (n >= 2 && p[0] == '0' && p[1] == 'x') { + + type = ngx_hextoi(p + 2, n - 2); + if (type == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "invalid PROXY protocol TLV \"%V\"", name); + return NGX_ERROR; + } + + return ngx_proxy_protocol_lookup_tlv(c, tlvs, type, value); + } + + for ( /* void */ ; te->type; te++) { + if (te->name.len == n && ngx_strncmp(te->name.data, p, n) == 0) { + return ngx_proxy_protocol_lookup_tlv(c, tlvs, te->type, value); + } + } + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "unknown PROXY protocol TLV \"%V\"", name); + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, ngx_str_t *tlvs, + ngx_uint_t type, ngx_str_t *value) +{ + u_char *p; + size_t n, len; + ngx_proxy_protocol_tlv_t *tlv; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol v2 lookup tlv:%02xi", type); + + p = tlvs->data; + n = tlvs->len; + + while (n) { + if (n < sizeof(ngx_proxy_protocol_tlv_t)) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV"); + return NGX_ERROR; + } + + tlv = (ngx_proxy_protocol_tlv_t *) p; + len = ngx_proxy_protocol_parse_uint16(tlv->len); + + p += sizeof(ngx_proxy_protocol_tlv_t); + n -= sizeof(ngx_proxy_protocol_tlv_t); + + if (n < len) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV"); + return NGX_ERROR; + } + + if (tlv->type == type) { + value->data = p; + value->len = len; + return NGX_OK; + } + + p += len; + n -= len; + } + + return NGX_DECLINED; +} diff --git a/src/core/ngx_proxy_protocol.h b/src/core/ngx_proxy_protocol.h index b716220..d1749f5 100644 --- a/src/core/ngx_proxy_protocol.h +++ b/src/core/ngx_proxy_protocol.h @@ -13,7 +13,8 @@ #include -#define NGX_PROXY_PROTOCOL_MAX_HEADER 107 +#define NGX_PROXY_PROTOCOL_V1_MAX_HEADER 107 +#define NGX_PROXY_PROTOCOL_MAX_HEADER 4096 struct ngx_proxy_protocol_s { @@ -21,6 +22,7 @@ struct ngx_proxy_protocol_s { ngx_str_t dst_addr; in_port_t src_port; in_port_t dst_port; + ngx_str_t tlvs; }; @@ -28,6 +30,8 @@ u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last); u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last); +ngx_int_t ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name, + ngx_str_t *value); #endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */ diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 6d129e5..c76c178 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -157,6 +157,8 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) cln->handler = ngx_resolver_cleanup; cln->data = r; + r->ipv4 = 1; + ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, ngx_resolver_rbtree_insert_value); @@ -225,6 +227,23 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) } #if (NGX_HAVE_INET6) + if (ngx_strncmp(names[i].data, "ipv4=", 5) == 0) { + + if (ngx_strcmp(&names[i].data[5], "on") == 0) { + r->ipv4 = 1; + + } else if (ngx_strcmp(&names[i].data[5], "off") == 0) { + r->ipv4 = 0; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter: %V", &names[i]); + return NULL; + } + + continue; + } + if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) { if (ngx_strcmp(&names[i].data[5], "on") == 0) { @@ -273,6 +292,14 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) } } +#if (NGX_HAVE_INET6) + if (r->ipv4 + r->ipv6 == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"ipv4\" and \"ipv6\" cannot both be \"off\""); + return NULL; + } +#endif + if (n && r->connections.nelts == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no name servers defined"); return NULL; @@ -836,7 +863,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, r->last_connection = 0; } - rn->naddrs = (u_short) -1; + rn->naddrs = r->ipv4 ? (u_short) -1 : 0; rn->tcp = 0; #if (NGX_HAVE_INET6) rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; @@ -1263,7 +1290,7 @@ ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) rec->log.action = "resolving"; } - if (rn->naddrs == (u_short) -1) { + if (rn->query && rn->naddrs == (u_short) -1) { rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen) : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen); @@ -1389,6 +1416,7 @@ ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, rec->tcp->data = rec; rec->tcp->write->handler = ngx_resolver_tcp_write; + rec->tcp->write->cancelable = 1; rec->tcp->read->handler = ngx_resolver_tcp_read; rec->tcp->read->resolver = 1; @@ -1764,10 +1792,13 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n, q = ngx_queue_next(q)) { rn = ngx_queue_data(q, ngx_resolver_node_t, queue); - qident = (rn->query[0] << 8) + rn->query[1]; - if (qident == ident) { - goto dns_error_name; + if (rn->query) { + qident = (rn->query[0] << 8) + rn->query[1]; + + if (qident == ident) { + goto dns_error_name; + } } #if (NGX_HAVE_INET6) @@ -3644,7 +3675,7 @@ ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); #if (NGX_HAVE_INET6) - p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len); + p = ngx_resolver_alloc(r, len * (r->ipv4 + r->ipv6)); #else p = ngx_resolver_alloc(r, len); #endif @@ -3657,19 +3688,21 @@ ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, #if (NGX_HAVE_INET6) if (r->ipv6) { - rn->query6 = p + len; + rn->query6 = r->ipv4 ? (p + len) : p; } #endif query = (ngx_resolver_hdr_t *) p; - ident = ngx_random(); + if (r->ipv4) { + ident = ngx_random(); - ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolve: \"%V\" A %i", name, ident & 0xffff); + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve: \"%V\" A %i", name, ident & 0xffff); - query->ident_hi = (u_char) ((ident >> 8) & 0xff); - query->ident_lo = (u_char) (ident & 0xff); + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + } /* recursion query */ query->flags_hi = 1; query->flags_lo = 0; @@ -3730,7 +3763,9 @@ ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, p = rn->query6; - ngx_memcpy(p, rn->query, rn->qlen); + if (r->ipv4) { + ngx_memcpy(p, rn->query, rn->qlen); + } query = (ngx_resolver_hdr_t *) p; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index 0bd3921..06026b7 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -175,8 +175,10 @@ struct ngx_resolver_s { ngx_queue_t srv_expire_queue; ngx_queue_t addr_expire_queue; + unsigned ipv4:1; + #if (NGX_HAVE_INET6) - ngx_uint_t ipv6; /* unsigned ipv6:1; */ + unsigned ipv6:1; ngx_rbtree_t addr6_rbtree; ngx_rbtree_node_t addr6_sentinel; ngx_queue_t addr6_resend_queue; diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 98f270a..f8f7384 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1364,7 +1364,12 @@ ngx_utf8_decode(u_char **p, size_t n) u = **p; - if (u >= 0xf0) { + if (u >= 0xf8) { + + (*p)++; + return 0xffffffff; + + } else if (u >= 0xf0) { u &= 0x07; valid = 0xffff; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index 0fb9be7..713eb42 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -140,12 +140,12 @@ ngx_copy(u_char *dst, u_char *src, size_t len) #endif -#define ngx_memmove(dst, src, n) (void) memmove(dst, src, n) -#define ngx_movemem(dst, src, n) (((u_char *) memmove(dst, src, n)) + (n)) +#define ngx_memmove(dst, src, n) (void) memmove(dst, src, n) +#define ngx_movemem(dst, src, n) (((u_char *) memmove(dst, src, n)) + (n)) /* msvc and icc7 compile memcmp() to the inline loop */ -#define ngx_memcmp(s1, s2, n) memcmp((const char *) s1, (const char *) s2, n) +#define ngx_memcmp(s1, s2, n) memcmp(s1, s2, n) u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n); diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c index 3c7b63a..bad45bd 100644 --- a/src/core/ngx_syslog.c +++ b/src/core/ngx_syslog.c @@ -18,6 +18,7 @@ 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 u_char *ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len); static char *facilities[] = { @@ -66,6 +67,9 @@ ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) ngx_str_set(&peer->tag, "nginx"); } + peer->hostname = &cf->cycle->hostname; + peer->logp = &cf->cycle->new_log; + peer->conn.fd = (ngx_socket_t) -1; peer->conn.read = &ngx_syslog_dummy_event; @@ -243,7 +247,7 @@ ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf) } return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time, - &ngx_cycle->hostname, &peer->tag); + peer->hostname, &peer->tag); } @@ -286,15 +290,19 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) { ssize_t n; + if (peer->log.handler == NULL) { + peer->log = *peer->logp; + peer->log.handler = ngx_syslog_log_error; + peer->log.data = peer; + peer->log.action = "logging to syslog"; + } + if (peer->conn.fd == (ngx_socket_t) -1) { if (ngx_syslog_init_peer(peer) != NGX_OK) { return NGX_ERROR; } } - /* log syslog socket events with valid log */ - peer->conn.log = ngx_cycle->log; - if (ngx_send) { n = ngx_send(&peer->conn, buf, len); @@ -306,7 +314,7 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) if (n == NGX_ERROR) { if (ngx_close_socket(peer->conn.fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -324,24 +332,25 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) 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_log_error(NGX_LOG_ALERT, &peer->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_log_error(NGX_LOG_ALERT, &peer->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, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, "connect() failed"); goto failed; } peer->conn.fd = fd; + peer->conn.log = &peer->log; /* UDP sockets are always ready to write */ peer->conn.write->ready = 1; @@ -351,7 +360,7 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) failed: if (ngx_close_socket(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -372,7 +381,30 @@ ngx_syslog_cleanup(void *data) } if (ngx_close_socket(peer->conn.fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } } + + +static u_char * +ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_syslog_peer_t *peer; + + p = buf; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + } + + peer = log->data; + + if (peer) { + p = ngx_snprintf(p, len, ", server: %V", &peer->server.name); + } + + return p; +} diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h index 50dcd35..e2d54ac 100644 --- a/src/core/ngx_syslog.h +++ b/src/core/ngx_syslog.h @@ -9,14 +9,20 @@ typedef struct { - ngx_uint_t facility; - ngx_uint_t severity; - ngx_str_t tag; + ngx_uint_t facility; + ngx_uint_t severity; + ngx_str_t tag; - ngx_addr_t server; - ngx_connection_t conn; - unsigned busy:1; - unsigned nohostname:1; + ngx_str_t *hostname; + + ngx_addr_t server; + ngx_connection_t conn; + + ngx_log_t log; + ngx_log_t *logp; + + unsigned busy:1; + unsigned nohostname:1; } ngx_syslog_peer_t; diff --git a/src/event/modules/ngx_iocp_module.c b/src/event/modules/ngx_iocp_module.c new file mode 100644 index 0000000..dca5ced --- /dev/null +++ b/src/event/modules/ngx_iocp_module.c @@ -0,0 +1,379 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static ngx_int_t ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer); +static ngx_thread_value_t __stdcall ngx_iocp_timer(void *data); +static void ngx_iocp_done(ngx_cycle_t *cycle); +static ngx_int_t ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t key); +static ngx_int_t ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags); +static ngx_int_t ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags); +static void *ngx_iocp_create_conf(ngx_cycle_t *cycle); +static char *ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf); + + +static ngx_str_t iocp_name = ngx_string("iocp"); + +static ngx_command_t ngx_iocp_commands[] = { + + { ngx_string("iocp_threads"), + NGX_EVENT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + 0, + offsetof(ngx_iocp_conf_t, threads), + NULL }, + + { ngx_string("post_acceptex"), + NGX_EVENT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + 0, + offsetof(ngx_iocp_conf_t, post_acceptex), + NULL }, + + { ngx_string("acceptex_read"), + NGX_EVENT_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + 0, + offsetof(ngx_iocp_conf_t, acceptex_read), + NULL }, + + ngx_null_command +}; + + +static ngx_event_module_t ngx_iocp_module_ctx = { + &iocp_name, + ngx_iocp_create_conf, /* create configuration */ + ngx_iocp_init_conf, /* init configuration */ + + { + ngx_iocp_add_event, /* add an event */ + NULL, /* delete an event */ + NULL, /* enable an event */ + NULL, /* disable an event */ + NULL, /* add an connection */ + ngx_iocp_del_connection, /* delete an connection */ + NULL, /* trigger a notify */ + ngx_iocp_process_events, /* process the events */ + ngx_iocp_init, /* init the events */ + ngx_iocp_done /* done the events */ + } + +}; + +ngx_module_t ngx_iocp_module = { + NGX_MODULE_V1, + &ngx_iocp_module_ctx, /* module context */ + ngx_iocp_commands, /* module directives */ + NGX_EVENT_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +ngx_os_io_t ngx_iocp_io = { + ngx_overlapped_wsarecv, + NULL, + ngx_udp_overlapped_wsarecv, + NULL, + NULL, + NULL, + ngx_overlapped_wsasend_chain, + 0 +}; + + +static HANDLE iocp; +static ngx_tid_t timer_thread; +static ngx_msec_t msec; + + +static ngx_int_t +ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer) +{ + ngx_iocp_conf_t *cf; + + cf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); + + if (iocp == NULL) { + iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, + cf->threads); + } + + if (iocp == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateIoCompletionPort() failed"); + return NGX_ERROR; + } + + ngx_io = ngx_iocp_io; + + ngx_event_actions = ngx_iocp_module_ctx.actions; + + ngx_event_flags = NGX_USE_IOCP_EVENT; + + if (timer == 0) { + return NGX_OK; + } + + /* + * The waitable timer could not be used, because + * GetQueuedCompletionStatus() does not set a thread to alertable state + */ + + if (timer_thread == NULL) { + + msec = timer; + + if (ngx_create_thread(&timer_thread, ngx_iocp_timer, &msec, cycle->log) + != 0) + { + return NGX_ERROR; + } + } + + ngx_event_flags |= NGX_USE_TIMER_EVENT; + + return NGX_OK; +} + + +static ngx_thread_value_t __stdcall +ngx_iocp_timer(void *data) +{ + ngx_msec_t timer = *(ngx_msec_t *) data; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "THREAD %p %p", &msec, data); + + for ( ;; ) { + Sleep(timer); + + ngx_time_update(); +#if 1 + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer"); +#endif + } + +#if defined(__WATCOMC__) || defined(__GNUC__) + return 0; +#endif +} + + +static void +ngx_iocp_done(ngx_cycle_t *cycle) +{ + if (CloseHandle(iocp) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "iocp CloseHandle() failed"); + } + + iocp = NULL; +} + + +static ngx_int_t +ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t key) +{ + ngx_connection_t *c; + + c = (ngx_connection_t *) ev->data; + + c->read->active = 1; + c->write->active = 1; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "iocp add: fd:%d k:%ui ov:%p", c->fd, key, &ev->ovlp); + + if (CreateIoCompletionPort((HANDLE) c->fd, iocp, key, 0) == NULL) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, + "CreateIoCompletionPort() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags) +{ +#if 0 + if (flags & NGX_CLOSE_EVENT) { + return NGX_OK; + } + + if (CancelIo((HANDLE) c->fd) == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CancelIo() failed"); + return NGX_ERROR; + } +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) +{ + int rc; + u_int key; + u_long bytes; + ngx_err_t err; + ngx_msec_t delta; + ngx_event_t *ev; + ngx_event_ovlp_t *ovlp; + + if (timer == NGX_TIMER_INFINITE) { + timer = INFINITE; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "iocp timer: %M", timer); + + rc = GetQueuedCompletionStatus(iocp, &bytes, (PULONG_PTR) &key, + (LPOVERLAPPED *) &ovlp, (u_long) timer); + + if (rc == 0) { + err = ngx_errno; + } else { + err = 0; + } + + delta = ngx_current_msec; + + if (flags & NGX_UPDATE_TIME) { + ngx_time_update(); + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "iocp: %d b:%d k:%d ov:%p", rc, bytes, key, ovlp); + + if (timer != INFINITE) { + delta = ngx_current_msec - delta; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "iocp timer: %M, delta: %M", timer, delta); + } + + if (err) { + if (ovlp == NULL) { + if (err != WAIT_TIMEOUT) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "GetQueuedCompletionStatus() failed"); + + return NGX_ERROR; + } + + return NGX_OK; + } + + ovlp->error = err; + } + + if (ovlp == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "GetQueuedCompletionStatus() returned no operation"); + return NGX_ERROR; + } + + + ev = ovlp->event; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, "iocp event:%p", ev); + + + if (err == ERROR_NETNAME_DELETED /* the socket was closed */ + || err == ERROR_OPERATION_ABORTED /* the operation was canceled */) + { + + /* + * the WSA_OPERATION_ABORTED completion notification + * for a file descriptor that was closed + */ + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, + "iocp: aborted event %p", ev); + + return NGX_OK; + } + + if (err) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "GetQueuedCompletionStatus() returned operation error"); + } + + switch (key) { + + case NGX_IOCP_ACCEPT: + if (bytes) { + ev->ready = 1; + } + break; + + case NGX_IOCP_IO: + ev->complete = 1; + ev->ready = 1; + break; + + case NGX_IOCP_CONNECT: + ev->ready = 1; + } + + ev->available = bytes; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "iocp event handler: %p", ev->handler); + + ev->handler(ev); + + return NGX_OK; +} + + +static void * +ngx_iocp_create_conf(ngx_cycle_t *cycle) +{ + ngx_iocp_conf_t *cf; + + cf = ngx_palloc(cycle->pool, sizeof(ngx_iocp_conf_t)); + if (cf == NULL) { + return NULL; + } + + cf->threads = NGX_CONF_UNSET; + cf->post_acceptex = NGX_CONF_UNSET; + cf->acceptex_read = NGX_CONF_UNSET; + + return cf; +} + + +static char * +ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_iocp_conf_t *cf = conf; + + ngx_conf_init_value(cf->threads, 0); + ngx_conf_init_value(cf->post_acceptex, 10); + ngx_conf_init_value(cf->acceptex_read, 1); + + return NGX_CONF_OK; +} diff --git a/src/event/modules/ngx_iocp_module.h b/src/event/modules/ngx_iocp_module.h new file mode 100644 index 0000000..dc73983 --- /dev/null +++ b/src/event/modules/ngx_iocp_module.h @@ -0,0 +1,22 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_IOCP_MODULE_H_INCLUDED_ +#define _NGX_IOCP_MODULE_H_INCLUDED_ + + +typedef struct { + int threads; + int post_acceptex; + int acceptex_read; +} ngx_iocp_conf_t; + + +extern ngx_module_t ngx_iocp_module; + + +#endif /* _NGX_IOCP_MODULE_H_INCLUDED_ */ diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 47229b5..d81547a 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -416,6 +416,7 @@ ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) { #if (NGX_HAVE_REUSEPORT) ngx_uint_t i; + ngx_core_conf_t *ccf; ngx_listening_t *ls; #endif @@ -442,7 +443,9 @@ ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_REUSEPORT) - if (!ngx_test_config) { + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (!ngx_test_config && ccf->master) { ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -810,7 +813,9 @@ ngx_event_process_init(ngx_cycle_t *cycle) rev->deferred_accept = ls[i].deferred_accept; #endif - if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { + if (!(ngx_event_flags & NGX_USE_IOCP_EVENT) + && cycle->old_cycle) + { if (ls[i].previous) { /* diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 548c906..deac04e 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -494,12 +494,6 @@ extern ngx_module_t ngx_event_core_module; void ngx_event_accept(ngx_event_t *ev); -#if !(NGX_WIN32) -void ngx_event_recvmsg(ngx_event_t *ev); -void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, - ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); -#endif -void ngx_delete_udp_connection(void *data); ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); @@ -529,6 +523,7 @@ ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat); #include #include +#include #if (NGX_WIN32) #include diff --git a/src/event/ngx_event_acceptex.c b/src/event/ngx_event_acceptex.c new file mode 100644 index 0000000..f4a1c4b --- /dev/null +++ b/src/event/ngx_event_acceptex.c @@ -0,0 +1,229 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static void ngx_close_posted_connection(ngx_connection_t *c); + + +void +ngx_event_acceptex(ngx_event_t *rev) +{ + ngx_listening_t *ls; + ngx_connection_t *c; + + c = rev->data; + ls = c->listening; + + c->log->handler = ngx_accept_log_error; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "AcceptEx: %d", c->fd); + + if (rev->ovlp.error) { + ngx_log_error(NGX_LOG_CRIT, c->log, rev->ovlp.error, + "AcceptEx() %V failed", &ls->addr_text); + return; + } + + /* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */ + + if (setsockopt(c->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + (char *) &ls->fd, sizeof(ngx_socket_t)) + == -1) + { + ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, + "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed for %V", + &c->addr_text); + /* TODO: close socket */ + return; + } + + ngx_getacceptexsockaddrs(c->buffer->pos, + ls->post_accept_buffer_size, + ls->socklen + 16, + ls->socklen + 16, + &c->local_sockaddr, &c->local_socklen, + &c->sockaddr, &c->socklen); + + if (ls->post_accept_buffer_size) { + c->buffer->last += rev->available; + c->buffer->end = c->buffer->start + ls->post_accept_buffer_size; + + } else { + c->buffer = NULL; + } + + if (ls->addr_ntop) { + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); + if (c->addr_text.data == NULL) { + /* TODO: close socket */ + return; + } + + 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) { + /* TODO: close socket */ + return; + } + } + + ngx_event_post_acceptex(ls, 1); + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + + c->start_time = ngx_current_msec; + + ls->handler(c); + + return; + +} + + +ngx_int_t +ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n) +{ + u_long rcvd; + ngx_err_t err; + ngx_log_t *log; + ngx_uint_t i; + ngx_event_t *rev, *wev; + ngx_socket_t s; + ngx_connection_t *c; + + for (i = 0; i < n; i++) { + + /* TODO: look up reused sockets */ + + s = ngx_socket(ls->sockaddr->sa_family, ls->type, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &ls->log, 0, + ngx_socket_n " s:%d", s); + + if (s == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, &ls->log, ngx_socket_errno, + ngx_socket_n " failed"); + + return NGX_ERROR; + } + + c = ngx_get_connection(s, &ls->log); + + if (c == NULL) { + return NGX_ERROR; + } + + c->pool = ngx_create_pool(ls->pool_size, &ls->log); + if (c->pool == NULL) { + ngx_close_posted_connection(c); + return NGX_ERROR; + } + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_close_posted_connection(c); + return NGX_ERROR; + } + + c->buffer = ngx_create_temp_buf(c->pool, ls->post_accept_buffer_size + + 2 * (ls->socklen + 16)); + if (c->buffer == NULL) { + ngx_close_posted_connection(c); + return NGX_ERROR; + } + + c->local_sockaddr = ngx_palloc(c->pool, ls->socklen); + if (c->local_sockaddr == NULL) { + ngx_close_posted_connection(c); + return NGX_ERROR; + } + + c->sockaddr = ngx_palloc(c->pool, ls->socklen); + if (c->sockaddr == NULL) { + ngx_close_posted_connection(c); + return NGX_ERROR; + } + + *log = ls->log; + c->log = log; + + c->recv = ngx_recv; + c->send = ngx_send; + c->recv_chain = ngx_recv_chain; + c->send_chain = ngx_send_chain; + + c->listening = ls; + + rev = c->read; + wev = c->write; + + rev->ovlp.event = rev; + wev->ovlp.event = wev; + rev->handler = ngx_event_acceptex; + + rev->ready = 1; + wev->ready = 1; + + rev->log = c->log; + wev->log = c->log; + + if (ngx_add_event(rev, 0, NGX_IOCP_IO) == NGX_ERROR) { + ngx_close_posted_connection(c); + return NGX_ERROR; + } + + if (ngx_acceptex(ls->fd, s, c->buffer->pos, ls->post_accept_buffer_size, + ls->socklen + 16, ls->socklen + 16, + &rcvd, (LPOVERLAPPED) &rev->ovlp) + == 0) + { + err = ngx_socket_errno; + if (err != WSA_IO_PENDING) { + ngx_log_error(NGX_LOG_ALERT, &ls->log, err, + "AcceptEx() %V failed", &ls->addr_text); + + ngx_close_posted_connection(c); + return NGX_ERROR; + } + } + } + + return NGX_OK; +} + + +static void +ngx_close_posted_connection(ngx_connection_t *c) +{ + ngx_socket_t fd; + + ngx_free_connection(c); + + fd = c->fd; + c->fd = (ngx_socket_t) -1; + + if (ngx_close_socket(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + if (c->pool) { + ngx_destroy_pool(c->pool); + } +} + + +u_char * +ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + return ngx_snprintf(buf, len, " while posting AcceptEx() on %V", log->data); +} diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index adbbde6..668084a 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -179,6 +179,8 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) c->recv = ngx_udp_recv; c->send = ngx_send; c->send_chain = ngx_udp_send_chain; + + c->need_flush_buf = 1; } c->log_error = pc->log_error; diff --git a/src/event/ngx_event_connectex.c b/src/event/ngx_event_connectex.c new file mode 100644 index 0000000..36b1514 --- /dev/null +++ b/src/event/ngx_event_connectex.c @@ -0,0 +1,206 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_MAX_PENDING_CONN 10 + + +static CRITICAL_SECTION connect_lock; +static int nconnects; +static ngx_connection_t pending_connects[NGX_MAX_PENDING_CONN]; + +static HANDLE pending_connect_event; + +__declspec(thread) int nevents = 0; +__declspec(thread) WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS + 1]; +__declspec(thread) ngx_connection_t *conn[WSA_MAXIMUM_WAIT_EVENTS + 1]; + + + +int ngx_iocp_wait_connect(ngx_connection_t *c) +{ + for ( ;; ) { + EnterCriticalSection(&connect_lock); + + if (nconnects < NGX_MAX_PENDING_CONN) { + pending_connects[--nconnects] = c; + LeaveCriticalSection(&connect_lock); + + if (SetEvent(pending_connect_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, + "SetEvent() failed"); + return NGX_ERROR; + + break; + } + + LeaveCriticalSection(&connect_lock); + ngx_log_error(NGX_LOG_NOTICE, c->log, 0, + "max number of pending connect()s is %d", + NGX_MAX_PENDING_CONN); + msleep(100); + } + + if (!started) { + if (ngx_iocp_new_thread(1) == NGX_ERROR) { + return NGX_ERROR; + } + started = 1; + } + + return NGX_OK; +} + + +int ngx_iocp_new_thread(int main) +{ + u_int id; + + if (main) { + pending_connect_event = CreateEvent(NULL, 0, 1, NULL); + if (pending_connect_event == INVALID_HANDLE_VALUE) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, + "CreateThread() failed"); + return NGX_ERROR; + } + } + + if (CreateThread(NULL, 0, ngx_iocp_wait_events, main, 0, &id) + == INVALID_HANDLE_VALUE) + { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, + "CreateThread() failed"); + return NGX_ERROR; + } + + SetEvent(event) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, + "SetEvent() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +int ngx_iocp_new_connect() +{ + EnterCriticalSection(&connect_lock); + c = pending_connects[--nconnects]; + LeaveCriticalSection(&connect_lock); + + conn[nevents] = c; + + events[nevents] = WSACreateEvent(); + if (events[nevents] == INVALID_HANDLE_VALUE) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, + "WSACreateEvent() failed"); + return NGX_ERROR; + } + + if (WSAEventSelect(c->fd, events[nevents], FD_CONNECT) == -1) + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, + "WSAEventSelect() failed"); + return NGX_ERROR; + } + + nevents++; + + return NGX_OK; +} + + +void ngx_iocp_wait_events(int main) +{ + WSANETWORKEVENTS ne; + + nevents = 1; + events[0] = pending_connect_event; + conn[0] = NULL; + + for ( ;; ) { + offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1 : 0; + timeout = (nevents == 1 && !first) ? 60000 : INFINITE; + + n = WSAWaitForMultipleEvents(nevents - offset, events[offset], + 0, timeout, 0); + if (n == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + "WSAWaitForMultipleEvents() failed"); + continue; + } + + if (n == WAIT_TIMEOUT) { + if (nevents == 2 && !main) { + ExitThread(0); + } + + ngx_log_error(NGX_LOG_ALERT, log, 0, + "WSAWaitForMultipleEvents() " + "returned unexpected WAIT_TIMEOUT"); + continue; + } + + n -= WSA_WAIT_EVENT_0; + + if (events[n] == NULL) { + + /* the pending_connect_event */ + + if (nevents == WSA_MAXIMUM_WAIT_EVENTS) { + ngx_iocp_new_thread(0); + } else { + ngx_iocp_new_connect(); + } + + continue; + } + + if (WSAEnumNetworkEvents(c[n].fd, events[n], &ne) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + "WSAEnumNetworkEvents() failed"); + continue; + } + + if (ne.lNetworkEvents & FD_CONNECT) { + conn[n].write->ovlp.error = ne.iErrorCode[FD_CONNECT_BIT]; + + if (PostQueuedCompletionStatus(iocp, 0, NGX_IOCP_CONNECT, + &conn[n].write->ovlp) == 0) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + "PostQueuedCompletionStatus() failed"); + continue; + } + + if (n < nevents) { + conn[n] = conn[nevents]; + events[n] = events[nevents]; + } + + nevents--; + continue; + } + + if (ne.lNetworkEvents & FD_ACCEPT) { + + /* CHECK ERROR ??? */ + + ngx_event_post_acceptex(conn[n].listening, 1); + continue; + } + + ngx_log_error(NGX_LOG_ALERT, c[n].log, 0, + "WSAWaitForMultipleEvents() " + "returned unexpected network event %ul", + ne.lNetworkEvents); + } +} diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 1e6fc96..104e8da 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -71,10 +71,11 @@ 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, +static int ngx_ssl_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); -static void ngx_ssl_session_ticket_keys_cleanup(void *data); +static ngx_int_t ngx_ssl_rotate_ticket_keys(SSL_CTX *ssl_ctx, ngx_log_t *log); +static void ngx_ssl_ticket_keys_cleanup(void *data); #endif #ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT @@ -131,7 +132,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_ticket_keys_index; int ngx_ssl_ocsp_index; int ngx_ssl_certificate_index; int ngx_ssl_next_certificate_index; @@ -208,9 +209,9 @@ 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_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, + NULL); + if (ngx_ssl_ticket_keys_index == -1) { ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_CTX_get_ex_new_index() failed"); return NGX_ERROR; @@ -1083,6 +1084,53 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) } } +#endif + +#ifdef TLS1_3_VERSION + + if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP + && SSL_version(ssl_conn) == TLS1_3_VERSION) + { + time_t now, time, timeout, conf_timeout; + SSL_SESSION *sess; + + /* + * OpenSSL with TLSv1.3 updates the session creation time on + * session resumption and keeps the session timeout unmodified, + * making it possible to maintain the session forever, bypassing + * client certificate expiration and revocation. To make sure + * session timeouts are actually used, we now update the session + * creation time and reduce the session timeout accordingly. + * + * BoringSSL with TLSv1.3 ignores configured session timeouts + * and uses a hardcoded timeout instead, 7 days. So we update + * session timeout to the configured value as soon as a session + * is created. + */ + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + sess = SSL_get0_session(ssl_conn); + + if (!c->ssl->session_timeout_set && sess) { + c->ssl->session_timeout_set = 1; + + now = ngx_time(); + time = SSL_SESSION_get_time(sess); + timeout = SSL_SESSION_get_timeout(sess); + conf_timeout = SSL_CTX_get_timeout(c->ssl->session_ctx); + + timeout = ngx_min(timeout, conf_timeout); + + if (now - time >= timeout) { + SSL_SESSION_set1_id_context(sess, (unsigned char *) "", 0); + + } else { + SSL_SESSION_set_time(sess, now); + SSL_SESSION_set_timeout(sess, timeout - (now - time)); + } + } + } + #endif if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP) { @@ -1426,9 +1474,9 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name) SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE); -#if SSL_CTRL_SET_ECDH_AUTO +#ifdef SSL_CTRL_SET_ECDH_AUTO /* not needed in OpenSSL 1.1.0+ */ - SSL_CTX_set_ecdh_auto(ssl->ctx, 1); + (void) SSL_CTX_set_ecdh_auto(ssl->ctx, 1); #endif if (ngx_strcmp(name->data, "auto") == 0) { @@ -1769,7 +1817,7 @@ ngx_ssl_handshake(ngx_connection_t *c) #endif #endif -#ifdef BIO_get_ktls_send +#if (defined BIO_get_ktls_send && !NGX_WIN32) if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -1914,7 +1962,7 @@ ngx_ssl_try_early_data(ngx_connection_t *c) c->read->ready = 1; c->write->ready = 1; -#ifdef BIO_get_ktls_send +#if (defined BIO_get_ktls_send && !NGX_WIN32) if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -2156,6 +2204,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) #endif if (c->ssl->last == NGX_ERROR) { + c->read->ready = 0; c->read->error = 1; return NGX_ERROR; } @@ -2222,6 +2271,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) #if (NGX_HAVE_FIONREAD) if (ngx_socket_nread(c->fd, &c->read->available) == -1) { + c->read->ready = 0; c->read->error = 1; ngx_connection_error(c, ngx_socket_errno, ngx_socket_nread_n " failed"); @@ -2258,6 +2308,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) return 0; case NGX_ERROR: + c->read->ready = 0; c->read->error = 1; /* fall through */ @@ -2278,6 +2329,7 @@ ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf, size_t size) size_t readbytes; if (c->ssl->last == NGX_ERROR) { + c->read->ready = 0; c->read->error = 1; return NGX_ERROR; } @@ -2377,6 +2429,7 @@ ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf, size_t size) return 0; case NGX_ERROR: + c->read->ready = 0; c->read->error = 1; /* fall through */ @@ -2943,7 +2996,7 @@ ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) static ssize_t ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) { -#ifdef BIO_get_ktls_send +#if (defined BIO_get_ktls_send && !NGX_WIN32) int sslerr, flags; ssize_t n; @@ -2972,7 +3025,7 @@ ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) n = SSL_sendfile(c->ssl->connection, file->file->fd, file->file_pos, size, flags); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %d", n); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %z", n); if (n > 0) { @@ -3336,30 +3389,74 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, } else if (sslerr == SSL_ERROR_SSL) { - n = ERR_GET_REASON(ERR_peek_error()); + n = ERR_GET_REASON(ERR_peek_last_error()); /* handshake failures */ if (n == SSL_R_BAD_CHANGE_CIPHER_SPEC /* 103 */ #ifdef SSL_R_NO_SUITABLE_KEY_SHARE || n == SSL_R_NO_SUITABLE_KEY_SHARE /* 101 */ #endif +#ifdef SSL_R_BAD_ALERT + || n == SSL_R_BAD_ALERT /* 102 */ +#endif +#ifdef SSL_R_BAD_KEY_SHARE + || n == SSL_R_BAD_KEY_SHARE /* 108 */ +#endif +#ifdef SSL_R_BAD_EXTENSION + || n == SSL_R_BAD_EXTENSION /* 110 */ +#endif + || n == SSL_R_BAD_DIGEST_LENGTH /* 111 */ +#ifdef SSL_R_MISSING_SIGALGS_EXTENSION + || n == SSL_R_MISSING_SIGALGS_EXTENSION /* 112 */ +#endif + || n == SSL_R_BAD_PACKET_LENGTH /* 115 */ #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM || n == SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM /* 118 */ +#endif +#ifdef SSL_R_BAD_KEY_UPDATE + || n == SSL_R_BAD_KEY_UPDATE /* 122 */ #endif || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG /* 129 */ + || n == SSL_R_CCS_RECEIVED_EARLY /* 133 */ +#ifdef SSL_R_DECODE_ERROR + || n == SSL_R_DECODE_ERROR /* 137 */ +#endif +#ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED + || n == SSL_R_DATA_BETWEEN_CCS_AND_FINISHED /* 145 */ +#endif + || n == SSL_R_DATA_LENGTH_TOO_LONG /* 146 */ || n == SSL_R_DIGEST_CHECK_FAILED /* 149 */ + || n == SSL_R_ENCRYPTED_LENGTH_TOO_LONG /* 150 */ || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */ || n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */ +#ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS + || n == SSL_R_GOT_A_FIN_BEFORE_A_CCS /* 154 */ +#endif || n == SSL_R_HTTPS_PROXY_REQUEST /* 155 */ || n == SSL_R_HTTP_REQUEST /* 156 */ || n == SSL_R_LENGTH_MISMATCH /* 159 */ +#ifdef SSL_R_LENGTH_TOO_SHORT + || n == SSL_R_LENGTH_TOO_SHORT /* 160 */ +#endif +#ifdef SSL_R_NO_RENEGOTIATION + || n == SSL_R_NO_RENEGOTIATION /* 182 */ +#endif #ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ #endif || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */ +#ifdef SSL_R_BAD_CIPHER + || n == SSL_R_BAD_CIPHER /* 186 */ +#endif || n == SSL_R_NO_COMPRESSION_SPECIFIED /* 187 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ +#ifdef SSL_R_PACKET_LENGTH_TOO_LONG + || n == SSL_R_PACKET_LENGTH_TOO_LONG /* 198 */ +#endif || n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */ +#ifdef SSL_R_TOO_MANY_WARNING_ALERTS + || n == SSL_R_TOO_MANY_WARNING_ALERTS /* 220 */ +#endif #ifdef SSL_R_CLIENTHELLO_TLSEXT || n == SSL_R_CLIENTHELLO_TLSEXT /* 226 */ #endif @@ -3369,6 +3466,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_CALLBACK_FAILED || n == SSL_R_CALLBACK_FAILED /* 234 */ #endif +#ifdef SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG + || n == SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG /* 234 */ +#endif #ifdef SSL_R_NO_APPLICATION_PROTOCOL || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */ #endif @@ -3378,13 +3478,44 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_UNKNOWN_PROTOCOL /* 252 */ #ifdef SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS || n == SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS /* 253 */ +#endif +#ifdef SSL_R_INVALID_COMPRESSION_LIST + || n == SSL_R_INVALID_COMPRESSION_LIST /* 256 */ +#endif +#ifdef SSL_R_MISSING_KEY_SHARE + || n == SSL_R_MISSING_KEY_SHARE /* 258 */ #endif || n == SSL_R_UNSUPPORTED_PROTOCOL /* 258 */ #ifdef SSL_R_NO_SHARED_GROUP || n == SSL_R_NO_SHARED_GROUP /* 266 */ #endif || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */ +#ifdef SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA + || n == SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA /* 270 */ +#endif + || n == SSL_R_BAD_LENGTH /* 271 */ || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */ +#ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY + || n == SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY /* 291 */ +#endif +#ifdef SSL_R_APPLICATION_DATA_ON_SHUTDOWN + || n == SSL_R_APPLICATION_DATA_ON_SHUTDOWN /* 291 */ +#endif +#ifdef SSL_R_BAD_LEGACY_VERSION + || n == SSL_R_BAD_LEGACY_VERSION /* 292 */ +#endif +#ifdef SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA + || n == SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA /* 293 */ +#endif +#ifdef SSL_R_RECORD_TOO_SMALL + || n == SSL_R_RECORD_TOO_SMALL /* 298 */ +#endif +#ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG + || n == SSL_R_SSL3_SESSION_ID_TOO_LONG /* 300 */ +#endif +#ifdef SSL_R_BAD_ECPOINT + || n == SSL_R_BAD_ECPOINT /* 306 */ +#endif #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG || n == SSL_R_RENEGOTIATE_EXT_TOO_LONG /* 335 */ || n == SSL_R_RENEGOTIATION_ENCODING_ERR /* 336 */ @@ -3399,11 +3530,23 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_INAPPROPRIATE_FALLBACK || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif +#ifdef SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS + || n == SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS /* 376 */ +#endif +#ifdef SSL_R_NO_SHARED_SIGATURE_ALGORITHMS + || n == SSL_R_NO_SHARED_SIGATURE_ALGORITHMS /* 376 */ +#endif #ifdef SSL_R_CERT_CB_ERROR || n == SSL_R_CERT_CB_ERROR /* 377 */ #endif #ifdef SSL_R_VERSION_TOO_LOW || n == SSL_R_VERSION_TOO_LOW /* 396 */ +#endif +#ifdef SSL_R_TOO_MANY_WARN_ALERTS + || n == SSL_R_TOO_MANY_WARN_ALERTS /* 409 */ +#endif +#ifdef SSL_R_BAD_RECORD_TYPE + || n == SSL_R_BAD_RECORD_TYPE /* 443 */ #endif || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE @@ -3749,6 +3892,12 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) ngx_queue_init(&cache->expire_queue); + cache->ticket_keys[0].expire = 0; + cache->ticket_keys[1].expire = 0; + cache->ticket_keys[2].expire = 0; + + cache->fail_time = 0; + len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len; shpool->log_ctx = ngx_slab_alloc(shpool, len); @@ -3767,16 +3916,16 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) /* * The length of the session id is 16 bytes for SSLv2 sessions and - * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes. - * It seems that the typical length of the external ASN1 representation - * of a session is 118 or 119 bytes for SSLv3/TSLv1. + * between 1 and 32 bytes for SSLv3 and TLS, typically 32 bytes. + * Typical length of the external ASN1 representation of a session + * is about 150 bytes plus SNI server name. * - * Thus on 32-bit platforms we allocate separately an rbtree node, - * a session id, and an ASN1 representation, they take accordingly - * 64, 32, and 128 bytes. + * On 32-bit platforms we allocate an rbtree node, a session id, and + * an ASN1 representation in a single allocation, it typically takes + * 256 bytes. * * On 64-bit platforms we allocate separately an rbtree node + session_id, - * and an ASN1 representation, they take accordingly 128 and 128 bytes. + * and an ASN1 representation, they take accordingly 128 and 256 bytes. * * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, * so they are outside the code locked by shared pool mutex @@ -3786,7 +3935,8 @@ static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) { int len; - u_char *p, *id, *cached_sess, *session_id; + u_char *p, *session_id; + size_t n; uint32_t hash; SSL_CTX *ssl_ctx; unsigned int session_id_length; @@ -3797,17 +3947,42 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) ngx_ssl_session_cache_t *cache; u_char buf[NGX_SSL_MAX_SESSION_SIZE]; +#ifdef TLS1_3_VERSION + + /* + * OpenSSL tries to save TLSv1.3 sessions into session cache + * even when using tickets for stateless session resumption, + * "because some applications just want to know about the creation + * of a session"; do not cache such sessions + */ + + if (SSL_version(ssl_conn) == TLS1_3_VERSION + && (SSL_get_options(ssl_conn) & SSL_OP_NO_TICKET) == 0) + { + return 0; + } + +#endif + len = i2d_SSL_SESSION(sess, NULL); /* do not cache too big session */ - if (len > (int) NGX_SSL_MAX_SESSION_SIZE) { + if (len > NGX_SSL_MAX_SESSION_SIZE) { return 0; } p = buf; i2d_SSL_SESSION(sess, &p); + session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); + + /* do not cache sessions with too long session id */ + + if (session_id_length > 32) { + return 0; + } + c = ngx_ssl_get_connection(ssl_conn); ssl_ctx = c->ssl->session_ctx; @@ -3821,23 +3996,13 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) /* drop one or two expired sessions */ ngx_ssl_expire_sessions(cache, shpool, 1); - cached_sess = ngx_slab_alloc_locked(shpool, len); +#if (NGX_PTR_SIZE == 8) + n = sizeof(ngx_ssl_sess_id_t); +#else + n = offsetof(ngx_ssl_sess_id_t, session) + len; +#endif - if (cached_sess == NULL) { - - /* drop the oldest non-expired session and try once more */ - - ngx_ssl_expire_sessions(cache, shpool, 0); - - cached_sess = ngx_slab_alloc_locked(shpool, len); - - if (cached_sess == NULL) { - sess_id = NULL; - goto failed; - } - } - - sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); + sess_id = ngx_slab_alloc_locked(shpool, n); if (sess_id == NULL) { @@ -3845,41 +4010,34 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) ngx_ssl_expire_sessions(cache, shpool, 0); - sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); + sess_id = ngx_slab_alloc_locked(shpool, n); if (sess_id == NULL) { goto failed; } } - session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); - #if (NGX_PTR_SIZE == 8) - id = sess_id->sess_id; + sess_id->session = ngx_slab_alloc_locked(shpool, len); -#else - - id = ngx_slab_alloc_locked(shpool, session_id_length); - - if (id == NULL) { + if (sess_id->session == NULL) { /* drop the oldest non-expired session and try once more */ ngx_ssl_expire_sessions(cache, shpool, 0); - id = ngx_slab_alloc_locked(shpool, session_id_length); + sess_id->session = ngx_slab_alloc_locked(shpool, len); - if (id == NULL) { + if (sess_id->session == NULL) { goto failed; } } #endif - ngx_memcpy(cached_sess, buf, len); - - ngx_memcpy(id, session_id, session_id_length); + ngx_memcpy(sess_id->session, buf, len); + ngx_memcpy(sess_id->id, session_id, session_id_length); hash = ngx_crc32_short(session_id, session_id_length); @@ -3889,9 +4047,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) sess_id->node.key = hash; sess_id->node.data = (u_char) session_id_length; - sess_id->id = id; sess_id->len = len; - sess_id->session = cached_sess; sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); @@ -3905,18 +4061,17 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) failed: - if (cached_sess) { - ngx_slab_free_locked(shpool, cached_sess); - } - if (sess_id) { ngx_slab_free_locked(shpool, sess_id); } ngx_shmtx_unlock(&shpool->mutex); - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "could not allocate new session%s", shpool->log_ctx); + if (cache->fail_time != ngx_time()) { + cache->fail_time = ngx_time(); + ngx_log_error(NGX_LOG_WARN, c->log, 0, + "could not allocate new session%s", shpool->log_ctx); + } return 0; } @@ -4002,9 +4157,10 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, ngx_rbtree_delete(&cache->session_rbtree, node); + ngx_explicit_memzero(sess_id->session, sess_id->len); + +#if (NGX_PTR_SIZE == 8) ngx_slab_free_locked(shpool, sess_id->session); -#if (NGX_PTR_SIZE == 4) - ngx_slab_free_locked(shpool, sess_id->id); #endif ngx_slab_free_locked(shpool, sess_id); @@ -4092,9 +4248,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) ngx_rbtree_delete(&cache->session_rbtree, node); + ngx_explicit_memzero(sess_id->session, sess_id->len); + +#if (NGX_PTR_SIZE == 8) ngx_slab_free_locked(shpool, sess_id->session); -#if (NGX_PTR_SIZE == 4) - ngx_slab_free_locked(shpool, sess_id->id); #endif ngx_slab_free_locked(shpool, sess_id); @@ -4141,9 +4298,10 @@ ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); + ngx_explicit_memzero(sess_id->session, sess_id->len); + +#if (NGX_PTR_SIZE == 8) ngx_slab_free_locked(shpool, sess_id->session); -#if (NGX_PTR_SIZE == 4) - ngx_slab_free_locked(shpool, sess_id->id); #endif ngx_slab_free_locked(shpool, sess_id); } @@ -4197,23 +4355,25 @@ ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) { - u_char buf[80]; - size_t size; - 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_pool_cleanup_t *cln; - ngx_ssl_session_ticket_key_t *key; + u_char buf[80]; + size_t size; + 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_pool_cleanup_t *cln; + ngx_ssl_ticket_key_t *key; - if (paths == NULL) { + if (paths == NULL + && SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_session_cache_index) == NULL) + { return NGX_OK; } - keys = ngx_array_create(cf->pool, paths->nelts, - sizeof(ngx_ssl_session_ticket_key_t)); + keys = ngx_array_create(cf->pool, paths ? paths->nelts : 3, + sizeof(ngx_ssl_ticket_key_t)); if (keys == NULL) { return NGX_ERROR; } @@ -4223,9 +4383,41 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) return NGX_ERROR; } - cln->handler = ngx_ssl_session_ticket_keys_cleanup; + cln->handler = ngx_ssl_ticket_keys_cleanup; cln->data = keys; + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_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_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; + } + + if (paths == NULL) { + + /* placeholder for keys in shared memory */ + + key = ngx_array_push_n(keys, 3); + key[0].shared = 1; + key[0].expire = 0; + key[1].shared = 1; + key[1].expire = 0; + key[2].shared = 1; + key[2].expire = 0; + + return NGX_OK; + } + path = paths->elts; for (i = 0; i < paths->nelts; i++) { @@ -4280,6 +4472,9 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) goto failed; } + key->shared = 0; + key->expire = 1; + if (size == 48) { key->size = 48; ngx_memcpy(key->name, buf, 16); @@ -4301,25 +4496,6 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) ngx_explicit_memzero(&buf, 80); } - 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: @@ -4336,29 +4512,33 @@ failed: static int -ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, +ngx_ssl_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc) { - size_t size; - SSL_CTX *ssl_ctx; - ngx_uint_t i; - ngx_array_t *keys; - ngx_connection_t *c; - ngx_ssl_session_ticket_key_t *key; - const EVP_MD *digest; - const EVP_CIPHER *cipher; + size_t size; + SSL_CTX *ssl_ctx; + ngx_uint_t i; + ngx_array_t *keys; + ngx_connection_t *c; + ngx_ssl_ticket_key_t *key; + const EVP_MD *digest; + const EVP_CIPHER *cipher; c = ngx_ssl_get_connection(ssl_conn); ssl_ctx = c->ssl->session_ctx; + if (ngx_ssl_rotate_ticket_keys(ssl_ctx, c->log) != NGX_OK) { + return -1; + } + #ifdef OPENSSL_NO_SHA256 digest = EVP_sha1(); #else digest = EVP_sha256(); #endif - keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index); + keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_ticket_keys_index); if (keys == NULL) { return -1; } @@ -4369,7 +4549,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, /* encrypt session ticket */ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl session ticket encrypt, key: \"%*xs\" (%s session)", + "ssl ticket encrypt, key: \"%*xs\" (%s session)", (size_t) 16, key[0].name, SSL_session_reused(ssl_conn) ? "reused" : "new"); @@ -4416,7 +4596,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl session ticket decrypt, key: \"%*xs\" not found", + "ssl ticket decrypt, key: \"%*xs\" not found", (size_t) 16, name); return 0; @@ -4424,7 +4604,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, found: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl session ticket decrypt, key: \"%*xs\"%s", + "ssl ticket decrypt, key: \"%*xs\"%s", (size_t) 16, key[i].name, (i == 0) ? " (default)" : ""); if (key[i].size == 48) { @@ -4461,7 +4641,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, /* renew if non-default key */ - if (i != 0) { + if (i != 0 && key[i].expire) { return 2; } @@ -4470,13 +4650,142 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, } +static ngx_int_t +ngx_ssl_rotate_ticket_keys(SSL_CTX *ssl_ctx, ngx_log_t *log) +{ + time_t now, expire; + ngx_array_t *keys; + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_ssl_ticket_key_t *key; + ngx_ssl_session_cache_t *cache; + u_char buf[80]; + + keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_ticket_keys_index); + if (keys == NULL) { + return NGX_OK; + } + + key = keys->elts; + + if (!key[0].shared) { + return NGX_OK; + } + + /* + * if we don't need to update expiration of the current key + * and the previous key is still needed, don't sync with shared + * memory to save some work; in the worst case other worker process + * will switch to the next key, but this process will still be able + * to decrypt tickets encrypted with it + */ + + now = ngx_time(); + expire = now + SSL_CTX_get_timeout(ssl_ctx); + + if (key[0].expire >= expire && key[1].expire >= now) { + return NGX_OK; + } + + shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); + + cache = shm_zone->data; + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + key = cache->ticket_keys; + + if (key[0].expire == 0) { + + /* initialize the current key */ + + if (RAND_bytes(buf, 80) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "RAND_bytes() failed"); + ngx_shmtx_unlock(&shpool->mutex); + return NGX_ERROR; + } + + key[0].shared = 1; + key[0].expire = expire; + key[0].size = 80; + ngx_memcpy(key[0].name, buf, 16); + ngx_memcpy(key[0].hmac_key, buf + 16, 32); + ngx_memcpy(key[0].aes_key, buf + 48, 32); + + ngx_explicit_memzero(&buf, 80); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, + "ssl ticket key: \"%*xs\"", + (size_t) 16, key[0].name); + + /* + * copy the current key to the next key, as initialization of + * the previous key will replace the current key with the next + * key + */ + + key[2] = key[0]; + } + + if (key[1].expire < now) { + + /* + * if the previous key is no longer needed (or not initialized), + * replace it with the current key, replace the current key with + * the next key, and generate new next key + */ + + key[1] = key[0]; + key[0] = key[2]; + + if (RAND_bytes(buf, 80) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "RAND_bytes() failed"); + ngx_shmtx_unlock(&shpool->mutex); + return NGX_ERROR; + } + + key[2].shared = 1; + key[2].expire = 0; + key[2].size = 80; + ngx_memcpy(key[2].name, buf, 16); + ngx_memcpy(key[2].hmac_key, buf + 16, 32); + ngx_memcpy(key[2].aes_key, buf + 48, 32); + + ngx_explicit_memzero(&buf, 80); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, + "ssl ticket key: \"%*xs\"", + (size_t) 16, key[2].name); + } + + /* + * update expiration of the current key: it is going to be needed + * at least till the session being created expires + */ + + if (expire > key[0].expire) { + key[0].expire = expire; + } + + /* sync keys to the worker process memory */ + + ngx_memcpy(keys->elts, cache->ticket_keys, + 2 * sizeof(ngx_ssl_ticket_key_t)); + + ngx_shmtx_unlock(&shpool->mutex); + + return NGX_OK; +} + + static void -ngx_ssl_session_ticket_keys_cleanup(void *data) +ngx_ssl_ticket_keys_cleanup(void *data) { ngx_array_t *keys = data; ngx_explicit_memzero(keys->elts, - keys->nelts * sizeof(ngx_ssl_session_ticket_key_t)); + keys->nelts * sizeof(ngx_ssl_ticket_key_t)); } #else diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index c9e86d9..860ea26 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -114,6 +114,7 @@ struct ngx_ssl_connection_s { unsigned no_send_shutdown:1; unsigned shutdown_without_free:1; unsigned handshake_buffer_set:1; + unsigned session_timeout_set:1; unsigned try_early_data:1; unsigned in_early:1; unsigned in_ocsp:1; @@ -134,37 +135,37 @@ typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t; struct ngx_ssl_sess_id_s { ngx_rbtree_node_t node; - u_char *id; size_t len; - u_char *session; ngx_queue_t queue; time_t expire; + u_char id[32]; #if (NGX_PTR_SIZE == 8) - void *stub; - u_char sess_id[32]; + u_char *session; +#else + u_char session[1]; #endif }; +typedef struct { + u_char name[16]; + u_char hmac_key[32]; + u_char aes_key[32]; + time_t expire; + unsigned size:8; + unsigned shared:1; +} ngx_ssl_ticket_key_t; + + typedef struct { ngx_rbtree_t session_rbtree; ngx_rbtree_node_t sentinel; ngx_queue_t expire_queue; + ngx_ssl_ticket_key_t ticket_keys[3]; + time_t fail_time; } ngx_ssl_session_cache_t; -#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB - -typedef struct { - size_t size; - u_char name[16]; - u_char hmac_key[32]; - u_char aes_key[32]; -} ngx_ssl_session_ticket_key_t; - -#endif - - #define NGX_SSL_SSLv2 0x0002 #define NGX_SSL_SSLv3 0x0004 #define NGX_SSL_TLSv1 0x0008 @@ -204,10 +205,12 @@ ngx_int_t ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder, ngx_uint_t depth, ngx_shm_zone_t *shm_zone); ngx_int_t ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); + ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s); void ngx_ssl_ocsp_cleanup(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data); + ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords); @@ -314,7 +317,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_ticket_keys_index; extern int ngx_ssl_ocsp_index; extern int ngx_ssl_certificate_index; extern int ngx_ssl_next_certificate_index; diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index a524ae0..d7a94c7 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -46,18 +46,8 @@ ngx_event_recvmsg(ngx_event_t *ev) ngx_connection_t *c, *lc; static u_char buffer[65535]; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - -#if (NGX_HAVE_IP_RECVDSTADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; -#elif (NGX_HAVE_IP_PKTINFO) - u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; -#endif - +#if (NGX_HAVE_ADDRINFO_CMSG) + u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; #endif if (ev->timedout) { @@ -92,25 +82,13 @@ ngx_event_recvmsg(ngx_event_t *ev) msg.msg_iov = iov; msg.msg_iovlen = 1; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - +#if (NGX_HAVE_ADDRINFO_CMSG) if (ls->wildcard) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); -#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) - if (ls->sockaddr->sa_family == AF_INET) { - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); - } -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - if (ls->sockaddr->sa_family == AF_INET6) { - msg.msg_control = &msg_control6; - msg.msg_controllen = sizeof(msg_control6); - } -#endif + ngx_memzero(&msg_control, sizeof(msg_control)); } - #endif n = recvmsg(lc->fd, &msg, 0); @@ -129,7 +107,7 @@ ngx_event_recvmsg(ngx_event_t *ev) return; } -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) +#if (NGX_HAVE_ADDRINFO_CMSG) if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "recvmsg() truncated data"); @@ -159,7 +137,7 @@ ngx_event_recvmsg(ngx_event_t *ev) local_sockaddr = ls->sockaddr; local_socklen = ls->socklen; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) +#if (NGX_HAVE_ADDRINFO_CMSG) if (ls->wildcard) { struct cmsghdr *cmsg; @@ -171,59 +149,9 @@ ngx_event_recvmsg(ngx_event_t *ev) cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - -#if (NGX_HAVE_IP_RECVDSTADDR) - - if (cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_RECVDSTADDR - && local_sockaddr->sa_family == AF_INET) - { - struct in_addr *addr; - struct sockaddr_in *sin; - - addr = (struct in_addr *) CMSG_DATA(cmsg); - sin = (struct sockaddr_in *) local_sockaddr; - sin->sin_addr = *addr; - + if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) { break; } - -#elif (NGX_HAVE_IP_PKTINFO) - - if (cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_PKTINFO - && local_sockaddr->sa_family == AF_INET) - { - struct in_pktinfo *pkt; - struct sockaddr_in *sin; - - pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); - sin = (struct sockaddr_in *) local_sockaddr; - sin->sin_addr = pkt->ipi_addr; - - break; - } - -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - - if (cmsg->cmsg_level == IPPROTO_IPV6 - && cmsg->cmsg_type == IPV6_PKTINFO - && local_sockaddr->sa_family == AF_INET6) - { - struct in6_pktinfo *pkt6; - struct sockaddr_in6 *sin6; - - pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); - sin6 = (struct sockaddr_in6 *) local_sockaddr; - sin6->sin6_addr = pkt6->ipi6_addr; - - break; - } - -#endif - } } @@ -318,6 +246,8 @@ ngx_event_recvmsg(ngx_event_t *ev) c->send = ngx_udp_send; c->send_chain = ngx_udp_send_chain; + c->need_flush_buf = 1; + c->log = log; c->pool->log = log; c->listening = ls; diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h new file mode 100644 index 0000000..51ca665 --- /dev/null +++ b/src/event/ngx_event_udp.h @@ -0,0 +1,58 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_UDP_H_INCLUDED_ +#define _NGX_EVENT_UDP_H_INCLUDED_ + + +#include +#include + + +#if !(NGX_WIN32) + +#if ((NGX_HAVE_MSGHDR_MSG_CONTROL) \ + && (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_RECVDSTADDR \ + || NGX_HAVE_IP_PKTINFO \ + || (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO))) +#define NGX_HAVE_ADDRINFO_CMSG 1 + +#endif + + +#if (NGX_HAVE_ADDRINFO_CMSG) + +typedef union { +#if (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_RECVDSTADDR) + struct in_addr addr; +#endif + +#if (NGX_HAVE_IP_PKTINFO) + struct in_pktinfo pkt; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + struct in6_pktinfo pkt6; +#endif +} ngx_addrinfo_t; + +size_t ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, + struct sockaddr *local_sockaddr); +ngx_int_t ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg, + struct sockaddr *local_sockaddr); + +#endif + +void ngx_event_recvmsg(ngx_event_t *ev); +ssize_t ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags); +void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +#endif + +void ngx_delete_udp_connection(void *data); + + +#endif /* _NGX_EVENT_UDP_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index 0693319..02d41e8 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -339,6 +339,7 @@ ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm) *p = '"'; r->headers_out.www_authenticate->hash = 1; + r->headers_out.www_authenticate->next = NULL; ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate"); r->headers_out.www_authenticate->value.data = basic; r->headers_out.www_authenticate->value.len = len; diff --git a/src/http/modules/ngx_http_auth_request_module.c b/src/http/modules/ngx_http_auth_request_module.c index bab79e4..8bc98aa 100644 --- a/src/http/modules/ngx_http_auth_request_module.c +++ b/src/http/modules/ngx_http_auth_request_module.c @@ -101,7 +101,7 @@ ngx_module_t ngx_http_auth_request_module = { static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r) { - ngx_table_elt_t *h, *ho; + ngx_table_elt_t *h, *ho, **ph; ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_auth_request_ctx_t *ctx; @@ -147,15 +147,21 @@ ngx_http_auth_request_handler(ngx_http_request_t *r) h = sr->upstream->headers_in.www_authenticate; } - if (h) { + ph = &r->headers_out.www_authenticate; + + while (h) { ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { return NGX_ERROR; } *ho = *h; + ho->next = NULL; - r->headers_out.www_authenticate = ho; + *ph = ho; + ph = &ho->next; + + h = h->next; } return ctx->status; diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 0cc9ae1..cfb9892 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -1082,6 +1082,7 @@ ngx_http_dav_location(ngx_http_request_t *r) } r->headers_out.location->hash = 1; + r->headers_out.location->next = NULL; ngx_str_set(&r->headers_out.location->key, "Location"); escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI); diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 4a8dc33..2d9a18f 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -835,14 +835,14 @@ static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r) { off_t file_pos; - u_char ch, *pos, *lowcase_key; + u_char ch, sep, *pos, *lowcase_key; size_t size, len, key_len, val_len, padding, allocated; ngx_uint_t i, n, next, hash, skip_empty, header_params; ngx_buf_t *b; ngx_chain_t *cl, *body; ngx_list_part_t *part; - ngx_table_elt_t *header, **ignored; + ngx_table_elt_t *header, *hn, **ignored; ngx_http_upstream_t *u; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; @@ -900,7 +900,11 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) allocated = 0; lowcase_key = NULL; - if (params->number) { + if (ngx_http_link_multi_headers(r) != NGX_OK) { + return NGX_ERROR; + } + + if (params->number || r->headers_in.multi) { n = 0; part = &r->headers_in.headers.part; @@ -930,6 +934,12 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) i = 0; } + for (n = 0; n < header_params; n++) { + if (&header[i] == ignored[n]) { + goto next_length; + } + } + if (params->number) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; @@ -959,15 +969,23 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) ignored[header_params++] = &header[i]; continue; } - - n += sizeof("HTTP_") - 1; - - } else { - n = sizeof("HTTP_") - 1 + header[i].key.len; } - len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1) - + n + header[i].value.len; + key_len = sizeof("HTTP_") - 1 + header[i].key.len; + + val_len = header[i].value.len; + + for (hn = header[i].next; hn; hn = hn->next) { + val_len += hn->value.len + 2; + ignored[header_params++] = hn; + } + + len += ((key_len > 127) ? 4 : 1) + key_len + + ((val_len > 127) ? 4 : 1) + val_len; + + next_length: + + continue; } } @@ -1109,7 +1127,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) for (n = 0; n < header_params; n++) { if (&header[i] == ignored[n]) { - goto next; + goto next_value; } } @@ -1125,6 +1143,11 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) } val_len = header[i].value.len; + + for (hn = header[i].next; hn; hn = hn->next) { + val_len += hn->value.len + 2; + } + if (val_len > 127) { *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80); *b->last++ = (u_char) ((val_len >> 16) & 0xff); @@ -1150,13 +1173,34 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) *b->last++ = ch; } - b->last = ngx_copy(b->last, header[i].value.data, val_len); + b->last = ngx_copy(b->last, header[i].value.data, + header[i].value.len); + + if (header[i].next) { + + if (header[i].key.len == sizeof("Cookie") - 1 + && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie", + sizeof("Cookie") - 1) + == 0) + { + sep = ';'; + + } else { + sep = ','; + } + + for (hn = header[i].next; hn; hn = hn->next) { + *b->last++ = sep; + *b->last++ = ' '; + b->last = ngx_copy(b->last, hn->value.data, hn->value.len); + } + } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "fastcgi param: \"%*s: %*s\"", key_len, b->last - (key_len + val_len), val_len, b->last - val_len); - next: + next_value: continue; } @@ -1963,8 +2007,12 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); - if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_ERROR; + if (hh) { + rc = hh->handler(r, h, hh->offset); + + if (rc != NGX_OK) { + return rc; + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c index cc06d53..ef2bff4 100644 --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -232,9 +232,10 @@ ngx_http_flv_handler(ngx_http_request_t *r) b->file_pos = start; b->file_last = of.size; - b->in_file = b->file_last ? 1: 0; + b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index 153b6aa..ef4e9b8 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -327,15 +327,15 @@ static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr) { - ngx_array_t *xfwd; + ngx_table_elt_t *xfwd; if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) { return NGX_ERROR; } - xfwd = &r->headers_in.x_forwarded_for; + xfwd = r->headers_in.x_forwarded_for; - if (xfwd->nelts > 0 && ctx->proxies != NULL) { + if (xfwd != NULL && ctx->proxies != NULL) { (void) ngx_http_get_forwarded_addr(r, addr, xfwd, NULL, ctx->proxies, ctx->proxy_recursive); } diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index 5ea4f5f..eaf9876 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -240,16 +240,16 @@ static u_long ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) { ngx_addr_t addr; - ngx_array_t *xfwd; + ngx_table_elt_t *xfwd; struct sockaddr_in *sin; addr.sockaddr = r->connection->sockaddr; addr.socklen = r->connection->socklen; /* addr.name = r->connection->addr_text; */ - xfwd = &r->headers_in.x_forwarded_for; + xfwd = r->headers_in.x_forwarded_for; - if (xfwd->nelts > 0 && gcf->proxies != NULL) { + if (xfwd != NULL && gcf->proxies != NULL) { (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, gcf->proxies, gcf->proxy_recursive); } @@ -292,7 +292,7 @@ static geoipv6_t ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) { ngx_addr_t addr; - ngx_array_t *xfwd; + ngx_table_elt_t *xfwd; in_addr_t addr4; struct in6_addr addr6; struct sockaddr_in *sin; @@ -302,9 +302,9 @@ ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) addr.socklen = r->connection->socklen; /* addr.name = r->connection->addr_text; */ - xfwd = &r->headers_in.x_forwarded_for; + xfwd = r->headers_in.x_forwarded_for; - if (xfwd->nelts > 0 && gcf->proxies != NULL) { + if (xfwd != NULL && gcf->proxies != NULL) { (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, gcf->proxies, gcf->proxy_recursive); } diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 864fc4f..dfe49c5 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -209,6 +209,8 @@ static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); +static ngx_int_t ngx_http_grpc_merge_ssl(ngx_conf_t *cf, + ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_loc_conf_t *prev); static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf); #endif @@ -562,7 +564,7 @@ ngx_http_grpc_handler(ngx_http_request_t *r) ctx->host = glcf->host; #if (NGX_HTTP_SSL) - u->ssl = (glcf->upstream.ssl != NULL); + u->ssl = glcf->ssl; if (u->ssl) { ngx_str_set(&u->schema, "grpcs://"); @@ -1891,8 +1893,12 @@ ngx_http_grpc_process_header(ngx_http_request_t *r) hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); - if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_ERROR; + if (hh) { + rc = hh->handler(r, h, hh->offset); + + if (rc != NGX_OK) { + return rc; + } } continue; @@ -4459,12 +4465,17 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) + if (ngx_http_grpc_merge_ssl(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + 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_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); @@ -4520,7 +4531,7 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->grpc_values = prev->grpc_values; #if (NGX_HTTP_SSL) - conf->upstream.ssl = prev->upstream.ssl; + conf->ssl = prev->ssl; #endif } @@ -4869,18 +4880,64 @@ ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) } +static ngx_int_t +ngx_http_grpc_merge_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf, + ngx_http_grpc_loc_conf_t *prev) +{ + ngx_uint_t preserve; + + if (conf->ssl_protocols == 0 + && conf->ssl_ciphers.data == NULL + && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_verify == NGX_CONF_UNSET + && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT + && conf->ssl_trusted_certificate.data == NULL + && conf->ssl_crl.data == NULL + && conf->upstream.ssl_session_reuse == NGX_CONF_UNSET + && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR) + { + if (prev->upstream.ssl) { + conf->upstream.ssl = prev->upstream.ssl; + return NGX_OK; + } + + preserve = 1; + + } else { + preserve = 0; + } + + conf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (conf->upstream.ssl == NULL) { + return NGX_ERROR; + } + + conf->upstream.ssl->log = cf->log; + + /* + * special handling to preserve conf->upstream.ssl + * in the "http" section to inherit it to all servers + */ + + if (preserve) { + prev->upstream.ssl = conf->upstream.ssl; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) { ngx_pool_cleanup_t *cln; - glcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (glcf->upstream.ssl == NULL) { - return NGX_ERROR; + if (glcf->upstream.ssl->ctx) { + return NGX_OK; } - glcf->upstream.ssl->log = cf->log; - if (ngx_ssl_create(glcf->upstream.ssl, glcf->ssl_protocols, NULL) != NGX_OK) { @@ -4902,8 +4959,9 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) return NGX_ERROR; } - if (glcf->upstream.ssl_certificate) { - + if (glcf->upstream.ssl_certificate + && glcf->upstream.ssl_certificate->value.len) + { if (glcf->upstream.ssl_certificate_key == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"grpc_ssl_certificate_key\" is defined " diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index b8c5ccc..ed0de60 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -57,6 +57,7 @@ typedef struct { unsigned nomem:1; unsigned buffering:1; unsigned zlib_ng:1; + unsigned state_allocated:1; size_t zin; size_t zout; @@ -280,6 +281,7 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r) } h->hash = 1; + h->next = NULL; ngx_str_set(&h->key, "Content-Encoding"); ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; @@ -513,9 +515,10 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } else { /* * Another zlib variant, https://github.com/zlib-ng/zlib-ng. - * It forces window bits to 13 for fast compression level, - * uses 16-byte padding in one of window-sized buffers, and - * uses 128K hash. + * It used to force window bits to 13 for fast compression level, + * uses (64 + sizeof(void*)) additional space on all allocations + * for alignment, 16-byte padding in one of window-sized buffers, + * and 128K hash. */ if (conf->level == 1) { @@ -523,7 +526,8 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) - + 131072 + (1 << (memlevel + 8)); + + 131072 + (1 << (memlevel + 8)) + + 4 * (64 + sizeof(void*)); ctx->zlib_ng = 1; } } @@ -925,13 +929,16 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) alloc = items * size; - if (items == 1 && alloc % 512 != 0 && alloc < 8192) { - + if (items == 1 && alloc % 512 != 0 && alloc < 8192 + && !ctx->state_allocated) + { /* * The zlib deflate_state allocation, it takes about 6K, * we allocate 8K. Other allocations are divisible by 512. */ + ctx->state_allocated = 1; + alloc = 8192; } diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c index 7652a9a..91b38d1 100644 --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -242,10 +242,13 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r) } h->hash = 1; + h->next = NULL; ngx_str_set(&h->key, "Content-Encoding"); ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; + r->allow_ranges = 1; + /* we need to allocate all before the header would be sent */ b = ngx_calloc_buf(r->pool); @@ -270,6 +273,7 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r) b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index a4c8cc2..90e6da8 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -329,8 +329,7 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) time_t now, expires_time, max_age; ngx_str_t value; ngx_int_t rc; - ngx_uint_t i; - ngx_table_elt_t *e, *cc, **ccp; + ngx_table_elt_t *e, *cc; ngx_http_expires_t expires; expires = conf->expires; @@ -363,6 +362,7 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) } r->headers_out.expires = e; + e->next = NULL; e->hash = 1; ngx_str_set(&e->key, "Expires"); @@ -371,38 +371,29 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); e->value.len = len - 1; - ccp = r->headers_out.cache_control.elts; + cc = r->headers_out.cache_control; - if (ccp == NULL) { - - if (ngx_array_init(&r->headers_out.cache_control, r->pool, - 1, sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - return NGX_ERROR; - } + if (cc == NULL) { cc = ngx_list_push(&r->headers_out.headers); if (cc == NULL) { + e->hash = 0; return NGX_ERROR; } + r->headers_out.cache_control = cc; + cc->next = NULL; + cc->hash = 1; ngx_str_set(&cc->key, "Cache-Control"); - ccp = ngx_array_push(&r->headers_out.cache_control); - if (ccp == NULL) { - return NGX_ERROR; - } - - *ccp = cc; - } else { - for (i = 1; i < r->headers_out.cache_control.nelts; i++) { - ccp[i]->hash = 0; + for (cc = cc->next; cc; cc = cc->next) { + cc->hash = 0; } - cc = ccp[0]; + cc = r->headers_out.cache_control; + cc->next = NULL; } if (expires == NGX_HTTP_EXPIRES_EPOCH) { @@ -420,6 +411,8 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) e->value.data = ngx_pnalloc(r->pool, len); if (e->value.data == NULL) { + e->hash = 0; + cc->hash = 0; return NGX_ERROR; } @@ -457,6 +450,7 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) cc->value.data = ngx_pnalloc(r->pool, sizeof("max-age=") + NGX_TIME_T_LEN + 1); if (cc->value.data == NULL) { + cc->hash = 0; return NGX_ERROR; } @@ -564,22 +558,12 @@ static ngx_int_t ngx_http_add_multi_header_lines(ngx_http_request_t *r, ngx_http_header_val_t *hv, ngx_str_t *value) { - ngx_array_t *pa; ngx_table_elt_t *h, **ph; if (value->len == 0) { return NGX_OK; } - pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset); - - if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK) - { - return NGX_ERROR; - } - } - h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { return NGX_ERROR; @@ -589,12 +573,12 @@ ngx_http_add_multi_header_lines(ngx_http_request_t *r, h->key = hv->key; h->value = *value; - ph = ngx_array_push(pa); - if (ph == NULL) { - return NGX_ERROR; - } + ph = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); + + while (*ph) { ph = &(*ph)->next; } *ph = h; + h->next = NULL; return NGX_OK; } @@ -642,6 +626,7 @@ ngx_http_set_response_header(ngx_http_request_t *r, ngx_http_header_val_t *hv, } *old = h; + h->next = NULL; } h->hash = 1; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index c82df6e..11bbd91 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -401,6 +401,7 @@ found: } h->hash = 1; + h->next = NULL; ngx_str_set(&h->key, "Content-Encoding"); ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 4eff01e..03175de 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -714,6 +714,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r) b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; @@ -2430,7 +2431,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, } start_sample += count; - start_time -= count * duration; + start_time -= (uint64_t) count * duration; entries--; entry++; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 7c4061c..9cc202c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -236,6 +236,8 @@ static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless); #if (NGX_HTTP_SSL) +static ngx_int_t ngx_http_proxy_merge_ssl(ngx_conf_t *cf, + ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev); static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf); #endif @@ -959,7 +961,7 @@ ngx_http_proxy_handler(ngx_http_request_t *r) ctx->vars = plcf->vars; u->schema = plcf->vars.schema; #if (NGX_HTTP_SSL) - u->ssl = (plcf->upstream.ssl != NULL); + u->ssl = plcf->ssl; #endif } else { @@ -1930,8 +1932,12 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); - if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_ERROR; + if (hh) { + rc = hh->handler(r, h, hh->offset); + + if (rc != NGX_OK) { + return rc; + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1965,6 +1971,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) ngx_str_set(&h->key, "Server"); ngx_str_null(&h->value); h->lowcase_key = (u_char *) "server"; + h->next = NULL; } if (r->upstream->headers_in.date == NULL) { @@ -1978,6 +1985,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) ngx_str_set(&h->key, "Date"); ngx_str_null(&h->value); h->lowcase_key = (u_char *) "date"; + h->next = NULL; } /* clear content length if response is chunked */ @@ -2559,22 +2567,20 @@ static ngx_int_t ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - size_t len; - u_char *p; - ngx_uint_t i, n; - ngx_table_elt_t **h; + size_t len; + u_char *p; + ngx_table_elt_t *h, *xfwd; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - n = r->headers_in.x_forwarded_for.nelts; - h = r->headers_in.x_forwarded_for.elts; + xfwd = r->headers_in.x_forwarded_for; len = 0; - for (i = 0; i < n; i++) { - len += h[i]->value.len + sizeof(", ") - 1; + for (h = xfwd; h; h = h->next) { + len += h->value.len + sizeof(", ") - 1; } if (len == 0) { @@ -2593,8 +2599,8 @@ ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, v->len = len; v->data = p; - for (i = 0; i < n; i++) { - p = ngx_copy(p, h[i]->value.data, h[i]->value.len); + for (h = xfwd; h; h = h->next) { + p = ngx_copy(p, h->value.data, h->value.len); *p++ = ','; *p++ = ' '; } @@ -3720,12 +3726,17 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) + if (ngx_http_proxy_merge_ssl(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + 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_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); @@ -3853,7 +3864,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->proxy_values = prev->proxy_values; #if (NGX_HTTP_SSL) - conf->upstream.ssl = prev->upstream.ssl; + conf->ssl = prev->ssl; #endif } @@ -4918,18 +4929,64 @@ ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) } +static ngx_int_t +ngx_http_proxy_merge_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, + ngx_http_proxy_loc_conf_t *prev) +{ + ngx_uint_t preserve; + + if (conf->ssl_protocols == 0 + && conf->ssl_ciphers.data == NULL + && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_verify == NGX_CONF_UNSET + && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT + && conf->ssl_trusted_certificate.data == NULL + && conf->ssl_crl.data == NULL + && conf->upstream.ssl_session_reuse == NGX_CONF_UNSET + && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR) + { + if (prev->upstream.ssl) { + conf->upstream.ssl = prev->upstream.ssl; + return NGX_OK; + } + + preserve = 1; + + } else { + preserve = 0; + } + + conf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (conf->upstream.ssl == NULL) { + return NGX_ERROR; + } + + conf->upstream.ssl->log = cf->log; + + /* + * special handling to preserve conf->upstream.ssl + * in the "http" section to inherit it to all servers + */ + + if (preserve) { + prev->upstream.ssl = conf->upstream.ssl; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) { ngx_pool_cleanup_t *cln; - plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (plcf->upstream.ssl == NULL) { - return NGX_ERROR; + if (plcf->upstream.ssl->ctx) { + return NGX_OK; } - plcf->upstream.ssl->log = cf->log; - if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL) != NGX_OK) { @@ -4951,8 +5008,9 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) return NGX_ERROR; } - if (plcf->upstream.ssl_certificate) { - + if (plcf->upstream.ssl_certificate + && plcf->upstream.ssl_certificate->value.len) + { if (plcf->upstream.ssl_certificate_key == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"proxy_ssl_certificate_key\" is defined " diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index ae08ebb..27d1875 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -258,6 +258,7 @@ next_filter: } r->headers_out.accept_ranges->hash = 1; + r->headers_out.accept_ranges->next = NULL; ngx_str_set(&r->headers_out.accept_ranges->key, "Accept-Ranges"); ngx_str_set(&r->headers_out.accept_ranges->value, "bytes"); @@ -424,9 +425,14 @@ ngx_http_range_singlepart_header(ngx_http_request_t *r, return NGX_ERROR; } + if (r->headers_out.content_range) { + r->headers_out.content_range->hash = 0; + } + r->headers_out.content_range = content_range; content_range->hash = 1; + content_range->next = NULL; ngx_str_set(&content_range->key, "Content-Range"); content_range->value.data = ngx_pnalloc(r->pool, @@ -580,6 +586,11 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, r->headers_out.content_length = NULL; } + if (r->headers_out.content_range) { + r->headers_out.content_range->hash = 0; + r->headers_out.content_range = NULL; + } + return ngx_http_next_header_filter(r); } @@ -596,9 +607,14 @@ ngx_http_range_not_satisfiable(ngx_http_request_t *r) return NGX_ERROR; } + if (r->headers_out.content_range) { + r->headers_out.content_range->hash = 0; + } + r->headers_out.content_range = content_range; content_range->hash = 1; + content_range->next = NULL; ngx_str_set(&content_range->key, "Content-Range"); content_range->value.data = ngx_pnalloc(r->pool, diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index 9586ebe..f6731e7 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -134,9 +134,8 @@ ngx_http_realip_handler(ngx_http_request_t *r) ngx_str_t *value; ngx_uint_t i, hash; ngx_addr_t addr; - ngx_array_t *xfwd; ngx_list_part_t *part; - ngx_table_elt_t *header; + ngx_table_elt_t *header, *xfwd; ngx_connection_t *c; ngx_http_realip_ctx_t *ctx; ngx_http_realip_loc_conf_t *rlcf; @@ -168,9 +167,9 @@ ngx_http_realip_handler(ngx_http_request_t *r) case NGX_HTTP_REALIP_XFWD: - xfwd = &r->headers_in.x_forwarded_for; + xfwd = r->headers_in.x_forwarded_for; - if (xfwd->elts == NULL) { + if (xfwd == NULL) { return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index e5d31ae..9fc18dc 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -633,14 +633,14 @@ static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r) { off_t content_length_n; - u_char ch, *key, *val, *lowcase_key; + u_char ch, sep, *key, *val, *lowcase_key; size_t len, key_len, val_len, allocated; ngx_buf_t *b; ngx_str_t content_length; ngx_uint_t i, n, hash, skip_empty, header_params; ngx_chain_t *cl, *body; ngx_list_part_t *part; - ngx_table_elt_t *header, **ignored; + ngx_table_elt_t *header, *hn, **ignored; ngx_http_scgi_params_t *params; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; @@ -707,7 +707,11 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) allocated = 0; lowcase_key = NULL; - if (params->number) { + if (ngx_http_link_multi_headers(r) != NGX_OK) { + return NGX_ERROR; + } + + if (params->number || r->headers_in.multi) { n = 0; part = &r->headers_in.headers.part; @@ -737,6 +741,12 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) i = 0; } + for (n = 0; n < header_params; n++) { + if (&header[i] == ignored[n]) { + goto next_length; + } + } + if (params->number) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; @@ -770,6 +780,15 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) len += sizeof("HTTP_") - 1 + header[i].key.len + 1 + header[i].value.len + 1; + + for (hn = header[i].next; hn; hn = hn->next) { + len += hn->value.len + 2; + ignored[header_params++] = hn; + } + + next_length: + + continue; } } @@ -869,7 +888,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) for (n = 0; n < header_params; n++) { if (&header[i] == ignored[n]) { - goto next; + goto next_value; } } @@ -893,12 +912,33 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) val = b->last; b->last = ngx_copy(val, header[i].value.data, header[i].value.len); + + if (header[i].next) { + + if (header[i].key.len == sizeof("Cookie") - 1 + && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie", + sizeof("Cookie") - 1) + == 0) + { + sep = ';'; + + } else { + sep = ','; + } + + for (hn = header[i].next; hn; hn = hn->next) { + *b->last++ = sep; + *b->last++ = ' '; + b->last = ngx_copy(b->last, hn->value.data, hn->value.len); + } + } + *b->last++ = (u_char) 0; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "scgi param: \"%s: %s\"", key, val); - next: + next_value: continue; } @@ -1074,8 +1114,12 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); - if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_ERROR; + if (hh) { + rc = hh->handler(r, h, hh->offset); + + if (rc != NGX_OK) { + return rc; + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index 6737965..e7601b8 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -329,7 +329,7 @@ static ngx_http_variable_t ngx_http_ssi_vars[] = { static ngx_int_t ngx_http_ssi_header_filter(ngx_http_request_t *r) { - ngx_http_ssi_ctx_t *ctx; + ngx_http_ssi_ctx_t *ctx, *mctx; ngx_http_ssi_loc_conf_t *slcf; slcf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); @@ -341,6 +341,8 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) return ngx_http_next_header_filter(r); } + mctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_ssi_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -367,6 +369,26 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) r->filter_need_in_memory = 1; if (r == r->main) { + + if (mctx) { + + /* + * if there was a shared context previously used as main, + * copy variables and blocks + */ + + ctx->variables = mctx->variables; + ctx->blocks = mctx->blocks; + +#if (NGX_PCRE) + ctx->ncaptures = mctx->ncaptures; + ctx->captures = mctx->captures; + ctx->captures_data = mctx->captures_data; +#endif + + mctx->shared = 0; + } + ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); @@ -379,6 +401,10 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) } else { ngx_http_weak_etag(r); } + + } else if (mctx == NULL) { + ngx_http_set_ctx(r->main, ctx, ngx_http_ssi_filter_module); + ctx->shared = 1; } return ngx_http_next_header_filter(r); @@ -405,6 +431,7 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); if (ctx == NULL + || (ctx->shared && r == r->main) || (in == NULL && ctx->buf == NULL && ctx->in == NULL diff --git a/src/http/modules/ngx_http_ssi_filter_module.h b/src/http/modules/ngx_http_ssi_filter_module.h index 0bd01a0..419bf97 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.h +++ b/src/http/modules/ngx_http_ssi_filter_module.h @@ -71,6 +71,7 @@ typedef struct { u_char *captures_data; #endif + unsigned shared:1; unsigned conditional:2; unsigned encoding:2; unsigned block:1; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index d74d460..4c4a598 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -632,8 +632,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, NGX_SSL_BUFSIZE); @@ -1093,7 +1094,7 @@ ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) len++; } - if (len == 0) { + if (len == 0 || j == value[i].len) { goto invalid; } @@ -1183,7 +1184,7 @@ ngx_http_ssl_ocsp_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) len++; } - if (len == 0) { + if (len == 0 || j == value[1].len) { goto invalid; } diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index cf29d5a..8b0bb14 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -195,6 +195,7 @@ ngx_http_static_handler(ngx_http_request_t *r) } r->headers_out.location->hash = 1; + r->headers_out.location->next = NULL; ngx_str_set(&r->headers_out.location->key, "Location"); r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; @@ -237,10 +238,6 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (r != r->main && of.size == 0) { - return ngx_http_send_header(r); - } - r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ @@ -264,9 +261,10 @@ ngx_http_static_handler(ngx_http_request_t *r) b->file_pos = 0; b->file_last = of.size; - b->in_file = b->file_last ? 1: 0; - b->last_buf = (r == r->main) ? 1: 0; + b->in_file = b->file_last ? 1 : 0; + b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index 1e33c5c..e528444 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -319,10 +319,9 @@ ngx_http_userid_set_variable(ngx_http_request_t *r, static ngx_http_userid_ctx_t * ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) { - ngx_int_t n; - ngx_str_t src, dst; - ngx_table_elt_t **cookies; - ngx_http_userid_ctx_t *ctx; + ngx_str_t src, dst; + ngx_table_elt_t *cookie; + ngx_http_userid_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); @@ -339,9 +338,9 @@ ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module); } - n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, - &ctx->cookie); - if (n == NGX_DECLINED) { + cookie = ngx_http_parse_multi_header_lines(r, r->headers_in.cookie, + &conf->name, &ctx->cookie); + if (cookie == NULL) { return ctx; } @@ -349,10 +348,9 @@ ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) "uid cookie: \"%V\"", &ctx->cookie); if (ctx->cookie.len < 22) { - cookies = r->headers_in.cookies.elts; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent too short userid cookie \"%V\"", - &cookies[n]->value); + &cookie->value); return ctx; } @@ -370,10 +368,9 @@ ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) dst.data = (u_char *) ctx->uid_got; if (ngx_decode_base64(&dst, &src) == NGX_ERROR) { - cookies = r->headers_in.cookies.elts; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid userid cookie \"%V\"", - &cookies[n]->value); + &cookie->value); return ctx; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index d46741a..e4f721b 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -96,6 +96,8 @@ static char *ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); +static ngx_int_t ngx_http_uwsgi_merge_ssl(ngx_conf_t *cf, + ngx_http_uwsgi_loc_conf_t *conf, ngx_http_uwsgi_loc_conf_t *prev); static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf); #endif @@ -668,7 +670,7 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) if (uwcf->uwsgi_lengths == NULL) { #if (NGX_HTTP_SSL) - u->ssl = (uwcf->upstream.ssl != NULL); + u->ssl = uwcf->ssl; if (u->ssl) { ngx_str_set(&u->schema, "suwsgi://"); @@ -845,13 +847,13 @@ ngx_http_uwsgi_create_key(ngx_http_request_t *r) static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r) { - u_char ch, *lowcase_key; + u_char ch, sep, *lowcase_key; size_t key_len, val_len, len, allocated; ngx_uint_t i, n, hash, skip_empty, header_params; ngx_buf_t *b; ngx_chain_t *cl, *body; ngx_list_part_t *part; - ngx_table_elt_t *header, **ignored; + ngx_table_elt_t *header, *hn, **ignored; ngx_http_uwsgi_params_t *params; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; @@ -905,7 +907,11 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) allocated = 0; lowcase_key = NULL; - if (params->number) { + if (ngx_http_link_multi_headers(r) != NGX_OK) { + return NGX_ERROR; + } + + if (params->number || r->headers_in.multi) { n = 0; part = &r->headers_in.headers.part; @@ -935,6 +941,12 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) i = 0; } + for (n = 0; n < header_params; n++) { + if (&header[i] == ignored[n]) { + goto next_length; + } + } + if (params->number) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; @@ -968,6 +980,15 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) len += 2 + sizeof("HTTP_") - 1 + header[i].key.len + 2 + header[i].value.len; + + for (hn = header[i].next; hn; hn = hn->next) { + len += hn->value.len + 2; + ignored[header_params++] = hn; + } + + next_length: + + continue; } } @@ -1086,7 +1107,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) for (n = 0; n < header_params; n++) { if (&header[i] == ignored[n]) { - goto next; + goto next_value; } } @@ -1109,15 +1130,41 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) } val_len = header[i].value.len; + + for (hn = header[i].next; hn; hn = hn->next) { + val_len += hn->value.len + 2; + } + *b->last++ = (u_char) (val_len & 0xff); *b->last++ = (u_char) ((val_len >> 8) & 0xff); - b->last = ngx_copy(b->last, header[i].value.data, val_len); + b->last = ngx_copy(b->last, header[i].value.data, + header[i].value.len); + + if (header[i].next) { + + if (header[i].key.len == sizeof("Cookie") - 1 + && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie", + sizeof("Cookie") - 1) + == 0) + { + sep = ';'; + + } else { + sep = ','; + } + + for (hn = header[i].next; hn; hn = hn->next) { + *b->last++ = sep; + *b->last++ = ' '; + b->last = ngx_copy(b->last, hn->value.data, hn->value.len); + } + } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uwsgi param: \"%*s: %*s\"", key_len, b->last - (key_len + 2 + val_len), val_len, b->last - val_len); - next: + next_value: continue; } @@ -1295,8 +1342,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); - if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_ERROR; + if (hh) { + rc = hh->handler(r, h, hh->offset); + + if (rc != NGX_OK) { + return rc; + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1816,12 +1867,17 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) + if (ngx_http_uwsgi_merge_ssl(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + 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_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); @@ -1878,7 +1934,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->uwsgi_values = prev->uwsgi_values; #if (NGX_HTTP_SSL) - conf->upstream.ssl = prev->upstream.ssl; + conf->ssl = prev->ssl; #endif } @@ -2405,18 +2461,64 @@ ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) } +static ngx_int_t +ngx_http_uwsgi_merge_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, + ngx_http_uwsgi_loc_conf_t *prev) +{ + ngx_uint_t preserve; + + if (conf->ssl_protocols == 0 + && conf->ssl_ciphers.data == NULL + && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR + && conf->upstream.ssl_verify == NGX_CONF_UNSET + && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT + && conf->ssl_trusted_certificate.data == NULL + && conf->ssl_crl.data == NULL + && conf->upstream.ssl_session_reuse == NGX_CONF_UNSET + && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR) + { + if (prev->upstream.ssl) { + conf->upstream.ssl = prev->upstream.ssl; + return NGX_OK; + } + + preserve = 1; + + } else { + preserve = 0; + } + + conf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (conf->upstream.ssl == NULL) { + return NGX_ERROR; + } + + conf->upstream.ssl->log = cf->log; + + /* + * special handling to preserve conf->upstream.ssl + * in the "http" section to inherit it to all servers + */ + + if (preserve) { + prev->upstream.ssl = conf->upstream.ssl; + } + + return NGX_OK; +} + + 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; + if (uwcf->upstream.ssl->ctx) { + return NGX_OK; } - uwcf->upstream.ssl->log = cf->log; - if (ngx_ssl_create(uwcf->upstream.ssl, uwcf->ssl_protocols, NULL) != NGX_OK) { @@ -2438,8 +2540,9 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) return NGX_ERROR; } - if (uwcf->upstream.ssl_certificate) { - + if (uwcf->upstream.ssl_certificate + && uwcf->upstream.ssl_certificate->value.len) + { if (uwcf->upstream.ssl_certificate_key == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"uwsgi_ssl_certificate_key\" is defined " diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index caf7c08..fd59e29 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -269,10 +269,9 @@ header_in(r, key) u_char *p, *lowcase_key, *value, sep; STRLEN len; ssize_t size; - ngx_uint_t i, n, hash; - ngx_array_t *a; + ngx_uint_t i, hash; ngx_list_part_t *part; - ngx_table_elt_t *h, **ph; + ngx_table_elt_t *h, *header, **ph; ngx_http_header_t *hh; ngx_http_core_main_conf_t *cmcf; @@ -302,78 +301,23 @@ header_in(r, key) if (hh) { - if (hh->offset == offsetof(ngx_http_headers_in_t, cookies)) { + if (hh->offset == offsetof(ngx_http_headers_in_t, cookie)) { sep = ';'; - goto multi; - } -#if (NGX_HTTP_X_FORWARDED_FOR) - if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) { + + } else { sep = ','; - goto multi; } -#endif ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset); - if (*ph) { - ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); - - goto done; - } - - XSRETURN_UNDEF; - - multi: - - /* Cookie, X-Forwarded-For */ - - a = (ngx_array_t *) ((char *) &r->headers_in + hh->offset); - - n = a->nelts; - - if (n == 0) { - XSRETURN_UNDEF; - } - - ph = a->elts; - - if (n == 1) { - ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); - - goto done; - } - - size = - (ssize_t) (sizeof("; ") - 1); - - for (i = 0; i < n; i++) { - size += ph[i]->value.len + sizeof("; ") - 1; - } - - value = ngx_pnalloc(r->pool, size); - if (value == NULL) { - ctx->error = 1; - croak("ngx_pnalloc() failed"); - } - - p = value; - - for (i = 0; /* void */ ; i++) { - p = ngx_copy(p, ph[i]->value.data, ph[i]->value.len); - - if (i == n - 1) { - break; - } - - *p++ = sep; *p++ = ' '; - } - - ngx_http_perl_set_targ(value, size); - - goto done; + goto found; } /* iterate over all headers */ + sep = ','; + ph = &header; + part = &r->headers_in.headers.part; h = part->elts; @@ -395,12 +339,49 @@ header_in(r, key) continue; } - ngx_http_perl_set_targ(h[i].value.data, h[i].value.len); + *ph = &h[i]; + ph = &h[i].next; + } + *ph = NULL; + ph = &header; + + found: + + if (*ph == NULL) { + XSRETURN_UNDEF; + } + + if ((*ph)->next == NULL) { + ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); goto done; } - XSRETURN_UNDEF; + size = - (ssize_t) (sizeof("; ") - 1); + + for (h = *ph; h; h = h->next) { + size += h->value.len + sizeof("; ") - 1; + } + + value = ngx_pnalloc(r->pool, size); + if (value == NULL) { + ctx->error = 1; + croak("ngx_pnalloc() failed"); + } + + p = value; + + for (h = *ph; h; h = h->next) { + p = ngx_copy(p, h->value.data, h->value.len); + + if (h->next == NULL) { + break; + } + + *p++ = sep; *p++ = ' '; + } + + ngx_http_perl_set_targ(value, size); done: @@ -591,6 +572,7 @@ header_out(r, key, value) } header->hash = 1; + header->next = NULL; if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { header->hash = 0; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 73c08d5..93e1cd4 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1130,7 +1130,7 @@ ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect) || (lq->inclusive && lq->inclusive->auto_redirect)); - node->len = (u_char) len; + node->len = (u_short) len; ngx_memcpy(node->name, &lq->name->data[prefix], len); ngx_queue_split(locations, q, &tail); @@ -1228,7 +1228,8 @@ static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) { - ngx_uint_t i, default_server, proxy_protocol; + ngx_uint_t i, default_server, proxy_protocol, + protocols, protocols_prev; ngx_http_conf_addr_t *addr; #if (NGX_HTTP_SSL) ngx_uint_t ssl; @@ -1264,12 +1265,18 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, default_server = addr[i].opt.default_server; proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol; + protocols = lsopt->proxy_protocol; + protocols_prev = addr[i].opt.proxy_protocol; #if (NGX_HTTP_SSL) ssl = lsopt->ssl || addr[i].opt.ssl; + protocols |= lsopt->ssl << 1; + protocols_prev |= addr[i].opt.ssl << 1; #endif #if (NGX_HTTP_V2) http2 = lsopt->http2 || addr[i].opt.http2; + protocols |= lsopt->http2 << 2; + protocols_prev |= addr[i].opt.http2 << 2; #endif if (lsopt->set) { @@ -1299,6 +1306,57 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, addr[i].default_server = cscf; } + /* check for conflicting protocol options */ + + if ((protocols | protocols_prev) != protocols_prev) { + + /* options added */ + + if ((addr[i].opt.set && !lsopt->set) + || addr[i].protocols_changed + || (protocols | protocols_prev) != protocols) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols_prev; + addr[i].protocols_set = 1; + addr[i].protocols_changed = 1; + + } else if ((protocols_prev | protocols) != protocols) { + + /* options removed */ + + if (lsopt->set + || (addr[i].protocols_set && protocols != addr[i].protocols)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols; + addr[i].protocols_set = 1; + addr[i].protocols_changed = 1; + + } else { + + /* the same options */ + + if ((lsopt->set && addr[i].protocols_changed) + || (addr[i].protocols_set && protocols != addr[i].protocols)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols; + addr[i].protocols_set = 1; + } + addr[i].opt.default_server = default_server; addr[i].opt.proxy_protocol = proxy_protocol; #if (NGX_HTTP_SSL) @@ -1355,6 +1413,9 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } addr->opt = *lsopt; + addr->protocols = 0; + addr->protocols_set = 0; + addr->protocols_changed = 0; addr->hash.buckets = NULL; addr->hash.size = 0; addr->wc_head = NULL; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index be8b7cd..a7f312f 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -103,10 +103,10 @@ ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_uint_t *flags); ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t allow_underscores); -ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, - ngx_str_t *name, ngx_str_t *value); -ngx_int_t ngx_http_parse_set_cookie_lines(ngx_array_t *headers, - ngx_str_t *name, ngx_str_t *value); +ngx_table_elt_t *ngx_http_parse_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value); +ngx_table_elt_t *ngx_http_parse_set_cookie_lines(ngx_http_request_t *r, + ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value); ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value); void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index c7463dc..2140e06 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1007,6 +1007,7 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, } r->headers_out.location->hash = 1; + r->headers_out.location->next = NULL; ngx_str_set(&r->headers_out.location->key, "Location"); if (r->args.len == 0) { @@ -1087,6 +1088,7 @@ ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_int_t rc; + ngx_table_elt_t *h; ngx_http_core_loc_conf_t *clcf; if (r != r->main) { @@ -1121,8 +1123,8 @@ ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) if (rc == NGX_OK) { r->access_code = 0; - if (r->headers_out.www_authenticate) { - r->headers_out.www_authenticate->hash = 0; + for (h = r->headers_out.www_authenticate; h; h = h->next) { + h->hash = 0; } r->phase_handler = ph->next; @@ -1687,6 +1689,7 @@ ngx_http_set_etag(ngx_http_request_t *r) } etag->hash = 1; + etag->next = NULL; ngx_str_set(&etag->key, "ETag"); etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3); @@ -1781,6 +1784,7 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, } r->headers_out.location->hash = 1; + r->headers_out.location->next = NULL; ngx_str_set(&r->headers_out.location->key, "Location"); r->headers_out.location->value = val; @@ -1799,10 +1803,6 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, } } - if (r != r->main && val.len == 0) { - return ngx_http_send_header(r); - } - b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1813,6 +1813,7 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, b->memory = val.len ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->memory) ? 0 : 1; out.buf = b; out.next = NULL; @@ -2024,8 +2025,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r) { time_t date, expires; ngx_uint_t p; - ngx_array_t *cc; - ngx_table_elt_t *e, *d, *ae; + ngx_table_elt_t *e, *d, *ae, *cc; ngx_http_core_loc_conf_t *clcf; r->gzip_tested = 1; @@ -2118,30 +2118,30 @@ ngx_http_gzip_ok(ngx_http_request_t *r) return NGX_DECLINED; } - cc = &r->headers_out.cache_control; + cc = r->headers_out.cache_control; - if (cc->elts) { + if (cc) { if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE) - && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache, + && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_no_cache, NULL) - >= 0) + != NULL) { goto ok; } if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE) - && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store, + && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_no_store, NULL) - >= 0) + != NULL) { goto ok; } if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE) - && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private, + && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_private, NULL) - >= 0) + != NULL) { goto ok; } @@ -2712,12 +2712,12 @@ ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, - ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies, + ngx_table_elt_t *headers, ngx_str_t *value, ngx_array_t *proxies, int recursive) { - ngx_int_t rc; - ngx_uint_t i, found; - ngx_table_elt_t **h; + ngx_int_t rc; + ngx_uint_t found; + ngx_table_elt_t *h, *next; if (headers == NULL) { return ngx_http_get_forwarded_addr_internal(r, addr, value->data, @@ -2725,16 +2725,23 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, recursive); } - i = headers->nelts; - h = headers->elts; + /* revert headers order */ + + for (h = headers, headers = NULL; h; h = next) { + next = h->next; + h->next = headers; + headers = h; + } + + /* iterate over all headers in reverse order */ rc = NGX_DECLINED; found = 0; - while (i-- > 0) { - rc = ngx_http_get_forwarded_addr_internal(r, addr, h[i]->value.data, - h[i]->value.len, proxies, + for (h = headers; h; h = h->next) { + rc = ngx_http_get_forwarded_addr_internal(r, addr, h->value.data, + h->value.len, proxies, recursive); if (!recursive) { @@ -2753,6 +2760,14 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, found = 1; } + /* restore headers order */ + + for (h = headers, headers = NULL; h; h = next) { + next = h->next; + h->next = headers; + headers = h; + } + return rc; } @@ -2802,6 +2817,80 @@ ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr, } +ngx_int_t +ngx_http_link_multi_headers(ngx_http_request_t *r) +{ + ngx_uint_t i, j; + ngx_list_part_t *part, *ppart; + ngx_table_elt_t *header, *pheader, **ph; + + if (r->headers_in.multi_linked) { + return NGX_OK; + } + + r->headers_in.multi_linked = 1; + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + header[i].next = NULL; + + /* + * search for previous headers with the same name; + * if there are any, link to them + */ + + ppart = &r->headers_in.headers.part; + pheader = ppart->elts; + + for (j = 0; /* void */; j++) { + + if (j >= ppart->nelts) { + if (ppart->next == NULL) { + break; + } + + ppart = ppart->next; + pheader = ppart->elts; + j = 0; + } + + if (part == ppart && i == j) { + break; + } + + if (header[i].key.len == pheader[j].key.len + && ngx_strncasecmp(header[i].key.data, pheader[j].key.data, + header[i].key.len) + == 0) + { + ph = &pheader[j].next; + while (*ph) { ph = &(*ph)->next; } + *ph = &header[i]; + + r->headers_in.multi = 1; + + break; + } + } + } + + return NGX_OK; +} + + static char * ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { @@ -3871,7 +3960,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value, size; ngx_url_t u; - ngx_uint_t n; + ngx_uint_t n, i; ngx_http_listen_opt_t lsopt; cscf->listen = 1; @@ -4197,6 +4286,16 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } for (n = 0; n < u.naddrs; n++) { + + for (i = 0; i < n; i++) { + if (ngx_cmp_sockaddr(u.addrs[n].sockaddr, u.addrs[n].socklen, + u.addrs[i].sockaddr, u.addrs[i].socklen, 1) + == NGX_OK) + { + goto next; + } + } + lsopt.sockaddr = u.addrs[n].sockaddr; lsopt.socklen = u.addrs[n].socklen; lsopt.addr_text = u.addrs[n].name; @@ -4205,6 +4304,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) { return NGX_CONF_ERROR; } + + next: + continue; } return NGX_CONF_OK; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 004a98e..e41bc68 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -274,6 +274,10 @@ typedef struct { typedef struct { ngx_http_listen_opt_t opt; + unsigned protocols:3; + unsigned protocols_set:1; + unsigned protocols_changed:1; + ngx_hash_t hash; ngx_hash_wildcard_t *wc_head; ngx_hash_wildcard_t *wc_tail; @@ -463,8 +467,8 @@ struct ngx_http_location_tree_node_s { ngx_http_core_loc_conf_t *exact; ngx_http_core_loc_conf_t *inclusive; + u_short len; u_char auto_redirect; - u_char len; u_char name[1]; }; @@ -529,9 +533,11 @@ ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, - ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies, + ngx_table_elt_t *headers, ngx_str_t *value, ngx_array_t *proxies, int recursive); +ngx_int_t ngx_http_link_multi_headers(ngx_http_request_t *r); + extern ngx_module_t ngx_http_core_module; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index c40093b..aa5fd19 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1575,10 +1575,6 @@ ngx_http_cache_send(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache send: %s", c->file.name.data); - if (r != r->main && c->length - c->body_start == 0) { - return ngx_http_send_header(r); - } - /* we need to allocate all before the header would be sent */ b = ngx_calloc_buf(r->pool); @@ -1600,9 +1596,10 @@ ngx_http_cache_send(ngx_http_request_t *r) b->file_pos = c->body_start; b->file_last = c->length; - b->in_file = (c->length - c->body_start) ? 1: 0; - b->last_buf = (r == r->main) ? 1: 0; + b->in_file = (c->length - c->body_start) ? 1 : 0; + b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = c->file.fd; b->file->name = c->file.name; @@ -1756,6 +1753,11 @@ ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) break; } + if (fcn->deleting) { + wait = 1; + break; + } + p = ngx_hex_dump(key, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 6460da2..d4f2dae 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1960,27 +1960,24 @@ unsafe: } -ngx_int_t -ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, - ngx_str_t *value) +ngx_table_elt_t * +ngx_http_parse_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value) { - ngx_uint_t i; - u_char *start, *last, *end, ch; - ngx_table_elt_t **h; + u_char *start, *last, *end, ch; + ngx_table_elt_t *h; - h = headers->elts; + for (h = headers; h; h = h->next) { - for (i = 0; i < headers->nelts; i++) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "parse header: \"%V: %V\"", &h->key, &h->value); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, - "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value); - - if (name->len > h[i]->value.len) { + if (name->len > h->value.len) { continue; } - start = h[i]->value.data; - end = h[i]->value.data + h[i]->value.len; + start = h->value.data; + end = h->value.data + h->value.len; while (start < end) { @@ -1994,7 +1991,7 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, if (value == NULL) { if (start == end || *start == ',') { - return i; + return h; } goto skip; @@ -2014,7 +2011,7 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, value->len = last - start; value->data = start; - return i; + return h; skip: @@ -2029,31 +2026,28 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, } } - return NGX_DECLINED; + return NULL; } -ngx_int_t -ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name, - ngx_str_t *value) +ngx_table_elt_t * +ngx_http_parse_set_cookie_lines(ngx_http_request_t *r, + ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value) { - ngx_uint_t i; - u_char *start, *last, *end; - ngx_table_elt_t **h; + u_char *start, *last, *end; + ngx_table_elt_t *h; - h = headers->elts; + for (h = headers; h; h = h->next) { - for (i = 0; i < headers->nelts; i++) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "parse header: \"%V: %V\"", &h->key, &h->value); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, - "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value); - - if (name->len >= h[i]->value.len) { + if (name->len >= h->value.len) { continue; } - start = h[i]->value.data; - end = h[i]->value.data + h[i]->value.len; + start = h->value.data; + end = h->value.data + h->value.len; if (ngx_strncasecmp(start, name->data, name->len) != 0) { continue; @@ -2077,10 +2071,10 @@ ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name, value->len = last - start; value->data = start; - return i; + return h; } - return NGX_DECLINED; + return NULL; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 013b715..5e0340b 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -22,8 +22,6 @@ static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); -static ngx_int_t ngx_http_process_multi_header_lines(ngx_http_request_t *r, - ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, @@ -164,7 +162,7 @@ ngx_http_header_t ngx_http_headers_in[] = { #if (NGX_HTTP_X_FORWARDED_FOR) { ngx_string("X-Forwarded-For"), offsetof(ngx_http_headers_in_t, x_forwarded_for), - ngx_http_process_multi_header_lines }, + ngx_http_process_header_line }, #endif #if (NGX_HTTP_REALIP) @@ -196,8 +194,8 @@ ngx_http_header_t ngx_http_headers_in[] = { ngx_http_process_header_line }, #endif - { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies), - ngx_http_process_multi_header_lines }, + { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookie), + ngx_http_process_header_line }, { ngx_null_string, 0, NULL } }; @@ -1742,9 +1740,10 @@ ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); - if (*ph == NULL) { - *ph = h; - } + while (*ph) { ph = &(*ph)->next; } + + *ph = h; + h->next = NULL; return NGX_OK; } @@ -1760,6 +1759,7 @@ ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, if (*ph == NULL) { *ph = h; + h->next = NULL; return NGX_OK; } @@ -1792,6 +1792,7 @@ ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, } r->headers_in.host = h; + h->next = NULL; host = h->value; @@ -1827,6 +1828,10 @@ static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { + if (ngx_http_process_header_line(r, h, offset) != NGX_OK) { + return NGX_ERROR; + } + if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; @@ -1844,12 +1849,10 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, { u_char *user_agent, *msie; - if (r->headers_in.user_agent) { - return NGX_OK; + if (ngx_http_process_header_line(r, h, offset) != NGX_OK) { + return NGX_ERROR; } - r->headers_in.user_agent = h; - /* check some widespread browsers while the header is in CPU cache */ user_agent = h->value.data; @@ -1911,35 +1914,6 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, } -static ngx_int_t -ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h, - ngx_uint_t offset) -{ - ngx_array_t *headers; - ngx_table_elt_t **ph; - - headers = (ngx_array_t *) ((char *) &r->headers_in + offset); - - if (headers->elts == NULL) { - if (ngx_array_init(headers, r->pool, 1, sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_ERROR; - } - } - - ph = ngx_array_push(headers); - if (ph == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_ERROR; - } - - *ph = h; - return NGX_OK; -} - - ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) { @@ -2779,7 +2753,8 @@ ngx_http_finalize_connection(ngx_http_request_t *r) || (clcf->lingering_close == NGX_HTTP_LINGERING_ON && (r->lingering_close || r->header_in->pos < r->header_in->last - || r->connection->read->ready))) + || r->connection->read->ready + || r->connection->pipeline))) { ngx_http_set_lingering_close(r->connection); return; @@ -3149,6 +3124,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) c->sent = 0; c->destroyed = 0; + c->pipeline = 1; if (rev->timer_set) { ngx_del_timer(rev); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index b1269d2..8c9eed2 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -212,7 +212,7 @@ typedef struct { ngx_table_elt_t *keep_alive; #if (NGX_HTTP_X_FORWARDED_FOR) - ngx_array_t x_forwarded_for; + ngx_table_elt_t *x_forwarded_for; #endif #if (NGX_HTTP_REALIP) @@ -231,17 +231,19 @@ typedef struct { ngx_table_elt_t *date; #endif + ngx_table_elt_t *cookie; + ngx_str_t user; ngx_str_t passwd; - ngx_array_t cookies; - ngx_str_t server; off_t content_length_n; time_t keep_alive_n; unsigned connection_type:2; unsigned chunked:1; + unsigned multi:1; + unsigned multi_linked:1; unsigned msie:1; unsigned msie6:1; unsigned opera:1; @@ -272,6 +274,9 @@ typedef struct { ngx_table_elt_t *expires; ngx_table_elt_t *etag; + ngx_table_elt_t *cache_control; + ngx_table_elt_t *link; + ngx_str_t *override_charset; size_t content_type_len; @@ -280,9 +285,6 @@ typedef struct { u_char *content_type_lowcase; ngx_uint_t content_type_hash; - ngx_array_t cache_control; - ngx_array_t link; - off_t content_length_n; off_t content_offset; time_t date_time; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index bebdbd9..a2b9f1b 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -1243,6 +1243,7 @@ ngx_http_script_regex_end_code(ngx_http_script_engine_t *e) } r->headers_out.location->hash = 1; + r->headers_out.location->next = NULL; ngx_str_set(&r->headers_out.location->key, "Location"); r->headers_out.location->value = e->buf; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 72f56fd..eaf42e3 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -649,6 +649,7 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) } location->hash = 1; + location->next = NULL; ngx_str_set(&location->key, "Location"); location->value = uri; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index ded833c..3ae822b 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -101,6 +101,9 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r, @@ -147,11 +150,6 @@ static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); -#if (NGX_HTTP_GZIP) -static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, - ngx_table_elt_t *h, ngx_uint_t offset); -#endif - static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -231,7 +229,7 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { offsetof(ngx_http_headers_out_t, server), 0 }, { ngx_string("WWW-Authenticate"), - ngx_http_upstream_process_header_line, + ngx_http_upstream_process_multi_header_lines, offsetof(ngx_http_upstream_headers_in_t, www_authenticate), ngx_http_upstream_copy_header_line, 0, 0 }, @@ -241,12 +239,13 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_rewrite_location, 0, 0 }, { ngx_string("Refresh"), - ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, refresh), ngx_http_upstream_rewrite_refresh, 0, 0 }, { ngx_string("Set-Cookie"), ngx_http_upstream_process_set_cookie, - offsetof(ngx_http_upstream_headers_in_t, cookies), + offsetof(ngx_http_upstream_headers_in_t, set_cookie), ngx_http_upstream_rewrite_set_cookie, 0, 1 }, { ngx_string("Content-Disposition"), @@ -264,8 +263,7 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { offsetof(ngx_http_headers_out_t, expires), 1 }, { ngx_string("Accept-Ranges"), - ngx_http_upstream_process_header_line, - offsetof(ngx_http_upstream_headers_in_t, accept_ranges), + ngx_http_upstream_ignore_header_line, 0, ngx_http_upstream_copy_allow_ranges, offsetof(ngx_http_headers_out_t, accept_ranges), 1 }, @@ -316,12 +314,10 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_process_transfer_encoding, 0, ngx_http_upstream_ignore_header_line, 0, 0 }, -#if (NGX_HTTP_GZIP) { ngx_string("Content-Encoding"), - ngx_http_upstream_process_header_line, - offsetof(ngx_http_upstream_headers_in_t, content_encoding), - ngx_http_upstream_copy_content_encoding, 0, 0 }, -#endif + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_copy_header_line, + offsetof(ngx_http_headers_out_t, content_encoding), 0 }, { ngx_null_string, NULL, 0, NULL, 0, 0 } }; @@ -1694,8 +1690,10 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, } } - if (u->conf->ssl_certificate && (u->conf->ssl_certificate->lengths - || u->conf->ssl_certificate_key->lengths)) + if (u->conf->ssl_certificate + && u->conf->ssl_certificate->value.len + && (u->conf->ssl_certificate->lengths + || u->conf->ssl_certificate_key->lengths)) { if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, @@ -2651,7 +2649,7 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r, { ngx_int_t status; ngx_uint_t i; - ngx_table_elt_t *h; + ngx_table_elt_t *h, *ho, **ph; ngx_http_err_page_t *err_page; ngx_http_core_loc_conf_t *clcf; @@ -2680,23 +2678,36 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r, if (status == NGX_HTTP_UNAUTHORIZED && u->headers_in.www_authenticate) { - h = ngx_list_push(&r->headers_out.headers); + h = u->headers_in.www_authenticate; + ph = &r->headers_out.www_authenticate; - if (h == NULL) { - ngx_http_upstream_finalize_request(r, u, + while (h) { + ho = ngx_list_push(&r->headers_out.headers); + + if (ho == NULL) { + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; + return NGX_OK; + } + + *ho = *h; + ho->next = NULL; + + *ph = ho; + ph = &ho->next; + + h = h->next; } - - *h = *u->headers_in.www_authenticate; - - r->headers_out.www_authenticate = h; } #if (NGX_HTTP_CACHE) if (r->cache) { + if (u->headers_in.no_cache || u->headers_in.expired) { + u->cacheable = 0; + } + if (u->cacheable) { time_t valid; @@ -2791,6 +2802,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + if (u->headers_in.no_cache || u->headers_in.expired) { + u->cacheable = 0; + } + if (u->headers_in.x_accel_redirect && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT)) { @@ -2811,6 +2826,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) i = 0; } + if (h[i].hash == 0) { + continue; + } + hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, h[i].lowcase_key, h[i].key.len); @@ -2864,6 +2883,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) i = 0; } + if (h[i].hash == 0) { + continue; + } + if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, h[i].lowcase_key, h[i].key.len)) { @@ -4615,10 +4638,36 @@ ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); - if (*ph == NULL) { - *ph = h; + if (*ph) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &(*ph)->key, &(*ph)->value); + h->hash = 0; + return NGX_OK; } + *ph = h; + h->next = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_table_elt_t **ph; + + ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); + + while (*ph) { ph = &(*ph)->next; } + + *ph = h; + h->next = NULL; + return NGX_OK; } @@ -4639,9 +4688,34 @@ ngx_http_upstream_process_content_length(ngx_http_request_t *r, u = r->upstream; + if (u->headers_in.content_length) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\"", + &h->key, &h->value, + &u->headers_in.content_length->key, + &u->headers_in.content_length->value); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (u->headers_in.transfer_encoding) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent \"Content-Length\" and " + "\"Transfer-Encoding\" headers at the same time"); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + h->next = NULL; u->headers_in.content_length = h; u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len); + if (u->headers_in.content_length_n == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent invalid \"Content-Length\" header: " + "\"%V: %V\"", &h->key, &h->value); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + return NGX_OK; } @@ -4654,6 +4728,18 @@ ngx_http_upstream_process_last_modified(ngx_http_request_t *r, u = r->upstream; + if (u->headers_in.last_modified) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.last_modified->key, + &u->headers_in.last_modified->value); + h->hash = 0; + return NGX_OK; + } + + h->next = NULL; u->headers_in.last_modified = h; u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, h->value.len); @@ -4666,26 +4752,16 @@ static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_array_t *pa; ngx_table_elt_t **ph; ngx_http_upstream_t *u; u = r->upstream; - pa = &u->headers_in.cookies; + ph = &u->headers_in.set_cookie; - if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK) - { - return NGX_ERROR; - } - } - - ph = ngx_array_push(pa); - if (ph == NULL) { - return NGX_ERROR; - } + while (*ph) { ph = &(*ph)->next; } *ph = h; + h->next = NULL; #if (NGX_HTTP_CACHE) if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) { @@ -4701,26 +4777,16 @@ static ngx_int_t ngx_http_upstream_process_cache_control(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_array_t *pa; - ngx_table_elt_t **ph; - ngx_http_upstream_t *u; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; u = r->upstream; - pa = &u->headers_in.cache_control; + ph = &u->headers_in.cache_control; - if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) - { - return NGX_ERROR; - } - } - - ph = ngx_array_push(pa); - if (ph == NULL) { - return NGX_ERROR; - } + while (*ph) { ph = &(*ph)->next; } *ph = h; + h->next = NULL; #if (NGX_HTTP_CACHE) { @@ -4735,18 +4801,18 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, return NGX_OK; } - if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) { - return NGX_OK; - } - start = h->value.data; last = start + h->value.len; + if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) { + goto extensions; + } + if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL) { - u->cacheable = 0; + u->headers_in.no_cache = 1; return NGX_OK; } @@ -4776,13 +4842,16 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (n == 0) { - u->cacheable = 0; + u->headers_in.no_cache = 1; return NGX_OK; } r->cache->valid_sec = ngx_time() + n; + u->headers_in.expired = 0; } +extensions: + p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=", 23 - 1); @@ -4842,7 +4911,20 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_http_upstream_t *u; u = r->upstream; + + if (u->headers_in.expires) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.expires->key, + &u->headers_in.expires->value); + h->hash = 0; + return NGX_OK; + } + u->headers_in.expires = h; + h->next = NULL; #if (NGX_HTTP_CACHE) { @@ -4863,7 +4945,7 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h, expires = ngx_parse_http_time(h->value.data, h->value.len); if (expires == NGX_ERROR || expires < ngx_time()) { - u->cacheable = 0; + u->headers_in.expired = 1; return NGX_OK; } @@ -4882,7 +4964,20 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, ngx_http_upstream_t *u; u = r->upstream; + + if (u->headers_in.x_accel_expires) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.x_accel_expires->key, + &u->headers_in.x_accel_expires->value); + h->hash = 0; + return NGX_OK; + } + u->headers_in.x_accel_expires = h; + h->next = NULL; #if (NGX_HTTP_CACHE) { @@ -4914,6 +5009,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, default: r->cache->valid_sec = ngx_time() + n; + u->headers_in.no_cache = 0; + u->headers_in.expired = 0; return NGX_OK; } } @@ -4925,6 +5022,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, if (n != NGX_ERROR) { r->cache->valid_sec = n; + u->headers_in.no_cache = 0; + u->headers_in.expired = 0; } } #endif @@ -4941,7 +5040,20 @@ ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_http_upstream_t *u; u = r->upstream; + + if (u->headers_in.x_accel_limit_rate) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.x_accel_limit_rate->key, + &u->headers_in.x_accel_limit_rate->value); + h->hash = 0; + return NGX_OK; + } + u->headers_in.x_accel_limit_rate = h; + h->next = NULL; if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) { return NGX_OK; @@ -5000,7 +5112,11 @@ static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) { + ngx_http_upstream_t *u; + + u = r->upstream; + + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) { return NGX_OK; } @@ -5014,13 +5130,22 @@ static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - r->upstream->headers_in.connection = h; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; + + u = r->upstream; + ph = &u->headers_in.connection; + + while (*ph) { ph = &(*ph)->next; } + + *ph = h; + h->next = NULL; if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, (u_char *) "close", 5 - 1) != NULL) { - r->upstream->headers_in.connection_close = 1; + u->headers_in.connection_close = 1; } return NGX_OK; @@ -5031,13 +5156,40 @@ static ngx_int_t ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - r->upstream->headers_in.transfer_encoding = h; + ngx_http_upstream_t *u; - if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, - (u_char *) "chunked", 7 - 1) - != NULL) + u = r->upstream; + + if (u->headers_in.transfer_encoding) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\"", + &h->key, &h->value, + &u->headers_in.transfer_encoding->key, + &u->headers_in.transfer_encoding->value); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (u->headers_in.content_length) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent \"Content-Length\" and " + "\"Transfer-Encoding\" headers at the same time"); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + u->headers_in.transfer_encoding = h; + h->next = NULL; + + if (h->value.len == 7 + && ngx_strncasecmp(h->value.data, (u_char *) "chunked", 7) == 0) { - r->upstream->headers_in.chunked = 1; + u->headers_in.chunked = 1; + + } else { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unknown \"Transfer-Encoding\": \"%V\"", + &h->value); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; } return NGX_OK; @@ -5048,29 +5200,74 @@ static ngx_int_t ngx_http_upstream_process_vary(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_http_upstream_t *u; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; u = r->upstream; - u->headers_in.vary = h; + ph = &u->headers_in.vary; + + while (*ph) { ph = &(*ph)->next; } + + *ph = h; + h->next = NULL; #if (NGX_HTTP_CACHE) + { + u_char *p; + size_t len; + ngx_str_t vary; if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) { return NGX_OK; } - if (r->cache == NULL) { + if (r->cache == NULL || !u->cacheable) { return NGX_OK; } - if (h->value.len > NGX_HTTP_CACHE_VARY_LEN - || (h->value.len == 1 && h->value.data[0] == '*')) - { + if (h->value.len == 1 && h->value.data[0] == '*') { + u->cacheable = 0; + return NGX_OK; + } + + if (u->headers_in.vary->next) { + + len = 0; + + for (h = u->headers_in.vary; h; h = h->next) { + len += h->value.len + 2; + } + + len -= 2; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + vary.len = len; + vary.data = p; + + for (h = u->headers_in.vary; h; h = h->next) { + p = ngx_copy(p, h->value.data, h->value.len); + + if (h->next == NULL) { + break; + } + + *p++ = ','; *p++ = ' '; + } + + } else { + vary = h->value; + } + + if (vary.len > NGX_HTTP_CACHE_VARY_LEN) { u->cacheable = 0; } - r->cache->vary = h->value; - + r->cache->vary = vary; + } #endif return NGX_OK; @@ -5093,6 +5290,7 @@ ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, if (offset) { ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset); *ph = ho; + ho->next = NULL; } return NGX_OK; @@ -5103,18 +5301,8 @@ static ngx_int_t ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_array_t *pa; ngx_table_elt_t *ho, **ph; - pa = (ngx_array_t *) ((char *) &r->headers_out + offset); - - if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) - { - return NGX_ERROR; - } - } - ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { return NGX_ERROR; @@ -5122,12 +5310,12 @@ ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, *ho = *h; - ph = ngx_array_push(pa); - if (ph == NULL) { - return NGX_ERROR; - } + ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset); + + while (*ph) { ph = &(*ph)->next; } *ph = ho; + ho->next = NULL; return NGX_OK; } @@ -5197,6 +5385,7 @@ ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h, } *ho = *h; + ho->next = NULL; r->headers_out.last_modified = ho; r->headers_out.last_modified_time = @@ -5219,6 +5408,7 @@ ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h, } *ho = *h; + ho->next = NULL; if (r->upstream->rewrite_redirect) { rc = r->upstream->rewrite_redirect(r, ho, 0); @@ -5264,6 +5454,7 @@ ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h, } *ho = *h; + ho->next = NULL; if (r->upstream->rewrite_redirect) { @@ -5309,6 +5500,7 @@ ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, } *ho = *h; + ho->next = NULL; if (r->upstream->rewrite_cookie) { rc = r->upstream->rewrite_cookie(r, ho); @@ -5362,6 +5554,7 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, } *ho = *h; + ho->next = NULL; r->headers_out.accept_ranges = ho; @@ -5369,29 +5562,6 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, } -#if (NGX_HTTP_GZIP) - -static ngx_int_t -ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, - ngx_table_elt_t *h, ngx_uint_t offset) -{ - ngx_table_elt_t *ho; - - ho = ngx_list_push(&r->headers_out.headers); - if (ho == NULL) { - return NGX_ERROR; - } - - *ho = *h; - - r->headers_out.content_encoding = ho; - - return NGX_OK; -} - -#endif - - static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf) { @@ -5703,7 +5873,7 @@ ngx_http_upstream_header_variable(ngx_http_request_t *r, return NGX_OK; } - return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data, &r->upstream->headers_in.headers.part, sizeof("upstream_http_") - 1); } @@ -5718,7 +5888,7 @@ ngx_http_upstream_trailer_variable(ngx_http_request_t *r, return NGX_OK; } - return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data, &r->upstream->headers_in.trailers.part, sizeof("upstream_trailer_") - 1); } @@ -5740,9 +5910,9 @@ ngx_http_upstream_cookie_variable(ngx_http_request_t *r, s.len = name->len - (sizeof("upstream_cookie_") - 1); s.data = name->data + sizeof("upstream_cookie_") - 1; - if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, + if (ngx_http_parse_set_cookie_lines(r, r->upstream->headers_in.set_cookie, &s, &cookie) - == NGX_DECLINED) + == NULL) { v->not_found = 1; return NGX_OK; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 3db7b06..9a17a03 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -280,23 +280,21 @@ typedef struct { ngx_table_elt_t *last_modified; ngx_table_elt_t *location; - ngx_table_elt_t *accept_ranges; + ngx_table_elt_t *refresh; ngx_table_elt_t *www_authenticate; ngx_table_elt_t *transfer_encoding; ngx_table_elt_t *vary; -#if (NGX_HTTP_GZIP) - ngx_table_elt_t *content_encoding; -#endif - - ngx_array_t cache_control; - ngx_array_t cookies; + ngx_table_elt_t *cache_control; + ngx_table_elt_t *set_cookie; off_t content_length_n; time_t last_modified_time; unsigned connection_close:1; unsigned chunked:1; + unsigned no_cache:1; + unsigned expired:1; } ngx_http_upstream_headers_in_t; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 942dacd..16ffda3 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -27,8 +27,6 @@ static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, static ngx_int_t ngx_http_variable_cookies(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data, u_char sep); @@ -63,6 +61,8 @@ 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_proxy_protocol_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_proxy_protocol_tlv(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, @@ -178,12 +178,12 @@ static ngx_http_variable_t ngx_http_core_variables[] = { #endif #if (NGX_HTTP_X_FORWARDED_FOR) - { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers, + { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header, offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 }, #endif { ngx_string("http_cookie"), NULL, ngx_http_variable_cookies, - offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 }, + offsetof(ngx_http_request_t, headers_in.cookie), 0, 0 }, { ngx_string("content_length"), NULL, ngx_http_variable_content_length, 0, 0, 0 }, @@ -216,6 +216,10 @@ static ngx_http_variable_t ngx_http_core_variables[] = { ngx_http_variable_proxy_protocol_port, offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 }, + { ngx_string("proxy_protocol_tlv_"), NULL, + ngx_http_variable_proxy_protocol_tlv, + 0, NGX_HTTP_VAR_PREFIX, 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 }, @@ -327,10 +331,10 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("sent_http_transfer_encoding"), NULL, ngx_http_variable_sent_transfer_encoding, 0, 0, 0 }, - { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers, + { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_header, offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 }, - { ngx_string("sent_http_link"), NULL, ngx_http_variable_headers, + { ngx_string("sent_http_link"), NULL, ngx_http_variable_header, offsetof(ngx_http_request_t, headers_out.link), 0, 0 }, { ngx_string("limit_rate"), ngx_http_variable_set_limit_rate, @@ -807,22 +811,7 @@ static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) r + data); - - if (h) { - v->len = h->value.len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = h->value.data; - - } else { - v->not_found = 1; - } - - return NGX_OK; + return ngx_http_variable_headers_internal(r, v, data, ','); } @@ -834,38 +823,25 @@ ngx_http_variable_cookies(ngx_http_request_t *r, } -static ngx_int_t -ngx_http_variable_headers(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - return ngx_http_variable_headers_internal(r, v, data, ','); -} - - static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data, u_char sep) { - size_t len; - u_char *p, *end; - ngx_uint_t i, n; - ngx_array_t *a; - ngx_table_elt_t **h; + size_t len; + u_char *p; + ngx_table_elt_t *h, *th; - a = (ngx_array_t *) ((char *) r + data); - - n = a->nelts; - h = a->elts; + h = *(ngx_table_elt_t **) ((char *) r + data); len = 0; - for (i = 0; i < n; i++) { + for (th = h; th; th = th->next) { - if (h[i]->hash == 0) { + if (th->hash == 0) { continue; } - len += h[i]->value.len + 2; + len += th->value.len + 2; } if (len == 0) { @@ -879,9 +855,9 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r, v->no_cacheable = 0; v->not_found = 0; - if (n == 1) { - v->len = (*h)->value.len; - v->data = (*h)->value.data; + if (h->next == NULL) { + v->len = h->value.len; + v->data = h->value.data; return NGX_OK; } @@ -894,17 +870,15 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r, v->len = len; v->data = p; - end = p + len; + for (th = h; th; th = th->next) { - for (i = 0; /* void */ ; i++) { - - if (h[i]->hash == 0) { + if (th->hash == 0) { continue; } - p = ngx_copy(p, h[i]->value.data, h[i]->value.len); + p = ngx_copy(p, th->value.data, th->value.len); - if (p == end) { + if (th->next == NULL) { break; } @@ -919,7 +893,7 @@ static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data, &r->headers_in.headers.part, sizeof("http_") - 1); } @@ -929,7 +903,7 @@ static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data, &r->headers_out.headers.part, sizeof("sent_http_") - 1); } @@ -939,19 +913,26 @@ static ngx_int_t ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data, &r->headers_out.trailers.part, sizeof("sent_trailer_") - 1); } ngx_int_t -ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var, +ngx_http_variable_unknown_header(ngx_http_request_t *r, + ngx_http_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part, size_t prefix) { - u_char ch; + u_char *p, ch; + size_t len; ngx_uint_t i, n; - ngx_table_elt_t *header; + ngx_table_elt_t *header, *h, **ph; + + ph = &h; +#if (NGX_SUPPRESS_WARN) + len = 0; +#endif header = part->elts; @@ -971,7 +952,11 @@ ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var, continue; } - for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) { + if (header[i].key.len != var->len - prefix) { + continue; + } + + for (n = 0; n < var->len - prefix; n++) { ch = header[i].key.data[n]; if (ch >= 'A' && ch <= 'Z') { @@ -986,18 +971,59 @@ ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var, } } - if (n + prefix == var->len && n == header[i].key.len) { - v->len = header[i].value.len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = header[i].value.data; - - return NGX_OK; + if (n != var->len - prefix) { + continue; } + + len += header[i].value.len + 2; + + *ph = &header[i]; + ph = &header[i].next; } - v->not_found = 1; + *ph = NULL; + + if (h == NULL) { + v->not_found = 1; + return NGX_OK; + } + + len -= 2; + + if (h->next == NULL) { + + v->len = h->value.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = h->value.data; + + return NGX_OK; + } + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + for ( ;; ) { + + p = ngx_copy(p, h->value.data, h->value.len); + + if (h->next == NULL) { + break; + } + + *p++ = ','; *p++ = ' '; + + h = h->next; + } return NGX_OK; } @@ -1050,8 +1076,8 @@ ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v, s.len = name->len - (sizeof("cookie_") - 1); s.data = name->data + sizeof("cookie_") - 1; - if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie) - == NGX_DECLINED) + if (ngx_http_parse_multi_header_lines(r, r->headers_in.cookie, &s, &cookie) + == NULL) { v->not_found = 1; return NGX_OK; @@ -1366,6 +1392,39 @@ ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_variable_proxy_protocol_tlv(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *name = (ngx_str_t *) data; + + ngx_int_t rc; + ngx_str_t tlv, value; + + tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1); + tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1; + + rc = ngx_proxy_protocol_get_tlv(r->connection, &tlv, &value); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + v->not_found = 1; + return NGX_OK; + } + + v->len = value.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = value.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) @@ -1879,7 +1938,7 @@ ngx_http_variable_sent_location(ngx_http_request_t *r, ngx_str_set(&name, "sent_http_location"); - return ngx_http_variable_unknown_header(v, &name, + return ngx_http_variable_unknown_header(r, v, &name, &r->headers_out.headers.part, sizeof("sent_http_") - 1); } diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h index f3f7f3c..6a661a2 100644 --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -57,8 +57,9 @@ ngx_http_variable_value_t *ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key); -ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, - ngx_str_t *var, ngx_list_part_t *part, size_t prefix); +ngx_int_t ngx_http_variable_unknown_header(ngx_http_request_t *r, + ngx_http_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part, + size_t prefix); #if (NGX_PCRE) diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 932f26d..89ab49e 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -227,7 +227,8 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) - && !(last && c->need_last_buf)) + && !(last && c->need_last_buf) + && !(flush && c->need_flush_buf)) { if (last || flush || sync) { for (cl = r->out; cl; /* void */) { diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 0e45a7b..ea3f27c 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1730,6 +1730,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, size_t len; ngx_int_t rc; ngx_table_elt_t *h; + ngx_connection_t *fc; ngx_http_header_t *hh; ngx_http_request_t *r; ngx_http_v2_header_t *header; @@ -1789,17 +1790,11 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, } r = h2c->state.stream->request; + fc = r->connection; /* TODO Optimization: validate headers while parsing. */ if (ngx_http_v2_validate_header(r, header) != NGX_OK) { - if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream, - NGX_HTTP_V2_PROTOCOL_ERROR) - == NGX_ERROR) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } - + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); goto error; } @@ -1886,6 +1881,8 @@ error: h2c->state.stream = NULL; + ngx_http_run_posted_requests(fc); + return ngx_http_v2_state_header_complete(h2c, pos, end); } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 70ee287..4e25293 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -153,12 +153,12 @@ struct ngx_http_v2_connection_s { ngx_queue_t dependencies; ngx_queue_t closed; + ngx_uint_t closed_nodes; ngx_uint_t last_sid; ngx_uint_t last_push; time_t lingering_time; - unsigned closed_nodes:8; unsigned settings_ack:1; unsigned table_update:1; unsigned blocked:1; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 9ffb155..5f8626a 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -665,6 +665,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) fc->send_chain = ngx_http_v2_send_chain; fc->need_last_buf = 1; + fc->need_flush_buf = 1; return ngx_http_v2_filter_send(fc, stream); } @@ -673,14 +674,14 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) static ngx_int_t ngx_http_v2_push_resources(ngx_http_request_t *r) { - u_char *start, *end, *last; - ngx_int_t rc; - ngx_str_t path; - ngx_uint_t i, push; - ngx_table_elt_t **h; - ngx_http_v2_loc_conf_t *h2lcf; - ngx_http_complex_value_t *pushes; - ngx_str_t binary[NGX_HTTP_V2_PUSH_HEADERS]; + u_char *start, *end, *last; + ngx_int_t rc; + ngx_str_t path; + ngx_uint_t i, push; + ngx_table_elt_t *h; + ngx_http_v2_loc_conf_t *h2lcf; + ngx_http_complex_value_t *pushes; + ngx_str_t binary[NGX_HTTP_V2_PUSH_HEADERS]; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http2 push resources"); @@ -724,15 +725,13 @@ ngx_http_v2_push_resources(ngx_http_request_t *r) return NGX_OK; } - h = r->headers_out.link.elts; - - for (i = 0; i < r->headers_out.link.nelts; i++) { + for (h = r->headers_out.link; h; h = h->next) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 parse link: \"%V\"", &h[i]->value); + "http2 parse link: \"%V\"", &h->value); - start = h[i]->value.data; - end = h[i]->value.data + h[i]->value.len; + start = h->value.data; + end = h->value.data + h->value.len; next_link: @@ -1815,7 +1814,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, static ngx_inline ngx_int_t ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) { - if (stream->queued == 0) { + ngx_connection_t *c; + + c = stream->connection->connection; + + if (stream->queued == 0 && !c->buffered) { fc->buffered &= ~NGX_HTTP_V2_BUFFERED; return NGX_OK; } diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 115671c..487c5de 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -308,7 +308,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value, size; ngx_url_t u; ngx_uint_t i, n, m; - ngx_mail_listen_t *ls, *als; + ngx_mail_listen_t *ls, *als, *nls; ngx_mail_module_t *module; ngx_mail_core_main_conf_t *cmcf; @@ -333,7 +333,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module); - ls = ngx_array_push_n(&cmcf->listen, u.naddrs); + ls = ngx_array_push(&cmcf->listen); if (ls == NULL) { return NGX_CONF_ERROR; } @@ -568,20 +568,40 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - als = cmcf->listen.elts; - for (n = 0; n < u.naddrs; n++) { - ls[n] = ls[0]; - ls[n].sockaddr = u.addrs[n].sockaddr; - ls[n].socklen = u.addrs[n].socklen; - ls[n].addr_text = u.addrs[n].name; - ls[n].wildcard = ngx_inet_wildcard(ls[n].sockaddr); + for (i = 0; i < n; i++) { + if (ngx_cmp_sockaddr(u.addrs[n].sockaddr, u.addrs[n].socklen, + u.addrs[i].sockaddr, u.addrs[i].socklen, 1) + == NGX_OK) + { + goto next; + } + } - for (i = 0; i < cmcf->listen.nelts - u.naddrs + n; i++) { + if (n != 0) { + nls = ngx_array_push(&cmcf->listen); + if (nls == NULL) { + return NGX_CONF_ERROR; + } + + *nls = *ls; + + } else { + nls = ls; + } + + nls->sockaddr = u.addrs[n].sockaddr; + nls->socklen = u.addrs[n].socklen; + nls->addr_text = u.addrs[n].name; + nls->wildcard = ngx_inet_wildcard(nls->sockaddr); + + als = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts - 1; i++) { if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen, - ls[n].sockaddr, ls[n].socklen, 1) + nls->sockaddr, nls->socklen, 1) != NGX_OK) { continue; @@ -589,9 +609,12 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate \"%V\" address and port pair", - &ls[n].addr_text); + &nls->addr_text); return NGX_CONF_ERROR; } + + next: + continue; } return NGX_CONF_OK; diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index a7ab077..efed9ab 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -327,7 +327,9 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos < s->buffer->last) { + if (s->buffer->pos < s->buffer->last + || s->connection->read->ready) + { ngx_post_event(c->write, &ngx_posted_events); } @@ -486,7 +488,9 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos < s->buffer->last) { + if (s->buffer->pos < s->buffer->last + || s->connection->read->ready) + { ngx_post_event(c->write, &ngx_posted_events); } @@ -821,7 +825,9 @@ 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"); - if (s->buffer->pos < s->buffer->last) { + if (s->buffer->pos < s->buffer->last + || s->connection->read->ready) + { ngx_post_event(c->write, &ngx_posted_events); } @@ -890,7 +896,7 @@ ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s) u_char *p; ssize_t n, size; ngx_connection_t *c; - u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + u_char buf[NGX_PROXY_PROTOCOL_V1_MAX_HEADER]; s->connection->log->action = "sending PROXY protocol header to upstream"; @@ -898,7 +904,7 @@ ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s) "mail proxy send PROXY protocol header"); p = ngx_proxy_protocol_write(s->connection, buf, - buf + NGX_PROXY_PROTOCOL_MAX_HEADER); + buf + NGX_PROXY_PROTOCOL_V1_MAX_HEADER); if (p == NULL) { ngx_mail_proxy_internal_server_error(s); return NGX_ERROR; diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 2a1043e..28737ac 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -360,8 +360,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); @@ -682,7 +683,7 @@ ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) len++; } - if (len == 0) { + if (len == 0 || j == value[i].len) { goto invalid; } diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h index 3036cae..88fef47 100644 --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -103,6 +103,10 @@ typedef struct iocb ngx_aiocb_t; #include #endif +#if (NGX_HAVE_UDP_SEGMENT) +#include +#endif + #define NGX_LISTEN_BACKLOG 511 diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 07cd05e..98d2dd2 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -736,6 +736,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) ngx_set_shutdown_timer(cycle); ngx_close_listening_sockets(cycle); ngx_close_idle_connections(cycle); + ngx_event_process_posted(cycle, &ngx_posted_events); } } @@ -758,7 +759,6 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) ngx_cpuset_t *cpu_affinity; struct rlimit rlmt; ngx_core_conf_t *ccf; - ngx_listening_t *ls; if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ @@ -888,15 +888,6 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) tp = ngx_timeofday(); srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); - /* - * disable deleting previous events for the listening sockets because - * in the worker processes there are no events at all at this point - */ - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { - ls[i].previous = NULL; - } - for (i = 0; cycle->modules[i]; i++) { if (cycle->modules[i]->init_process) { if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) { diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index b1ae4b5..48fa0a7 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -46,6 +46,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) return 0; } else { + rev->ready = 0; return NGX_AGAIN; } } @@ -55,12 +56,15 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) #if (NGX_HAVE_EPOLLRDHUP) - if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ngx_use_epoll_rdhup) + { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "readv: eof:%d, avail:%d", rev->pending_eof, rev->available); if (rev->available == 0 && !rev->pending_eof) { + rev->ready = 0; return NGX_AGAIN; } } diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c index ddfae4d..cc04a5f 100644 --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -52,7 +52,9 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) #if (NGX_HAVE_EPOLLRDHUP) - if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ngx_use_epoll_rdhup) + { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: eof:%d, avail:%d", rev->pending_eof, rev->available); diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c index 3d1d6dd..fa917b5 100644 --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -12,7 +12,7 @@ static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log); -static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec); +static ssize_t ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec); ngx_chain_t * @@ -88,7 +88,7 @@ ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) send += vec.size; - n = ngx_sendmsg(c, &vec); + n = ngx_sendmsg_vec(c, &vec); if (n == NGX_ERROR) { return NGX_CHAIN_ERROR; @@ -204,24 +204,13 @@ ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log) static ssize_t -ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) +ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec) { - ssize_t n; - ngx_err_t err; - struct msghdr msg; - -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - -#if (NGX_HAVE_IP_SENDSRCADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; -#elif (NGX_HAVE_IP_PKTINFO) - u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; -#endif + struct msghdr msg; +#if (NGX_HAVE_ADDRINFO_CMSG) + struct cmsghdr *cmsg; + u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; #endif ngx_memzero(&msg, sizeof(struct msghdr)); @@ -234,88 +223,180 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) msg.msg_iov = vec->iovs; msg.msg_iovlen = vec->count; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - +#if (NGX_HAVE_ADDRINFO_CMSG) if (c->listening && c->listening->wildcard && c->local_sockaddr) { + msg.msg_control = msg_control; + msg.msg_controllen = sizeof(msg_control); + ngx_memzero(msg_control, sizeof(msg_control)); + + cmsg = CMSG_FIRSTHDR(&msg); + + msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr); + } +#endif + + return ngx_sendmsg(c, &msg, 0); +} + + +#if (NGX_HAVE_ADDRINFO_CMSG) + +size_t +ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) +{ + size_t len; +#if (NGX_HAVE_IP_SENDSRCADDR) + struct in_addr *addr; + struct sockaddr_in *sin; +#elif (NGX_HAVE_IP_PKTINFO) + struct in_pktinfo *pkt; + struct sockaddr_in *sin; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; +#endif + + +#if (NGX_HAVE_IP_SENDSRCADDR) || (NGX_HAVE_IP_PKTINFO) + + if (local_sockaddr->sa_family == AF_INET) { + + cmsg->cmsg_level = IPPROTO_IP; + #if (NGX_HAVE_IP_SENDSRCADDR) - if (c->local_sockaddr->sa_family == AF_INET) { - struct cmsghdr *cmsg; - struct in_addr *addr; - struct sockaddr_in *sin; + cmsg->cmsg_type = IP_SENDSRCADDR; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + len = CMSG_SPACE(sizeof(struct in_addr)); - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); + sin = (struct sockaddr_in *) local_sockaddr; - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_SENDSRCADDR; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - - sin = (struct sockaddr_in *) c->local_sockaddr; - - addr = (struct in_addr *) CMSG_DATA(cmsg); - *addr = sin->sin_addr; - } + addr = (struct in_addr *) CMSG_DATA(cmsg); + *addr = sin->sin_addr; #elif (NGX_HAVE_IP_PKTINFO) - if (c->local_sockaddr->sa_family == AF_INET) { - struct cmsghdr *cmsg; - struct in_pktinfo *pkt; - struct sockaddr_in *sin; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + len = CMSG_SPACE(sizeof(struct in_pktinfo)); - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); + sin = (struct sockaddr_in *) local_sockaddr; - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + ngx_memzero(pkt, sizeof(struct in_pktinfo)); + pkt->ipi_spec_dst = sin->sin_addr; - sin = (struct sockaddr_in *) c->local_sockaddr; +#endif + return len; + } - pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); - ngx_memzero(pkt, sizeof(struct in_pktinfo)); - pkt->ipi_spec_dst = sin->sin_addr; - } +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + if (local_sockaddr->sa_family == AF_INET6) { + + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + len = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + sin6 = (struct sockaddr_in6 *) local_sockaddr; + + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + ngx_memzero(pkt6, sizeof(struct in6_pktinfo)); + pkt6->ipi6_addr = sin6->sin6_addr; + + return len; + } +#endif + + return 0; +} + + +ngx_int_t +ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) +{ + +#if (NGX_HAVE_IP_RECVDSTADDR) + struct in_addr *addr; + struct sockaddr_in *sin; +#elif (NGX_HAVE_IP_PKTINFO) + struct in_pktinfo *pkt; + struct sockaddr_in *sin; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; +#endif + + +#if (NGX_HAVE_IP_RECVDSTADDR) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_RECVDSTADDR + && local_sockaddr->sa_family == AF_INET) + { + addr = (struct in_addr *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) local_sockaddr; + sin->sin_addr = *addr; + + return NGX_OK; + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && local_sockaddr->sa_family == AF_INET) + { + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) local_sockaddr; + sin->sin_addr = pkt->ipi_addr; + + return NGX_OK; + } #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - if (c->local_sockaddr->sa_family == AF_INET6) { - struct cmsghdr *cmsg; - struct in6_pktinfo *pkt6; - struct sockaddr_in6 *sin6; + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && local_sockaddr->sa_family == AF_INET6) + { + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + sin6 = (struct sockaddr_in6 *) local_sockaddr; + sin6->sin6_addr = pkt6->ipi6_addr; - msg.msg_control = &msg_control6; - msg.msg_controllen = sizeof(msg_control6); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - - pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); - ngx_memzero(pkt6, sizeof(struct in6_pktinfo)); - pkt6->ipi6_addr = sin6->sin6_addr; - } - -#endif + return NGX_OK; } #endif + return NGX_DECLINED; +} + +#endif + + +ssize_t +ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags) +{ + ssize_t n; + ngx_err_t err; +#if (NGX_DEBUG) + size_t size; + ngx_uint_t i; +#endif + eintr: - n = sendmsg(c->fd, &msg, 0); - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "sendmsg: %z of %uz", n, vec->size); + n = sendmsg(c->fd, msg, flags); if (n == -1) { err = ngx_errno; @@ -338,5 +419,14 @@ eintr: } } +#if (NGX_DEBUG) + for (i = 0, size = 0; i < (size_t) msg->msg_iovlen; i++) { + size += msg->msg_iov[i].iov_len; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendmsg: %z of %uz", n, size); +#endif + return n; } diff --git a/src/os/win32/nginx.ico b/src/os/win32/nginx.ico new file mode 100644 index 0000000000000000000000000000000000000000..70f79db1c631c154f1d5002e0f5fc7139a0358bc GIT binary patch literal 1350 zcma)+ziJ~f5XL`80i|0%KtL|9bQN+C*emZbQl$@RuG{Ud2`K}4i#&qiAbt%&USP{D zmQ21+@~j3wnH z|Av*p*r%x4m7`O=k?!2EM(NI;y_Mc~ABBuiYpmoVw*co9*!C8f0;?j&$UsTVg+oI& zfHNoVM<6HKlLPCf=b0n_Ez-qIKYRZ*j>mN}xi9(6d3zn3qxzW6m-@XgPK9Uuf`3r& zWkvZxncs^RcH`uG>3ETAAokmONyu>{Df1u8&2JkdDcYEVjZM#1QmR$RZtv&aALRRJ z)OrqPMcieeCncHE*h?gSO#Y_MI literal 0 HcmV?d00001 diff --git a/src/os/win32/nginx.rc b/src/os/win32/nginx.rc new file mode 100644 index 0000000..dc8b7ab --- /dev/null +++ b/src/os/win32/nginx.rc @@ -0,0 +1,6 @@ + +// Copyright (C) Igor Sysoev +// Copyright (C) Nginx, Inc. + + +nginx icon discardable "src\\os\\win32\\nginx.ico" diff --git a/src/os/win32/nginx_icon16.xpm b/src/os/win32/nginx_icon16.xpm new file mode 100644 index 0000000..45e4bad --- /dev/null +++ b/src/os/win32/nginx_icon16.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * nginx_xpm[] = { +"16 16 2 2", +/* colors */ +" c none", +"GG c #009900", +/* pixels */ +" ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGG ", +" GGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGG GGGGGGGGGGGGGGGGGG ", +" GGGGGG GGGGGGGGGGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" " +}; diff --git a/src/os/win32/nginx_icon32.xpm b/src/os/win32/nginx_icon32.xpm new file mode 100644 index 0000000..eb26638 --- /dev/null +++ b/src/os/win32/nginx_icon32.xpm @@ -0,0 +1,39 @@ +/* XPM */ +static char * nginx_xpm[] = { +"32 32 2 2", +/* colors */ +" c none", +"GG c #009900", +/* pixels */ +" ", +" ", +" ", +" ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG ", +" GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" ", +" ", +" ", +" " diff --git a/src/os/win32/nginx_icon48.xpm b/src/os/win32/nginx_icon48.xpm new file mode 100644 index 0000000..c25ba0f --- /dev/null +++ b/src/os/win32/nginx_icon48.xpm @@ -0,0 +1,55 @@ +/* XPM */ +static char * nginx_xpm[] = { +"48 48 2 2", +/* colors */ +" c none", +"GG c #009900", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" ", +" ", +" ", +" ", +" ", diff --git a/src/os/win32/ngx_alloc.c b/src/os/win32/ngx_alloc.c new file mode 100644 index 0000000..0c0ef30 --- /dev/null +++ b/src/os/win32/ngx_alloc.c @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +ngx_uint_t ngx_pagesize; +ngx_uint_t ngx_pagesize_shift; +ngx_uint_t ngx_cacheline_size; + + +void *ngx_alloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = malloc(size); + if (p == NULL) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "malloc(%uz) failed", size); + } + + ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size); + + return p; +} + + +void *ngx_calloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = ngx_alloc(size, log); + + if (p) { + ngx_memzero(p, size); + } + + return p; +} diff --git a/src/os/win32/ngx_alloc.h b/src/os/win32/ngx_alloc.h new file mode 100644 index 0000000..5a0fa3f --- /dev/null +++ b/src/os/win32/ngx_alloc.h @@ -0,0 +1,27 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ALLOC_H_INCLUDED_ +#define _NGX_ALLOC_H_INCLUDED_ + + +#include +#include + + +void *ngx_alloc(size_t size, ngx_log_t *log); +void *ngx_calloc(size_t size, ngx_log_t *log); + +#define ngx_free free +#define ngx_memalign(alignment, size, log) ngx_alloc(size, log) + +extern ngx_uint_t ngx_pagesize; +extern ngx_uint_t ngx_pagesize_shift; +extern ngx_uint_t ngx_cacheline_size; + + +#endif /* _NGX_ALLOC_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_atomic.h b/src/os/win32/ngx_atomic.h new file mode 100644 index 0000000..113f561 --- /dev/null +++ b/src/os/win32/ngx_atomic.h @@ -0,0 +1,69 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ATOMIC_H_INCLUDED_ +#define _NGX_ATOMIC_H_INCLUDED_ + + +#include +#include + + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + + +#if defined( __WATCOMC__ ) || defined( __BORLANDC__ ) || defined(__GNUC__) \ + || ( _MSC_VER >= 1300 ) + +/* the new SDK headers */ + +#define ngx_atomic_cmp_set(lock, old, set) \ + ((ngx_atomic_uint_t) InterlockedCompareExchange((long *) lock, set, old) \ + == old) + +#else + +/* the old MS VC6.0SP2 SDK headers */ + +#define ngx_atomic_cmp_set(lock, old, set) \ + (InterlockedCompareExchange((void **) lock, (void *) set, (void *) old) \ + == (void *) old) + +#endif + + +#define ngx_atomic_fetch_add(p, add) InterlockedExchangeAdd((long *) p, add) + + +#define ngx_memory_barrier() + + +#if defined( __BORLANDC__ ) || ( __WATCOMC__ < 1230 ) + +/* + * Borland C++ 5.5 (tasm32) and Open Watcom C prior to 1.3 + * do not understand the "pause" instruction + */ + +#define ngx_cpu_pause() +#else +#define ngx_cpu_pause() __asm { pause } +#endif + + +void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); + +#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1)) +#define ngx_unlock(lock) *(lock) = 0 + + +#endif /* _NGX_ATOMIC_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_dlopen.c b/src/os/win32/ngx_dlopen.c new file mode 100644 index 0000000..804f49d --- /dev/null +++ b/src/os/win32/ngx_dlopen.c @@ -0,0 +1,22 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +char * +ngx_dlerror(void) +{ + u_char *p; + static u_char errstr[NGX_MAX_ERROR_STR]; + + p = ngx_strerror(ngx_errno, errstr, NGX_MAX_ERROR_STR); + *p = '\0'; + + return (char *) errstr; +} diff --git a/src/os/win32/ngx_dlopen.h b/src/os/win32/ngx_dlopen.h new file mode 100644 index 0000000..0d6b405 --- /dev/null +++ b/src/os/win32/ngx_dlopen.h @@ -0,0 +1,32 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_DLOPEN_H_INCLUDED_ +#define _NGX_DLOPEN_H_INCLUDED_ + + +#include +#include + + +#define NGX_HAVE_DLOPEN 1 + + +#define ngx_dlopen(path) LoadLibrary((char *) path) +#define ngx_dlopen_n "LoadLibrary()" + +#define ngx_dlsym(handle, symbol) (void *) GetProcAddress(handle, symbol) +#define ngx_dlsym_n "GetProcAddress()" + +#define ngx_dlclose(handle) (FreeLibrary(handle) ? 0 : -1) +#define ngx_dlclose_n "FreeLibrary()" + + +char *ngx_dlerror(void); + + +#endif /* _NGX_DLOPEN_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_errno.c b/src/os/win32/ngx_errno.c new file mode 100644 index 0000000..966d3de --- /dev/null +++ b/src/os/win32/ngx_errno.c @@ -0,0 +1,60 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +u_char * +ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) +{ + u_int len; + static u_long lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + + if (size == 0) { + return errstr; + } + + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, lang, (char *) errstr, size, NULL); + + if (len == 0 && lang) { + + /* + * Try to use English messages first and fallback to a language, + * based on locale: non-English Windows have no English messages + * at all. This way allows to use English messages at least on + * Windows with MUI. + */ + + lang = 0; + + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, lang, (char *) errstr, size, NULL); + } + + if (len == 0) { + return ngx_snprintf(errstr, size, + "FormatMessage() error:(%d)", GetLastError()); + } + + /* remove ".\r\n\0" */ + while (errstr[len] == '\0' || errstr[len] == CR + || errstr[len] == LF || errstr[len] == '.') + { + --len; + } + + return &errstr[++len]; +} + + +ngx_int_t +ngx_strerror_init(void) +{ + return NGX_OK; +} diff --git a/src/os/win32/ngx_errno.h b/src/os/win32/ngx_errno.h new file mode 100644 index 0000000..255a39d --- /dev/null +++ b/src/os/win32/ngx_errno.h @@ -0,0 +1,71 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ERRNO_H_INCLUDED_ +#define _NGX_ERRNO_H_INCLUDED_ + + +#include +#include + + +typedef DWORD ngx_err_t; + +#define ngx_errno GetLastError() +#define ngx_set_errno(err) SetLastError(err) +#define ngx_socket_errno WSAGetLastError() +#define ngx_set_socket_errno(err) WSASetLastError(err) + +#define NGX_EPERM ERROR_ACCESS_DENIED +#define NGX_ENOENT ERROR_FILE_NOT_FOUND +#define NGX_ENOPATH ERROR_PATH_NOT_FOUND +#define NGX_ENOMEM ERROR_NOT_ENOUGH_MEMORY +#define NGX_EACCES ERROR_ACCESS_DENIED +/* + * there are two EEXIST error codes: + * ERROR_FILE_EXISTS used by CreateFile(CREATE_NEW), + * and ERROR_ALREADY_EXISTS used by CreateDirectory(); + * MoveFile() uses both + */ +#define NGX_EEXIST ERROR_ALREADY_EXISTS +#define NGX_EEXIST_FILE ERROR_FILE_EXISTS +#define NGX_EXDEV ERROR_NOT_SAME_DEVICE +#define NGX_ENOTDIR ERROR_PATH_NOT_FOUND +#define NGX_EISDIR ERROR_CANNOT_MAKE +#define NGX_ENOSPC ERROR_DISK_FULL +#define NGX_EPIPE EPIPE +#define NGX_EAGAIN WSAEWOULDBLOCK +#define NGX_EINPROGRESS WSAEINPROGRESS +#define NGX_ENOPROTOOPT WSAENOPROTOOPT +#define NGX_EOPNOTSUPP WSAEOPNOTSUPP +#define NGX_EADDRINUSE WSAEADDRINUSE +#define NGX_ECONNABORTED WSAECONNABORTED +#define NGX_ECONNRESET WSAECONNRESET +#define NGX_ENOTCONN WSAENOTCONN +#define NGX_ETIMEDOUT WSAETIMEDOUT +#define NGX_ECONNREFUSED WSAECONNREFUSED +#define NGX_ENAMETOOLONG ERROR_BAD_PATHNAME +#define NGX_ENETDOWN WSAENETDOWN +#define NGX_ENETUNREACH WSAENETUNREACH +#define NGX_EHOSTDOWN WSAEHOSTDOWN +#define NGX_EHOSTUNREACH WSAEHOSTUNREACH +#define NGX_ENOMOREFILES ERROR_NO_MORE_FILES +#define NGX_EILSEQ ERROR_NO_UNICODE_TRANSLATION +#define NGX_ELOOP 0 +#define NGX_EBADF WSAEBADF + +#define NGX_EALREADY WSAEALREADY +#define NGX_EINVAL WSAEINVAL +#define NGX_EMFILE WSAEMFILE +#define NGX_ENFILE WSAEMFILE + + +u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size); +ngx_int_t ngx_strerror_init(void); + + +#endif /* _NGX_ERRNO_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_event_log.c b/src/os/win32/ngx_event_log.c new file mode 100644 index 0000000..e11ed1e --- /dev/null +++ b/src/os/win32/ngx_event_log.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#define NGX_MAX_ERROR_STR 2048 + + +void ngx_cdecl +ngx_event_log(ngx_err_t err, const char *fmt, ...) +{ + u_char *p, *last; + long types; + HKEY key; + HANDLE ev; + va_list args; + u_char text[NGX_MAX_ERROR_STR]; + const char *msgarg[9]; + static u_char netmsg[] = "%SystemRoot%\\System32\\netmsg.dll"; + + last = text + NGX_MAX_ERROR_STR; + p = text + GetModuleFileName(NULL, (char *) text, NGX_MAX_ERROR_STR - 50); + + *p++ = ':'; + ngx_linefeed(p); + + va_start(args, fmt); + p = ngx_vslprintf(p, last, fmt, args); + va_end(args); + + if (err) { + p = ngx_log_errno(p, last, err); + } + + if (p > last - NGX_LINEFEED_SIZE - 1) { + p = last - NGX_LINEFEED_SIZE - 1; + } + + ngx_linefeed(p); + + *p = '\0'; + + /* + * we do not log errors here since we use + * Event Log only to log our own logs open errors + */ + + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\nginx", + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &key, NULL) + != 0) + { + return; + } + + if (RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ, + netmsg, sizeof(netmsg) - 1) + != 0) + { + return; + } + + types = EVENTLOG_ERROR_TYPE; + + if (RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, + (u_char *) &types, sizeof(long)) + != 0) + { + return; + } + + RegCloseKey(key); + + ev = RegisterEventSource(NULL, "nginx"); + + msgarg[0] = (char *) text; + msgarg[1] = NULL; + msgarg[2] = NULL; + msgarg[3] = NULL; + msgarg[4] = NULL; + msgarg[5] = NULL; + msgarg[6] = NULL; + msgarg[7] = NULL; + msgarg[8] = NULL; + + /* + * the 3299 event id in netmsg.dll has the generic message format: + * "%1 %2 %3 %4 %5 %6 %7 %8 %9" + */ + + ReportEvent(ev, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, msgarg, NULL); + + DeregisterEventSource(ev); +} diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c new file mode 100644 index 0000000..90644ad --- /dev/null +++ b/src/os/win32/ngx_files.c @@ -0,0 +1,1459 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#define NGX_UTF16_BUFLEN 256 +#define NGX_UTF8_BUFLEN 512 + +static ngx_int_t ngx_win32_check_filename(u_short *u, size_t len, + ngx_uint_t dirname); +static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, + size_t reserved); +static u_char *ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, + size_t *allocated); +uint32_t ngx_utf16_decode(u_short **u, size_t n); + + +/* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */ + +ngx_fd_t +ngx_open_file(u_char *name, u_long mode, u_long create, u_long access) +{ + size_t len; + u_short *u; + ngx_fd_t fd; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return INVALID_HANDLE_VALUE; + } + + fd = INVALID_HANDLE_VALUE; + + if (create == NGX_FILE_OPEN + && ngx_win32_check_filename(u, len, 0) != NGX_OK) + { + goto failed; + } + + fd = CreateFileW(u, mode, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return fd; +} + + +ngx_fd_t +ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access) +{ + size_t len; + u_short *u; + ngx_fd_t fd; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return INVALID_HANDLE_VALUE; + } + + fd = CreateFileW(u, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, + CREATE_NEW, + persistent ? 0: + FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return fd; +} + + +ssize_t +ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +{ + u_long n; + ngx_err_t err; + OVERLAPPED ovlp, *povlp; + + ovlp.Internal = 0; + ovlp.InternalHigh = 0; + ovlp.Offset = (u_long) offset; + ovlp.OffsetHigh = (u_long) (offset >> 32); + ovlp.hEvent = NULL; + + povlp = &ovlp; + + if (ReadFile(file->fd, buf, size, &n, povlp) == 0) { + err = ngx_errno; + + if (err == ERROR_HANDLE_EOF) { + return 0; + } + + ngx_log_error(NGX_LOG_ERR, file->log, err, + "ReadFile() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->offset += n; + + return n; +} + + +ssize_t +ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +{ + u_long n; + OVERLAPPED ovlp, *povlp; + + ovlp.Internal = 0; + ovlp.InternalHigh = 0; + ovlp.Offset = (u_long) offset; + ovlp.OffsetHigh = (u_long) (offset >> 32); + ovlp.hEvent = NULL; + + povlp = &ovlp; + + if (WriteFile(file->fd, buf, size, &n, povlp) == 0) { + ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, + "WriteFile() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + if (n != size) { + ngx_log_error(NGX_LOG_CRIT, file->log, 0, + "WriteFile() \"%s\" has written only %ul of %uz", + file->name.data, n, size); + return NGX_ERROR; + } + + file->offset += n; + + return n; +} + + +ssize_t +ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, + ngx_pool_t *pool) +{ + u_char *buf, *prev; + size_t size; + ssize_t total, n; + + total = 0; + + while (cl) { + buf = cl->buf->pos; + prev = buf; + size = 0; + + /* coalesce the neighbouring bufs */ + + while (cl && prev == cl->buf->pos) { + size += cl->buf->last - cl->buf->pos; + prev = cl->buf->last; + cl = cl->next; + } + + n = ngx_write_file(file, buf, size, offset); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + total += n; + offset += n; + } + + return total; +} + + +ssize_t +ngx_read_fd(ngx_fd_t fd, void *buf, size_t size) +{ + u_long n; + + if (ReadFile(fd, buf, size, &n, NULL) != 0) { + return (size_t) n; + } + + return -1; +} + + +ssize_t +ngx_write_fd(ngx_fd_t fd, void *buf, size_t size) +{ + u_long n; + + if (WriteFile(fd, buf, size, &n, NULL) != 0) { + return (size_t) n; + } + + return -1; +} + + +ssize_t +ngx_write_console(ngx_fd_t fd, void *buf, size_t size) +{ + u_long n; + + (void) CharToOemBuff(buf, buf, size); + + if (WriteFile(fd, buf, size, &n, NULL) != 0) { + return (size_t) n; + } + + return -1; +} + + +ngx_int_t +ngx_delete_file(u_char *name) +{ + long rc; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { + goto failed; + } + + rc = DeleteFileW(u); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + +ngx_int_t +ngx_rename_file(u_char *from, u_char *to) +{ + long rc; + size_t len; + u_short *fu, *tu; + ngx_err_t err; + u_short utf16f[NGX_UTF16_BUFLEN]; + u_short utf16t[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + fu = ngx_utf8_to_utf16(utf16f, from, &len, 0); + + if (fu == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + tu = NULL; + + if (ngx_win32_check_filename(fu, len, 0) != NGX_OK) { + goto failed; + } + + len = NGX_UTF16_BUFLEN; + tu = ngx_utf8_to_utf16(utf16t, to, &len, 0); + + if (tu == NULL) { + goto failed; + } + + if (ngx_win32_check_filename(tu, len, 1) != NGX_OK) { + goto failed; + } + + rc = MoveFileW(fu, tu); + +failed: + + if (fu != utf16f) { + err = ngx_errno; + ngx_free(fu); + ngx_set_errno(err); + } + + if (tu && tu != utf16t) { + err = ngx_errno; + ngx_free(tu); + ngx_set_errno(err); + } + + return rc; +} + + +ngx_err_t +ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) +{ + u_char *name; + ngx_err_t err; + ngx_uint_t collision; + ngx_atomic_uint_t num; + + name = ngx_alloc(to->len + 1 + NGX_ATOMIC_T_LEN + 1 + sizeof("DELETE"), + log); + if (name == NULL) { + return NGX_ENOMEM; + } + + ngx_memcpy(name, to->data, to->len); + + collision = 0; + + /* mutex_lock() (per cache or single ?) */ + + for ( ;; ) { + num = ngx_next_temp_number(collision); + + ngx_sprintf(name + to->len, ".%0muA.DELETE%Z", num); + + if (ngx_rename_file(to->data, name) != NGX_FILE_ERROR) { + break; + } + + err = ngx_errno; + + if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) { + collision = 1; + continue; + } + + ngx_log_error(NGX_LOG_CRIT, log, err, + "MoveFile() \"%s\" to \"%s\" failed", to->data, name); + goto failed; + } + + if (ngx_rename_file(from->data, to->data) == NGX_FILE_ERROR) { + err = ngx_errno; + + } else { + err = 0; + } + + if (ngx_delete_file(name) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + "DeleteFile() \"%s\" failed", name); + } + +failed: + + /* mutex_unlock() */ + + ngx_free(name); + + return err; +} + + +ngx_int_t +ngx_file_info(u_char *file, ngx_file_info_t *sb) +{ + size_t len; + long rc; + u_short *u; + ngx_err_t err; + WIN32_FILE_ATTRIBUTE_DATA fa; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + + u = ngx_utf8_to_utf16(utf16, file, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { + goto failed; + } + + rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa); + + sb->dwFileAttributes = fa.dwFileAttributes; + sb->ftCreationTime = fa.ftCreationTime; + sb->ftLastAccessTime = fa.ftLastAccessTime; + sb->ftLastWriteTime = fa.ftLastWriteTime; + sb->nFileSizeHigh = fa.nFileSizeHigh; + sb->nFileSizeLow = fa.nFileSizeLow; + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + +ngx_int_t +ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) +{ + uint64_t intervals; + FILETIME ft; + + /* 116444736000000000 is commented in src/os/win32/ngx_time.c */ + + intervals = s * 10000000 + 116444736000000000; + + ft.dwLowDateTime = (DWORD) intervals; + ft.dwHighDateTime = (DWORD) (intervals >> 32); + + if (SetFileTime(fd, NULL, NULL, &ft) != 0) { + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_create_file_mapping(ngx_file_mapping_t *fm) +{ + LARGE_INTEGER size; + + fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + + if (fm->fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", fm->name); + return NGX_ERROR; + } + + fm->handle = NULL; + + size.QuadPart = fm->size; + + if (SetFilePointerEx(fm->fd, size, NULL, FILE_BEGIN) == 0) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "SetFilePointerEx(\"%s\", %uz) failed", + fm->name, fm->size); + goto failed; + } + + if (SetEndOfFile(fm->fd) == 0) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "SetEndOfFile() \"%s\" failed", fm->name); + goto failed; + } + + fm->handle = CreateFileMapping(fm->fd, NULL, PAGE_READWRITE, + (u_long) ((off_t) fm->size >> 32), + (u_long) ((off_t) fm->size & 0xffffffff), + NULL); + if (fm->handle == NULL) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "CreateFileMapping(%s, %uz) failed", + fm->name, fm->size); + goto failed; + } + + fm->addr = MapViewOfFile(fm->handle, FILE_MAP_WRITE, 0, 0, 0); + + if (fm->addr != NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "MapViewOfFile(%uz) of file mapping \"%s\" failed", + fm->size, fm->name); + +failed: + + if (fm->handle) { + if (CloseHandle(fm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + "CloseHandle() of file mapping \"%s\" failed", + fm->name); + } + } + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } + + return NGX_ERROR; +} + + +void +ngx_close_file_mapping(ngx_file_mapping_t *fm) +{ + if (UnmapViewOfFile(fm->addr) == 0) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + "UnmapViewOfFile(%p) of file mapping \"%s\" failed", + fm->addr, &fm->name); + } + + if (CloseHandle(fm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + "CloseHandle() of file mapping \"%s\" failed", + &fm->name); + } + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } +} + + +u_char * +ngx_realpath(u_char *path, u_char *resolved) +{ + /* STUB */ + return path; +} + + +size_t +ngx_getcwd(u_char *buf, size_t size) +{ + u_char *p; + size_t n; + u_short utf16[NGX_MAX_PATH]; + + n = GetCurrentDirectoryW(NGX_MAX_PATH, utf16); + + if (n == 0) { + return 0; + } + + if (n > NGX_MAX_PATH) { + ngx_set_errno(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + p = ngx_utf16_to_utf8(buf, utf16, &size, NULL); + + if (p == NULL) { + return 0; + } + + if (p != buf) { + ngx_free(p); + ngx_set_errno(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + return size - 1; +} + + +ngx_int_t +ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) +{ + size_t len; + u_short *u, *p; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN - 2; + u = ngx_utf8_to_utf16(utf16, name->data, &len, 2); + + if (u == NULL) { + return NGX_ERROR; + } + + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { + goto failed; + } + + p = &u[len - 1]; + + *p++ = '/'; + *p++ = '*'; + *p = '\0'; + + dir->dir = FindFirstFileW(u, &dir->finddata); + + if (dir->dir == INVALID_HANDLE_VALUE) { + goto failed; + } + + if (u != utf16) { + ngx_free(u); + } + + dir->valid_info = 1; + dir->ready = 1; + dir->name = NULL; + dir->allocated = 0; + + return NGX_OK; + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_read_dir(ngx_dir_t *dir) +{ + u_char *name; + size_t len, allocated; + + if (dir->ready) { + dir->ready = 0; + goto convert; + } + + if (FindNextFileW(dir->dir, &dir->finddata) != 0) { + dir->type = 1; + goto convert; + } + + return NGX_ERROR; + +convert: + + name = dir->name; + len = dir->allocated; + + name = ngx_utf16_to_utf8(name, dir->finddata.cFileName, &len, &allocated); + + if (name == NULL) { + return NGX_ERROR; + } + + if (name != dir->name) { + + if (dir->name) { + ngx_free(dir->name); + } + + dir->name = name; + dir->allocated = allocated; + } + + dir->namelen = len - 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_close_dir(ngx_dir_t *dir) +{ + if (dir->name) { + ngx_free(dir->name); + } + + if (FindClose(dir->dir) == 0) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_create_dir(u_char *name, ngx_uint_t access) +{ + long rc; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 1) != NGX_OK) { + goto failed; + } + + rc = CreateDirectoryW(u, NULL); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + +ngx_int_t +ngx_delete_dir(u_char *name) +{ + long rc; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { + goto failed; + } + + rc = RemoveDirectoryW(u); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + +ngx_int_t +ngx_open_glob(ngx_glob_t *gl) +{ + u_char *p; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, gl->pattern, &len, 0); + + if (u == NULL) { + return NGX_ERROR; + } + + gl->dir = FindFirstFileW(u, &gl->finddata); + + if (gl->dir == INVALID_HANDLE_VALUE) { + + err = ngx_errno; + + if (u != utf16) { + ngx_free(u); + } + + if ((err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) + && gl->test) + { + gl->no_match = 1; + return NGX_OK; + } + + ngx_set_errno(err); + + return NGX_ERROR; + } + + for (p = gl->pattern; *p; p++) { + if (*p == '/') { + gl->last = p + 1 - gl->pattern; + } + } + + if (u != utf16) { + ngx_free(u); + } + + gl->ready = 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name) +{ + u_char *p; + size_t len; + ngx_err_t err; + u_char utf8[NGX_UTF8_BUFLEN]; + + if (gl->no_match) { + return NGX_DONE; + } + + if (gl->ready) { + gl->ready = 0; + goto convert; + } + + ngx_free(gl->name.data); + gl->name.data = NULL; + + if (FindNextFileW(gl->dir, &gl->finddata) != 0) { + goto convert; + } + + err = ngx_errno; + + if (err == NGX_ENOMOREFILES) { + return NGX_DONE; + } + + ngx_log_error(NGX_LOG_ALERT, gl->log, err, + "FindNextFile(%s) failed", gl->pattern); + + return NGX_ERROR; + +convert: + + len = NGX_UTF8_BUFLEN; + p = ngx_utf16_to_utf8(utf8, gl->finddata.cFileName, &len, NULL); + + if (p == NULL) { + return NGX_ERROR; + } + + gl->name.len = gl->last + len - 1; + + gl->name.data = ngx_alloc(gl->name.len + 1, gl->log); + if (gl->name.data == NULL) { + goto failed; + } + + ngx_memcpy(gl->name.data, gl->pattern, gl->last); + ngx_cpystrn(gl->name.data + gl->last, p, len); + + if (p != utf8) { + ngx_free(p); + } + + *name = gl->name; + + return NGX_OK; + +failed: + + if (p != utf8) { + err = ngx_errno; + ngx_free(p); + ngx_set_errno(err); + } + + return NGX_ERROR; +} + + +void +ngx_close_glob(ngx_glob_t *gl) +{ + if (gl->name.data) { + ngx_free(gl->name.data); + } + + if (gl->dir == INVALID_HANDLE_VALUE) { + return; + } + + if (FindClose(gl->dir) == 0) { + ngx_log_error(NGX_LOG_ALERT, gl->log, ngx_errno, + "FindClose(%s) failed", gl->pattern); + } +} + + +ngx_int_t +ngx_de_info(u_char *name, ngx_dir_t *dir) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_de_link_info(u_char *name, ngx_dir_t *dir) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_read_ahead(ngx_fd_t fd, size_t n) +{ + return ~NGX_FILE_ERROR; +} + + +ngx_int_t +ngx_directio_on(ngx_fd_t fd) +{ + return ~NGX_FILE_ERROR; +} + + +ngx_int_t +ngx_directio_off(ngx_fd_t fd) +{ + return ~NGX_FILE_ERROR; +} + + +size_t +ngx_fs_bsize(u_char *name) +{ + u_long sc, bs, nfree, ncl; + size_t len; + u_short *u; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return 512; + } + + if (GetDiskFreeSpaceW(u, &sc, &bs, &nfree, &ncl) == 0) { + + if (u != utf16) { + ngx_free(u); + } + + return 512; + } + + if (u != utf16) { + ngx_free(u); + } + + return sc * bs; +} + + +off_t +ngx_fs_available(u_char *name) +{ + size_t len; + u_short *u; + ULARGE_INTEGER navail; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_MAX_OFF_T_VALUE; + } + + if (GetDiskFreeSpaceExW(u, &navail, NULL, NULL) == 0) { + + if (u != utf16) { + ngx_free(u); + } + + return NGX_MAX_OFF_T_VALUE; + } + + if (u != utf16) { + ngx_free(u); + } + + return (off_t) navail.QuadPart; +} + + +static ngx_int_t +ngx_win32_check_filename(u_short *u, size_t len, ngx_uint_t dirname) +{ + u_long n; + u_short *lu, *p, *slash, ch; + ngx_err_t err; + enum { + sw_start = 0, + sw_normal, + sw_after_slash, + sw_after_colon, + sw_after_dot + } state; + + /* check for NTFS streams (":"), trailing dots and spaces */ + + lu = NULL; + slash = NULL; + state = sw_start; + +#if (NGX_SUPPRESS_WARN) + ch = 0; +#endif + + for (p = u; *p; p++) { + ch = *p; + + switch (state) { + + case sw_start: + + /* + * skip till first "/" to allow paths starting with drive and + * relative path, like "c:html/" + */ + + if (ch == '/' || ch == '\\') { + state = sw_after_slash; + slash = p; + } + + break; + + case sw_normal: + + if (ch == ':') { + state = sw_after_colon; + break; + } + + if (ch == '.' || ch == ' ') { + state = sw_after_dot; + break; + } + + if (ch == '/' || ch == '\\') { + state = sw_after_slash; + slash = p; + break; + } + + break; + + case sw_after_slash: + + if (ch == '/' || ch == '\\') { + break; + } + + if (ch == '.') { + break; + } + + if (ch == ':') { + state = sw_after_colon; + break; + } + + state = sw_normal; + break; + + case sw_after_colon: + + if (ch == '/' || ch == '\\') { + state = sw_after_slash; + slash = p; + break; + } + + goto invalid; + + case sw_after_dot: + + if (ch == '/' || ch == '\\') { + goto invalid; + } + + if (ch == ':') { + goto invalid; + } + + if (ch == '.' || ch == ' ') { + break; + } + + state = sw_normal; + break; + } + } + + if (state == sw_after_dot) { + goto invalid; + } + + if (dirname && slash) { + ch = *slash; + *slash = '\0'; + len = slash - u + 1; + } + + /* check if long name match */ + + lu = malloc(len * 2); + if (lu == NULL) { + return NGX_ERROR; + } + + n = GetLongPathNameW(u, lu, len); + + if (n == 0) { + + if (dirname && slash && ngx_errno == NGX_ENOENT) { + ngx_set_errno(NGX_ENOPATH); + } + + goto failed; + } + + if (n != len - 1 || _wcsicmp(u, lu) != 0) { + goto invalid; + } + + if (dirname && slash) { + *slash = ch; + } + + ngx_free(lu); + + return NGX_OK; + +invalid: + + ngx_set_errno(NGX_ENOENT); + +failed: + + if (dirname && slash) { + *slash = ch; + } + + if (lu) { + err = ngx_errno; + ngx_free(lu); + ngx_set_errno(err); + } + + return NGX_ERROR; +} + + +static u_short * +ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, size_t reserved) +{ + u_char *p; + u_short *u, *last; + uint32_t n; + + p = utf8; + u = utf16; + last = utf16 + *len; + + while (u < last) { + + if (*p < 0x80) { + *u++ = (u_short) *p; + + if (*p == 0) { + *len = u - utf16; + return utf16; + } + + p++; + + continue; + } + + if (u + 1 == last) { + *len = u - utf16; + break; + } + + n = ngx_utf8_decode(&p, 4); + + if (n > 0x10ffff) { + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n > 0xffff) { + n -= 0x10000; + *u++ = (u_short) (0xd800 + (n >> 10)); + *u++ = (u_short) (0xdc00 + (n & 0x03ff)); + continue; + } + + *u++ = (u_short) n; + } + + /* the given buffer is not enough, allocate a new one */ + + u = malloc(((p - utf8) + ngx_strlen(p) + 1 + reserved) * sizeof(u_short)); + if (u == NULL) { + return NULL; + } + + ngx_memcpy(u, utf16, *len * 2); + + utf16 = u; + u += *len; + + for ( ;; ) { + + if (*p < 0x80) { + *u++ = (u_short) *p; + + if (*p == 0) { + *len = u - utf16; + return utf16; + } + + p++; + + continue; + } + + n = ngx_utf8_decode(&p, 4); + + if (n > 0x10ffff) { + ngx_free(utf16); + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n > 0xffff) { + n -= 0x10000; + *u++ = (u_short) (0xd800 + (n >> 10)); + *u++ = (u_short) (0xdc00 + (n & 0x03ff)); + continue; + } + + *u++ = (u_short) n; + } + + /* unreachable */ +} + + +static u_char * +ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, size_t *allocated) +{ + u_char *p, *last; + u_short *u, *j; + uint32_t n; + + u = utf16; + p = utf8; + last = utf8 + *len; + + while (p < last) { + + if (*u < 0x80) { + *p++ = (u_char) *u; + + if (*u == 0) { + *len = p - utf8; + return utf8; + } + + u++; + + continue; + } + + if (p >= last - 4) { + *len = p - utf8; + break; + } + + n = ngx_utf16_decode(&u, 2); + + if (n > 0x10ffff) { + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n >= 0x10000) { + *p++ = (u_char) (0xf0 + (n >> 18)); + *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + if (n >= 0x0800) { + *p++ = (u_char) (0xe0 + (n >> 12)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + *p++ = (u_char) (0xc0 + (n >> 6)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + } + + /* the given buffer is not enough, allocate a new one */ + + for (j = u; *j; j++) { /* void */ } + + p = malloc((j - utf16) * 4 + 1); + if (p == NULL) { + return NULL; + } + + if (allocated) { + *allocated = (j - utf16) * 4 + 1; + } + + ngx_memcpy(p, utf8, *len); + + utf8 = p; + p += *len; + + for ( ;; ) { + + if (*u < 0x80) { + *p++ = (u_char) *u; + + if (*u == 0) { + *len = p - utf8; + return utf8; + } + + u++; + + continue; + } + + n = ngx_utf16_decode(&u, 2); + + if (n > 0x10ffff) { + ngx_free(utf8); + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n >= 0x10000) { + *p++ = (u_char) (0xf0 + (n >> 18)); + *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + if (n >= 0x0800) { + *p++ = (u_char) (0xe0 + (n >> 12)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + *p++ = (u_char) (0xc0 + (n >> 6)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + } + + /* unreachable */ +} + + +/* + * ngx_utf16_decode() decodes one or two UTF-16 code units + * the return values: + * 0x80 - 0x10ffff valid character + * 0x110000 - 0xfffffffd invalid sequence + * 0xfffffffe incomplete sequence + * 0xffffffff error + */ + +uint32_t +ngx_utf16_decode(u_short **u, size_t n) +{ + uint32_t k, m; + + k = **u; + + if (k < 0xd800 || k > 0xdfff) { + (*u)++; + return k; + } + + if (k > 0xdbff) { + (*u)++; + return 0xffffffff; + } + + if (n < 2) { + return 0xfffffffe; + } + + (*u)++; + + m = *(*u)++; + + if (m < 0xdc00 || m > 0xdfff) { + return 0xffffffff; + + } + + return 0x10000 + ((k - 0xd800) << 10) + (m - 0xdc00); +} diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h new file mode 100644 index 0000000..6e59a6f --- /dev/null +++ b/src/os/win32/ngx_files.h @@ -0,0 +1,271 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_FILES_H_INCLUDED_ +#define _NGX_FILES_H_INCLUDED_ + + +#include +#include + + +typedef HANDLE ngx_fd_t; +typedef BY_HANDLE_FILE_INFORMATION ngx_file_info_t; +typedef uint64_t ngx_file_uniq_t; + + +typedef struct { + u_char *name; + size_t size; + void *addr; + ngx_fd_t fd; + HANDLE handle; + ngx_log_t *log; +} ngx_file_mapping_t; + + +typedef struct { + HANDLE dir; + WIN32_FIND_DATAW finddata; + + u_char *name; + size_t namelen; + size_t allocated; + + unsigned valid_info:1; + unsigned type:1; + unsigned ready:1; +} ngx_dir_t; + + +typedef struct { + HANDLE dir; + WIN32_FIND_DATAW finddata; + + unsigned ready:1; + unsigned test:1; + unsigned no_match:1; + + u_char *pattern; + ngx_str_t name; + size_t last; + ngx_log_t *log; +} ngx_glob_t; + + + +/* INVALID_FILE_ATTRIBUTES is specified but not defined at least in MSVC6SP2 */ +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES 0xffffffff +#endif + +/* INVALID_SET_FILE_POINTER is not defined at least in MSVC6SP2 */ +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER 0xffffffff +#endif + + +#define NGX_INVALID_FILE INVALID_HANDLE_VALUE +#define NGX_FILE_ERROR 0 + + +ngx_fd_t ngx_open_file(u_char *name, u_long mode, u_long create, u_long access); +#define ngx_open_file_n "CreateFile()" + +#define NGX_FILE_RDONLY GENERIC_READ +#define NGX_FILE_WRONLY GENERIC_WRITE +#define NGX_FILE_RDWR GENERIC_READ|GENERIC_WRITE +#define NGX_FILE_APPEND FILE_APPEND_DATA|SYNCHRONIZE +#define NGX_FILE_NONBLOCK 0 + +#define NGX_FILE_CREATE_OR_OPEN OPEN_ALWAYS +#define NGX_FILE_OPEN OPEN_EXISTING +#define NGX_FILE_TRUNCATE CREATE_ALWAYS + +#define NGX_FILE_DEFAULT_ACCESS 0 +#define NGX_FILE_OWNER_ACCESS 0 + + +ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent, + ngx_uint_t access); +#define ngx_open_tempfile_n "CreateFile()" + + +#define ngx_close_file CloseHandle +#define ngx_close_file_n "CloseHandle()" + + +ssize_t ngx_read_fd(ngx_fd_t fd, void *buf, size_t size); +#define ngx_read_fd_n "ReadFile()" + + +ssize_t ngx_write_fd(ngx_fd_t fd, void *buf, size_t size); +#define ngx_write_fd_n "WriteFile()" + + +ssize_t ngx_write_console(ngx_fd_t fd, void *buf, size_t size); + + +#define ngx_linefeed(p) *p++ = CR; *p++ = LF; +#define NGX_LINEFEED_SIZE 2 +#define NGX_LINEFEED CRLF + + +ngx_int_t ngx_delete_file(u_char *name); +#define ngx_delete_file_n "DeleteFile()" + + +ngx_int_t ngx_rename_file(u_char *from, u_char *to); +#define ngx_rename_file_n "MoveFile()" +ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log); + + + +ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s); +#define ngx_set_file_time_n "SetFileTime()" + + +ngx_int_t ngx_file_info(u_char *filename, ngx_file_info_t *fi); +#define ngx_file_info_n "GetFileAttributesEx()" + + +#define ngx_fd_info(fd, fi) GetFileInformationByHandle(fd, fi) +#define ngx_fd_info_n "GetFileInformationByHandle()" + + +#define ngx_link_info(name, fi) ngx_file_info(name, fi) +#define ngx_link_info_n "GetFileAttributesEx()" + + +#define ngx_is_dir(fi) \ + (((fi)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) +#define ngx_is_file(fi) \ + (((fi)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) +#define ngx_is_link(fi) 0 +#define ngx_is_exec(fi) 0 + +#define ngx_file_access(fi) 0 + +#define ngx_file_size(fi) \ + (((off_t) (fi)->nFileSizeHigh << 32) | (fi)->nFileSizeLow) +#define ngx_file_fs_size(fi) ngx_file_size(fi) + +#define ngx_file_uniq(fi) (*(ngx_file_uniq_t *) &(fi)->nFileIndexHigh) + + +/* 116444736000000000 is commented in src/os/win32/ngx_time.c */ + +#define ngx_file_mtime(fi) \ + (time_t) (((((unsigned __int64) (fi)->ftLastWriteTime.dwHighDateTime << 32) \ + | (fi)->ftLastWriteTime.dwLowDateTime) \ + - 116444736000000000) / 10000000) + +ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm); +void ngx_close_file_mapping(ngx_file_mapping_t *fm); + + +u_char *ngx_realpath(u_char *path, u_char *resolved); +#define ngx_realpath_n "" + + +size_t ngx_getcwd(u_char *buf, size_t size); +#define ngx_getcwd_n "GetCurrentDirectory()" + + +#define ngx_path_separator(c) ((c) == '/' || (c) == '\\') + +#define NGX_HAVE_MAX_PATH 1 +#define NGX_MAX_PATH MAX_PATH + + +ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir); +#define ngx_open_dir_n "FindFirstFile()" + + +ngx_int_t ngx_read_dir(ngx_dir_t *dir); +#define ngx_read_dir_n "FindNextFile()" + + +ngx_int_t ngx_close_dir(ngx_dir_t *dir); +#define ngx_close_dir_n "FindClose()" + + +ngx_int_t ngx_create_dir(u_char *name, ngx_uint_t access); +#define ngx_create_dir_n "CreateDirectory()" + + +ngx_int_t ngx_delete_dir(u_char *name); +#define ngx_delete_dir_n "RemoveDirectory()" + + +#define ngx_dir_access(a) (a) + + +#define ngx_de_name(dir) (dir)->name +#define ngx_de_namelen(dir) (dir)->namelen + +ngx_int_t ngx_de_info(u_char *name, ngx_dir_t *dir); +#define ngx_de_info_n "dummy()" + +ngx_int_t ngx_de_link_info(u_char *name, ngx_dir_t *dir); +#define ngx_de_link_info_n "dummy()" + +#define ngx_de_is_dir(dir) \ + (((dir)->finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) +#define ngx_de_is_file(dir) \ + (((dir)->finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) +#define ngx_de_is_link(dir) 0 +#define ngx_de_access(dir) 0 +#define ngx_de_size(dir) \ + (((off_t) (dir)->finddata.nFileSizeHigh << 32) | (dir)->finddata.nFileSizeLow) +#define ngx_de_fs_size(dir) ngx_de_size(dir) + +/* 116444736000000000 is commented in src/os/win32/ngx_time.c */ + +#define ngx_de_mtime(dir) \ + (time_t) (((((unsigned __int64) \ + (dir)->finddata.ftLastWriteTime.dwHighDateTime << 32) \ + | (dir)->finddata.ftLastWriteTime.dwLowDateTime) \ + - 116444736000000000) / 10000000) + + +ngx_int_t ngx_open_glob(ngx_glob_t *gl); +#define ngx_open_glob_n "FindFirstFile()" + +ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name); +void ngx_close_glob(ngx_glob_t *gl); + + +ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset); +#define ngx_read_file_n "ReadFile()" + +ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, + off_t offset); + +ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce, + off_t offset, ngx_pool_t *pool); + +ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n); +#define ngx_read_ahead_n "ngx_read_ahead_n" + +ngx_int_t ngx_directio_on(ngx_fd_t fd); +#define ngx_directio_on_n "ngx_directio_on_n" + +ngx_int_t ngx_directio_off(ngx_fd_t fd); +#define ngx_directio_off_n "ngx_directio_off_n" + +size_t ngx_fs_bsize(u_char *name); +off_t ngx_fs_available(u_char *name); + + +#define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE) +#define ngx_stderr GetStdHandle(STD_ERROR_HANDLE) +#define ngx_set_stderr(fd) SetStdHandle(STD_ERROR_HANDLE, fd) +#define ngx_set_stderr_n "SetStdHandle(STD_ERROR_HANDLE)" + + +#endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_os.h b/src/os/win32/ngx_os.h new file mode 100644 index 0000000..15f5aa0 --- /dev/null +++ b/src/os/win32/ngx_os.h @@ -0,0 +1,68 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_OS_H_INCLUDED_ +#define _NGX_OS_H_INCLUDED_ + + +#include +#include + + +#define NGX_IO_SENDFILE 1 + + +typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size); +typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size); +typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +typedef struct { + ngx_recv_pt recv; + ngx_recv_chain_pt recv_chain; + ngx_recv_pt udp_recv; + ngx_send_pt send; + ngx_send_pt udp_send; + ngx_send_chain_pt udp_send_chain; + ngx_send_chain_pt send_chain; + ngx_uint_t flags; +} ngx_os_io_t; + + +ngx_int_t ngx_os_init(ngx_log_t *log); +void ngx_os_status(ngx_log_t *log); +ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid); + +ssize_t ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_udp_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, + size_t size); +ssize_t ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit); +ssize_t ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size); +ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +ngx_chain_t *ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +void ngx_cdecl ngx_event_log(ngx_err_t err, const char *fmt, ...); + + +extern ngx_os_io_t ngx_os_io; +extern ngx_uint_t ngx_ncpu; +extern ngx_uint_t ngx_max_wsabufs; +extern ngx_int_t ngx_max_sockets; +extern ngx_uint_t ngx_inherited_nonblocking; +extern ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; +extern ngx_uint_t ngx_win32_version; +extern char ngx_unique[]; + + +#endif /* _NGX_OS_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_process.c b/src/os/win32/ngx_process.c new file mode 100644 index 0000000..57b1ae9 --- /dev/null +++ b/src/os/win32/ngx_process.c @@ -0,0 +1,238 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +int ngx_argc; +char **ngx_argv; +char **ngx_os_argv; + +ngx_int_t ngx_last_process; +ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + + +ngx_pid_t +ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn) +{ + u_long rc, n, code; + ngx_int_t s; + ngx_pid_t pid; + ngx_exec_ctx_t ctx; + HANDLE events[2]; + char file[MAX_PATH + 1]; + + if (respawn >= 0) { + s = respawn; + + } else { + for (s = 0; s < ngx_last_process; s++) { + if (ngx_processes[s].handle == NULL) { + break; + } + } + + if (s == NGX_MAX_PROCESSES) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "no more than %d processes can be spawned", + NGX_MAX_PROCESSES); + return NGX_INVALID_PID; + } + } + + n = GetModuleFileName(NULL, file, MAX_PATH); + + if (n == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "GetModuleFileName() failed"); + return NGX_INVALID_PID; + } + + file[n] = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "GetModuleFileName: \"%s\"", file); + + ctx.path = file; + ctx.name = name; + ctx.args = GetCommandLine(); + ctx.argv = NULL; + ctx.envp = NULL; + + pid = ngx_execute(cycle, &ctx); + + if (pid == NGX_INVALID_PID) { + return pid; + } + + ngx_memzero(&ngx_processes[s], sizeof(ngx_process_t)); + + ngx_processes[s].handle = ctx.child; + ngx_processes[s].pid = pid; + ngx_processes[s].name = name; + + ngx_sprintf(ngx_processes[s].term_event, "ngx_%s_term_%P%Z", name, pid); + ngx_sprintf(ngx_processes[s].quit_event, "ngx_%s_quit_%P%Z", name, pid); + ngx_sprintf(ngx_processes[s].reopen_event, "ngx_%s_reopen_%P%Z", + name, pid); + + events[0] = ngx_master_process_event; + events[1] = ctx.child; + + rc = WaitForMultipleObjects(2, events, 0, 5000); + + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "WaitForMultipleObjects: %ul", rc); + + switch (rc) { + + case WAIT_OBJECT_0: + + ngx_processes[s].term = OpenEvent(EVENT_MODIFY_STATE, 0, + (char *) ngx_processes[s].term_event); + if (ngx_processes[s].term == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", + ngx_processes[s].term_event); + goto failed; + } + + ngx_processes[s].quit = OpenEvent(EVENT_MODIFY_STATE, 0, + (char *) ngx_processes[s].quit_event); + if (ngx_processes[s].quit == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", + ngx_processes[s].quit_event); + goto failed; + } + + ngx_processes[s].reopen = OpenEvent(EVENT_MODIFY_STATE, 0, + (char *) ngx_processes[s].reopen_event); + if (ngx_processes[s].reopen == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", + ngx_processes[s].reopen_event); + goto failed; + } + + if (ResetEvent(ngx_master_process_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", + ngx_master_process_event_name); + goto failed; + } + + break; + + case WAIT_OBJECT_0 + 1: + if (GetExitCodeProcess(ctx.child, &code) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "GetExitCodeProcess(%P) failed", pid); + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "%s process %P exited with code %Xl", + name, pid, code); + + goto failed; + + case WAIT_TIMEOUT: + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "the event \"%s\" was not signaled for 5s", + ngx_master_process_event_name); + goto failed; + + case WAIT_FAILED: + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "WaitForSingleObject(\"%s\") failed", + ngx_master_process_event_name); + + goto failed; + } + + if (respawn >= 0) { + return pid; + } + + switch (respawn) { + + case NGX_PROCESS_RESPAWN: + ngx_processes[s].just_spawn = 0; + break; + + case NGX_PROCESS_JUST_RESPAWN: + ngx_processes[s].just_spawn = 1; + break; + } + + if (s == ngx_last_process) { + ngx_last_process++; + } + + return pid; + +failed: + + if (ngx_processes[s].reopen) { + ngx_close_handle(ngx_processes[s].reopen); + } + + if (ngx_processes[s].quit) { + ngx_close_handle(ngx_processes[s].quit); + } + + if (ngx_processes[s].term) { + ngx_close_handle(ngx_processes[s].term); + } + + TerminateProcess(ngx_processes[s].handle, 2); + + if (ngx_processes[s].handle) { + ngx_close_handle(ngx_processes[s].handle); + ngx_processes[s].handle = NULL; + } + + return NGX_INVALID_PID; +} + + +ngx_pid_t +ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ngx_memzero(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + + ngx_memzero(&pi, sizeof(PROCESS_INFORMATION)); + + if (CreateProcess(ctx->path, ctx->args, + NULL, NULL, 0, CREATE_NO_WINDOW, NULL, NULL, &si, &pi) + == 0) + { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno, + "CreateProcess(\"%s\") failed", ngx_argv[0]); + + return 0; + } + + ctx->child = pi.hProcess; + + if (CloseHandle(pi.hThread) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CloseHandle(pi.hThread) failed"); + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, + "start %s process %P", ctx->name, pi.dwProcessId); + + return pi.dwProcessId; +} diff --git a/src/os/win32/ngx_process.h b/src/os/win32/ngx_process.h new file mode 100644 index 0000000..7ec4cd9 --- /dev/null +++ b/src/os/win32/ngx_process.h @@ -0,0 +1,80 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROCESS_H_INCLUDED_ +#define _NGX_PROCESS_H_INCLUDED_ + + +typedef DWORD ngx_pid_t; +#define NGX_INVALID_PID 0 + + +#define ngx_getpid GetCurrentProcessId +#define ngx_getppid() 0 +#define ngx_log_pid ngx_pid + + +#define NGX_PROCESS_SYNC_NAME \ + (sizeof("ngx_cache_manager_mutex_") + NGX_INT32_LEN) + + +typedef uint64_t ngx_cpuset_t; + + +typedef struct { + HANDLE handle; + ngx_pid_t pid; + char *name; + + HANDLE term; + HANDLE quit; + HANDLE reopen; + + u_char term_event[NGX_PROCESS_SYNC_NAME]; + u_char quit_event[NGX_PROCESS_SYNC_NAME]; + u_char reopen_event[NGX_PROCESS_SYNC_NAME]; + + unsigned just_spawn:1; + unsigned exiting:1; +} ngx_process_t; + + +typedef struct { + char *path; + char *name; + char *args; + char *const *argv; + char *const *envp; + HANDLE child; +} ngx_exec_ctx_t; + + +ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn); +ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); + +#define ngx_debug_point() +#define ngx_sched_yield() SwitchToThread() + + +#define NGX_MAX_PROCESSES (MAXIMUM_WAIT_OBJECTS - 4) + +#define NGX_PROCESS_RESPAWN -2 +#define NGX_PROCESS_JUST_RESPAWN -3 + + +extern int ngx_argc; +extern char **ngx_argv; +extern char **ngx_os_argv; + +extern ngx_int_t ngx_last_process; +extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + +extern ngx_pid_t ngx_pid; +extern ngx_pid_t ngx_parent; + + +#endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c new file mode 100644 index 0000000..0c848ef --- /dev/null +++ b/src/os/win32/ngx_process_cycle.c @@ -0,0 +1,1044 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static void ngx_console_init(ngx_cycle_t *cycle); +static int __stdcall ngx_console_handler(u_long type); +static ngx_int_t ngx_create_signal_events(ngx_cycle_t *cycle); +static ngx_int_t ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_reopen_worker_processes(ngx_cycle_t *cycle); +static void ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old); +static void ngx_terminate_worker_processes(ngx_cycle_t *cycle); +static ngx_uint_t ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h); +static void ngx_master_process_exit(ngx_cycle_t *cycle); +static void ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn); +static void ngx_worker_process_exit(ngx_cycle_t *cycle); +static ngx_thread_value_t __stdcall ngx_worker_thread(void *data); +static ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data); +static void ngx_cache_manager_process_handler(void); +static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data); + + +ngx_uint_t ngx_process; +ngx_uint_t ngx_worker; +ngx_pid_t ngx_pid; +ngx_pid_t ngx_parent; + +ngx_uint_t ngx_inherited; +ngx_pid_t ngx_new_binary; + +sig_atomic_t ngx_terminate; +sig_atomic_t ngx_quit; +sig_atomic_t ngx_reopen; +sig_atomic_t ngx_reconfigure; +ngx_uint_t ngx_exiting; + + +HANDLE ngx_master_process_event; +char ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME]; + +static HANDLE ngx_stop_event; +static char ngx_stop_event_name[NGX_PROCESS_SYNC_NAME]; +static HANDLE ngx_quit_event; +static char ngx_quit_event_name[NGX_PROCESS_SYNC_NAME]; +static HANDLE ngx_reopen_event; +static char ngx_reopen_event_name[NGX_PROCESS_SYNC_NAME]; +static HANDLE ngx_reload_event; +static char ngx_reload_event_name[NGX_PROCESS_SYNC_NAME]; + +HANDLE ngx_cache_manager_mutex; +char ngx_cache_manager_mutex_name[NGX_PROCESS_SYNC_NAME]; +HANDLE ngx_cache_manager_event; + + +void +ngx_master_process_cycle(ngx_cycle_t *cycle) +{ + u_long nev, ev, timeout; + ngx_err_t err; + ngx_int_t n; + ngx_msec_t timer; + ngx_uint_t live; + HANDLE events[MAXIMUM_WAIT_OBJECTS]; + + ngx_sprintf((u_char *) ngx_master_process_event_name, + "ngx_master_%s%Z", ngx_unique); + + if (ngx_process == NGX_PROCESS_WORKER) { + ngx_worker_process_cycle(cycle, ngx_master_process_event_name); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master started"); + + ngx_console_init(cycle); + + SetEnvironmentVariable("ngx_unique", ngx_unique); + + ngx_master_process_event = CreateEvent(NULL, 1, 0, + ngx_master_process_event_name); + if (ngx_master_process_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", + ngx_master_process_event_name); + exit(2); + } + + if (ngx_create_signal_events(cycle) != NGX_OK) { + exit(2); + } + + ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, + "ngx_cache_manager_mutex_%s%Z", ngx_unique); + + ngx_cache_manager_mutex = CreateMutex(NULL, 0, + ngx_cache_manager_mutex_name); + if (ngx_cache_manager_mutex == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateMutex(\"%s\") failed", ngx_cache_manager_mutex_name); + exit(2); + } + + + events[0] = ngx_stop_event; + events[1] = ngx_quit_event; + events[2] = ngx_reopen_event; + events[3] = ngx_reload_event; + + ngx_close_listening_sockets(cycle); + + if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) { + exit(2); + } + + timer = 0; + timeout = INFINITE; + + for ( ;; ) { + + nev = 4; + for (n = 0; n < ngx_last_process; n++) { + if (ngx_processes[n].handle) { + events[nev++] = ngx_processes[n].handle; + } + } + + if (timer) { + timeout = timer > ngx_current_msec ? timer - ngx_current_msec : 0; + } + + ev = WaitForMultipleObjects(nev, events, 0, timeout); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "master WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_OBJECT_0) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + + if (ResetEvent(ngx_stop_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", ngx_stop_event_name); + } + + if (timer == 0) { + timer = ngx_current_msec + 5000; + } + + ngx_terminate = 1; + ngx_quit_worker_processes(cycle, 0); + + continue; + } + + if (ev == WAIT_OBJECT_0 + 1) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "shutting down"); + + if (ResetEvent(ngx_quit_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", ngx_quit_event_name); + } + + ngx_quit = 1; + ngx_quit_worker_processes(cycle, 0); + + continue; + } + + if (ev == WAIT_OBJECT_0 + 2) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + + if (ResetEvent(ngx_reopen_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", + ngx_reopen_event_name); + } + + ngx_reopen_files(cycle, -1); + ngx_reopen_worker_processes(cycle); + + continue; + } + + if (ev == WAIT_OBJECT_0 + 3) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); + + if (ResetEvent(ngx_reload_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", + ngx_reload_event_name); + } + + cycle = ngx_init_cycle(cycle); + if (cycle == NULL) { + cycle = (ngx_cycle_t *) ngx_cycle; + continue; + } + + ngx_cycle = cycle; + + ngx_close_listening_sockets(cycle); + + if (ngx_start_worker_processes(cycle, NGX_PROCESS_JUST_RESPAWN)) { + ngx_quit_worker_processes(cycle, 1); + } + + continue; + } + + if (ev > WAIT_OBJECT_0 + 3 && ev < WAIT_OBJECT_0 + nev) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "reap worker"); + + live = ngx_reap_worker(cycle, events[ev]); + + if (!live && (ngx_terminate || ngx_quit)) { + ngx_master_process_exit(cycle); + } + + continue; + } + + if (ev == WAIT_TIMEOUT) { + ngx_terminate_worker_processes(cycle); + + ngx_master_process_exit(cycle); + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "WaitForMultipleObjects() failed"); + + continue; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "WaitForMultipleObjects() returned unexpected value %ul", ev); + } +} + + +static void +ngx_console_init(ngx_cycle_t *cycle) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (ccf->daemon) { + if (FreeConsole() == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "FreeConsole() failed"); + } + + return; + } + + if (SetConsoleCtrlHandler(ngx_console_handler, 1) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetConsoleCtrlHandler() failed"); + } +} + + +static int __stdcall +ngx_console_handler(u_long type) +{ + char *msg; + + switch (type) { + + case CTRL_C_EVENT: + msg = "Ctrl-C pressed, exiting"; + break; + + case CTRL_BREAK_EVENT: + msg = "Ctrl-Break pressed, exiting"; + break; + + case CTRL_CLOSE_EVENT: + msg = "console closing, exiting"; + break; + + case CTRL_LOGOFF_EVENT: + msg = "user logs off, exiting"; + break; + + default: + return 0; + } + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, msg); + + if (ngx_stop_event == NULL) { + return 1; + } + + if (SetEvent(ngx_stop_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "SetEvent(\"%s\") failed", ngx_stop_event_name); + } + + return 1; +} + + +static ngx_int_t +ngx_create_signal_events(ngx_cycle_t *cycle) +{ + ngx_sprintf((u_char *) ngx_stop_event_name, + "Global\\ngx_stop_%s%Z", ngx_unique); + + ngx_stop_event = CreateEvent(NULL, 1, 0, ngx_stop_event_name); + if (ngx_stop_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_stop_event_name); + return NGX_ERROR; + } + + + ngx_sprintf((u_char *) ngx_quit_event_name, + "Global\\ngx_quit_%s%Z", ngx_unique); + + ngx_quit_event = CreateEvent(NULL, 1, 0, ngx_quit_event_name); + if (ngx_quit_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_quit_event_name); + return NGX_ERROR; + } + + + ngx_sprintf((u_char *) ngx_reopen_event_name, + "Global\\ngx_reopen_%s%Z", ngx_unique); + + ngx_reopen_event = CreateEvent(NULL, 1, 0, ngx_reopen_event_name); + if (ngx_reopen_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_reopen_event_name); + return NGX_ERROR; + } + + + ngx_sprintf((u_char *) ngx_reload_event_name, + "Global\\ngx_reload_%s%Z", ngx_unique); + + ngx_reload_event = CreateEvent(NULL, 1, 0, ngx_reload_event_name); + if (ngx_reload_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_reload_event_name); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type) +{ + ngx_int_t n; + ngx_core_conf_t *ccf; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + for (n = 0; n < ccf->worker_processes; n++) { + if (ngx_spawn_process(cycle, "worker", type) == NGX_INVALID_PID) { + break; + } + } + + return n; +} + + +static void +ngx_reopen_worker_processes(ngx_cycle_t *cycle) +{ + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].handle == NULL) { + continue; + } + + if (SetEvent(ngx_processes[n].reopen) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", + ngx_processes[n].reopen_event); + } + } +} + + +static void +ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old) +{ + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "process: %d %P %p e:%d j:%d", + n, + ngx_processes[n].pid, + ngx_processes[n].handle, + ngx_processes[n].exiting, + ngx_processes[n].just_spawn); + + if (old && ngx_processes[n].just_spawn) { + ngx_processes[n].just_spawn = 0; + continue; + } + + if (ngx_processes[n].handle == NULL) { + continue; + } + + if (SetEvent(ngx_processes[n].quit) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", + ngx_processes[n].quit_event); + } + + ngx_processes[n].exiting = 1; + } +} + + +static void +ngx_terminate_worker_processes(ngx_cycle_t *cycle) +{ + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].handle == NULL) { + continue; + } + + if (TerminateProcess(ngx_processes[n].handle, 0) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "TerminateProcess(\"%p\") failed", + ngx_processes[n].handle); + } + + ngx_processes[n].exiting = 1; + + ngx_close_handle(ngx_processes[n].reopen); + ngx_close_handle(ngx_processes[n].quit); + ngx_close_handle(ngx_processes[n].term); + ngx_close_handle(ngx_processes[n].handle); + } +} + + +static ngx_uint_t +ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h) +{ + u_long code; + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].handle != h) { + continue; + } + + if (GetExitCodeProcess(h, &code) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "GetExitCodeProcess(%P) failed", + ngx_processes[n].pid); + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, + "%s process %P exited with code %Xl", + ngx_processes[n].name, ngx_processes[n].pid, code); + + ngx_close_handle(ngx_processes[n].reopen); + ngx_close_handle(ngx_processes[n].quit); + ngx_close_handle(ngx_processes[n].term); + ngx_close_handle(h); + + ngx_processes[n].handle = NULL; + ngx_processes[n].term = NULL; + ngx_processes[n].quit = NULL; + ngx_processes[n].reopen = NULL; + + if (!ngx_processes[n].exiting && !ngx_terminate && !ngx_quit) { + + if (ngx_spawn_process(cycle, ngx_processes[n].name, n) + == NGX_INVALID_PID) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "could not respawn %s", ngx_processes[n].name); + + if (n == ngx_last_process - 1) { + ngx_last_process--; + } + } + } + + goto found; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unknown process handle %p", h); + +found: + + for (n = 0; n < ngx_last_process; n++) { + + ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "process: %d %P %p e:%d j:%d", + n, + ngx_processes[n].pid, + ngx_processes[n].handle, + ngx_processes[n].exiting, + ngx_processes[n].just_spawn); + + if (ngx_processes[n].handle) { + return 1; + } + } + + return 0; +} + + +static void +ngx_master_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + + ngx_delete_pidfile(cycle); + + ngx_close_handle(ngx_cache_manager_mutex); + ngx_close_handle(ngx_stop_event); + ngx_close_handle(ngx_quit_event); + ngx_close_handle(ngx_reopen_event); + ngx_close_handle(ngx_reload_event); + ngx_close_handle(ngx_master_process_event); + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_master) { + cycle->modules[i]->exit_master(cycle); + } + } + + ngx_destroy_pool(cycle->pool); + + exit(0); +} + + +static void +ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn) +{ + char wtevn[NGX_PROCESS_SYNC_NAME]; + char wqevn[NGX_PROCESS_SYNC_NAME]; + char wroevn[NGX_PROCESS_SYNC_NAME]; + HANDLE mev, events[3]; + u_long nev, ev; + ngx_err_t err; + ngx_tid_t wtid, cmtid, cltid; + ngx_log_t *log; + + log = cycle->log; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "worker started"); + + ngx_sprintf((u_char *) wtevn, "ngx_worker_term_%P%Z", ngx_pid); + events[0] = CreateEvent(NULL, 1, 0, wtevn); + if (events[0] == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "CreateEvent(\"%s\") failed", wtevn); + goto failed; + } + + ngx_sprintf((u_char *) wqevn, "ngx_worker_quit_%P%Z", ngx_pid); + events[1] = CreateEvent(NULL, 1, 0, wqevn); + if (events[1] == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "CreateEvent(\"%s\") failed", wqevn); + goto failed; + } + + ngx_sprintf((u_char *) wroevn, "ngx_worker_reopen_%P%Z", ngx_pid); + events[2] = CreateEvent(NULL, 1, 0, wroevn); + if (events[2] == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "CreateEvent(\"%s\") failed", wroevn); + goto failed; + } + + mev = OpenEvent(EVENT_MODIFY_STATE, 0, mevn); + if (mev == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "OpenEvent(\"%s\") failed", mevn); + goto failed; + } + + if (SetEvent(mev) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "SetEvent(\"%s\") failed", mevn); + goto failed; + } + + + ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, + "ngx_cache_manager_mutex_%s%Z", ngx_unique); + + ngx_cache_manager_mutex = OpenMutex(SYNCHRONIZE, 0, + ngx_cache_manager_mutex_name); + if (ngx_cache_manager_mutex == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "OpenMutex(\"%s\") failed", ngx_cache_manager_mutex_name); + goto failed; + } + + ngx_cache_manager_event = CreateEvent(NULL, 1, 0, NULL); + if (ngx_cache_manager_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"ngx_cache_manager_event\") failed"); + goto failed; + } + + + if (ngx_create_thread(&wtid, ngx_worker_thread, NULL, log) != 0) { + goto failed; + } + + if (ngx_create_thread(&cmtid, ngx_cache_manager_thread, NULL, log) != 0) { + goto failed; + } + + if (ngx_create_thread(&cltid, ngx_cache_loader_thread, NULL, log) != 0) { + goto failed; + } + + for ( ;; ) { + ev = WaitForMultipleObjects(3, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "worker WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_OBJECT_0) { + ngx_terminate = 1; + ngx_log_error(NGX_LOG_NOTICE, log, 0, "exiting"); + + if (ResetEvent(events[0]) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "ResetEvent(\"%s\") failed", wtevn); + } + + break; + } + + if (ev == WAIT_OBJECT_0 + 1) { + ngx_quit = 1; + ngx_log_error(NGX_LOG_NOTICE, log, 0, "gracefully shutting down"); + break; + } + + if (ev == WAIT_OBJECT_0 + 2) { + ngx_reopen = 1; + ngx_log_error(NGX_LOG_NOTICE, log, 0, "reopening logs"); + + if (ResetEvent(events[2]) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "ResetEvent(\"%s\") failed", wroevn); + } + + continue; + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "WaitForMultipleObjects() failed"); + + goto failed; + } + } + + /* wait threads */ + + if (SetEvent(ngx_cache_manager_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "SetEvent(\"ngx_cache_manager_event\") failed"); + } + + events[1] = wtid; + events[2] = cmtid; + + nev = 3; + + for ( ;; ) { + ev = WaitForMultipleObjects(nev, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "worker exit WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_OBJECT_0) { + break; + } + + if (ev == WAIT_OBJECT_0 + 1) { + if (nev == 2) { + break; + } + + events[1] = events[2]; + nev = 2; + continue; + } + + if (ev == WAIT_OBJECT_0 + 2) { + nev = 2; + continue; + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "WaitForMultipleObjects() failed"); + break; + } + } + + ngx_close_handle(ngx_cache_manager_event); + ngx_close_handle(events[0]); + ngx_close_handle(events[1]); + ngx_close_handle(events[2]); + ngx_close_handle(mev); + + ngx_worker_process_exit(cycle); + +failed: + + exit(2); +} + + +static ngx_thread_value_t __stdcall +ngx_worker_thread(void *data) +{ + ngx_int_t n; + ngx_time_t *tp; + ngx_cycle_t *cycle; + + tp = ngx_timeofday(); + srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); + + cycle = (ngx_cycle_t *) ngx_cycle; + + for (n = 0; cycle->modules[n]; n++) { + if (cycle->modules[n]->init_process) { + if (cycle->modules[n]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(2); + } + } + } + + while (!ngx_quit) { + + if (ngx_exiting) { + if (ngx_event_no_timers_left() == NGX_OK) { + break; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "worker cycle"); + + ngx_process_events_and_timers(cycle); + + if (ngx_terminate) { + return 0; + } + + if (ngx_quit) { + ngx_quit = 0; + + if (!ngx_exiting) { + ngx_exiting = 1; + ngx_set_shutdown_timer(cycle); + ngx_close_listening_sockets(cycle); + ngx_close_idle_connections(cycle); + ngx_event_process_posted(cycle, &ngx_posted_events); + } + } + + if (ngx_reopen) { + ngx_reopen = 0; + ngx_reopen_files(cycle, -1); + } + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + + return 0; +} + + +static void +ngx_worker_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_connection_t *c; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { + cycle->modules[i]->exit_process(cycle); + } + } + + if (ngx_exiting) { + c = cycle->connections; + for (i = 0; i < cycle->connection_n; i++) { + if (c[i].fd != (ngx_socket_t) -1 + && c[i].read + && !c[i].read->accept + && !c[i].read->channel + && !c[i].read->resolver) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "*%uA open socket #%d left in connection %ui", + c[i].number, c[i].fd, i); + } + } + } + + ngx_destroy_pool(cycle->pool); + + exit(0); +} + + +static ngx_thread_value_t __stdcall +ngx_cache_manager_thread(void *data) +{ + u_long ev; + HANDLE events[2]; + ngx_err_t err; + ngx_cycle_t *cycle; + + cycle = (ngx_cycle_t *) ngx_cycle; + + events[0] = ngx_cache_manager_event; + events[1] = ngx_cache_manager_mutex; + + for ( ;; ) { + ev = WaitForMultipleObjects(2, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "cache manager WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "WaitForMultipleObjects() failed"); + } + + /* + * ev == WAIT_OBJECT_0 + * ev == WAIT_OBJECT_0 + 1 + * ev == WAIT_ABANDONED_0 + 1 + */ + + if (ngx_terminate || ngx_quit || ngx_exiting) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + return 0; + } + + break; + } + + for ( ;; ) { + + if (ngx_terminate || ngx_quit || ngx_exiting) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + break; + } + + ngx_cache_manager_process_handler(); + } + + if (ReleaseMutex(ngx_cache_manager_mutex) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "ReleaseMutex() failed"); + } + + return 0; +} + + +static void +ngx_cache_manager_process_handler(void) +{ + u_long ev; + ngx_uint_t i; + ngx_msec_t next, n; + ngx_path_t **path; + + next = 60 * 60 * 1000; + + path = ngx_cycle->paths.elts; + for (i = 0; i < ngx_cycle->paths.nelts; i++) { + + if (path[i]->manager) { + n = path[i]->manager(path[i]->data); + + next = (n <= next) ? n : next; + + ngx_time_update(); + } + } + + if (next == 0) { + next = 1; + } + + ev = WaitForSingleObject(ngx_cache_manager_event, (u_long) next); + + if (ev != WAIT_TIMEOUT) { + + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "cache manager WaitForSingleObject: %ul", ev); + } +} + + +static ngx_thread_value_t __stdcall +ngx_cache_loader_thread(void *data) +{ + ngx_uint_t i; + ngx_path_t **path; + ngx_cycle_t *cycle; + + ngx_msleep(60000); + + cycle = (ngx_cycle_t *) ngx_cycle; + + path = cycle->paths.elts; + for (i = 0; i < cycle->paths.nelts; i++) { + + if (ngx_terminate || ngx_quit || ngx_exiting) { + break; + } + + if (path[i]->loader) { + path[i]->loader(path[i]->data); + ngx_time_update(); + } + } + + return 0; +} + + +void +ngx_single_process_cycle(ngx_cycle_t *cycle) +{ + ngx_tid_t tid; + + ngx_console_init(cycle); + + if (ngx_create_signal_events(cycle) != NGX_OK) { + exit(2); + } + + if (ngx_create_thread(&tid, ngx_worker_thread, NULL, cycle->log) != 0) { + /* fatal */ + exit(2); + } + + /* STUB */ + WaitForSingleObject(ngx_stop_event, INFINITE); +} + + +ngx_int_t +ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid) +{ + HANDLE ev; + ngx_int_t rc; + char evn[NGX_PROCESS_SYNC_NAME]; + + ngx_sprintf((u_char *) evn, "Global\\ngx_%s_%P%Z", sig, pid); + + ev = OpenEvent(EVENT_MODIFY_STATE, 0, evn); + if (ev == NULL) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", evn); + return 1; + } + + if (SetEvent(ev) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", evn); + rc = 1; + + } else { + rc = 0; + } + + ngx_close_handle(ev); + + return rc; +} + + +void +ngx_close_handle(HANDLE h) +{ + if (CloseHandle(h) == 0) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, + "CloseHandle(%p) failed", h); + } +} diff --git a/src/os/win32/ngx_process_cycle.h b/src/os/win32/ngx_process_cycle.h new file mode 100644 index 0000000..95d2743 --- /dev/null +++ b/src/os/win32/ngx_process_cycle.h @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_ +#define _NGX_PROCESS_CYCLE_H_INCLUDED_ + + +#include +#include + + +#define NGX_PROCESS_SINGLE 0 +#define NGX_PROCESS_MASTER 1 +#define NGX_PROCESS_SIGNALLER 2 +#define NGX_PROCESS_WORKER 3 + + +void ngx_master_process_cycle(ngx_cycle_t *cycle); +void ngx_single_process_cycle(ngx_cycle_t *cycle); +void ngx_close_handle(HANDLE h); + + +extern ngx_uint_t ngx_process; +extern ngx_uint_t ngx_worker; +extern ngx_pid_t ngx_pid; +extern ngx_uint_t ngx_exiting; + +extern sig_atomic_t ngx_quit; +extern sig_atomic_t ngx_terminate; +extern sig_atomic_t ngx_reopen; + +extern ngx_uint_t ngx_inherited; +extern ngx_pid_t ngx_new_binary; + + +extern HANDLE ngx_master_process_event; +extern char ngx_master_process_event_name[]; + + +#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_service.c b/src/os/win32/ngx_service.c new file mode 100644 index 0000000..835d9cf --- /dev/null +++ b/src/os/win32/ngx_service.c @@ -0,0 +1,134 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + + +#define NGX_SERVICE_CONTROL_SHUTDOWN 128 +#define NGX_SERVICE_CONTROL_REOPEN 129 + + +SERVICE_TABLE_ENTRY st[] = { + { "nginx", service_main }, + { NULL, NULL } +}; + + +ngx_int_t +ngx_service(ngx_log_t *log) +{ + /* primary thread */ + + /* StartServiceCtrlDispatcher() should be called within 30 seconds */ + + if (StartServiceCtrlDispatcher(st) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "StartServiceCtrlDispatcher() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +void +service_main(u_int argc, char **argv) +{ + SERVICE_STATUS status; + SERVICE_STATUS_HANDLE service; + + /* thread spawned by SCM */ + + service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx); + if (service == INVALID_HANDLE_VALUE) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "RegisterServiceCtrlHandlerEx() failed"); + return; + } + + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP + |SERVICE_ACCEPT_PARAMCHANGE; + status.dwWin32ExitCode = NO_ERROR; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 1; + status.dwWaitHint = 2000; + + /* SetServiceStatus() should be called within 80 seconds */ + + if (SetServiceStatus(service, &status) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "SetServiceStatus() failed"); + return; + } + + /* init */ + + status.dwCurrentState = SERVICE_RUNNING; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + if (SetServiceStatus(service, &status) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "SetServiceStatus() failed"); + return; + } + + /* call master or worker loop */ + + /* + * master should use event notification and look status + * single should use iocp to get notifications from service handler + */ + +} + + +u_int +service_handler(u_int control, u_int type, void *data, void *ctx) +{ + /* primary thread */ + + switch (control) { + + case SERVICE_CONTROL_INTERROGATE: + status = NGX_IOCP_INTERROGATE; + break; + + case SERVICE_CONTROL_STOP: + status = NGX_IOCP_STOP; + break; + + case SERVICE_CONTROL_PARAMCHANGE: + status = NGX_IOCP_RECONFIGURE; + break; + + case NGX_SERVICE_CONTROL_SHUTDOWN: + status = NGX_IOCP_REOPEN; + break; + + case NGX_SERVICE_CONTROL_REOPEN: + status = NGX_IOCP_REOPEN; + break; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; + } + + if (ngx_single) { + if (PostQueuedCompletionStatus(iocp, ... status, ...) == 0) { + err = ngx_errno; + ngx_log_error(NGX_LOG_ALERT, log, err, + "PostQueuedCompletionStatus() failed"); + return err; + } + + } else { + Event + } + + return NO_ERROR; +} diff --git a/src/os/win32/ngx_shmem.c b/src/os/win32/ngx_shmem.c new file mode 100644 index 0000000..c3ed699 --- /dev/null +++ b/src/os/win32/ngx_shmem.c @@ -0,0 +1,161 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +/* + * Base addresses selected by system for shared memory mappings are likely + * to be different on Windows Vista and later versions due to address space + * layout randomization. This is however incompatible with storing absolute + * addresses within the shared memory. + * + * To make it possible to store absolute addresses we create mappings + * at the same address in all processes by starting mappings at predefined + * addresses. The addresses were selected somewhat randomly in order to + * minimize the probability that some other library doing something similar + * conflicts with us. The addresses are from the following typically free + * blocks: + * + * - 0x10000000 .. 0x70000000 (about 1.5 GB in total) on 32-bit platforms + * - 0x000000007fff0000 .. 0x000007f68e8b0000 (about 8 TB) on 64-bit platforms + * + * Additionally, we allow to change the mapping address once it was detected + * to be different from one originally used. This is needed to support + * reconfiguration. + */ + + +#ifdef _WIN64 +#define NGX_SHMEM_BASE 0x0000047047e00000 +#else +#define NGX_SHMEM_BASE 0x2efe0000 +#endif + + +ngx_uint_t ngx_allocation_granularity; + + +ngx_int_t +ngx_shm_alloc(ngx_shm_t *shm) +{ + u_char *name; + uint64_t size; + static u_char *base = (u_char *) NGX_SHMEM_BASE; + + name = ngx_alloc(shm->name.len + 2 + NGX_INT32_LEN, shm->log); + if (name == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(name, "%V_%s%Z", &shm->name, ngx_unique); + + ngx_set_errno(0); + + size = shm->size; + + shm->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + (u_long) (size >> 32), + (u_long) (size & 0xffffffff), + (char *) name); + + if (shm->handle == NULL) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "CreateFileMapping(%uz, %s) failed", + shm->size, name); + ngx_free(name); + + return NGX_ERROR; + } + + ngx_free(name); + + if (ngx_errno == ERROR_ALREADY_EXISTS) { + shm->exists = 1; + } + + shm->addr = MapViewOfFileEx(shm->handle, FILE_MAP_WRITE, 0, 0, 0, base); + + if (shm->addr != NULL) { + base += ngx_align(size, ngx_allocation_granularity); + return NGX_OK; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, shm->log, ngx_errno, + "MapViewOfFileEx(%uz, %p) of file mapping \"%V\" failed, " + "retry without a base address", + shm->size, base, &shm->name); + + /* + * Order of shared memory zones may be different in the master process + * and worker processes after reconfiguration. As a result, the above + * may fail due to a conflict with a previously created mapping remapped + * to a different address. Additionally, there may be a conflict with + * some other uses of the memory. In this case we retry without a base + * address to let the system assign the address itself. + */ + + shm->addr = MapViewOfFile(shm->handle, FILE_MAP_WRITE, 0, 0, 0); + + if (shm->addr != NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "MapViewOfFile(%uz) of file mapping \"%V\" failed", + shm->size, &shm->name); + + if (CloseHandle(shm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "CloseHandle() of file mapping \"%V\" failed", + &shm->name); + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_shm_remap(ngx_shm_t *shm, u_char *addr) +{ + if (UnmapViewOfFile(shm->addr) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "UnmapViewOfFile(%p) of file mapping \"%V\" failed", + shm->addr, &shm->name); + return NGX_ERROR; + } + + shm->addr = MapViewOfFileEx(shm->handle, FILE_MAP_WRITE, 0, 0, 0, addr); + + if (shm->addr != NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "MapViewOfFileEx(%uz, %p) of file mapping \"%V\" failed", + shm->size, addr, &shm->name); + + return NGX_ERROR; +} + + +void +ngx_shm_free(ngx_shm_t *shm) +{ + if (UnmapViewOfFile(shm->addr) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "UnmapViewOfFile(%p) of file mapping \"%V\" failed", + shm->addr, &shm->name); + } + + if (CloseHandle(shm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "CloseHandle() of file mapping \"%V\" failed", + &shm->name); + } +} diff --git a/src/os/win32/ngx_shmem.h b/src/os/win32/ngx_shmem.h new file mode 100644 index 0000000..ee47429 --- /dev/null +++ b/src/os/win32/ngx_shmem.h @@ -0,0 +1,33 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SHMEM_H_INCLUDED_ +#define _NGX_SHMEM_H_INCLUDED_ + + +#include +#include + + +typedef struct { + u_char *addr; + size_t size; + ngx_str_t name; + HANDLE handle; + ngx_log_t *log; + ngx_uint_t exists; /* unsigned exists:1; */ +} ngx_shm_t; + + +ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); +ngx_int_t ngx_shm_remap(ngx_shm_t *shm, u_char *addr); +void ngx_shm_free(ngx_shm_t *shm); + +extern ngx_uint_t ngx_allocation_granularity; + + +#endif /* _NGX_SHMEM_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_socket.c b/src/os/win32/ngx_socket.c new file mode 100644 index 0000000..b1b4afb --- /dev/null +++ b/src/os/win32/ngx_socket.c @@ -0,0 +1,49 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +int +ngx_nonblocking(ngx_socket_t s) +{ + unsigned long nb = 1; + + return ioctlsocket(s, FIONBIO, &nb); +} + + +int +ngx_blocking(ngx_socket_t s) +{ + unsigned long nb = 0; + + return ioctlsocket(s, FIONBIO, &nb); +} + + +int +ngx_socket_nread(ngx_socket_t s, int *n) +{ + unsigned long nread; + + if (ioctlsocket(s, FIONREAD, &nread) == -1) { + return -1; + } + + *n = nread; + + return 0; +} + + +int +ngx_tcp_push(ngx_socket_t s) +{ + return 0; +} diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h new file mode 100644 index 0000000..ab56bc8 --- /dev/null +++ b/src/os/win32/ngx_socket.h @@ -0,0 +1,253 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SOCKET_H_INCLUDED_ +#define _NGX_SOCKET_H_INCLUDED_ + + +#include +#include + + +#define NGX_WRITE_SHUTDOWN SD_SEND + + +typedef SOCKET ngx_socket_t; +typedef int socklen_t; + + +#define ngx_socket(af, type, proto) \ + WSASocketW(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED) + +#define ngx_socket_n "WSASocketW()" + +int ngx_nonblocking(ngx_socket_t s); +int ngx_blocking(ngx_socket_t s); + +#define ngx_nonblocking_n "ioctlsocket(FIONBIO)" +#define ngx_blocking_n "ioctlsocket(!FIONBIO)" + +int ngx_socket_nread(ngx_socket_t s, int *n); +#define ngx_socket_nread_n "ioctlsocket(FIONREAD)" + +#define ngx_shutdown_socket shutdown +#define ngx_shutdown_socket_n "shutdown()" + +#define ngx_close_socket closesocket +#define ngx_close_socket_n "closesocket()" + + +#ifndef WSAID_ACCEPTEX + +typedef BOOL (PASCAL FAR * LPFN_ACCEPTEX)( + IN SOCKET sListenSocket, + IN SOCKET sAcceptSocket, + IN PVOID lpOutputBuffer, + IN DWORD dwReceiveDataLength, + IN DWORD dwLocalAddressLength, + IN DWORD dwRemoteAddressLength, + OUT LPDWORD lpdwBytesReceived, + IN LPOVERLAPPED lpOverlapped + ); + +#define WSAID_ACCEPTEX \ + {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} + +#endif + + +#ifndef WSAID_GETACCEPTEXSOCKADDRS + +typedef VOID (PASCAL FAR * LPFN_GETACCEPTEXSOCKADDRS)( + IN PVOID lpOutputBuffer, + IN DWORD dwReceiveDataLength, + IN DWORD dwLocalAddressLength, + IN DWORD dwRemoteAddressLength, + OUT struct sockaddr **LocalSockaddr, + OUT LPINT LocalSockaddrLength, + OUT struct sockaddr **RemoteSockaddr, + OUT LPINT RemoteSockaddrLength + ); + +#define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} + +#endif + + +#ifndef WSAID_TRANSMITFILE + +#ifndef TF_DISCONNECT + +#define TF_DISCONNECT 1 +#define TF_REUSE_SOCKET 2 +#define TF_WRITE_BEHIND 4 +#define TF_USE_DEFAULT_WORKER 0 +#define TF_USE_SYSTEM_THREAD 16 +#define TF_USE_KERNEL_APC 32 + +typedef struct _TRANSMIT_FILE_BUFFERS { + LPVOID Head; + DWORD HeadLength; + LPVOID Tail; + DWORD TailLength; +} TRANSMIT_FILE_BUFFERS, *PTRANSMIT_FILE_BUFFERS, FAR *LPTRANSMIT_FILE_BUFFERS; + +#endif + +typedef BOOL (PASCAL FAR * LPFN_TRANSMITFILE)( + IN SOCKET hSocket, + IN HANDLE hFile, + IN DWORD nNumberOfBytesToWrite, + IN DWORD nNumberOfBytesPerSend, + IN LPOVERLAPPED lpOverlapped, + IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + IN DWORD dwReserved + ); + +#define WSAID_TRANSMITFILE \ + {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} + +#endif + + +#ifndef WSAID_TRANSMITPACKETS + +/* OpenWatcom has a swapped TP_ELEMENT_FILE and TP_ELEMENT_MEMORY definition */ + +#ifndef TP_ELEMENT_FILE + +#ifdef _MSC_VER +#pragma warning(disable:4201) /* Nonstandard extension, nameless struct/union */ +#endif + +typedef struct _TRANSMIT_PACKETS_ELEMENT { + ULONG dwElFlags; +#define TP_ELEMENT_MEMORY 1 +#define TP_ELEMENT_FILE 2 +#define TP_ELEMENT_EOP 4 + ULONG cLength; + union { + struct { + LARGE_INTEGER nFileOffset; + HANDLE hFile; + }; + PVOID pBuffer; + }; +} TRANSMIT_PACKETS_ELEMENT, *PTRANSMIT_PACKETS_ELEMENT, + FAR *LPTRANSMIT_PACKETS_ELEMENT; + +#ifdef _MSC_VER +#pragma warning(default:4201) +#endif + +#endif + +typedef BOOL (PASCAL FAR * LPFN_TRANSMITPACKETS) ( + SOCKET hSocket, + TRANSMIT_PACKETS_ELEMENT *lpPacketArray, + DWORD nElementCount, + DWORD nSendSize, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags + ); + +#define WSAID_TRANSMITPACKETS \ + {0xd9689da0,0x1f90,0x11d3,{0x99,0x71,0x00,0xc0,0x4f,0x68,0xc8,0x76}} + +#endif + + +#ifndef WSAID_CONNECTEX + +typedef BOOL (PASCAL FAR * LPFN_CONNECTEX) ( + IN SOCKET s, + IN const struct sockaddr FAR *name, + IN int namelen, + IN PVOID lpSendBuffer OPTIONAL, + IN DWORD dwSendDataLength, + OUT LPDWORD lpdwBytesSent, + IN LPOVERLAPPED lpOverlapped + ); + +#define WSAID_CONNECTEX \ + {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}} + +#endif + + +#ifndef WSAID_DISCONNECTEX + +typedef BOOL (PASCAL FAR * LPFN_DISCONNECTEX) ( + IN SOCKET s, + IN LPOVERLAPPED lpOverlapped, + IN DWORD dwFlags, + IN DWORD dwReserved + ); + +#define WSAID_DISCONNECTEX \ + {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} + +#endif + + +extern LPFN_ACCEPTEX ngx_acceptex; +extern LPFN_GETACCEPTEXSOCKADDRS ngx_getacceptexsockaddrs; +extern LPFN_TRANSMITFILE ngx_transmitfile; +extern LPFN_TRANSMITPACKETS ngx_transmitpackets; +extern LPFN_CONNECTEX ngx_connectex; +extern LPFN_DISCONNECTEX ngx_disconnectex; + + +#if (NGX_HAVE_POLL && !defined POLLIN) + +/* + * WSAPoll() is only available if _WIN32_WINNT >= 0x0600. + * If it is not available during compilation, we try to + * load it dynamically at runtime. + */ + +#define NGX_LOAD_WSAPOLL 1 + +#define POLLRDNORM 0x0100 +#define POLLRDBAND 0x0200 +#define POLLIN (POLLRDNORM | POLLRDBAND) +#define POLLPRI 0x0400 + +#define POLLWRNORM 0x0010 +#define POLLOUT (POLLWRNORM) +#define POLLWRBAND 0x0020 + +#define POLLERR 0x0001 +#define POLLHUP 0x0002 +#define POLLNVAL 0x0004 + +typedef struct pollfd { + + SOCKET fd; + SHORT events; + SHORT revents; + +} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + +typedef int (WSAAPI *ngx_wsapoll_pt)( + LPWSAPOLLFD fdArray, + ULONG fds, + INT timeout + ); + +extern ngx_wsapoll_pt WSAPoll; +extern ngx_uint_t ngx_have_wsapoll; + +#endif + + +int ngx_tcp_push(ngx_socket_t s); +#define ngx_tcp_push_n "tcp_push()" + + +#endif /* _NGX_SOCKET_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_stat.c b/src/os/win32/ngx_stat.c new file mode 100644 index 0000000..51bcd96 --- /dev/null +++ b/src/os/win32/ngx_stat.c @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +int ngx_file_type(char *file, ngx_file_info_t *sb) +{ + sb->dwFileAttributes = GetFileAttributes(file); + + if (sb->dwFileAttributes == INVALID_FILE_ATTRIBUTES) { + return -1; + } + + return 0; +} + +/* +int ngx_stat(char *file, ngx_stat_t *sb) +{ + *sb = GetFileAttributes(file); + + if (*sb == INVALID_FILE_ATTRIBUTES) { + return -1; + } + + return 0; +} +*/ diff --git a/src/os/win32/ngx_thread.c b/src/os/win32/ngx_thread.c new file mode 100644 index 0000000..a13de2d --- /dev/null +++ b/src/os/win32/ngx_thread.c @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +ngx_err_t +ngx_create_thread(ngx_tid_t *tid, + ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log) +{ + u_long id; + ngx_err_t err; + + *tid = CreateThread(NULL, 0, func, arg, 0, &id); + + if (*tid != NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "create thread " NGX_TID_T_FMT, id); + return 0; + } + + err = ngx_errno; + ngx_log_error(NGX_LOG_ALERT, log, err, "CreateThread() failed"); + return err; +} diff --git a/src/os/win32/ngx_thread.h b/src/os/win32/ngx_thread.h new file mode 100644 index 0000000..4012276 --- /dev/null +++ b/src/os/win32/ngx_thread.h @@ -0,0 +1,27 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_THREAD_H_INCLUDED_ +#define _NGX_THREAD_H_INCLUDED_ + + +#include +#include + + +typedef HANDLE ngx_tid_t; +typedef DWORD ngx_thread_value_t; + + +ngx_err_t ngx_create_thread(ngx_tid_t *tid, + ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log); + +#define ngx_log_tid GetCurrentThreadId() +#define NGX_TID_T_FMT "%ud" + + +#endif /* _NGX_THREAD_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_time.c b/src/os/win32/ngx_time.c new file mode 100644 index 0000000..79149b2 --- /dev/null +++ b/src/os/win32/ngx_time.c @@ -0,0 +1,83 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +void +ngx_gettimeofday(struct timeval *tp) +{ + uint64_t intervals; + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + + /* + * A file time is a 64-bit value that represents the number + * of 100-nanosecond intervals that have elapsed since + * January 1, 1601 12:00 A.M. UTC. + * + * Between January 1, 1970 (Epoch) and January 1, 1601 there were + * 134774 days, + * 11644473600 seconds or + * 11644473600,000,000,0 100-nanosecond intervals. + * + * See also MSKB Q167296. + */ + + intervals = ((uint64_t) ft.dwHighDateTime << 32) | ft.dwLowDateTime; + intervals -= 116444736000000000; + + tp->tv_sec = (long) (intervals / 10000000); + tp->tv_usec = (long) ((intervals % 10000000) / 10); +} + + +void +ngx_libc_localtime(time_t s, struct tm *tm) +{ + struct tm *t; + + t = localtime(&s); + *tm = *t; +} + + +void +ngx_libc_gmtime(time_t s, struct tm *tm) +{ + struct tm *t; + + t = gmtime(&s); + *tm = *t; +} + + +ngx_int_t +ngx_gettimezone(void) +{ + u_long n; + TIME_ZONE_INFORMATION tz; + + n = GetTimeZoneInformation(&tz); + + switch (n) { + + case TIME_ZONE_ID_UNKNOWN: + return -tz.Bias; + + case TIME_ZONE_ID_STANDARD: + return -(tz.Bias + tz.StandardBias); + + case TIME_ZONE_ID_DAYLIGHT: + return -(tz.Bias + tz.DaylightBias); + + default: /* TIME_ZONE_ID_INVALID */ + return 0; + } +} diff --git a/src/os/win32/ngx_time.h b/src/os/win32/ngx_time.h new file mode 100644 index 0000000..6c2f806 --- /dev/null +++ b/src/os/win32/ngx_time.h @@ -0,0 +1,51 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_TIME_H_INCLUDED_ +#define _NGX_TIME_H_INCLUDED_ + + +#include +#include + + +typedef ngx_rbtree_key_t ngx_msec_t; +typedef ngx_rbtree_key_int_t ngx_msec_int_t; + +typedef SYSTEMTIME ngx_tm_t; +typedef FILETIME ngx_mtime_t; + +#define ngx_tm_sec wSecond +#define ngx_tm_min wMinute +#define ngx_tm_hour wHour +#define ngx_tm_mday wDay +#define ngx_tm_mon wMonth +#define ngx_tm_year wYear +#define ngx_tm_wday wDayOfWeek + +#define ngx_tm_sec_t u_short +#define ngx_tm_min_t u_short +#define ngx_tm_hour_t u_short +#define ngx_tm_mday_t u_short +#define ngx_tm_mon_t u_short +#define ngx_tm_year_t u_short +#define ngx_tm_wday_t u_short + + +#define ngx_msleep Sleep + +#define NGX_HAVE_GETTIMEZONE 1 + +#define ngx_timezone_update() + +ngx_int_t ngx_gettimezone(void); +void ngx_libc_localtime(time_t s, struct tm *tm); +void ngx_libc_gmtime(time_t s, struct tm *tm); +void ngx_gettimeofday(struct timeval *tp); + + +#endif /* _NGX_TIME_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_udp_wsarecv.c b/src/os/win32/ngx_udp_wsarecv.c new file mode 100644 index 0000000..5424375 --- /dev/null +++ b/src/os/win32/ngx_udp_wsarecv.c @@ -0,0 +1,149 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +ssize_t +ngx_udp_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_event_t *rev; + + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d rc:%d %ul of %z", c->fd, rc, bytes, size); + + rev = c->read; + + if (rc == -1) { + rev->ready = 0; + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() not ready"); + return NGX_AGAIN; + } + + rev->error = 1; + ngx_connection_error(c, err, "WSARecv() failed"); + + return NGX_ERROR; + } + + return bytes; +} + + +ssize_t +ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_event_t *rev; + LPWSAOVERLAPPED ovlp; + + rev = c->read; + + if (!rev->ready) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second wsa post"); + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "rev->complete: %d", rev->complete); + + if (rev->complete) { + rev->complete = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + if (rev->ovlp.error) { + ngx_connection_error(c, rev->ovlp.error, "WSARecv() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d %ul of %z", + c->fd, rev->available, size); + + return rev->available; + } + + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp, + &bytes, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSARecv() or WSAGetOverlappedResult() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d %ul of %z", c->fd, bytes, size); + + return bytes; + } + + ovlp = (LPWSAOVERLAPPED) &rev->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL); + + rev->complete = 0; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d rc:%d %ul of %z", + c->fd, rc, bytes, size); + + if (rc == -1) { + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + rev->active = 1; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() posted"); + return NGX_AGAIN; + } + + rev->error = 1; + ngx_connection_error(c, err, "WSARecv() failed"); + return NGX_ERROR; + } + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port + * then GetQueuedCompletionStatus() would anyway return its status + * despite that WSARecv() was already complete + */ + + rev->active = 1; + return NGX_AGAIN; + } + + rev->active = 0; + + return bytes; +} diff --git a/src/os/win32/ngx_user.c b/src/os/win32/ngx_user.c new file mode 100644 index 0000000..ea6da5a --- /dev/null +++ b/src/os/win32/ngx_user.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#if (NGX_CRYPT) + +ngx_int_t +ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + /* STUB: a plain text password */ + + *encrypted = key; + + return NGX_OK; +} + +#endif /* NGX_CRYPT */ diff --git a/src/os/win32/ngx_user.h b/src/os/win32/ngx_user.h new file mode 100644 index 0000000..61408e4 --- /dev/null +++ b/src/os/win32/ngx_user.h @@ -0,0 +1,25 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_USER_H_INCLUDED_ +#define _NGX_USER_H_INCLUDED_ + + +#include +#include + + +/* STUB */ +#define ngx_uid_t ngx_int_t +#define ngx_gid_t ngx_int_t + + +ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); + + +#endif /* _NGX_USER_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h new file mode 100644 index 0000000..406003a --- /dev/null +++ b/src/os/win32/ngx_win32_config.h @@ -0,0 +1,287 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_WIN32_CONFIG_H_INCLUDED_ +#define _NGX_WIN32_CONFIG_H_INCLUDED_ + + +#undef WIN32 +#define WIN32 0x0400 +#define _WIN32_WINNT 0x0501 + + +#define STRICT +#define WIN32_LEAN_AND_MEAN + +/* enable getenv() and gmtime() in msvc8 */ +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_DEPRECATE + +/* enable gethostbyname() in msvc2015 */ +#if !(NGX_HAVE_INET6) +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +/* + * we need to include explicitly before because + * the warning 4201 is enabled in + */ +#include + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +#include +#include /* ipv6 */ +#include +#include +#include /* offsetof() */ + +#ifdef __MINGW64_VERSION_MAJOR + +/* GCC MinGW-w64 supports _FILE_OFFSET_BITS */ +#define _FILE_OFFSET_BITS 64 + +#elif defined __GNUC__ + +/* GCC MinGW's stdio.h includes sys/types.h */ +#define _OFF_T_ +#define __have_typedef_off_t + +#endif + +#include +#include +#include +#ifdef __GNUC__ +#include +#endif +#include +#include + +#ifdef __WATCOMC__ +#define _TIME_T_DEFINED +typedef long time_t; +/* OpenWatcom defines time_t as "unsigned long" */ +#endif + +#include /* localtime(), strftime() */ + + +#ifdef _MSC_VER + +/* the end of the precompiled headers */ +#pragma hdrstop + +#pragma warning(default:4201) + +/* 'type cast': from function pointer to data pointer */ +#pragma warning(disable:4054) + +/* 'type cast': from data pointer to function pointer */ +#pragma warning(disable:4055) + +/* 'function' : different 'const' qualifiers */ +#pragma warning(disable:4090) + +/* unreferenced formal parameter */ +#pragma warning(disable:4100) + +/* FD_SET() and FD_CLR(): conditional expression is constant */ +#pragma warning(disable:4127) + +/* conversion from 'type1' to 'type2', possible loss of data */ +#pragma warning(disable:4244) + +/* conversion from 'size_t' to 'type', possible loss of data */ +#pragma warning(disable:4267) + +/* array is too small to include a terminating null character */ +#pragma warning(disable:4295) + +/* conversion from 'type1' to 'type2' of greater size */ +#pragma warning(disable:4306) + +#endif + + +#ifdef __WATCOMC__ + +/* symbol 'ngx_rbtree_min' has been defined, but not referenced */ +#pragma disable_message(202) + +#endif + + +#ifdef __BORLANDC__ + +/* the end of the precompiled headers */ +#pragma hdrstop + +/* functions containing (for|while|some if) are not expanded inline */ +#pragma warn -8027 + +/* unreferenced formal parameter */ +#pragma warn -8057 + +/* suspicious pointer arithmetic */ +#pragma warn -8072 + +#endif + + +#include + + +#define ngx_inline __inline +#define ngx_cdecl __cdecl + + +#ifdef _MSC_VER +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +typedef unsigned __int16 uint16_t; +#define ngx_libc_cdecl __cdecl + +#elif defined __BORLANDC__ +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +typedef unsigned __int16 uint16_t; +#define ngx_libc_cdecl __cdecl + +#else /* __WATCOMC__ */ +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short int uint16_t; +#define ngx_libc_cdecl + +#endif + +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#if __BORLANDC__ +typedef int intptr_t; +typedef u_int uintptr_t; +#endif + + +#ifndef __MINGW64_VERSION_MAJOR + +/* Windows defines off_t as long, which is 32-bit */ +typedef __int64 off_t; +#define _OFF_T_DEFINED + +#endif + + +#ifdef __WATCOMC__ + +/* off_t is redefined by sys/types.h used by zlib.h */ +#define __TYPES_H_INCLUDED +typedef int dev_t; +typedef unsigned int ino_t; + +#elif __BORLANDC__ + +/* off_t is redefined by sys/types.h used by zlib.h */ +#define __TYPES_H + +typedef int dev_t; +typedef unsigned int ino_t; + +#endif + + +#ifndef __GNUC__ +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef int ssize_t; +#endif +#endif + + +typedef uint32_t in_addr_t; +typedef u_short in_port_t; +typedef int sig_atomic_t; + + +#ifdef _WIN64 + +#define NGX_PTR_SIZE 8 +#define NGX_SIZE_T_LEN (sizeof("-9223372036854775808") - 1) +#define NGX_MAX_SIZE_T_VALUE 9223372036854775807 +#define NGX_TIME_T_LEN (sizeof("-9223372036854775808") - 1) +#define NGX_TIME_T_SIZE 8 +#define NGX_MAX_TIME_T_VALUE 9223372036854775807 + +#else + +#define NGX_PTR_SIZE 4 +#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1) +#define NGX_MAX_SIZE_T_VALUE 2147483647 +#define NGX_TIME_T_LEN (sizeof("-2147483648") - 1) +#define NGX_TIME_T_SIZE 4 +#define NGX_MAX_TIME_T_VALUE 2147483647 + +#endif + + +#define NGX_OFF_T_LEN (sizeof("-9223372036854775807") - 1) +#define NGX_MAX_OFF_T_VALUE 9223372036854775807 +#define NGX_SIG_ATOMIC_T_SIZE 4 + + +#define NGX_HAVE_LITTLE_ENDIAN 1 +#define NGX_HAVE_NONALIGNED 1 + + +#define NGX_WIN_NT 200000 + + +#define NGX_LISTEN_BACKLOG 511 + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 1 +#endif + +#ifndef NGX_HAVE_CASELESS_FILESYSTEM +#define NGX_HAVE_CASELESS_FILESYSTEM 1 +#endif + +#ifndef NGX_HAVE_WIN32_TRANSMITPACKETS +#define NGX_HAVE_WIN32_TRANSMITPACKETS 1 +#define NGX_HAVE_WIN32_TRANSMITFILE 0 +#endif + +#ifndef NGX_HAVE_WIN32_TRANSMITFILE +#define NGX_HAVE_WIN32_TRANSMITFILE 1 +#endif + +#if (NGX_HAVE_WIN32_TRANSMITPACKETS) || (NGX_HAVE_WIN32_TRANSMITFILE) +#define NGX_HAVE_SENDFILE 1 +#endif + +#ifndef NGX_HAVE_SO_SNDLOWAT +/* setsockopt(SO_SNDLOWAT) returns error WSAENOPROTOOPT */ +#define NGX_HAVE_SO_SNDLOWAT 0 +#endif + +#ifndef NGX_HAVE_FIONREAD +#define NGX_HAVE_FIONREAD 1 +#endif + +#define NGX_HAVE_GETADDRINFO 1 + +#define ngx_random rand +#define ngx_debug_init() + + +#endif /* _NGX_WIN32_CONFIG_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c new file mode 100644 index 0000000..de66a44 --- /dev/null +++ b/src/os/win32/ngx_win32_init.c @@ -0,0 +1,329 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +ngx_uint_t ngx_win32_version; +ngx_uint_t ngx_ncpu; +ngx_uint_t ngx_max_wsabufs; +ngx_int_t ngx_max_sockets; +ngx_uint_t ngx_inherited_nonblocking = 1; +ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; + +char ngx_unique[NGX_INT32_LEN + 1]; + + +ngx_os_io_t ngx_os_io = { + ngx_wsarecv, + ngx_wsarecv_chain, + ngx_udp_wsarecv, + ngx_wsasend, + NULL, + NULL, + ngx_wsasend_chain, + 0 +}; + + +typedef struct { + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; +} ngx_osviex_stub_t; + + +static u_int osviex; +static OSVERSIONINFOEX osvi; + +/* Should these pointers be per protocol ? */ +LPFN_ACCEPTEX ngx_acceptex; +LPFN_GETACCEPTEXSOCKADDRS ngx_getacceptexsockaddrs; +LPFN_TRANSMITFILE ngx_transmitfile; +LPFN_TRANSMITPACKETS ngx_transmitpackets; +LPFN_CONNECTEX ngx_connectex; +LPFN_DISCONNECTEX ngx_disconnectex; + +static GUID ax_guid = WSAID_ACCEPTEX; +static GUID as_guid = WSAID_GETACCEPTEXSOCKADDRS; +static GUID tf_guid = WSAID_TRANSMITFILE; +static GUID tp_guid = WSAID_TRANSMITPACKETS; +static GUID cx_guid = WSAID_CONNECTEX; +static GUID dx_guid = WSAID_DISCONNECTEX; + + +#if (NGX_LOAD_WSAPOLL) +ngx_wsapoll_pt WSAPoll; +ngx_uint_t ngx_have_wsapoll; +#endif + + +ngx_int_t +ngx_os_init(ngx_log_t *log) +{ + DWORD bytes; + SOCKET s; + WSADATA wsd; + ngx_err_t err; + ngx_time_t *tp; + ngx_uint_t n; + SYSTEM_INFO si; + + /* get Windows version */ + + ngx_memzero(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif + + osviex = GetVersionEx((OSVERSIONINFO *) &osvi); + + if (osviex == 0) { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "GetVersionEx() failed"); + return NGX_ERROR; + } + } + +#ifdef _MSC_VER +#pragma warning(default:4996) +#endif + + /* + * Windows 3.1 Win32s 0xxxxx + * + * Windows 95 140000 + * Windows 98 141000 + * Windows ME 149000 + * Windows NT 3.51 235100 + * Windows NT 4.0 240000 + * Windows NT 4.0 SP5 240050 + * Windows 2000 250000 + * Windows XP 250100 + * Windows 2003 250200 + * Windows Vista/2008 260000 + * + * Windows CE x.x 3xxxxx + */ + + ngx_win32_version = osvi.dwPlatformId * 100000 + + osvi.dwMajorVersion * 10000 + + osvi.dwMinorVersion * 100; + + if (osviex) { + ngx_win32_version += osvi.wServicePackMajor * 10 + + osvi.wServicePackMinor; + } + + GetSystemInfo(&si); + ngx_pagesize = si.dwPageSize; + ngx_allocation_granularity = si.dwAllocationGranularity; + ngx_ncpu = si.dwNumberOfProcessors; + ngx_cacheline_size = NGX_CPU_CACHE_LINE; + + for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ } + + /* delete default "C" locale for _wcsicmp() */ + setlocale(LC_ALL, ""); + + + /* init Winsock */ + + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "WSAStartup() failed"); + return NGX_ERROR; + } + + if (ngx_win32_version < NGX_WIN_NT) { + ngx_max_wsabufs = 16; + return NGX_OK; + } + + /* STUB: ngx_uint_t max */ + ngx_max_wsabufs = 1024 * 1024; + + /* + * get AcceptEx(), GetAcceptExSockAddrs(), TransmitFile(), + * TransmitPackets(), ConnectEx(), and DisconnectEx() addresses + */ + + s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (s == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &ax_guid, sizeof(GUID), + &ngx_acceptex, sizeof(LPFN_ACCEPTEX), &bytes, NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_ACCEPTEX) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &as_guid, sizeof(GUID), + &ngx_getacceptexsockaddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS), + &bytes, NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_GETACCEPTEXSOCKADDRS) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tf_guid, sizeof(GUID), + &ngx_transmitfile, sizeof(LPFN_TRANSMITFILE), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_TRANSMITFILE) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tp_guid, sizeof(GUID), + &ngx_transmitpackets, sizeof(LPFN_TRANSMITPACKETS), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_TRANSMITPACKETS) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &cx_guid, sizeof(GUID), + &ngx_connectex, sizeof(LPFN_CONNECTEX), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_CONNECTEX) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &dx_guid, sizeof(GUID), + &ngx_disconnectex, sizeof(LPFN_DISCONNECTEX), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_DISCONNECTEX) failed"); + } + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + +#if (NGX_LOAD_WSAPOLL) + { + HMODULE hmod; + + hmod = GetModuleHandle("ws2_32.dll"); + if (hmod == NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, + "GetModuleHandle(\"ws2_32.dll\") failed"); + goto nopoll; + } + + WSAPoll = (ngx_wsapoll_pt) (void *) GetProcAddress(hmod, "WSAPoll"); + if (WSAPoll == NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, + "GetProcAddress(\"WSAPoll\") failed"); + goto nopoll; + } + + ngx_have_wsapoll = 1; + + } + +nopoll: + +#endif + + if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1) + != 0) + { + ngx_process = NGX_PROCESS_WORKER; + + } else { + err = ngx_errno; + + if (err != ERROR_ENVVAR_NOT_FOUND) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "GetEnvironmentVariable(\"ngx_unique\") failed"); + return NGX_ERROR; + } + + ngx_sprintf((u_char *) ngx_unique, "%P%Z", ngx_pid); + } + + tp = ngx_timeofday(); + srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); + + return NGX_OK; +} + + +void +ngx_os_status(ngx_log_t *log) +{ + ngx_osviex_stub_t *osviex_stub; + + ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD); + + if (osviex) { + + /* + * the MSVC 6.0 SP2 defines wSuiteMask and wProductType + * as WORD wReserved[2] + */ + osviex_stub = (ngx_osviex_stub_t *) &osvi.wServicePackMinor; + + ngx_log_error(NGX_LOG_INFO, log, 0, + "OS: %ui build:%ud, \"%s\", suite:%Xd, type:%ud", + ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion, + osviex_stub->wSuiteMask, osviex_stub->wProductType); + + } else { + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + + /* Win9x build */ + + ngx_log_error(NGX_LOG_INFO, log, 0, + "OS: %ui build:%ud.%ud.%ud, \"%s\"", + ngx_win32_version, + osvi.dwBuildNumber >> 24, + (osvi.dwBuildNumber >> 16) & 0xff, + osvi.dwBuildNumber & 0xffff, + osvi.szCSDVersion); + + } else { + + /* + * VER_PLATFORM_WIN32_NT + * + * we do not currently support VER_PLATFORM_WIN32_CE + * and we do not support VER_PLATFORM_WIN32s at all + */ + + ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ui build:%ud, \"%s\"", + ngx_win32_version, osvi.dwBuildNumber, + osvi.szCSDVersion); + } + } +} diff --git a/src/os/win32/ngx_wsarecv.c b/src/os/win32/ngx_wsarecv.c new file mode 100644 index 0000000..b01405e --- /dev/null +++ b/src/os/win32/ngx_wsarecv.c @@ -0,0 +1,215 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +ssize_t +ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_int_t n; + ngx_event_t *rev; + + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d rc:%d %ul of %z", c->fd, rc, bytes, size); + + rev = c->read; + + if (rc == -1) { + rev->ready = 0; + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() not ready"); + return NGX_AGAIN; + } + + n = ngx_connection_error(c, err, "WSARecv() failed"); + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; + } + +#if (NGX_HAVE_FIONREAD) + + if (rev->available >= 0 && bytes > 0) { + rev->available -= bytes; + + /* + * negative rev->available means some additional bytes + * were received between kernel notification and WSARecv(), + * and therefore ev->ready can be safely reset even for + * edge-triggered event methods + */ + + if (rev->available < 0) { + rev->available = 0; + rev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + + } else if (bytes == size) { + + if (ngx_socket_nread(c->fd, &rev->available) == -1) { + n = ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + + if (n == NGX_ERROR) { + rev->ready = 0; + rev->error = 1; + } + + return n; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + } + +#endif + + if (bytes < size) { + rev->ready = 0; + } + + if (bytes == 0) { + rev->ready = 0; + rev->eof = 1; + } + + return bytes; +} + + +ssize_t +ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_int_t n; + ngx_event_t *rev; + LPWSAOVERLAPPED ovlp; + + rev = c->read; + + if (!rev->ready) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second wsa post"); + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "rev->complete: %d", rev->complete); + + if (rev->complete) { + rev->complete = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + if (rev->ovlp.error) { + ngx_connection_error(c, rev->ovlp.error, "WSARecv() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d %ul of %z", + c->fd, rev->available, size); + + return rev->available; + } + + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp, + &bytes, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSARecv() or WSAGetOverlappedResult() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d %ul of %z", c->fd, bytes, size); + + return bytes; + } + + ovlp = (LPWSAOVERLAPPED) &rev->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL); + + rev->complete = 0; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d rc:%d %ul of %z", + c->fd, rc, bytes, size); + + if (rc == -1) { + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + rev->active = 1; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() posted"); + return NGX_AGAIN; + } + + n = ngx_connection_error(c, err, "WSARecv() failed"); + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; + } + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port + * then GetQueuedCompletionStatus() would anyway return its status + * despite that WSARecv() was already complete + */ + + rev->active = 1; + return NGX_AGAIN; + } + + if (bytes == 0) { + rev->eof = 1; + rev->ready = 0; + + } else { + rev->ready = 1; + } + + rev->active = 0; + + return bytes; +} diff --git a/src/os/win32/ngx_wsarecv_chain.c b/src/os/win32/ngx_wsarecv_chain.c new file mode 100644 index 0000000..e60389b --- /dev/null +++ b/src/os/win32/ngx_wsarecv_chain.c @@ -0,0 +1,147 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_WSABUFS 64 + + +ssize_t +ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) +{ + int rc; + u_char *prev; + u_long bytes, flags; + size_t n, size; + ngx_err_t err; + ngx_array_t vec; + ngx_event_t *rev; + LPWSABUF wsabuf; + WSABUF wsabufs[NGX_WSABUFS]; + + prev = NULL; + wsabuf = NULL; + flags = 0; + size = 0; + bytes = 0; + + vec.elts = wsabufs; + vec.nelts = 0; + vec.size = sizeof(WSABUF); + vec.nalloc = NGX_WSABUFS; + vec.pool = c->pool; + + /* coalesce the neighbouring bufs */ + + while (chain) { + n = chain->buf->end - chain->buf->last; + + if (limit) { + if (size >= (size_t) limit) { + break; + } + + if (size + n > (size_t) limit) { + n = (size_t) limit - size; + } + } + + if (prev == chain->buf->last) { + wsabuf->len += n; + + } else { + if (vec.nelts == vec.nalloc) { + break; + } + + wsabuf = ngx_array_push(&vec); + if (wsabuf == NULL) { + return NGX_ERROR; + } + + wsabuf->buf = (char *) chain->buf->last; + wsabuf->len = n; + } + + size += n; + prev = chain->buf->end; + chain = chain->next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: %d:%d", vec.nelts, wsabuf->len); + + + rc = WSARecv(c->fd, vec.elts, vec.nelts, &bytes, &flags, NULL, NULL); + + rev = c->read; + + if (rc == -1) { + rev->ready = 0; + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() not ready"); + return NGX_AGAIN; + } + + rev->error = 1; + ngx_connection_error(c, err, "WSARecv() failed"); + return NGX_ERROR; + } + +#if (NGX_HAVE_FIONREAD) + + if (rev->available >= 0 && bytes > 0) { + rev->available -= bytes; + + /* + * negative rev->available means some additional bytes + * were received between kernel notification and WSARecv(), + * and therefore ev->ready can be safely reset even for + * edge-triggered event methods + */ + + if (rev->available < 0) { + rev->available = 0; + rev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + + } else if (bytes == size) { + + if (ngx_socket_nread(c->fd, &rev->available) == -1) { + rev->ready = 0; + rev->error = 1; + ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + } + +#endif + + if (bytes < size) { + rev->ready = 0; + } + + if (bytes == 0) { + rev->ready = 0; + rev->eof = 1; + } + + return bytes; +} diff --git a/src/os/win32/ngx_wsasend.c b/src/os/win32/ngx_wsasend.c new file mode 100644 index 0000000..d6a23d1 --- /dev/null +++ b/src/os/win32/ngx_wsasend.c @@ -0,0 +1,185 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +ssize_t +ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n; + u_long sent; + ngx_err_t err; + ngx_event_t *wev; + WSABUF wsabuf; + + wev = c->write; + + if (!wev->ready) { + return NGX_AGAIN; + } + + /* + * WSABUF must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + wsabuf.buf = (char *) buf; + wsabuf.len = size; + + sent = 0; + + n = WSASend(c->fd, &wsabuf, 1, &sent, 0, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size); + + if (n == 0) { + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; + } + + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "WSASend() not ready"); + wev->ready = 0; + return NGX_AGAIN; + } + + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + + return NGX_ERROR; +} + + +ssize_t +ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n; + u_long sent; + ngx_err_t err; + ngx_event_t *wev; + LPWSAOVERLAPPED ovlp; + WSABUF wsabuf; + + wev = c->write; + + if (!wev->ready) { + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "wev->complete: %d", wev->complete); + + if (!wev->complete) { + + /* post the overlapped WSASend() */ + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + wsabuf.buf = (char *) buf; + wsabuf.len = size; + + sent = 0; + + ovlp = (LPWSAOVERLAPPED) &c->write->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + n = WSASend(c->fd, &wsabuf, 1, &sent, 0, ovlp, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size); + + wev->complete = 0; + + if (n == 0) { + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port then + * GetQueuedCompletionStatus() would anyway return its status + * despite that WSASend() was already complete + */ + + wev->active = 1; + return NGX_AGAIN; + } + + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; + } + + err = ngx_socket_errno; + + if (err == WSA_IO_PENDING) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() posted"); + wev->active = 1; + return NGX_AGAIN; + } + + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + + return NGX_ERROR; + } + + /* the overlapped WSASend() complete */ + + wev->complete = 0; + wev->active = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + if (wev->ovlp.error) { + ngx_connection_error(c, wev->ovlp.error, "WSASend() failed"); + return NGX_ERROR; + } + + sent = wev->available; + + } else { + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp, + &sent, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSASend() or WSAGetOverlappedResult() failed"); + + return NGX_ERROR; + } + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSAGetOverlappedResult: fd:%d, %ul of %uz", + c->fd, sent, size); + + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; +} diff --git a/src/os/win32/ngx_wsasend_chain.c b/src/os/win32/ngx_wsasend_chain.c new file mode 100644 index 0000000..cd50e71 --- /dev/null +++ b/src/os/win32/ngx_wsasend_chain.c @@ -0,0 +1,296 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_WSABUFS 64 + + +ngx_chain_t * +ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int rc; + u_char *prev; + u_long size, sent, send, prev_send; + ngx_err_t err; + ngx_event_t *wev; + ngx_array_t vec; + ngx_chain_t *cl; + LPWSABUF wsabuf; + WSABUF wsabufs[NGX_WSABUFS]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + /* the maximum limit size is the maximum u_long value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize)) { + limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; + } + + send = 0; + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + vec.elts = wsabufs; + vec.size = sizeof(WSABUF); + vec.nalloc = ngx_min(NGX_WSABUFS, ngx_max_wsabufs); + vec.pool = c->pool; + + for ( ;; ) { + prev = NULL; + wsabuf = NULL; + prev_send = send; + + vec.nelts = 0; + + /* create the WSABUF and coalesce the neighbouring bufs */ + + for (cl = in; cl && send < limit; cl = cl->next) { + + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = (u_long) (limit - send); + } + + if (prev == cl->buf->pos) { + wsabuf->len += cl->buf->last - cl->buf->pos; + + } else { + if (vec.nelts == vec.nalloc) { + break; + } + + wsabuf = ngx_array_push(&vec); + if (wsabuf == NULL) { + return NGX_CHAIN_ERROR; + } + + wsabuf->buf = (char *) cl->buf->pos; + wsabuf->len = cl->buf->last - cl->buf->pos; + } + + prev = cl->buf->last; + send += size; + } + + sent = 0; + + rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, NULL, NULL); + + if (rc == -1) { + err = ngx_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() not ready"); + + } else { + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, s:%ul", c->fd, sent); + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (send - prev_send != sent) { + wev->ready = 0; + return in; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} + + +ngx_chain_t * +ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int rc; + u_char *prev; + u_long size, send, sent; + ngx_err_t err; + ngx_event_t *wev; + ngx_array_t vec; + ngx_chain_t *cl; + LPWSAOVERLAPPED ovlp; + LPWSABUF wsabuf; + WSABUF wsabufs[NGX_WSABUFS]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "wev->complete: %d", wev->complete); + + if (!wev->complete) { + + /* post the overlapped WSASend() */ + + /* the maximum limit size is the maximum u_long value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize)) + { + limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; + } + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + vec.elts = wsabufs; + vec.nelts = 0; + vec.size = sizeof(WSABUF); + vec.nalloc = ngx_min(NGX_WSABUFS, ngx_max_wsabufs); + vec.pool = c->pool; + + send = 0; + prev = NULL; + wsabuf = NULL; + + /* create the WSABUF and coalesce the neighbouring bufs */ + + for (cl = in; cl && send < limit; cl = cl->next) { + + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = (u_long) (limit - send); + } + + if (prev == cl->buf->pos) { + wsabuf->len += cl->buf->last - cl->buf->pos; + + } else { + if (vec.nelts == vec.nalloc) { + break; + } + + wsabuf = ngx_array_push(&vec); + if (wsabuf == NULL) { + return NGX_CHAIN_ERROR; + } + + wsabuf->buf = (char *) cl->buf->pos; + wsabuf->len = cl->buf->last - cl->buf->pos; + } + + prev = cl->buf->last; + send += size; + } + + ovlp = (LPWSAOVERLAPPED) &c->write->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, ovlp, NULL); + + wev->complete = 0; + + if (rc == -1) { + err = ngx_errno; + + if (err == WSA_IO_PENDING) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() posted"); + wev->active = 1; + return in; + + } else { + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + + } else if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port then + * GetQueuedCompletionStatus() would anyway return its status + * despite that WSASend() was already complete + */ + + wev->active = 1; + return in; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, s:%ul", c->fd, sent); + + } else { + + /* the overlapped WSASend() complete */ + + wev->complete = 0; + wev->active = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + if (wev->ovlp.error) { + ngx_connection_error(c, wev->ovlp.error, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + + sent = wev->available; + + } else { + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp, + &sent, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSASend() or WSAGetOverlappedResult() failed"); + + return NGX_CHAIN_ERROR; + } + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend ovlp: fd:%d, s:%ul", c->fd, sent); + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (in) { + wev->ready = 0; + + } else { + wev->ready = 1; + } + + return in; +} diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index d96d27a..f0b7934 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -578,7 +578,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value, size; ngx_url_t u; ngx_uint_t i, n, backlog; - ngx_stream_listen_t *ls, *als; + ngx_stream_listen_t *ls, *als, *nls; ngx_stream_core_main_conf_t *cmcf; cscf->listen = 1; @@ -602,7 +602,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - ls = ngx_array_push_n(&cmcf->listen, u.naddrs); + ls = ngx_array_push(&cmcf->listen); if (ls == NULL) { return NGX_CONF_ERROR; } @@ -886,23 +886,43 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } - als = cmcf->listen.elts; - for (n = 0; n < u.naddrs; n++) { - ls[n] = ls[0]; - ls[n].sockaddr = u.addrs[n].sockaddr; - ls[n].socklen = u.addrs[n].socklen; - ls[n].addr_text = u.addrs[n].name; - ls[n].wildcard = ngx_inet_wildcard(ls[n].sockaddr); + for (i = 0; i < n; i++) { + if (ngx_cmp_sockaddr(u.addrs[n].sockaddr, u.addrs[n].socklen, + u.addrs[i].sockaddr, u.addrs[i].socklen, 1) + == NGX_OK) + { + goto next; + } + } - for (i = 0; i < cmcf->listen.nelts - u.naddrs + n; i++) { - if (ls[n].type != als[i].type) { + if (n != 0) { + nls = ngx_array_push(&cmcf->listen); + if (nls == NULL) { + return NGX_CONF_ERROR; + } + + *nls = *ls; + + } else { + nls = ls; + } + + nls->sockaddr = u.addrs[n].sockaddr; + nls->socklen = u.addrs[n].socklen; + nls->addr_text = u.addrs[n].name; + nls->wildcard = ngx_inet_wildcard(nls->sockaddr); + + als = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts - 1; i++) { + if (nls->type != als[i].type) { continue; } if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen, - ls[n].sockaddr, ls[n].socklen, 1) + nls->sockaddr, nls->socklen, 1) != NGX_OK) { continue; @@ -910,9 +930,12 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate \"%V\" address and port pair", - &ls[n].addr_text); + &nls->addr_text); return NGX_CONF_ERROR; } + + next: + continue; } return NGX_CONF_OK; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 934e7d8..ed275c0 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -103,6 +103,8 @@ static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_merge_ssl(ngx_conf_t *cf, + ngx_stream_proxy_srv_conf_t *conf, ngx_stream_proxy_srv_conf_t *prev); static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); @@ -801,7 +803,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) #if (NGX_STREAM_SSL) - if (pc->type == SOCK_STREAM && pscf->ssl) { + if (pc->type == SOCK_STREAM && pscf->ssl_enable) { if (u->proxy_protocol) { if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { @@ -892,7 +894,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) return; } - p = ngx_pnalloc(c->pool, NGX_PROXY_PROTOCOL_MAX_HEADER); + p = ngx_pnalloc(c->pool, NGX_PROXY_PROTOCOL_V1_MAX_HEADER); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -900,7 +902,8 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) cl->buf->pos = p; - p = ngx_proxy_protocol_write(c, p, p + NGX_PROXY_PROTOCOL_MAX_HEADER); + p = ngx_proxy_protocol_write(c, p, + p + NGX_PROXY_PROTOCOL_V1_MAX_HEADER); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -944,14 +947,15 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) ngx_connection_t *c, *pc; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; - u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + u_char buf[NGX_PROXY_PROTOCOL_V1_MAX_HEADER]; c = s->connection; ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream proxy send PROXY protocol header"); - p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER); + p = ngx_proxy_protocol_write(c, buf, + buf + NGX_PROXY_PROTOCOL_V1_MAX_HEADER); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return NGX_ERROR; @@ -1069,8 +1073,10 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) } } - if (pscf->ssl_certificate && (pscf->ssl_certificate->lengths - || pscf->ssl_certificate_key->lengths)) + if (pscf->ssl_certificate + && pscf->ssl_certificate->value.len + && (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths)) { if (ngx_stream_proxy_ssl_certificate(s) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); @@ -1669,9 +1675,8 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, size = b->end - b->last; - if (size && src->read->ready && !src->read->delayed - && !src->read->error) - { + if (size && src->read->ready && !src->read->delayed) { + if (limit_rate) { limit = (off_t) limit_rate * (ngx_time() - u->start_sec + 1) - *received; @@ -1735,7 +1740,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, cl->buf->temporary = (n ? 1 : 0); cl->buf->last_buf = src->read->eof; - cl->buf->flush = 1; + cl->buf->flush = !src->read->eof; (*packets)++; *received += n; @@ -2148,14 +2153,19 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_STREAM_SSL) + if (ngx_stream_proxy_merge_ssl(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); ngx_conf_merge_value(conf->ssl_session_reuse, prev->ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); @@ -2196,18 +2206,64 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_STREAM_SSL) +static ngx_int_t +ngx_stream_proxy_merge_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *conf, + ngx_stream_proxy_srv_conf_t *prev) +{ + ngx_uint_t preserve; + + if (conf->ssl_protocols == 0 + && conf->ssl_ciphers.data == NULL + && conf->ssl_certificate == NGX_CONF_UNSET_PTR + && conf->ssl_certificate_key == NGX_CONF_UNSET_PTR + && conf->ssl_passwords == NGX_CONF_UNSET_PTR + && conf->ssl_verify == NGX_CONF_UNSET + && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT + && conf->ssl_trusted_certificate.data == NULL + && conf->ssl_crl.data == NULL + && conf->ssl_session_reuse == NGX_CONF_UNSET + && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR) + { + if (prev->ssl) { + conf->ssl = prev->ssl; + return NGX_OK; + } + + preserve = 1; + + } else { + preserve = 0; + } + + conf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (conf->ssl == NULL) { + return NGX_ERROR; + } + + conf->ssl->log = cf->log; + + /* + * special handling to preserve conf->ssl + * in the "stream" section to inherit it to all servers + */ + + if (preserve) { + prev->ssl = conf->ssl; + } + + return NGX_OK; +} + + static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) { ngx_pool_cleanup_t *cln; - pscf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (pscf->ssl == NULL) { - return NGX_ERROR; + if (pscf->ssl->ctx) { + return NGX_OK; } - pscf->ssl->log = cf->log; - if (ngx_ssl_create(pscf->ssl, pscf->ssl_protocols, NULL) != NGX_OK) { return NGX_ERROR; } @@ -2225,8 +2281,9 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) return NGX_ERROR; } - if (pscf->ssl_certificate) { - + if (pscf->ssl_certificate + && pscf->ssl_certificate->value.len) + { if (pscf->ssl_certificate_key == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"proxy_ssl_certificate_key\" is defined " diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index c530832..1ba1825 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -703,8 +703,9 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); @@ -1073,7 +1074,7 @@ ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) len++; } - if (len == 0) { + if (len == 0 || j == value[i].len) { goto invalid; } diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 8b59668..8126890 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -23,6 +23,8 @@ static ngx_int_t ngx_stream_variable_proxy_protocol_addr( ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_proxy_protocol_port( ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_proxy_protocol_tlv( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, @@ -79,6 +81,10 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { ngx_stream_variable_proxy_protocol_port, offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 }, + { ngx_string("proxy_protocol_tlv_"), NULL, + ngx_stream_variable_proxy_protocol_tlv, + 0, NGX_STREAM_VAR_PREFIX, 0 }, + { ngx_string("server_addr"), NULL, ngx_stream_variable_server_addr, 0, 0, 0 }, @@ -621,6 +627,39 @@ ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s, } +static ngx_int_t +ngx_stream_variable_proxy_protocol_tlv(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *name = (ngx_str_t *) data; + + ngx_int_t rc; + ngx_str_t tlv, value; + + tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1); + tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1; + + rc = ngx_proxy_protocol_get_tlv(s->connection, &tlv, &value); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + v->not_found = 1; + return NGX_OK; + } + + v->len = value.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = value.data; + + return NGX_OK; +} + + static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c index 156a61c..07dc7b5 100644 --- a/src/stream/ngx_stream_write_filter_module.c +++ b/src/stream/ngx_stream_write_filter_module.c @@ -235,7 +235,7 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) && !(last && c->need_last_buf) - && !(c->type == SOCK_DGRAM && flush)) + && !(flush && c->need_flush_buf)) { if (last || flush || sync) { for (cl = *out; cl; /* void */) { From 557d6885777f1f99dc38324d49c7e0fcd20bb255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 25 Apr 2023 22:37:22 +0200 Subject: [PATCH 02/89] d/changelog New version 1.24.0-1 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3bf98db..17a3a54 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.24.0-1) UNRELEASED; urgency=medium + + * New upstream version 1.24.0 + + -- Jan Mojžíš Tue, 25 Apr 2023 22:36:57 +0200 + nginx (1.22.1-9) unstable; urgency=medium * d/control: nginx-common Breaks+Replaces: nginx (<< 1.22.1-8) From 7478c72e84c7acd460e54d579b2d639fef0e88cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 25 Apr 2023 22:38:33 +0200 Subject: [PATCH 03/89] nginx ABI release: nginx-abi-1.24.0-1 --- debian/changelog | 1 + debian/libnginx-mod.abisubstvars | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 17a3a54..a471f46 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.24.0-1) UNRELEASED; urgency=medium * New upstream version 1.24.0 + * nginx ABI release: nginx-abi-1.24.0-1 -- Jan Mojžíš Tue, 25 Apr 2023 22:36:57 +0200 diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index 7cd29eb..e07fe78 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -5,7 +5,7 @@ # note that debian revision can increase without breaking ABI # # TODO: use $(DEB_VERSION_UPSTREAM) -nginx:abi=nginx-abi-1.22.1-7 +nginx:abi=nginx-abi-1.24.0-1 # ABI-compatible versions of third-party modules libnginx-mod-http-auth-pam:Version=1:1.5.3-3 From 9fe5d1ba9345791756dccb0bcaeb357b241c7b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 25 Apr 2023 22:39:28 +0200 Subject: [PATCH 04/89] d/p/bug-{1024605,973861}.patch removed, fixed in upstream --- debian/changelog | 1 + debian/patches/bug-1024605.patch | 102 ------------------------------- debian/patches/bug-973861.patch | 66 -------------------- debian/patches/series | 2 - 4 files changed, 1 insertion(+), 170 deletions(-) delete mode 100644 debian/patches/bug-1024605.patch delete mode 100644 debian/patches/bug-973861.patch diff --git a/debian/changelog b/debian/changelog index a471f46..32fcc6e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.24.0-1) UNRELEASED; urgency=medium * New upstream version 1.24.0 * nginx ABI release: nginx-abi-1.24.0-1 + * d/p/bug-{1024605,973861}.patch removed, fixed in upstream -- Jan Mojžíš Tue, 25 Apr 2023 22:36:57 +0200 diff --git a/debian/patches/bug-1024605.patch b/debian/patches/bug-1024605.patch deleted file mode 100644 index 28b7d18..0000000 --- a/debian/patches/bug-1024605.patch +++ /dev/null @@ -1,102 +0,0 @@ -Description: SSI: handling of subrequests from other modules -Author: User Ciel Zhao -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1024605 -Last-Update: 2022-11-21 -Origin: https://hg.nginx.org/nginx/raw-rev/49e7db44b57c -Forwarded: not-needed ---- -# HG changeset patch -# User Ciel Zhao -# Date 1669039294 -10800 -# Node ID 49e7db44b57c9f4d54b87d19a696178b913aec5c -# Parent 42bc158a47ecb3c2bd0396c723c307c757f2770e -SSI: handling of subrequests from other modules (ticket #1263). - -As the SSI parser always uses the context from the main request for storing -variables and blocks, that context should always exist for subrequests using -SSI, even though the main request does not necessarily have SSI enabled. - -However, `ngx_http_get_module_ctx(r->main, ...)` is getting NULL in such cases, -resulting in the worker crashing SIGSEGV when accessing its attributes. - -This patch links the first initialized context to the main request, and -upgrades it only when main context is initialized. - -diff -r 42bc158a47ec -r 49e7db44b57c src/http/modules/ngx_http_ssi_filter_module.c ---- a/src/http/modules/ngx_http_ssi_filter_module.c Tue Nov 08 12:48:21 2022 +0300 -+++ b/src/http/modules/ngx_http_ssi_filter_module.c Mon Nov 21 17:01:34 2022 +0300 -@@ -329,7 +329,7 @@ - static ngx_int_t - ngx_http_ssi_header_filter(ngx_http_request_t *r) - { -- ngx_http_ssi_ctx_t *ctx; -+ ngx_http_ssi_ctx_t *ctx, *mctx; - ngx_http_ssi_loc_conf_t *slcf; - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); -@@ -341,6 +341,8 @@ - return ngx_http_next_header_filter(r); - } - -+ mctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); -+ - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_ssi_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; -@@ -367,6 +369,26 @@ - r->filter_need_in_memory = 1; - - if (r == r->main) { -+ -+ if (mctx) { -+ -+ /* -+ * if there was a shared context previously used as main, -+ * copy variables and blocks -+ */ -+ -+ ctx->variables = mctx->variables; -+ ctx->blocks = mctx->blocks; -+ -+#if (NGX_PCRE) -+ ctx->ncaptures = mctx->ncaptures; -+ ctx->captures = mctx->captures; -+ ctx->captures_data = mctx->captures_data; -+#endif -+ -+ mctx->shared = 0; -+ } -+ - ngx_http_clear_content_length(r); - ngx_http_clear_accept_ranges(r); - -@@ -379,6 +401,10 @@ - } else { - ngx_http_weak_etag(r); - } -+ -+ } else if (mctx == NULL) { -+ ngx_http_set_ctx(r->main, ctx, ngx_http_ssi_filter_module); -+ ctx->shared = 1; - } - - return ngx_http_next_header_filter(r); -@@ -405,6 +431,7 @@ - ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); - - if (ctx == NULL -+ || (ctx->shared && r == r->main) - || (in == NULL - && ctx->buf == NULL - && ctx->in == NULL -diff -r 42bc158a47ec -r 49e7db44b57c src/http/modules/ngx_http_ssi_filter_module.h ---- a/src/http/modules/ngx_http_ssi_filter_module.h Tue Nov 08 12:48:21 2022 +0300 -+++ b/src/http/modules/ngx_http_ssi_filter_module.h Mon Nov 21 17:01:34 2022 +0300 -@@ -71,6 +71,7 @@ - u_char *captures_data; - #endif - -+ unsigned shared:1; - unsigned conditional:2; - unsigned encoding:2; - unsigned block:1; diff --git a/debian/patches/bug-973861.patch b/debian/patches/bug-973861.patch deleted file mode 100644 index 221eb8d..0000000 --- a/debian/patches/bug-973861.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 2485681308bd8d3108da31546cb91bb97813a3fb Mon Sep 17 00:00:00 2001 -From: Maxim Dounin -Date: Thu, 2 Feb 2023 23:38:48 +0300 -Subject: [PATCH] Lingering close for connections with pipelined requests. -Origin: https://hg.nginx.org/nginx/rev/cffaf3f2eec8 -Forwarded: not-needed - -This is expected to help with clients using pipelining with some constant -depth, such as apt[1][2]. - -When downloading many resources, apt uses pipelining with some constant -depth, a number of requests in flight. This essentially means that after -receiving a response it sends an additional request to the server, and -this can result in requests arriving to the server at any time. Further, -additional requests are sent one-by-one, and can be easily seen as such -(neither as pipelined, nor followed by pipelined requests). - -The only safe approach to close such connections (for example, when -keepalive_requests is reached) is with lingering. To do so, now nginx -monitors if pipelining was used on the connection, and if it was, closes -the connection with lingering. - -[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=973861#10 -[2] https://mailman.nginx.org/pipermail/nginx-devel/2023-January/ZA2SP5SJU55LHEBCJMFDB2AZVELRLTHI.html ---- - src/core/ngx_connection.h | 1 + - src/http/ngx_http_request.c | 4 +++- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h -index 6d3348d9..36e1be27 100644 ---- a/src/core/ngx_connection.h -+++ b/src/core/ngx_connection.h -@@ -172,6 +172,7 @@ struct ngx_connection_s { - unsigned timedout:1; - unsigned error:1; - unsigned destroyed:1; -+ unsigned pipeline:1; - - unsigned idle:1; - unsigned reusable:1; -diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c -index 131a2c83..5e0340b2 100644 ---- a/src/http/ngx_http_request.c -+++ b/src/http/ngx_http_request.c -@@ -2753,7 +2753,8 @@ ngx_http_finalize_connection(ngx_http_request_t *r) - || (clcf->lingering_close == NGX_HTTP_LINGERING_ON - && (r->lingering_close - || r->header_in->pos < r->header_in->last -- || r->connection->read->ready))) -+ || r->connection->read->ready -+ || r->connection->pipeline))) - { - ngx_http_set_lingering_close(r->connection); - return; -@@ -3123,6 +3124,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) - - c->sent = 0; - c->destroyed = 0; -+ c->pipeline = 1; - - if (rev->timer_set) { - ngx_del_timer(rev); --- -2.30.2 - diff --git a/debian/patches/series b/debian/patches/series index 21a2a69..52e1dc4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,5 +1,3 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch -bug-1024605.patch -bug-973861.patch From bb973756e23158b90aacedcc936cae114eeed96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 25 Apr 2023 22:40:28 +0200 Subject: [PATCH 05/89] d/copyright: updated copyright --- debian/changelog | 2 ++ debian/copyright | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/debian/changelog b/debian/changelog index 32fcc6e..b53cfd5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,8 @@ nginx (1.24.0-1) UNRELEASED; urgency=medium * New upstream version 1.24.0 * nginx ABI release: nginx-abi-1.24.0-1 * d/p/bug-{1024605,973861}.patch removed, fixed in upstream + * d/copyright: updated copyright for files src/event/ngx_event_udp.h, + src/os/win32/ngx_dlopen -- Jan Mojžíš Tue, 25 Apr 2023 22:36:57 +0200 diff --git a/debian/copyright b/debian/copyright index 5738011..7fc2b36 100644 --- a/debian/copyright +++ b/debian/copyright @@ -186,6 +186,10 @@ Copyright: Roman Arutyunyan Nginx, Inc. License: BSD-2-clause +Files: src/event/ngx_event_udp.h +Copyright: Nginx, Inc. +License: BSD-2-clause + Files: src/http/modules/ngx_http_auth_request_module.c src/http/modules/ngx_http_grpc_module.c src/http/modules/ngx_http_upstream_keepalive_module.c @@ -285,6 +289,12 @@ Files: src/os/unix/ngx_setaffinity.c Copyright: Nginx, Inc. License: BSD-2-clause +Files: src/os/win32/ngx_dlopen.c + src/os/win32/ngx_dlopen.h +Copyright: Nginx, Inc. + Maxim Dounin +License: BSD-2-clause + Files: src/stream/ngx_stream.c src/stream/ngx_stream.h src/stream/ngx_stream_core_module.c From b4078d94d481778cf4b142b68aa2b203d0ce4a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 26 Jun 2023 14:48:05 +0200 Subject: [PATCH 06/89] d/libnginx-mod.abisubstvars update version constraints of the 3rd party modules --- debian/changelog | 2 ++ debian/libnginx-mod.abisubstvars | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/debian/changelog b/debian/changelog index b53cfd5..8ade4e0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ nginx (1.24.0-1) UNRELEASED; urgency=medium * New upstream version 1.24.0 * nginx ABI release: nginx-abi-1.24.0-1 + * d/libnginx-mod.abisubstvars update version constraints of the 3rd party + modules * d/p/bug-{1024605,973861}.patch removed, fixed in upstream * d/copyright: updated copyright for files src/event/ngx_event_udp.h, src/os/win32/ngx_dlopen diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index e07fe78..556875b 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -8,16 +8,16 @@ nginx:abi=nginx-abi-1.24.0-1 # ABI-compatible versions of third-party modules -libnginx-mod-http-auth-pam:Version=1:1.5.3-3 -libnginx-mod-http-cache-purge:Version=1:2.3-4 -libnginx-mod-http-dav-ext:Version=1:3.0.0-3 -libnginx-mod-http-echo:Version=1:0.63-4 -libnginx-mod-http-fancyindex:Version=1:0.5.2-3 -libnginx-mod-http-geoip2:Version=1:3.4-3 -libnginx-mod-http-headers-more-filter:Version=1:0.34-3 -libnginx-mod-http-lua:Version=1:0.10.23-1 -libnginx-mod-http-subs-filter:Version=1:0.6.4-4 -libnginx-mod-http-uploadprogress:Version=1:0.9.2-3 -libnginx-mod-http-upstream-fair:Version=1:0.0~git20120408.a18b409-3 -libnginx-mod-nchan:Version=1:1.3.6+dfsg-2 -libnginx-mod-geoip2:Version=1:3.4-3 +libnginx-mod-http-auth-pam:Version=1:1.5.3-4 +libnginx-mod-http-cache-purge:Version=1:2.3-5 +libnginx-mod-http-dav-ext:Version=1:3.0.0-4 +libnginx-mod-http-echo:Version=1:0.63-5 +libnginx-mod-http-fancyindex:Version=1:0.5.2-4 +libnginx-mod-http-geoip2:Version=1:3.4-4 +libnginx-mod-http-headers-more-filter:Version=1:0.34-4 +libnginx-mod-http-lua:Version=1:0.10.23-2 +libnginx-mod-http-subs-filter:Version=1:0.6.4-5 +libnginx-mod-http-uploadprogress:Version=1:0.9.2-4 +libnginx-mod-http-upstream-fair:Version=1:0.0~git20120408.a18b409-4 +libnginx-mod-nchan:Version=1:1.3.6+dfsg-3 +libnginx-mod-geoip2:Version=1:3.4-4 From d6229b0698bb014efefbc0b13a41e4eb629bee2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 26 Jun 2023 15:20:12 +0200 Subject: [PATCH 07/89] d/changelog fix whitespace --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 8ade4e0..c249bfe 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ nginx (1.24.0-1) UNRELEASED; urgency=medium - * New upstream version 1.24.0 + * New upstream version 1.24.0 * nginx ABI release: nginx-abi-1.24.0-1 * d/libnginx-mod.abisubstvars update version constraints of the 3rd party modules From 54146b604bee2c7db53349477e9e293780df41b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 27 Jun 2023 23:19:52 +0200 Subject: [PATCH 08/89] release nginx 1.24.0-1, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index c249bfe..d060a12 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.24.0-1) UNRELEASED; urgency=medium +nginx (1.24.0-1) unstable; urgency=medium * New upstream version 1.24.0 * nginx ABI release: nginx-abi-1.24.0-1 @@ -8,7 +8,7 @@ nginx (1.24.0-1) UNRELEASED; urgency=medium * d/copyright: updated copyright for files src/event/ngx_event_udp.h, src/os/win32/ngx_dlopen - -- Jan Mojžíš Tue, 25 Apr 2023 22:36:57 +0200 + -- Jan Mojžíš Tue, 27 Jun 2023 23:19:31 +0200 nginx (1.22.1-9) unstable; urgency=medium From 2d48a8c8ece57bd74eb1539f6a8b0fbea37dabc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Fri, 30 Jun 2023 11:54:17 +0200 Subject: [PATCH 09/89] d/control add dependency nginx-common to nginx --- debian/changelog | 12 ++++++++++++ debian/control | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index d060a12..40bbef8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +nginx (1.24.0-2) UNRELEASED; urgency=medium + + * d/control added dependency nginx-common to nginx (Closes: 1039905) + After nginx installation, the nginx-common package is installed + automatically due to its dependencies. The nginx-common package includes + the systemd unit, which becomes enabled and activated upon installation. + When the nginx is removed, nginx-common package and the systemd unit will + remain in the system. Adding a dependency nginx-common to nginx solves + this problem. + + -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 + nginx (1.24.0-1) unstable; urgency=medium * New upstream version 1.24.0 diff --git a/debian/control b/debian/control index 7c37ce9..42833a8 100644 --- a/debian/control +++ b/debian/control @@ -51,7 +51,9 @@ Breaks: nginx (<< 1.22.1-8) Replaces: nginx (<< 1.22.1-8) Architecture: all Multi-Arch: foreign -Depends: ${misc:Depends} +Depends: ${misc:Depends}, + nginx (>= ${source:Version}), + nginx (<< ${source:Version}.1~), Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server From 3f8de1c0866b174a505deade1fb172bd6300f92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Thu, 13 Jul 2023 20:35:28 +0200 Subject: [PATCH 10/89] d/control fixed binNMU safe dependency declaration nginx to nginx-common --- debian/changelog | 2 ++ debian/control | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 40bbef8..c9e0031 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium When the nginx is removed, nginx-common package and the systemd unit will remain in the system. Adding a dependency nginx-common to nginx solves this problem. + * d/control fixed binNMU safe dependency declaration nginx to nginx-common, + nginx is 'any', nginx-common is 'all' -> dependency '= ${source:Version}' -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 diff --git a/debian/control b/debian/control index 42833a8..8d2d93f 100644 --- a/debian/control +++ b/debian/control @@ -24,8 +24,7 @@ Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, iproute2, - nginx-common (<< ${source:Version}.1~), - nginx-common (>= ${source:Version}), + nginx-common (= ${source:Version}), Breaks: nginx-light (<< 1.22.1-6~), nginx-extras (<< 1.22.1-6~), nginx-core (<< 1.22.1-6~), Replaces: nginx-light (<< 1.22.1-6~), nginx-extras (<< 1.22.1-6~), nginx-core (<< 1.22.1-6~), Provides: httpd, httpd-cgi, ${nginx:abi} From b8d9144432ae3f0f07f01f8da6c89b66526be8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 15 Jul 2023 20:24:35 +0200 Subject: [PATCH 11/89] * d/rules fixed debug-symbol-migration-possibly-complete lintian warning --- debian/changelog | 3 +++ debian/rules | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index c9e0031..9e666d8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,9 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium this problem. * d/control fixed binNMU safe dependency declaration nginx to nginx-common, nginx is 'any', nginx-common is 'all' -> dependency '= ${source:Version}' + * d/rules replaced '--dbgsym-migration='nginx-dbg (<< 1.10.1-3~)' by + -O--automatic-dbgsym, and fixed debug-symbol-migration-possibly-complete + lintian warning -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 diff --git a/debian/rules b/debian/rules index da5f06e..76c7576 100755 --- a/debian/rules +++ b/debian/rules @@ -118,8 +118,7 @@ build.src: pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 strip.arch.%: - #dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' - dh_strip --package=nginx -O--dbgsym-migration='nginx-dbg (<< 1.10.1-3~)' + dh_strip --package=nginx -O--automatic-dbgsym strip.mods.%: dh_strip --package=libnginx-mod-$(*) -O--automatic-dbgsym From 9d8220a199606811a7fc530df9d98d6f661b395e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 15 Jul 2023 21:24:09 +0200 Subject: [PATCH 12/89] d/po/ro.po add Romanian debconf translation --- debian/changelog | 2 ++ debian/po/ro.po | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 debian/po/ro.po diff --git a/debian/changelog b/debian/changelog index 9e666d8..ae17e79 100644 --- a/debian/changelog +++ b/debian/changelog @@ -12,6 +12,8 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/rules replaced '--dbgsym-migration='nginx-dbg (<< 1.10.1-3~)' by -O--automatic-dbgsym, and fixed debug-symbol-migration-possibly-complete lintian warning + * d/po/ro.po added Romanian debconf translation. (Closes: 1033084), + Thanks to Remus-Gabriel Chelu -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 diff --git a/debian/po/ro.po b/debian/po/ro.po new file mode 100644 index 0000000..9877cb1 --- /dev/null +++ b/debian/po/ro.po @@ -0,0 +1,81 @@ +# Mesajele în limba română pentru pachetul nginx. +# Romanian translation of nginx. +# Copyright © 2023 Christos Trochalakis +# This file is distributed under the same license as the nginx package. +# Christos Trochalakis , 2016. +# +# Remus-Gabriel Chelu , 2023. +# +# Cronologia traducerii fișierului „nginx”: +# Traducerea inițială, făcută de R-GC, pentru versiunea nginx 1.22.1-7(2016-10-04). +# Actualizare a traducerii pentru versiunea Y, făcută de X, Y(anul). +# +msgid "" +msgstr "" +"Project-Id-Version: nginx 1.22.1-7\n" +"Report-Msgid-Bugs-To: nginx@packages.debian.org\n" +"POT-Creation-Date: 2016-10-04 20:03+0300\n" +"PO-Revision-Date: 2023-03-13 12:29+0100\n" +"Last-Translator: Remus-Gabriel Chelu \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 || (n!=1 && n%100>=1 && " +"n%100<=19) ? 1 : 2);\n" +"X-Bugs: Report translation errors to the Language-Team address.\n" +"X-Generator: Poedit 3.2.2\n" + +# R-GC, scrie: +# după revzarea fișierului, RA spune: +# „Unele fișiere jurnal de «nginx» parsă fie nesecurizate” → „... par să ...” +# **** +# Corecție aplicată! +#. Type: note +#. Description +#: ../nginx.templates:1001 +msgid "Possible insecure nginx log files" +msgstr "Unele fișiere jurnal de «nginx» par să fie nesecurizate" + +#. Type: note +#. Description +#: ../nginx.templates:1001 +msgid "" +"The following log files under /var/log/nginx directory are symlinks owned by " +"www-data:" +msgstr "" +"Următoarele fișiere jurnal din directorul „/var/log/nginx” sunt legături " +"simbolice deținute de „www-data”:" + +#. Type: note +#. Description +#: ../nginx.templates:1001 +msgid "${logfiles}" +msgstr "${logfiles}" + +# R-GC, scrie: +# după revzarea fișierului, RA spune: +# „Deoarece până la nginx 1.4.4-4 directorul „/var/log/nginx” a fost deținut de „www-data”. Ca rezultat, „www-data” ar putea crea legături simbolice ...” +# → aici avem o fraza incompleta. Acel "deoarece" are nevoie de un efect, de exemplu: +# „Deoarece până la nginx 1.4.4-4 directorul ... a fost deținut de „www-data”, ca rezultat, ...” +# ***** +# Corecție aplicată, cu o corecție ;) → +# „... deținut de „www-data”; ca rezultat, ...” +# adică: , → ; +#. Type: note +#. Description +#: ../nginx.templates:1001 +msgid "" +"Since nginx 1.4.4-4 /var/log/nginx was owned by www-data. As a result www-data " +"could symlink log files to sensitive locations, which in turn could lead to " +"privilege escalation attacks. Although /var/log/nginx permissions are now fixed " +"it is possible that such insecure links already exist. So, please make sure to " +"check the above locations." +msgstr "" +"Deoarece până la nginx 1.4.4-4 directorul „/var/log/nginx” a fost deținut de " +"„www-data”; ca rezultat, „www-data” ar putea crea legături simbolice a " +"fișierelor jurnal către locații sensibile, ceea ce, la rândul său, ar putea " +"duce la atacuri de escaladare a privilegiilor. Deși permisiunile directorului „/" +"var/log/nginx” sunt acum remediate, este posibil ca astfel de legături nesigure " +"să existe deja. Prin urmare, asigurați-vă că verificați locațiile de mai sus." From 7b0bfbb9f32a1a1d173edd43c29e26a104054d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 17 Jul 2023 05:24:19 +0200 Subject: [PATCH 13/89] d/rules removed override_dh_strip --- debian/changelog | 5 ++--- debian/rules | 15 --------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/debian/changelog b/debian/changelog index ae17e79..f959d41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,9 +9,8 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium this problem. * d/control fixed binNMU safe dependency declaration nginx to nginx-common, nginx is 'any', nginx-common is 'all' -> dependency '= ${source:Version}' - * d/rules replaced '--dbgsym-migration='nginx-dbg (<< 1.10.1-3~)' by - -O--automatic-dbgsym, and fixed debug-symbol-migration-possibly-complete - lintian warning + * d/rules removed override_dh_strip, migration to automatic debug symbols is + already done, fixes debug-symbol-migration-possibly-complete lint. warning * d/po/ro.po added Romanian debconf translation. (Closes: 1033084), Thanks to Remus-Gabriel Chelu diff --git a/debian/rules b/debian/rules index 76c7576..1d037dd 100755 --- a/debian/rules +++ b/debian/rules @@ -6,14 +6,6 @@ debian_cflags:=$(shell dpkg-buildflags --get CFLAGS) -fPIC $(shell dpkg-buildfla debian_ldflags:=$(shell dpkg-buildflags --get LDFLAGS) -fPIC FLAVOURS := bin -DYN_MODS := \ - http-geoip \ - http-image-filter \ - http-perl \ - http-xslt-filter \ - mail \ - stream \ - stream-geoip BASEDIR = $(CURDIR) $(foreach flavour,$(FLAVOURS) src ,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) @@ -86,7 +78,6 @@ bin_configure_flags := \ override_dh_auto_configure: $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src -override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) override_dh_clean: $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src dh_clean @@ -117,12 +108,6 @@ build.src: echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 -strip.arch.%: - dh_strip --package=nginx -O--automatic-dbgsym - -strip.mods.%: - dh_strip --package=libnginx-mod-$(*) -O--automatic-dbgsym - config.arch.%: dh_testdir mkdir -p $(BUILDDIR_$*) From d99a0ddc0bd902aa0756942b9ac8fcc5cad59282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 17 Jul 2023 06:25:07 +0200 Subject: [PATCH 14/89] d/conf/mime.types copy mime.types from upstream nginx, no big changes, just reformat the text --- debian/conf/mime.types | 175 +++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 86 deletions(-) diff --git a/debian/conf/mime.types b/debian/conf/mime.types index 692b16c..1c00d70 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -1,96 +1,99 @@ types { - text/html html htm shtml; - text/css css; - text/xml xml; - image/gif gif; - image/jpeg jpeg jpg; - application/javascript js; - application/atom+xml atom; - application/rss+xml rss; + text/html html htm shtml; + text/css css; + text/xml xml; + image/gif gif; + image/jpeg jpeg jpg; + application/javascript js; + application/atom+xml atom; + application/rss+xml rss; - text/mathml mml; - text/plain txt; - text/vnd.sun.j2me.app-descriptor jad; - text/vnd.wap.wml wml; - text/x-component htc; + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; - image/avif avif; - image/png png; - image/svg+xml svg svgz; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/webp webp; - image/x-icon ico; - image/x-jng jng; - image/x-ms-bmp bmp; + image/avif avif; + image/png png; + image/svg+xml svg svgz; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/webp webp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; - font/woff woff; - font/woff2 woff2; + font/woff woff; + font/woff2 woff2; - 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.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/vnd.ms-excel xls; - application/vnd.ms-fontobject eot; - application/vnd.ms-powerpoint ppt; - application/vnd.oasis.opendocument.graphics odg; - application/vnd.oasis.opendocument.presentation odp; - application/vnd.oasis.opendocument.spreadsheet ods; - application/vnd.oasis.opendocument.text odt; - application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; - application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; - application/vnd.wap.wmlc wmlc; - application/wasm wasm; - application/x-7z-compressed 7z; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - application/x-makeself run; - application/x-perl pl pm; - application/x-pilot prc pdb; - application/x-rar-compressed rar; - application/x-redhat-package-manager rpm; - application/x-sea sea; - application/x-shockwave-flash swf; - application/x-stuffit sit; - application/x-tcl tcl tk; - application/x-x509-ca-cert der pem crt; - application/x-xpinstall xpi; - application/xhtml+xml xhtml; - application/xspf+xml xspf; - application/zip zip; + 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.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; + application/vnd.ms-powerpoint ppt; + application/vnd.oasis.opendocument.graphics odg; + application/vnd.oasis.opendocument.presentation odp; + application/vnd.oasis.opendocument.spreadsheet ods; + application/vnd.oasis.opendocument.text odt; + application/vnd.openxmlformats-officedocument.presentationml.presentation + pptx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + xlsx; + application/vnd.openxmlformats-officedocument.wordprocessingml.document + docx; + application/vnd.wap.wmlc wmlc; + application/wasm wasm; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/xspf+xml xspf; + application/zip zip; - application/octet-stream bin exe dll; - application/octet-stream deb; - application/octet-stream dmg; - application/octet-stream iso img; - application/octet-stream msi msp msm; + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream iso img; + application/octet-stream msi msp msm; - audio/midi mid midi kar; - audio/mpeg mp3; - audio/ogg ogg; - audio/x-m4a m4a; - audio/x-realaudio ra; + audio/midi mid midi kar; + audio/mpeg mp3; + audio/ogg ogg; + audio/x-m4a m4a; + audio/x-realaudio ra; - video/3gpp 3gpp 3gp; - video/mp2t ts; - video/mp4 mp4; - video/mpeg mpeg mpg; - video/quicktime mov; - video/webm webm; - video/x-flv flv; - video/x-m4v m4v; - video/x-mng mng; - video/x-ms-asf asx asf; - video/x-ms-wmv wmv; - video/x-msvideo avi; + video/3gpp 3gpp 3gp; + video/mp2t ts; + video/mp4 mp4; + video/mpeg mpeg mpg; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-m4v m4v; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; } From 1669ce81fafde1e06508bbcc46c67f90a867c385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 17 Jul 2023 06:25:37 +0200 Subject: [PATCH 15/89] d/conf/mime.types add video/ogg, video/x-matroska --- debian/changelog | 1 + debian/conf/mime.types | 2 ++ 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index f959d41..3a7ae65 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,7 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium already done, fixes debug-symbol-migration-possibly-complete lint. warning * d/po/ro.po added Romanian debconf translation. (Closes: 1033084), Thanks to Remus-Gabriel Chelu + * d/conf/mime.types added video/ogg, video/x-matroska (Closes: 1028144) -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 diff --git a/debian/conf/mime.types b/debian/conf/mime.types index 1c00d70..479781b 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -88,10 +88,12 @@ types { video/mp2t ts; video/mp4 mp4; video/mpeg mpeg mpg; + video/ogg ogv; video/quicktime mov; video/webm webm; video/x-flv flv; video/x-m4v m4v; + video/x-matroska mkv; video/x-mng mng; video/x-ms-asf asx asf; video/x-ms-wmv wmv; From f72db03173285ea75bea1af58a21449c932787e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 30 Aug 2023 15:50:18 +0200 Subject: [PATCH 16/89] d/po/sv.po added Swedish debconf translation --- debian/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3a7ae65..dcaf09e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,8 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium already done, fixes debug-symbol-migration-possibly-complete lint. warning * d/po/ro.po added Romanian debconf translation. (Closes: 1033084), Thanks to Remus-Gabriel Chelu + * d/po/sv.po added Swedish debconf translation. (Closes: 1050443), + Thanks to Peter Kvillegård * d/conf/mime.types added video/ogg, video/x-matroska (Closes: 1028144) -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 From dbecf37340289e32b3e0141e7c08e9c178cf24e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 30 Aug 2023 15:52:01 +0200 Subject: [PATCH 17/89] d/po/sv.po added Swedish debconf translation --- debian/po/sv.po | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 debian/po/sv.po diff --git a/debian/po/sv.po b/debian/po/sv.po new file mode 100644 index 0000000..152e111 --- /dev/null +++ b/debian/po/sv.po @@ -0,0 +1,58 @@ +# Swedish translation of nginx debconf messages +# Copyright (C) 2016 Christos Trochalakis +# This file is distributed under the same license as the nginx package. +# Christos Trochalakis , 2016. +# Peter Kvillegård , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: nginx 1.24.0-1\n" +"Report-Msgid-Bugs-To: nginx@packages.debian.org\n" +"POT-Creation-Date: 2016-10-04 20:03+0300\n" +"PO-Revision-Date: 2023-08-21 19:01+0200\n" +"Last-Translator: Peter Kvillegård \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.2.2\n" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "Possible insecure nginx log files" +msgstr "Möjligen osäkra loggfiler för nginx" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "" +"The following log files under /var/log/nginx directory are symlinks owned by " +"www-data:" +msgstr "" +"Följande loggfiler i katalogen /var/log/nginx är symboliska länkar som ägs " +"av www-data:" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "${logfiles}" +msgstr "${logfiles}" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "" +"Since nginx 1.4.4-4 /var/log/nginx was owned by www-data. As a result www-" +"data could symlink log files to sensitive locations, which in turn could " +"lead to privilege escalation attacks. Although /var/log/nginx permissions " +"are now fixed it is possible that such insecure links already exist. So, " +"please make sure to check the above locations." +msgstr "" +"Före nginx 1.4.4-4 ägdes /var/log/nginx av www-data, vilket innebar att www-" +"data kunde skapa loggfiler som var symboliska länkar till känsliga platser, " +"vilket i sin tur kunde leda till behörighetsintrång. Även om rättigheterna " +"för /var/log/nginx är fixade nu så är det möjligt att sådana osäkra länkar " +"finns kvar. Se till att kontrollera ovan nämnda platser." From 1c1713f7479092121dc0408dac3dccad1e53b4e4 Mon Sep 17 00:00:00 2001 From: Marcus Bointon Date: Mon, 25 Sep 2023 12:41:08 +0000 Subject: [PATCH 18/89] Add QUIC UFW app --- debian/ufw/nginx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debian/ufw/nginx b/debian/ufw/nginx index 0cb0449..ad886ba 100644 --- a/debian/ufw/nginx +++ b/debian/ufw/nginx @@ -12,3 +12,8 @@ ports=443/tcp title=Web Server (Nginx, HTTP + HTTPS) description=Small, but very powerful and efficient web server ports=80,443/tcp + +[Nginx QUIC] +title=Web Server (Nginx, HTTP + HTTPS + QUIC) +description=Small, but very powerful and efficient web server +ports=80,443/tcp|443/udp From f3ce71ad918201dcc04ee1193037dc93c9ee9aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 9 Oct 2023 15:27:38 +0200 Subject: [PATCH 19/89] d/control add nginx-dev dependency on ${nginx:abi} --- debian/changelog | 1 + debian/control | 1 + 2 files changed, 2 insertions(+) diff --git a/debian/changelog b/debian/changelog index dcaf09e..434e48d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,7 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/po/sv.po added Swedish debconf translation. (Closes: 1050443), Thanks to Peter Kvillegård * d/conf/mime.types added video/ogg, video/x-matroska (Closes: 1028144) + * d/control added nginx-dev dependency on ${nginx:abi} -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 diff --git a/debian/control b/debian/control index 8d2d93f..a1fcbe9 100644 --- a/debian/control +++ b/debian/control @@ -66,6 +66,7 @@ Package: nginx-dev Architecture: all Multi-Arch: foreign Depends: ${misc:Depends}, ${S:Build-Depends}, + ${nginx:abi}, nginx (<< ${source:Version}.1~), nginx (>= ${source:Version}), Provides: dh-sequence-nginx From 60b5a28e2db8e097f523594b1b540e5ef9254f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 10 Oct 2023 20:22:50 +0000 Subject: [PATCH 20/89] CVE-2023-44487 fix --- debian/changelog | 2 + debian/patches/CVE-2023-44487.patch | 75 +++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 78 insertions(+) create mode 100644 debian/patches/CVE-2023-44487.patch diff --git a/debian/changelog b/debian/changelog index dcaf09e..71d97fa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,8 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/po/sv.po added Swedish debconf translation. (Closes: 1050443), Thanks to Peter Kvillegård * d/conf/mime.types added video/ogg, video/x-matroska (Closes: 1028144) + * d/p/CVE-2023-44487.patch fixes CVE-2023-44487 denial of service (server + resource consumption) (Closes: 1053770) -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 diff --git a/debian/patches/CVE-2023-44487.patch b/debian/patches/CVE-2023-44487.patch new file mode 100644 index 0000000..401f30b --- /dev/null +++ b/debian/patches/CVE-2023-44487.patch @@ -0,0 +1,75 @@ +From 6ceef192e7af1c507826ac38a2d43f08bf265fb9 Mon Sep 17 00:00:00 2001 +From: Maxim Dounin +Date: Tue, 10 Oct 2023 15:13:39 +0300 +Subject: [PATCH] HTTP/2: per-iteration stream handling limit. +Origin: https://github.com/nginx/nginx/commit/6ceef192e7af1c507826ac38a2d43f08bf265fb9 +Forwarded: not-needed + +To ensure that attempts to flood servers with many streams are detected +early, a limit of no more than 2 * max_concurrent_streams new streams per one +event loop iteration was introduced. This limit is applied even if +max_concurrent_streams is not yet reached - for example, if corresponding +streams are handled synchronously or reset. + +Further, refused streams are now limited to maximum of max_concurrent_streams +and 100, similarly to priority_limit initial value, providing some tolerance +to clients trying to open several streams at the connection start, yet +low tolerance to flooding attempts. +--- + src/http/v2/ngx_http_v2.c | 15 +++++++++++++++ + src/http/v2/ngx_http_v2.h | 2 ++ + 2 files changed, 17 insertions(+) + +Index: nginx/src/http/v2/ngx_http_v2.c +=================================================================== +--- nginx.orig/src/http/v2/ngx_http_v2.c ++++ nginx/src/http/v2/ngx_http_v2.c +@@ -361,6 +361,7 @@ ngx_http_v2_read_handler(ngx_event_t *re + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); + + h2c->blocked = 1; ++ h2c->new_streams = 0; + + if (c->close) { + c->close = 0; +@@ -1321,6 +1322,14 @@ ngx_http_v2_state_headers(ngx_http_v2_co + goto rst_stream; + } + ++ if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent too many streams at once"); ++ ++ status = NGX_HTTP_V2_REFUSED_STREAM; ++ goto rst_stream; ++ } ++ + if (!h2c->settings_ack + && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) + && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW) +@@ -1386,6 +1395,12 @@ ngx_http_v2_state_headers(ngx_http_v2_co + + rst_stream: + ++ if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent too many refused streams"); ++ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR); ++ } ++ + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } +Index: nginx/src/http/v2/ngx_http_v2.h +=================================================================== +--- nginx.orig/src/http/v2/ngx_http_v2.h ++++ nginx/src/http/v2/ngx_http_v2.h +@@ -124,6 +124,8 @@ struct ngx_http_v2_connection_s { + ngx_uint_t processing; + ngx_uint_t frames; + ngx_uint_t idle; ++ ngx_uint_t new_streams; ++ ngx_uint_t refused_streams; + ngx_uint_t priority_limit; + + ngx_uint_t pushing; diff --git a/debian/patches/series b/debian/patches/series index 52e1dc4..48dd724 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,4 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch +CVE-2023-44487.patch From 81aeb5321d43de4dfecff4cea720da2568384414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 10 Oct 2023 21:50:39 +0000 Subject: [PATCH 21/89] dh-sequence-nginx: automatic libnginx-mod-stream dependencies --- debian/debhelper/nginx_mod.pm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/debian/debhelper/nginx_mod.pm b/debian/debhelper/nginx_mod.pm index 7df00d4..1b1ecaf 100644 --- a/debian/debhelper/nginx_mod.pm +++ b/debian/debhelper/nginx_mod.pm @@ -35,12 +35,18 @@ sub _NDK_SRC_DIR { sub new { my $class=shift; my $this= $class->SUPER::new(@_); + my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + chomp($ngx_ver); $this->prefer_out_of_source_building(@_); $this->{has_ndk} = $this->has_build_dep("libnginx-mod-http-ndk-dev"); + $this->{has_stream} = $this->has_build_dep("libnginx-mod-stream"); foreach my $cur (getpackages('arch')) { if ($this->{has_ndk} == 1) { addsubstvar($cur, "misc:Depends", "libnginx-mod-http-ndk"); } + if ($this->{has_stream} == 1) { + addsubstvar($cur, "misc:Depends", "libnginx-mod-stream (>= $ngx_ver), libnginx-mod-stream (<< $ngx_ver.1~)"); + } } return $this; } @@ -63,6 +69,7 @@ sub configure { --add-dynamic-module="$pwd_dir/$src_dir" \\ --builddir="$pwd_dir/$bld_dir" \\ ' . ($this->{has_ndk} ? '--add-module=' . $this->_NDK_SRC_DIR : '') . ' \\ + ' . ($this->{has_stream} ? '--with-stream' : '') . ' \\ "$@"', "dummy", @_); } @@ -79,6 +86,10 @@ sub test { unshift @_, "ndk_http_module.so"; } + if ( $this->{has_stream} and !grep( /^ngx_stream_module.so$/, @_ ) ) { + unshift @_, "ngx_stream_module.so"; + } + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' tmp_conf=$(mktemp -p .) for pre_dep in "$@"; do From 9515e05cd08ed2fc4e582875fdf495bd09dc4bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 10 Oct 2023 23:54:50 +0200 Subject: [PATCH 22/89] d/debhelper/nginx_mod.pm automatic libnginx-mod-stream dependencies --- debian/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/changelog b/debian/changelog index 39b11d1..583563e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,6 +19,7 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/p/CVE-2023-44487.patch fixes CVE-2023-44487 denial of service (server resource consumption) (Closes: 1053770) * d/control added nginx-dev dependency on ${nginx:abi} + * d/debhelper/nginx_mod.pm automatic libnginx-mod-stream dependencies -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 From 192281805a7f51013fa880bcfee393dec37d132d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 11 Oct 2023 00:39:21 +0200 Subject: [PATCH 23/89] release nginx 1.24.0-2, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 583563e..8ae5cba 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.24.0-2) UNRELEASED; urgency=medium +nginx (1.24.0-2) unstable; urgency=medium * d/control added dependency nginx-common to nginx (Closes: 1039905) After nginx installation, the nginx-common package is installed @@ -21,7 +21,7 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/control added nginx-dev dependency on ${nginx:abi} * d/debhelper/nginx_mod.pm automatic libnginx-mod-stream dependencies - -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 + -- Jan Mojžíš Wed, 11 Oct 2023 00:39:04 +0200 nginx (1.24.0-1) unstable; urgency=medium From 5953afe398bd9d93e8faecff1f8902461737573a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 11 Oct 2023 01:13:28 +0200 Subject: [PATCH 24/89] Revert "release nginx 1.24.0-2, upload to unstable" This reverts commit 192281805a7f51013fa880bcfee393dec37d132d. --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 8ae5cba..583563e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.24.0-2) unstable; urgency=medium +nginx (1.24.0-2) UNRELEASED; urgency=medium * d/control added dependency nginx-common to nginx (Closes: 1039905) After nginx installation, the nginx-common package is installed @@ -21,7 +21,7 @@ nginx (1.24.0-2) unstable; urgency=medium * d/control added nginx-dev dependency on ${nginx:abi} * d/debhelper/nginx_mod.pm automatic libnginx-mod-stream dependencies - -- Jan Mojžíš Wed, 11 Oct 2023 00:39:04 +0200 + -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 nginx (1.24.0-1) unstable; urgency=medium From 14846e923db103c3f03e26ef1a0ed145e59c6474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 11 Oct 2023 01:14:14 +0200 Subject: [PATCH 25/89] d/changelog update CVE-2023-44487 description --- debian/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 583563e..9e22cd0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,8 +16,9 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/po/sv.po added Swedish debconf translation. (Closes: 1050443), Thanks to Peter Kvillegård * d/conf/mime.types added video/ogg, video/x-matroska (Closes: 1028144) - * d/p/CVE-2023-44487.patch fixes CVE-2023-44487 denial of service (server - resource consumption) (Closes: 1053770) + * d/p/CVE-2023-44487.patch adds additional mitigations for CVE-2023-44487 + that according to NGINX developers on nginx-devel are already suitably + mitigated with the default config options for keepalive. (Closes: 1053770) * d/control added nginx-dev dependency on ${nginx:abi} * d/debhelper/nginx_mod.pm automatic libnginx-mod-stream dependencies From ea0383bdb1adb9eb9bd555e4a90547dac6baeafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 11 Oct 2023 01:18:04 +0200 Subject: [PATCH 26/89] release nginx 1.24.0-2, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9e22cd0..a03601e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.24.0-2) UNRELEASED; urgency=medium +nginx (1.24.0-2) unstable; urgency=medium * d/control added dependency nginx-common to nginx (Closes: 1039905) After nginx installation, the nginx-common package is installed @@ -22,7 +22,7 @@ nginx (1.24.0-2) UNRELEASED; urgency=medium * d/control added nginx-dev dependency on ${nginx:abi} * d/debhelper/nginx_mod.pm automatic libnginx-mod-stream dependencies - -- Jan Mojžíš Fri, 30 Jun 2023 09:52:25 +0200 + -- Jan Mojžíš Wed, 11 Oct 2023 01:17:51 +0200 nginx (1.24.0-1) unstable; urgency=medium From fbe69d2fe0c4f32afd7687e86684529b67c5cc58 Mon Sep 17 00:00:00 2001 From: K Widholm Date: Fri, 27 Oct 2023 02:06:46 +0000 Subject: [PATCH 27/89] Update file mime.types --- debian/conf/mime.types | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/conf/mime.types b/debian/conf/mime.types index 479781b..b6a3aa5 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -1,4 +1,3 @@ - types { text/html html htm shtml; text/css css; @@ -70,6 +69,7 @@ types { application/x-xpinstall xpi; application/xhtml+xml xhtml; application/xspf+xml xspf; + application/xslt+xml xsl xslt; application/zip zip; application/octet-stream bin exe dll; From 0b33ebb4a36e9784849f78bfb13a693de650e45d Mon Sep 17 00:00:00 2001 From: K Widholm Date: Fri, 27 Oct 2023 02:15:04 +0000 Subject: [PATCH 28/89] Update file mime.types --- debian/conf/mime.types | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/conf/mime.types b/debian/conf/mime.types index b6a3aa5..cf968c0 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -68,8 +68,8 @@ types { application/x-x509-ca-cert der pem crt; application/x-xpinstall xpi; application/xhtml+xml xhtml; - application/xspf+xml xspf; application/xslt+xml xsl xslt; + application/xspf+xml xspf; application/zip zip; application/octet-stream bin exe dll; From 488a716b96b45579fdfe787bdaaee8be96c6d336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 17:41:25 +0200 Subject: [PATCH 29/89] =?UTF-8?q?d/u/signing-key.asc=20add=20Roman=20Aruty?= =?UTF-8?q?unyan=E2=80=99s=20PGP=20public=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- debian/changelog | 7 ++ debian/upstream/signing-key.asc | 118 ++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/debian/changelog b/debian/changelog index a03601e..15fb8e3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.24.0-3) UNRELEASED; urgency=medium + + * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, + the key is used to sign the 1.26.0 release + + -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 + nginx (1.24.0-2) unstable; urgency=medium * d/control added dependency nginx-common to nginx (Closes: 1039905) diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc index 5e36f56..4b7818c 100644 --- a/debian/upstream/signing-key.asc +++ b/debian/upstream/signing-key.asc @@ -92,3 +92,121 @@ KSAulWi9OoqLyDWlsm3WccPIcJfbm71P+I/ha7ESVQfOxC92fQ7HQAboj7NhecJ4 RLqjzrWSHmPGClI= =J2qy -----END PGP PUBLIC KEY BLOCK----- + +# Roman Arutyunyan’s PGP public key, +# the key is used to sign the 1.26.0 release + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBGYXyiQBEAC4jm1y+ODV4+YDGj9vp2BgHB4FJeQdgrBiVX+Mb2qCrEqJgeKV +fVwKjkVYqnb76TTybdOKqCP5wdQrncKAKlXsMq6sdsiwPSrdRcjkeiE29WWrtbB4 +i+VObnoWklMblMxFQ1XQIkjs2wviidKjJw2VV3i4XnLSrHhWaWqviTLZCMQymoPs +F+Tfu1WX9OUfOquekZ5KjkyBxB4ep6+NPeuIkPnW0SiTUhU8tbi8v0aBZEHSZLqE +mq8KLROVuYSPvtU+NtaXAM09BHEVCfb409aDps9p6AFT+IN8yoOegGdEZjp6hJvS +HxbhuwqNEtg4dTEV515YUCgKabqU1QaqI/Y0+Pdkpep1KRFc9YUYttDkCw7Ybu2u +fwTGzwAbD+ThAIOdzmMDodzZaEMf+9fQG4bnO1PdNbXzyP7Kv9qzGa65+9oGCPOS +qTpISR8pvzoI8w/Z/vG71ob/nQ6Xm0L986ksErdGhu16ZI7lW2eDYqy2IoFfbeSz +HHxk484/pEibrlCRbP2Id+zULfxo1HGOGg+PAY9Q2uNzABsGDMnOhIvXHS+hP7oB +sO9A4Prqu6K6cMp3QI219tmmOUegJpmGGPzoNgxR7H30wNcjZPv4PWr/c0fP70Ny +ilgbdcEMDSHks30AmiuIvcUxo3A21p2nnpxsKAKYx42UJkyEK0HILMzcqwARAQAB +tCZSb21hbiBBcnV0eXVueWFuIDxyLmFydXR5dW55YW5AZjUuY29tPokCTgQTAQgA +OBYhBEM4eCXdsbuX7Da6XQB8jXwV2HNpBQJmF8pXAhsDBQsJCAcCBhUKCQgLAgQW +AgMBAh4BAheAAAoJEAB8jXwV2HNppvQP/AjzdPKkGRzJkb1ioto/IEP1YhA/Eayk +hvejJ0vyWVHXXH7FLW9fIZoApcsD1J8/7zIANm+62IfT3QNbL2R44IyhJB3AY22l +t0ToLxodfugegF3NPYYyFOSRUoPD4g2T/dMCPOBX4MNEAnAlCmxAMaJNmQUO76IY +GwELa3CH3Aqf7bthKy8P36G11hu7NgH6V9mVIRIpfnfpXFQIztj+vsWtswu4M5t7 +BNJwx4a2KTCVQpTdff5/0dO/5drQDxLbIg681WZk3Oe8Eu6nSc0Ud02NIkg1TQH/ +MryAp7o/ua3LRem+W/cktnT60p4uXPVZ3Rvg3zOmJSNJ+eIXY2+sDeZEPaROKldA +IbnBacTsZjdswIlrbzinY8ZVRosaFlvHg/ESTBRItALHWCRdzOR1Wv1qy/PQfEEL +qftDsCTQhssP1MHJWlejeqPlND3iT2vBDeOxqd6WhKuAc+L04iyBB6p867pwrgDF +ecg82DPehsAnO2XBAFuIE/SLewkYm0B9HK7/J4LZqPwTAksPf/dnbMAmHWoBDqsu +4U4U4SsJKsZ87R9ao8qO7IWCzHrXavHFmnbqweFfHToeKF/L4PB+tYoW3YmUOged +CglpJv13bNWmRwL7+x8b7BwpVwClxHBHteDX4RIN5iPH9h20J4jIpzRa1kNJsTu1 +v4ZkqLWJlkiiiQEzBBABCAAdFiEEcziXMGntP0Q/TTffpk/VsXrbOagFAmYdpjsA +CgkQpk/VsXrbOahISgf/U7ZO0yK0PsOcAFTB0TQBCNsAhxtJAEJoVoweuYiLk8jR +0OeDRCy0BC//qWDLFT7NKuP50SM2u0Csbg+n6b0bdy+vXbbGVzIAYzG09rPYe2Q5 +qwqyAx+MMzyICXul9lGNU2qN2qjUXMb0mCWUhxwMvzRUeS7shT1CBhGrnpoYkY56 +NhWj7iG1BbLwYVQzDZC/Rp6rvwJQgZo7+DjaMjryGAEI0ujpUp8ywrPaJpwIuXDI +D5BhcyUaEd3XOondHQNedlgERXHT4pN+oNMPWwN3+DeQYLS3FHiqyz05ZvoeWnao +A2/fWNA+BqIdjilp/TDDI4Ef7c9hp13weaZggYB3M4kBMwQQAQgAHRYhBFc7/Ws9 +j7xkEHmmq6v1vYJ72b9iBQJmHabkAAoJEKv1vYJ72b9iDgoIAP1QJjl4ynLAV9Bo +Ol4AAzxZ3x/2NEgLSnjLfhb/OduDxQlL9oPulWoLDG41xiZJkepEnQWmSsIYF6Xe +RsAB+eREU2uCxqCvBXpyIs5npXvVDV2/PQuVEop7HByx6Hjr9XK8hugihnEi1p+9 +Ecbu+89fi93m3C/5uIIil46cHByjRZ+5Yy1UFUB/wsYud1qMcYmvDaqEo5AqWNcM +gWUFhUfgGTtBbyvIWTeX0NHnrbzHP7lhmPfWsfOjAtO8PpM8Gz5RdNRq44DdRKdG +uWVby/kni868H+8/tHalDR0I9/Mmg2Uax0eggTVpECv/4+xBduqSB2iPwgRnSzhZ +6SVKJvKJAjMEEAEIAB0WIQT5TVS8DF1qZBfIzz/oLBEYr5TfbgUCZh5KVgAKCRDo +LBEYr5TfbitgD/wMamMFfFZnPS7JS1NWEMb5fbhHob1EkmedIpbpRDXUtj0ksehW +ZAEpmVF9btqS4B+B9tSK1VS2sy4XwEGodNVSGxdtF9W8+iAHAb6Hq1Z7ifWyb991 +Kt/pVk/8adxlU4G8h1fq0idhpnI8KvkAlPJR7+PoJOEN1+VdHS6tkE5LMTf6dF9F +iVxKQczOS1b/GmfL3kYfu6UvI07ZuaP+90mOt/TZTwkzsWjRY2vofCIPSDY94rLj +m6PmVFoU3PHLKW7yDz1YXkVE6SgQYGZ2bqB6OHJZnDXUTSHncHTbDVzZQekIs1lP +V6e5N8Xo/VOpv28feKAsBqQ8ML53djmGUL0azjEz1g2kgPmTuZdKzZ5kcUsULdQV +aRKcfyYD1oRpwwlw9GJAxliJHck1IdGGaCslrHtzkh3RMULlloAYitzD9jtKsrOj +R19s+JK/tIfFZZ5gR5qhzgOL8WgkSrIaq2o9R4sigBz1IxnXXC573RDA2F5FAeE/ +K6EmAO+BqVkImZcmP1JsLtr+OM+jihXIILACEJwhOKPtZth9zrLYkXWB1nCaDxHp +XEUpp6UPCQNgNX8NCghnJr5gis/SmYppgFlO9R9yZ7/LtP0tUX0CmhOeqGMnHt4R +F8n8D7EBwMWvWjlUbsDkMKX4JORgojguHJZciWQC1gVRwJ0iTH/ImtzDnbQhUm9t +YW4gQXJ1dHl1bnlhbiA8YXJ1dEBuZ2lueC5jb20+iQJOBBMBCAA4FiEEQzh4Jd2x +u5fsNrpdAHyNfBXYc2kFAmYXyiQCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AA +CgkQAHyNfBXYc2kRFw//VFuCnW3EwoLCWWgWCikgI9kbVDr0/Qiyf2Gb9sfOyzBN +q/+ZGjTs7EqTHbYUiCTgjy8t0SNKizoCXjSWLToTAXhOeTY3wDuHkdc3C2OPMPgm +HPGmdnfplmsZjj689sy0MTnlLmU/87texR/f3REAKtchVjo5AojuZxXJi+ryBvoz +KXi82M1JaYlIr15T+OiRtfZ3cgfTkb5CRa0YRV7QQ1zhOiF0AFKVVikFwRuquphT +y2cSLILLzOpwG/CjMJzO4VOASmGJmdicIfYSsZSzz37RrcfeYwR6quJ55Y9QF9IU +fg5AHWufpXaf6FbMsW1U1mOq0tMvwvdcO+u5I5SBj6IkqO4zavmW/i5zkxaq96wF +Qn6+oRkqHnNNn0hl/B4MWdEjDJsaDXfkQ3Snn4Bfl1JPT6cH2NDVYQn1siIOim/W +G5lhGLNB1TOAVLHblQ2xILadK0T33y6lfRUV3BOW01BDoF0ndyd7LjG5Di/cjfSo +1hvhTkW7QJGfzVV4IAAxEyHKlmgONfggZoplqukuPsq7eNNRPhvlZq632QXIqt6Y +xE43Nk0O41rX/tWtB7eNcPvfNOc+sGljnCSwpRWyx9xO7plELVD9KdtcyHrIgora +Flh7KsSbppSQ/iUKRNP+lfCQsMa1yrnQyxazss8OGlB7YpUJL4trQW35f/jXFD+J +ATMEEAEIAB0WIQRzOJcwae0/RD9NN9+mT9Wxets5qAUCZh2mQQAKCRCmT9Wxets5 +qPBjB/0SDkET7h/Vw2PJKxuYujsL+tn3SKXshgyCM2u00njJM9TqpZbZV681unKM +l8uHtj9b0Z4U0nHoNEC37wI5FJlxy1hLBw5f2fd/yi8LsD1KP2htjMUW+I2xjcdo +FusQsIF0s8SyW1DZ3vvN2WcZpKHwub1sY9ZFBfxRc6w+33N4dJwXVXP57kj3Ci8j +LDLfkaKyiuYgMtFYZiKKX0tfvaM5pXxLvLOzma9vwfjIMIllooZHDSI65jrbmMv0 +rfDKOX9Ws5Xi8n85jq6Oyq28QPLZUsmymCbhvBwq4FcdiyTl9sxCY4HLq0MzmJJ5 +DMhlFd2Ds3BopFTWCB2fvYyVoXRaiQEzBBABCAAdFiEEVzv9az2PvGQQeaarq/W9 +gnvZv2IFAmYdpugACgkQq/W9gnvZv2Jk4Qf+N0P/7FIHowlO01XmBB5KaztBmVb2 +Tj+jtYgPDHRf86O0kW40Rjx++zMlIRNWK4Ue5PKAi82Yue5uvZcVlpWpx/sMvL+N +C4Xds3Q3qnkxkoemoIMqUKGvePjBpyUWArBkBQ3FrvZtywnzyFWNrvOpeM+5HIuz +WBri/SHBHzQm1/Jl2r5pHcbUdSxB2o1v3f+SaS2vGxwigIf8v44pRfyeWgkoxYgN ++2zR0Ing6URZCYkAbwILsmmWGxJIuq+N9Xs1CQ1WZd5S78p/JBMDQ1prUDLCLFMc +AvlZpQ0HvzEbKGiIVNa1LEQRF4ZWjQOHaPJhg/D3r/Q7VaFlgsOqrwtQaYkCMwQQ +AQgAHRYhBPlNVLwMXWpkF8jPP+gsERivlN9uBQJmHkpZAAoJEOgsERivlN9u8fYQ +AK0s0CvQNTXrg/Oe92Ajj+CpFIGhEUgXsufpg3OF+4doXOoRrVcv6y/0dGC+u899 +Qiz5rzP8JkgT3Bvs/oFbQnESX7zob/GuBiRAnaanQQGjQsc8tXUcIgIB8vZI6Hxr +BZYyjXMrc1fAp1zy6F3YfVtjntp6Zt740zlcFSHPL6pKeNC8lCas7f7EPGm9ERlf +XvPOsMyKVDRTrtYVrQ17pgmWzMFl9eYzAV81X/cK7O9BmTvLb9HB9THl9QM6iKWd +UPNNhMseMA55i1y1trvv2rQSP2tm7xAijlffNu/LHyVjOJA+63rk9JqpQi2O/sI6 +naCZ5kLky3+OisbzJLtsIv3KWGF4jnpZJwPI97UbRAxrBCPd8BDXW06qQ0xfF9GA +sW46IDnf5uNV5Fj9T1IhZUUCU6XwwhcTENwcaJ2hubPzW19gvxieRpxdvnXhjUxR +UgqgFjtlpyBSABYr2REiaBTHkR1qVMa8tThpSyzfmfBNe9chBGQBdDMzTTUDf4dU +cw4UGGPXqrBEapleoZBszXLrZxQxCNmLGFBW3vcJDfRRTvg/OMCIwD72kfd8KY1t +SRRi5vQ3CvV8E0EEXshjxVk0fwS+5muM1thWZM4xCSgyH6Ka/5biMeUv1VNcKJne +J51xs9jfS/JltrT/ahWG4J9msJFtmYyrLh/nMxccXK75uQINBGYXyiQBEAC5tT5O +uysy75BcwAg8jIK+Cw6hNy+riOoCIzsMen8ps4tyDFLmRdpJmVOpmtvESaix2MHf +Hc/t9hOsQ8LmF3kDG/JisDXcB/v28EOiDpp5Ug/5UOFBnbu4DkxbakJF8KF/rQ9t +i29lt03saGCf2XbqzTLI6FvZ2TT8hDwAZF5aOtDEHV3ChBPn6gplnJADiZ9DioMZ +ji1HnL8Zu4IYHMNOgpxULi6TMhBH/MkHbyycOdt/EsQFamnLGeV8KR2fubYjrpbH +pLZzSRepQyvKIhHAFj6DUeDyEt2XAitxI8YI40IVO75Zu8ZZq0qYGML8Am+t6ZjJ +3ZR8/DWjxRUYeo+YVEe5f+oRl5GRNkLtGvTAD38Nb2/7SUYdSXA3y3Ocfo/bySwa +qggeFpDqK5eHXmrO4hvRqYoEyNyW4VQlGyvYq4s2cLeCF/S2w6dV8OFsksIoq8uq +R1/IQ8Bonsf7iAYpsMAZZOGKiJzr01W3GA4Ka3B/MmZP5CysUhFlFxMsDr3/TWfg +p3CHd5yGAnuWWWkjqVQzx0tcub3gyDsHCPuws8P2OKJ2lzNPqpp08MjYMMRZb4Y6 +9REXkKw7kXU8zM5+1IpW2U+z83NU86QR08PTpjATz05ltdGqF82Z+Ygl2nav8oqV +RqNd/k+WE60e1eJmgykjmz6nPbm0S2jt1C7QLQARAQABiQI2BBgBCAAgFiEEQzh4 +Jd2xu5fsNrpdAHyNfBXYc2kFAmYXyiQCGwwACgkQAHyNfBXYc2mTihAAqB+sv9lw +kRorE6iXwvvj2Dt2iIy7jc1AhZQOH/j7B4GHpV3Ej/ptdUwuzj/aX5EnEeDPZ2JU +sSKy2q0RpKGKdKOvgy5yVfd8xqujkawXv26QU53mgyfgQCZLhFFhq0MIAqnxPb8h +SCQeol18Wqs++LjeDMwkgMrHJeNhW2U2llqTS37YfRMOo0Vr022ZHlMlkyMz1sQH ++C2/nzmmtkI4+vlPeccoN+3239YzndW1+XM8S3dXNcsGTyLAbkCowfpuqQdIP0MY +lBwx/Xj9fxBNAuqGVCjrjGMg7mozMkeCDzrAoZiaD3Kud8zSs9VpAyAymrPQJSSS +96b+vr2mDKbV11QJeJZv/d02n4JMjK7Ai//3j/TqkJF4UoYH45g5hvGSrym1UKrf +n8TqHdtTFjcxAMXLbWICHdDk7/0ole8Bl8csiSHyKy/sGJ0b/7zcB88CS8OfsR3C +OanK13emeD6rHOp8wEWA1/PA1JoAC5suS/uIgPWa5ujLaViJ9pW6ohfzMqOtLABF +BB/FgD/qgPF+uTPPLQZw3XO8Q61kFq6x0RJGNgBEOpseounx+T6FCxZqrvjWm/WK +VQUiRBtJIvD7Z8UCP+NUzdj3hwLAXpXrPz0gkcbI+hdlTJHCC6i61Qf5OIWnhtw6 +kZv2zEcTtzlAYNEumy8KrJzICmPLS7BEC8w= +=ilJ3 +-----END PGP PUBLIC KEY BLOCK----- From cd2d231dd0a2a37834604ebd7830570742f2fbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 17:41:57 +0200 Subject: [PATCH 30/89] New upstream version 1.26.0 --- CHANGES | 106 +- CHANGES.ru | 111 +- LICENSE | 2 +- auto/install | 2 +- auto/lib/geoip/conf | 17 + auto/lib/google-perftools/conf | 16 + auto/lib/libgd/conf | 17 + auto/lib/openssl/conf | 63 +- auto/lib/pcre/conf | 16 + auto/make | 5 +- auto/modules | 109 +- auto/options | 15 + auto/os/conf | 15 + auto/os/linux | 48 + auto/os/win32 | 2 +- auto/sources | 2 +- auto/unix | 48 + contrib/vim/syntax/nginx.vim | 217 +- src/core/nginx.c | 56 +- src/core/nginx.h | 4 +- src/core/ngx_bpf.c | 143 ++ src/core/ngx_bpf.h | 43 + src/core/ngx_connection.c | 83 + src/core/ngx_connection.h | 8 +- src/core/ngx_core.h | 7 + src/core/ngx_inet.c | 2 +- src/core/ngx_module.h | 5 + src/core/ngx_queue.c | 52 +- src/core/ngx_queue.h | 3 + src/core/ngx_regex.c | 13 +- src/event/ngx_event.c | 34 +- src/event/ngx_event_openssl.c | 73 +- src/event/ngx_event_openssl.h | 13 +- src/event/ngx_event_openssl_stapling.c | 2 +- src/event/ngx_event_pipe.c | 8 +- src/event/ngx_event_udp.c | 13 +- src/event/ngx_event_udp.h | 8 + src/event/quic/bpf/bpfgen.sh | 113 + src/event/quic/bpf/makefile | 30 + .../quic/bpf/ngx_quic_reuseport_helper.c | 140 ++ src/event/quic/ngx_event_quic.c | 1452 +++++++++++ src/event/quic/ngx_event_quic.h | 129 + src/event/quic/ngx_event_quic_ack.c | 1188 +++++++++ src/event/quic/ngx_event_quic_ack.h | 30 + src/event/quic/ngx_event_quic_bpf.c | 657 +++++ src/event/quic/ngx_event_quic_bpf_code.c | 88 + src/event/quic/ngx_event_quic_connection.h | 305 +++ src/event/quic/ngx_event_quic_connid.c | 502 ++++ src/event/quic/ngx_event_quic_connid.h | 29 + src/event/quic/ngx_event_quic_frames.c | 894 +++++++ src/event/quic/ngx_event_quic_frames.h | 45 + src/event/quic/ngx_event_quic_migration.c | 1003 ++++++++ src/event/quic/ngx_event_quic_migration.h | 45 + .../quic/ngx_event_quic_openssl_compat.c | 651 +++++ .../quic/ngx_event_quic_openssl_compat.h | 59 + src/event/quic/ngx_event_quic_output.c | 1319 ++++++++++ src/event/quic/ngx_event_quic_output.h | 40 + src/event/quic/ngx_event_quic_protection.c | 1243 ++++++++++ src/event/quic/ngx_event_quic_protection.h | 120 + src/event/quic/ngx_event_quic_socket.c | 237 ++ src/event/quic/ngx_event_quic_socket.h | 28 + src/event/quic/ngx_event_quic_ssl.c | 590 +++++ src/event/quic/ngx_event_quic_ssl.h | 19 + src/event/quic/ngx_event_quic_streams.c | 1820 ++++++++++++++ src/event/quic/ngx_event_quic_streams.h | 44 + src/event/quic/ngx_event_quic_tokens.c | 309 +++ src/event/quic/ngx_event_quic_tokens.h | 34 + src/event/quic/ngx_event_quic_transport.c | 2202 +++++++++++++++++ src/event/quic/ngx_event_quic_transport.h | 397 +++ src/event/quic/ngx_event_quic_udp.c | 420 ++++ src/http/modules/ngx_http_access_module.c | 2 +- src/http/modules/ngx_http_fastcgi_module.c | 5 +- src/http/modules/ngx_http_geo_module.c | 8 +- src/http/modules/ngx_http_geoip_module.c | 2 +- src/http/modules/ngx_http_referer_module.c | 2 +- src/http/modules/ngx_http_rewrite_module.c | 1 + src/http/modules/ngx_http_scgi_module.c | 5 +- src/http/modules/ngx_http_ssi_filter_module.c | 2 +- src/http/modules/ngx_http_ssl_module.c | 209 +- src/http/modules/ngx_http_ssl_module.h | 5 - src/http/modules/ngx_http_uwsgi_module.c | 5 +- src/http/ngx_http.c | 28 +- src/http/ngx_http.h | 12 +- src/http/ngx_http_copy_filter_module.c | 45 +- src/http/ngx_http_core_module.c | 70 +- src/http/ngx_http_core_module.h | 4 + src/http/ngx_http_file_cache.c | 89 +- src/http/ngx_http_huff_decode.c | 6 +- src/http/ngx_http_parse.c | 3 - src/http/ngx_http_request.c | 163 +- src/http/ngx_http_request.h | 6 +- src/http/ngx_http_request_body.c | 28 + src/http/ngx_http_upstream.c | 43 +- src/http/ngx_http_variables.c | 6 +- src/http/ngx_http_write_filter_module.c | 8 + src/http/v2/ngx_http_v2.c | 399 +-- src/http/v2/ngx_http_v2.h | 32 +- src/http/v2/ngx_http_v2_filter_module.c | 622 +---- src/http/v2/ngx_http_v2_module.c | 124 +- src/http/v2/ngx_http_v2_module.h | 17 - src/http/v3/ngx_http_v3.c | 111 + src/http/v3/ngx_http_v3.h | 160 ++ src/http/v3/ngx_http_v3_encode.c | 304 +++ src/http/v3/ngx_http_v3_encode.h | 34 + src/http/v3/ngx_http_v3_filter_module.c | 852 +++++++ src/http/v3/ngx_http_v3_module.c | 393 +++ src/http/v3/ngx_http_v3_parse.c | 1933 +++++++++++++++ src/http/v3/ngx_http_v3_parse.h | 146 ++ src/http/v3/ngx_http_v3_request.c | 1710 +++++++++++++ src/http/v3/ngx_http_v3_table.c | 715 ++++++ src/http/v3/ngx_http_v3_table.h | 58 + src/http/v3/ngx_http_v3_uni.c | 624 +++++ src/http/v3/ngx_http_v3_uni.h | 32 + src/mail/ngx_mail_core_module.c | 4 +- src/mail/ngx_mail_handler.c | 6 +- src/mail/ngx_mail_ssl_module.c | 53 - src/mail/ngx_mail_ssl_module.h | 1 - src/os/unix/ngx_darwin_init.c | 16 +- src/os/unix/ngx_errno.h | 1 + src/os/unix/ngx_files.c | 4 + src/os/unix/ngx_linux_sendfile_chain.c | 1 + src/os/unix/ngx_posix_init.c | 5 +- src/os/unix/ngx_process_cycle.c | 10 +- src/os/unix/ngx_socket.h | 2 + src/os/win32/ngx_errno.h | 1 + src/os/win32/ngx_files.h | 3 +- src/os/win32/ngx_process_cycle.c | 2 +- src/os/win32/ngx_socket.h | 2 + src/os/win32/ngx_win32_config.h | 6 +- src/stream/ngx_stream.c | 904 +++++-- src/stream/ngx_stream.h | 181 +- src/stream/ngx_stream_access_module.c | 2 +- src/stream/ngx_stream_core_module.c | 765 ++++-- src/stream/ngx_stream_geo_module.c | 8 +- src/stream/ngx_stream_geoip_module.c | 2 +- src/stream/ngx_stream_handler.c | 10 +- src/stream/ngx_stream_pass_module.c | 327 +++ src/stream/ngx_stream_ssl_module.c | 410 ++- src/stream/ngx_stream_ssl_module.h | 7 +- src/stream/ngx_stream_ssl_preread_module.c | 57 +- src/stream/ngx_stream_variables.c | 23 + 141 files changed, 27334 insertions(+), 2065 deletions(-) create mode 100644 src/core/ngx_bpf.c create mode 100644 src/core/ngx_bpf.h create mode 100644 src/event/quic/bpf/bpfgen.sh create mode 100644 src/event/quic/bpf/makefile create mode 100644 src/event/quic/bpf/ngx_quic_reuseport_helper.c create mode 100644 src/event/quic/ngx_event_quic.c create mode 100644 src/event/quic/ngx_event_quic.h create mode 100644 src/event/quic/ngx_event_quic_ack.c create mode 100644 src/event/quic/ngx_event_quic_ack.h create mode 100644 src/event/quic/ngx_event_quic_bpf.c create mode 100644 src/event/quic/ngx_event_quic_bpf_code.c create mode 100644 src/event/quic/ngx_event_quic_connection.h create mode 100644 src/event/quic/ngx_event_quic_connid.c create mode 100644 src/event/quic/ngx_event_quic_connid.h create mode 100644 src/event/quic/ngx_event_quic_frames.c create mode 100644 src/event/quic/ngx_event_quic_frames.h create mode 100644 src/event/quic/ngx_event_quic_migration.c create mode 100644 src/event/quic/ngx_event_quic_migration.h create mode 100644 src/event/quic/ngx_event_quic_openssl_compat.c create mode 100644 src/event/quic/ngx_event_quic_openssl_compat.h create mode 100644 src/event/quic/ngx_event_quic_output.c create mode 100644 src/event/quic/ngx_event_quic_output.h create mode 100644 src/event/quic/ngx_event_quic_protection.c create mode 100644 src/event/quic/ngx_event_quic_protection.h create mode 100644 src/event/quic/ngx_event_quic_socket.c create mode 100644 src/event/quic/ngx_event_quic_socket.h create mode 100644 src/event/quic/ngx_event_quic_ssl.c create mode 100644 src/event/quic/ngx_event_quic_ssl.h create mode 100644 src/event/quic/ngx_event_quic_streams.c create mode 100644 src/event/quic/ngx_event_quic_streams.h create mode 100644 src/event/quic/ngx_event_quic_tokens.c create mode 100644 src/event/quic/ngx_event_quic_tokens.h create mode 100644 src/event/quic/ngx_event_quic_transport.c create mode 100644 src/event/quic/ngx_event_quic_transport.h create mode 100644 src/event/quic/ngx_event_quic_udp.c create mode 100644 src/http/v3/ngx_http_v3.c create mode 100644 src/http/v3/ngx_http_v3.h create mode 100644 src/http/v3/ngx_http_v3_encode.c create mode 100644 src/http/v3/ngx_http_v3_encode.h create mode 100644 src/http/v3/ngx_http_v3_filter_module.c create mode 100644 src/http/v3/ngx_http_v3_module.c create mode 100644 src/http/v3/ngx_http_v3_parse.c create mode 100644 src/http/v3/ngx_http_v3_parse.h create mode 100644 src/http/v3/ngx_http_v3_request.c create mode 100644 src/http/v3/ngx_http_v3_table.c create mode 100644 src/http/v3/ngx_http_v3_table.h create mode 100644 src/http/v3/ngx_http_v3_uni.c create mode 100644 src/http/v3/ngx_http_v3_uni.h create mode 100644 src/stream/ngx_stream_pass_module.c diff --git a/CHANGES b/CHANGES index 6774b29..f60c885 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,109 @@ -Changes with nginx 1.24.0 11 Apr 2023 +Changes with nginx 1.26.0 23 Apr 2024 - *) 1.24.x stable branch. + *) 1.26.x stable branch. + + +Changes with nginx 1.25.5 16 Apr 2024 + + *) Feature: virtual servers in the stream module. + + *) Feature: the ngx_stream_pass_module. + + *) Feature: the "deferred", "accept_filter", and "setfib" parameters of + the "listen" directive in the stream module. + + *) Feature: cache line size detection for some architectures. + Thanks to Piotr Sikora. + + *) Feature: support for Homebrew on Apple Silicon. + Thanks to Piotr Sikora. + + *) Bugfix: Windows cross-compilation bugfixes and improvements. + Thanks to Piotr Sikora. + + *) Bugfix: unexpected connection closure while using 0-RTT in QUIC. + Thanks to Vladimir Khomutov. + + +Changes with nginx 1.25.4 14 Feb 2024 + + *) Security: when using HTTP/3 a segmentation fault might occur in a + worker process while processing a specially crafted QUIC session + (CVE-2024-24989, CVE-2024-24990). + + *) Bugfix: connections with pending AIO operations might be closed + prematurely during graceful shutdown of old worker processes. + + *) Bugfix: socket leak alerts no longer logged when fast shutdown was + requested after graceful shutdown of old worker processes. + + *) Bugfix: a socket descriptor error, a socket leak, or a segmentation + fault in a worker process (for SSL proxying) might occur if AIO was + used in a subrequest. + + *) Bugfix: a segmentation fault might occur in a worker process if SSL + proxying was used along with the "image_filter" directive and errors + with code 415 were redirected with the "error_page" directive. + + *) Bugfixes and improvements in HTTP/3. + + +Changes with nginx 1.25.3 24 Oct 2023 + + *) Change: improved detection of misbehaving clients when using HTTP/2. + + *) Feature: startup speedup when using a large number of locations. + Thanks to Yusuke Nojima. + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2 without SSL; the bug had appeared in 1.25.1. + + *) Bugfix: the "Status" backend response header line with an empty + reason phrase was handled incorrectly. + + *) Bugfix: memory leak during reconfiguration when using the PCRE2 + library. + Thanks to ZhenZhong Wu. + + *) Bugfixes and improvements in HTTP/3. + + +Changes with nginx 1.25.2 15 Aug 2023 + + *) Feature: path MTU discovery when using HTTP/3. + + *) Feature: TLS_AES_128_CCM_SHA256 cipher suite support when using + HTTP/3. + + *) Change: now nginx uses appname "nginx" when loading OpenSSL + configuration. + + *) Change: now nginx does not try to load OpenSSL configuration if the + --with-openssl option was used to built OpenSSL and the OPENSSL_CONF + environment variable is not set. + + *) Bugfix: in the $body_bytes_sent variable when using HTTP/3. + + *) Bugfix: in HTTP/3. + + +Changes with nginx 1.25.1 13 Jun 2023 + + *) Feature: the "http2" directive, which enables HTTP/2 on a per-server + basis; the "http2" parameter of the "listen" directive is now + deprecated. + + *) Change: HTTP/2 server push support has been removed. + + *) Change: the deprecated "ssl" directive is not supported anymore. + + *) Bugfix: in HTTP/3 when using OpenSSL. + + +Changes with nginx 1.25.0 23 May 2023 + + *) Feature: experimental HTTP/3 support. Changes with nginx 1.23.4 28 Mar 2023 diff --git a/CHANGES.ru b/CHANGES.ru index 544f15b..7e42b52 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,7 +1,114 @@ -Изменения в nginx 1.24.0 11.04.2023 +Изменения в nginx 1.26.0 23.04.2024 - *) Стабильная ветка 1.24.x. + *) Стабильная ветка 1.26.x. + + +Изменения в nginx 1.25.5 16.04.2024 + + *) Добавление: виртуальные сервера в модуле stream. + + *) Добавление: модуль ngx_stream_pass_module. + + *) Добавление: параметры deferred, accept_filter и setfib директивы + listen в модуле stream. + + *) Добавление: определение размера строки кеша процессора для некоторых + архитектур. + Спасибо Piotr Sikora. + + *) Добавление: поддержка Homebrew на Apple Silicon. + Спасибо Piotr Sikora. + + *) Исправление: улучшения и исправления кросс-компиляции для Windows. + Спасибо Piotr Sikora. + + *) Исправление: неожиданное закрытие соединения при использовании 0-RTT + в QUIC. + Спасибо Владимиру Хомутову. + + +Изменения в nginx 1.25.4 14.02.2024 + + *) Безопасность: при использовании HTTP/3 в рабочем процессе мог + произойти segmentation fault во время обработки специально созданной + QUIC-сессии (CVE-2024-24989, CVE-2024-24990). + + *) Исправление: соединения с незавершенными AIO-операциями могли + закрываться преждевременно во время плавного завершения старых + рабочих процессов. + + *) Исправление: теперь nginx не пишет в лог сообщения об утечке сокетов, + если во время плавного завершения старых рабочих процессов было + запрошено быстрое завершение. + + *) Исправление: при использовании AIO в подзапросе могла происходить + ошибка на сокете, утечка сокетов, либо segmentation fault в рабочем + процессе (при SSL-проксировании). + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовалось SSL-проксирование и директива image_filter, а + ошибки с кодом 415 перенаправлялись с помощью директивы error_page. + + *) Исправления и улучшения в HTTP/3. + + +Изменения в nginx 1.25.3 24.10.2023 + + *) Изменение: улучшено детектирование некорректного поведения клиентов + при использовании HTTP/2. + + *) Добавление: уменьшение времени запуска при использовании большого + количества location'ов. + Спасибо Yusuke Nojima. + + *) Исправление: при использовании HTTP/2 без SSL в рабочем процессе мог + произойти segmentation fault; ошибка появилась в 1.25.1. + + *) Исправление: строка "Status" в заголовке ответа бэкенда с пустой + поясняющей фразой обрабатывалась некорректно. + + *) Исправление: утечки памяти во время переконфигурации при + использовании библиотеки PCRE2. + Спасибо ZhenZhong Wu. + + *) Исправления и улучшения в HTTP/3. + + +Изменения в nginx 1.25.2 15.08.2023 + + *) Добавление: path MTU discovery при использовании HTTP/3. + + *) Добавление: поддержка шифра TLS_AES_128_CCM_SHA256 при использовании + HTTP/3. + + *) Изменение: теперь при загрузке конфигурации OpenSSL nginx использует + appname "nginx". + + *) Изменение: теперь nginx не пытается загружать конфигурацию OpenSSL, + если для сборки OpenSSL использовался параметр --with-openssl и + переменная окружения OPENSSL_CONF не установлена. + + *) Исправление: в переменной $body_bytes_sent при использовании HTTP/3. + + *) Исправление: в HTTP/3. + + +Изменения в nginx 1.25.1 13.06.2023 + + *) Добавление: директива http2, позволяющая включать HTTP/2 в отдельных + блоках server; параметр http2 директивы listen объявлен устаревшим. + + *) Изменение: поддержка HTTP/2 server push упразднена. + + *) Изменение: устаревшая директива ssl больше не поддерживается. + + *) Исправление: в HTTP/3 при использовании OpenSSL. + + +Изменения в nginx 1.25.0 23.05.2023 + + *) Добавление: экспериментальная поддержка HTTP/3. Изменения в nginx 1.23.4 28.03.2023 diff --git a/LICENSE b/LICENSE index fdedcb7..985470e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2021 Igor Sysoev - * Copyright (C) 2011-2022 Nginx, Inc. + * Copyright (C) 2011-2024 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/auto/install b/auto/install index c764fdd..7f73e4b 100644 --- a/auto/install +++ b/auto/install @@ -112,7 +112,7 @@ install: build $NGX_INSTALL_PERL_MODULES test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \\ || mv '\$(DESTDIR)$NGX_SBIN_PATH' \\ '\$(DESTDIR)$NGX_SBIN_PATH.old' - cp $NGX_OBJS/nginx '\$(DESTDIR)$NGX_SBIN_PATH' + cp $NGX_OBJS/nginx$ngx_binext '\$(DESTDIR)$NGX_SBIN_PATH' test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \\ || mkdir -p '\$(DESTDIR)$NGX_CONF_PREFIX' diff --git a/auto/lib/geoip/conf b/auto/lib/geoip/conf index 8302aae..47165b1 100644 --- a/auto/lib/geoip/conf +++ b/auto/lib/geoip/conf @@ -64,6 +64,23 @@ if [ $ngx_found = no ]; then fi +if [ $ngx_found = no ]; then + + # Homebrew on Apple Silicon + + ngx_feature="GeoIP library in /opt/homebrew/" + ngx_feature_path="/opt/homebrew/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/homebrew/lib -L/opt/homebrew/lib -lGeoIP" + else + ngx_feature_libs="-L/opt/homebrew/lib -lGeoIP" + fi + + . auto/feature +fi + + if [ $ngx_found = yes ]; then CORE_INCS="$CORE_INCS $ngx_feature_path" diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf index 7f1a911..94dadac 100644 --- a/auto/lib/google-perftools/conf +++ b/auto/lib/google-perftools/conf @@ -46,6 +46,22 @@ if [ $ngx_found = no ]; then fi +if [ $ngx_found = no ]; then + + # Homebrew on Apple Silicon + + ngx_feature="Google perftools in /opt/homebrew/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/homebrew/lib -L/opt/homebrew/lib -lprofiler" + else + ngx_feature_libs="-L/opt/homebrew/lib -lprofiler" + fi + + . auto/feature +fi + + if [ $ngx_found = yes ]; then CORE_LIBS="$CORE_LIBS $ngx_feature_libs" diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf index 6786397..07f5656 100644 --- a/auto/lib/libgd/conf +++ b/auto/lib/libgd/conf @@ -65,6 +65,23 @@ if [ $ngx_found = no ]; then fi +if [ $ngx_found = no ]; then + + # Homebrew on Apple Silicon + + ngx_feature="GD library in /opt/homebrew/" + ngx_feature_path="/opt/homebrew/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/homebrew/lib -L/opt/homebrew/lib -lgd" + else + ngx_feature_libs="-L/opt/homebrew/lib -lgd" + fi + + . auto/feature +fi + + if [ $ngx_found = yes ]; then CORE_INCS="$CORE_INCS $ngx_feature_path" diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf index 4fb52df..fdf430d 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -5,12 +5,19 @@ if [ $OPENSSL != NONE ]; then + have=NGX_OPENSSL . auto/have + have=NGX_SSL . auto/have + + have=NGX_OPENSSL_NO_CONFIG . auto/have + + if [ $USE_OPENSSL_QUIC = YES ]; then + have=NGX_QUIC . auto/have + have=NGX_QUIC_OPENSSL_COMPAT . auto/have + fi + case "$CC" in cl | bcc32) - have=NGX_OPENSSL . auto/have - have=NGX_SSL . auto/have - CFLAGS="$CFLAGS -DNO_SYS_TYPES_H" CORE_INCS="$CORE_INCS $OPENSSL/openssl/include" @@ -33,9 +40,6 @@ if [ $OPENSSL != NONE ]; then ;; *) - have=NGX_OPENSSL . auto/have - have=NGX_SSL . auto/have - CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include" CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h" CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a" @@ -118,11 +122,58 @@ else . auto/feature fi + if [ $ngx_found = no ]; then + + # Homebrew on Apple Silicon + + ngx_feature="OpenSSL library in /opt/homebrew/" + ngx_feature_path="/opt/homebrew/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/homebrew/lib -L/opt/homebrew/lib -lssl -lcrypto" + else + ngx_feature_libs="-L/opt/homebrew/lib -lssl -lcrypto" + fi + + ngx_feature_libs="$ngx_feature_libs $NGX_LIBDL $NGX_LIBPTHREAD" + + . auto/feature + fi + if [ $ngx_found = yes ]; then have=NGX_SSL . auto/have CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" OPENSSL=YES + + if [ $USE_OPENSSL_QUIC = YES ]; then + + ngx_feature="OpenSSL QUIC support" + ngx_feature_name="NGX_QUIC" + ngx_feature_test="SSL_set_quic_method(NULL, NULL)" + . auto/feature + + if [ $ngx_found = no ]; then + have=NGX_QUIC_OPENSSL_COMPAT . auto/have + + ngx_feature="OpenSSL QUIC compatibility" + ngx_feature_test="SSL_CTX_add_custom_ext(NULL, 0, 0, + NULL, NULL, NULL, NULL, NULL)" + . auto/feature + fi + + if [ $ngx_found = no ]; then +cat << END + +$0: error: certain modules require OpenSSL QUIC support. +You can either do not enable the modules, or install the OpenSSL library with +QUIC support into the system, or build the OpenSSL library with QUIC support +statically from the source with nginx by using --with-openssl= option. + +END + exit 1 + fi + fi fi fi diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf index 20c1caf..cdf1809 100644 --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -182,6 +182,22 @@ else . auto/feature fi + if [ $ngx_found = no ]; then + + # Homebrew on Apple Silicon + + ngx_feature="PCRE library in /opt/homebrew/" + ngx_feature_path="/opt/homebrew/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/homebrew/lib -L/opt/homebrew/lib -lpcre" + else + ngx_feature_libs="-L/opt/homebrew/lib -lpcre" + fi + + . auto/feature + fi + if [ $ngx_found = yes ]; then CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" diff --git a/auto/make b/auto/make index ef7c9f6..25ee3fb 100644 --- a/auto/make +++ b/auto/make @@ -6,9 +6,10 @@ echo "creating $NGX_MAKEFILE" mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \ + $NGX_OBJS/src/event/quic \ $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \ - $NGX_OBJS/src/http $NGX_OBJS/src/http/v2 $NGX_OBJS/src/http/modules \ - $NGX_OBJS/src/http/modules/perl \ + $NGX_OBJS/src/http $NGX_OBJS/src/http/v2 $NGX_OBJS/src/http/v3 \ + $NGX_OBJS/src/http/modules $NGX_OBJS/src/http/modules/perl \ $NGX_OBJS/src/mail \ $NGX_OBJS/src/stream \ $NGX_OBJS/src/misc diff --git a/auto/modules b/auto/modules index 94867bf..1a5e421 100644 --- a/auto/modules +++ b/auto/modules @@ -102,7 +102,7 @@ if [ $HTTP = YES ]; then fi - if [ $HTTP_V2 = YES ]; then + if [ $HTTP_V2 = YES -o $HTTP_V3 = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_HUFF_SRCS" fi @@ -124,6 +124,7 @@ if [ $HTTP = YES ]; then # ngx_http_header_filter # ngx_http_chunked_filter # ngx_http_v2_filter + # ngx_http_v3_filter # ngx_http_range_header_filter # ngx_http_gzip_filter # ngx_http_postpone_filter @@ -156,6 +157,7 @@ if [ $HTTP = YES ]; then ngx_http_header_filter_module \ ngx_http_chunked_filter_module \ ngx_http_v2_filter_module \ + ngx_http_v3_filter_module \ ngx_http_range_header_filter_module \ ngx_http_gzip_filter_module \ ngx_http_postpone_filter_module \ @@ -217,6 +219,17 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_V3 = YES ]; then + ngx_module_name=ngx_http_v3_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/v3/ngx_http_v3_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_V3 + + . auto/module + fi + if :; then ngx_module_name=ngx_http_range_header_filter_module ngx_module_incs= @@ -410,7 +423,6 @@ if [ $HTTP = YES ]; then if [ $HTTP_V2 = YES ]; then have=NGX_HTTP_V2 . auto/have - have=NGX_HTTP_HEADERS . auto/have ngx_module_name=ngx_http_v2_module ngx_module_incs=src/http/v2 @@ -426,6 +438,32 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_V3 = YES ]; then + USE_OPENSSL_QUIC=YES + HTTP_SSL=YES + + have=NGX_HTTP_V3 . auto/have + + ngx_module_name=ngx_http_v3_module + ngx_module_incs=src/http/v3 + ngx_module_deps="src/http/v3/ngx_http_v3.h \ + src/http/v3/ngx_http_v3_encode.h \ + src/http/v3/ngx_http_v3_parse.h \ + src/http/v3/ngx_http_v3_table.h \ + src/http/v3/ngx_http_v3_uni.h" + ngx_module_srcs="src/http/v3/ngx_http_v3.c \ + src/http/v3/ngx_http_v3_encode.c \ + src/http/v3/ngx_http_v3_parse.c \ + src/http/v3/ngx_http_v3_table.c \ + src/http/v3/ngx_http_v3_uni.c \ + src/http/v3/ngx_http_v3_request.c \ + src/http/v3/ngx_http_v3_module.c" + ngx_module_libs= + ngx_module_link=$HTTP_V3 + + . auto/module + fi + if :; then ngx_module_name=ngx_http_static_module ngx_module_incs= @@ -1128,6 +1166,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_PASS = YES ]; then + ngx_module_name=ngx_stream_pass_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_pass_module.c + ngx_module_libs= + ngx_module_link=$STREAM_PASS + + . auto/module + fi + if [ $STREAM_SET = YES ]; then ngx_module_name=ngx_stream_set_module ngx_module_deps= @@ -1272,6 +1320,63 @@ if [ $USE_OPENSSL = YES ]; then fi +if [ $USE_OPENSSL_QUIC = YES ]; then + ngx_module_type=CORE + ngx_module_name=ngx_quic_module + ngx_module_incs= + ngx_module_deps="src/event/quic/ngx_event_quic.h \ + src/event/quic/ngx_event_quic_transport.h \ + src/event/quic/ngx_event_quic_protection.h \ + src/event/quic/ngx_event_quic_connection.h \ + src/event/quic/ngx_event_quic_frames.h \ + src/event/quic/ngx_event_quic_connid.h \ + src/event/quic/ngx_event_quic_migration.h \ + src/event/quic/ngx_event_quic_streams.h \ + src/event/quic/ngx_event_quic_ssl.h \ + src/event/quic/ngx_event_quic_tokens.h \ + src/event/quic/ngx_event_quic_ack.h \ + src/event/quic/ngx_event_quic_output.h \ + src/event/quic/ngx_event_quic_socket.h \ + src/event/quic/ngx_event_quic_openssl_compat.h" + ngx_module_srcs="src/event/quic/ngx_event_quic.c \ + src/event/quic/ngx_event_quic_udp.c \ + src/event/quic/ngx_event_quic_transport.c \ + src/event/quic/ngx_event_quic_protection.c \ + src/event/quic/ngx_event_quic_frames.c \ + src/event/quic/ngx_event_quic_connid.c \ + src/event/quic/ngx_event_quic_migration.c \ + src/event/quic/ngx_event_quic_streams.c \ + src/event/quic/ngx_event_quic_ssl.c \ + src/event/quic/ngx_event_quic_tokens.c \ + src/event/quic/ngx_event_quic_ack.c \ + src/event/quic/ngx_event_quic_output.c \ + src/event/quic/ngx_event_quic_socket.c \ + src/event/quic/ngx_event_quic_openssl_compat.c" + + ngx_module_libs= + ngx_module_link=YES + ngx_module_order= + + . auto/module + + if [ $QUIC_BPF = YES -a $SO_COOKIE_FOUND = YES ]; then + ngx_module_type=CORE + ngx_module_name=ngx_quic_bpf_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="src/event/quic/ngx_event_quic_bpf.c \ + src/event/quic/ngx_event_quic_bpf_code.c" + ngx_module_libs= + ngx_module_link=YES + ngx_module_order= + + . auto/module + + have=NGX_QUIC_BPF . auto/have + fi +fi + + if [ $USE_PCRE = YES ]; then ngx_module_type=CORE ngx_module_name=ngx_regex_module diff --git a/auto/options b/auto/options index 48f3a1a..6a6e990 100644 --- a/auto/options +++ b/auto/options @@ -45,6 +45,8 @@ USE_THREADS=NO NGX_FILE_AIO=NO +QUIC_BPF=NO + HTTP=YES NGX_HTTP_LOG_PATH= @@ -59,6 +61,7 @@ HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO HTTP_V2=NO +HTTP_V3=NO HTTP_SSI=YES HTTP_REALIP=NO HTTP_XSLT=NO @@ -124,6 +127,7 @@ STREAM_GEOIP=NO STREAM_MAP=YES STREAM_SPLIT_CLIENTS=YES STREAM_RETURN=YES +STREAM_PASS=YES STREAM_SET=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES @@ -149,6 +153,7 @@ PCRE_JIT=NO PCRE2=YES USE_OPENSSL=NO +USE_OPENSSL_QUIC=NO OPENSSL=NONE USE_ZLIB=NO @@ -166,6 +171,8 @@ USE_GEOIP=NO NGX_GOOGLE_PERFTOOLS=NO NGX_CPP_TEST=NO +SO_COOKIE_FOUND=NO + NGX_LIBATOMIC=NO NGX_CPU_CACHE_LINE= @@ -211,6 +218,8 @@ do --with-file-aio) NGX_FILE_AIO=YES ;; + --without-quic_bpf_module) QUIC_BPF=NONE ;; + --with-ipv6) NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG $0: warning: the \"--with-ipv6\" option is deprecated" @@ -228,6 +237,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --with-http_ssl_module) HTTP_SSL=YES ;; --with-http_v2_module) HTTP_V2=YES ;; + --with-http_v3_module) HTTP_V3=YES ;; --with-http_realip_module) HTTP_REALIP=YES ;; --with-http_addition_module) HTTP_ADDITION=YES ;; --with-http_xslt_module) HTTP_XSLT=YES ;; @@ -328,6 +338,7 @@ use the \"--with-mail_ssl_module\" option instead" --without-stream_split_clients_module) STREAM_SPLIT_CLIENTS=NO ;; --without-stream_return_module) STREAM_RETURN=NO ;; + --without-stream_pass_module) STREAM_PASS=NO ;; --without-stream_set_module) STREAM_SET=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; @@ -443,8 +454,11 @@ cat << END --with-file-aio enable file AIO support + --without-quic_bpf_module disable ngx_quic_bpf_module + --with-http_ssl_module enable ngx_http_ssl_module --with-http_v2_module enable ngx_http_v2_module + --with-http_v3_module enable ngx_http_v3_module --with-http_realip_module enable ngx_http_realip_module --with-http_addition_module enable ngx_http_addition_module --with-http_xslt_module enable ngx_http_xslt_module @@ -544,6 +558,7 @@ cat << END --without-stream_split_clients_module disable ngx_stream_split_clients_module --without-stream_return_module disable ngx_stream_return_module + --without-stream_pass_module disable ngx_stream_pass_module --without-stream_set_module disable ngx_stream_set_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module diff --git a/auto/os/conf b/auto/os/conf index d7f6e03..bb0ce4e 100644 --- a/auto/os/conf +++ b/auto/os/conf @@ -115,6 +115,21 @@ case "$NGX_MACHINE" in NGX_MACH_CACHE_LINE=64 ;; + ppc64* | powerpc64*) + have=NGX_ALIGNMENT value=16 . auto/define + NGX_MACH_CACHE_LINE=128 + ;; + + riscv64) + have=NGX_ALIGNMENT value=16 . auto/define + NGX_MACH_CACHE_LINE=64 + ;; + + s390x) + have=NGX_ALIGNMENT value=16 . auto/define + NGX_MACH_CACHE_LINE=256 + ;; + *) have=NGX_ALIGNMENT value=16 . auto/define NGX_MACH_CACHE_LINE=32 diff --git a/auto/os/linux b/auto/os/linux index eb67026..bc0556b 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -228,10 +228,58 @@ ngx_feature_test="struct crypt_data cd; crypt_r(\"key\", \"salt\", &cd);" . auto/feature +if [ $ngx_found = yes ]; then + CRYPT_LIB="-lcrypt" +fi + ngx_include="sys/vfs.h"; . auto/include +# BPF sockhash + +ngx_feature="BPF sockhash" +ngx_feature_name="NGX_HAVE_BPF" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="union bpf_attr attr = { 0 }; + + attr.map_flags = 0; + attr.map_type = BPF_MAP_TYPE_SOCKHASH; + + syscall(__NR_bpf, 0, &attr, 0);" +. auto/feature + +if [ $ngx_found = yes ]; then + CORE_SRCS="$CORE_SRCS src/core/ngx_bpf.c" + CORE_DEPS="$CORE_DEPS src/core/ngx_bpf.h" + + if [ $QUIC_BPF != NONE ]; then + QUIC_BPF=YES + fi +fi + + +ngx_feature="SO_COOKIE" +ngx_feature_name="NGX_HAVE_SO_COOKIE" +ngx_feature_run=no +ngx_feature_incs="#include + $NGX_INCLUDE_INTTYPES_H" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="socklen_t optlen = sizeof(uint64_t); + uint64_t cookie; + getsockopt(0, SOL_SOCKET, SO_COOKIE, &cookie, &optlen)" +. auto/feature + +if [ $ngx_found = yes ]; then + SO_COOKIE_FOUND=YES +fi + + # UDP segmentation offloading ngx_feature="UDP_SEGMENT" diff --git a/auto/os/win32 b/auto/os/win32 index b821ae6..bce764b 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -18,7 +18,7 @@ ngx_binext=".exe" case "$NGX_CC_NAME" in - gcc) + clang | gcc) CORE_LIBS="$CORE_LIBS -ladvapi32 -lws2_32" MAIN_LINK="$MAIN_LINK -Wl,--export-all-symbols" MAIN_LINK="$MAIN_LINK -Wl,--out-implib=$NGX_OBJS/libnginx.a" diff --git a/auto/sources b/auto/sources index a539093..46408ee 100644 --- a/auto/sources +++ b/auto/sources @@ -83,7 +83,7 @@ CORE_SRCS="src/core/nginx.c \ EVENT_MODULES="ngx_events_module ngx_event_core_module" -EVENT_INCS="src/event src/event/modules" +EVENT_INCS="src/event src/event/modules src/event/quic" EVENT_DEPS="src/event/ngx_event.h \ src/event/ngx_event_timer.h \ diff --git a/auto/unix b/auto/unix index 8671019..f29e69c 100644 --- a/auto/unix +++ b/auto/unix @@ -448,6 +448,54 @@ ngx_feature_test="setsockopt(0, IPPROTO_IPV6, IPV6_RECVPKTINFO, NULL, 0)" . auto/feature +# IP packet fragmentation + +ngx_feature="IP_MTU_DISCOVER" +ngx_feature_name="NGX_HAVE_IP_MTU_DISCOVER" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="(void) IP_PMTUDISC_DO; + setsockopt(0, IPPROTO_IP, IP_MTU_DISCOVER, NULL, 0)" +. auto/feature + + +ngx_feature="IPV6_MTU_DISCOVER" +ngx_feature_name="NGX_HAVE_IPV6_MTU_DISCOVER" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="(void) IPV6_PMTUDISC_DO; + setsockopt(0, IPPROTO_IPV6, IPV6_MTU_DISCOVER, NULL, 0)" +. auto/feature + + +ngx_feature="IP_DONTFRAG" +ngx_feature_name="NGX_HAVE_IP_DONTFRAG" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_DONTFRAG, NULL, 0)" +. auto/feature + + +ngx_feature="IPV6_DONTFRAG" +ngx_feature_name="NGX_HAVE_IPV6_DONTFRAG" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IPV6_DONTFRAG, NULL, 0)" +. auto/feature + + ngx_feature="TCP_DEFER_ACCEPT" ngx_feature_name="NGX_HAVE_DEFERRED_ACCEPT" ngx_feature_run=no diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 7d587fc..29eef7a 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -65,12 +65,12 @@ syn match ngxListenComment '#.*$' \ contained \ nextgroup=@ngxListenParams skipwhite skipempty syn keyword ngxListenOptions contained - \ default_server ssl http2 proxy_protocol + \ default_server ssl quic proxy_protocol \ setfib fastopen backlog rcvbuf sndbuf accept_filter deferred bind \ ipv6only reuseport so_keepalive \ nextgroup=@ngxListenParams skipwhite skipempty syn keyword ngxListenOptionsDeprecated contained - \ spdy + \ http2 \ nextgroup=@ngxListenParams skipwhite skipempty syn cluster ngxListenParams \ contains=ngxListenParam,ngxListenString,ngxListenComment @@ -90,7 +90,6 @@ syn keyword ngxDirectiveBlock contained if syn keyword ngxDirectiveBlock contained geo syn keyword ngxDirectiveBlock contained map syn keyword ngxDirectiveBlock contained split_clients -syn keyword ngxDirectiveBlock contained match syn keyword ngxDirectiveImportant contained include syn keyword ngxDirectiveImportant contained root @@ -113,7 +112,6 @@ syn keyword ngxDirectiveError contained post_action syn keyword ngxDirectiveDeprecated contained proxy_downstream_buffer syn keyword ngxDirectiveDeprecated contained proxy_upstream_buffer -syn keyword ngxDirectiveDeprecated contained ssl syn keyword ngxDirectiveDeprecated contained http2_idle_timeout syn keyword ngxDirectiveDeprecated contained http2_max_field_size syn keyword ngxDirectiveDeprecated contained http2_max_header_size @@ -136,7 +134,6 @@ syn keyword ngxDirective contained alias syn keyword ngxDirective contained allow syn keyword ngxDirective contained ancient_browser syn keyword ngxDirective contained ancient_browser_value -syn keyword ngxDirective contained api syn keyword ngxDirective contained auth_basic syn keyword ngxDirective contained auth_basic_user_file syn keyword ngxDirective contained auth_delay @@ -144,15 +141,6 @@ syn keyword ngxDirective contained auth_http syn keyword ngxDirective contained auth_http_header syn keyword ngxDirective contained auth_http_pass_client_cert syn keyword ngxDirective contained auth_http_timeout -syn keyword ngxDirective contained auth_jwt -syn keyword ngxDirective contained auth_jwt_claim_set -syn keyword ngxDirective contained auth_jwt_header_set -syn keyword ngxDirective contained auth_jwt_key_cache -syn keyword ngxDirective contained auth_jwt_key_file -syn keyword ngxDirective contained auth_jwt_key_request -syn keyword ngxDirective contained auth_jwt_leeway -syn keyword ngxDirective contained auth_jwt_require -syn keyword ngxDirective contained auth_jwt_type syn keyword ngxDirective contained auth_request syn keyword ngxDirective contained auth_request_set syn keyword ngxDirective contained autoindex @@ -193,8 +181,6 @@ syn keyword ngxDirective contained error_log syn keyword ngxDirective contained etag syn keyword ngxDirective contained eventport_events syn keyword ngxDirective contained expires -syn keyword ngxDirective contained f4f -syn keyword ngxDirective contained f4f_buffer_size syn keyword ngxDirective contained fastcgi_bind syn keyword ngxDirective contained fastcgi_buffer_size syn keyword ngxDirective contained fastcgi_buffering @@ -211,7 +197,6 @@ syn keyword ngxDirective contained fastcgi_cache_max_range_offset syn keyword ngxDirective contained fastcgi_cache_methods syn keyword ngxDirective contained fastcgi_cache_min_uses syn keyword ngxDirective contained fastcgi_cache_path -syn keyword ngxDirective contained fastcgi_cache_purge syn keyword ngxDirective contained fastcgi_cache_revalidate syn keyword ngxDirective contained fastcgi_cache_use_stale syn keyword ngxDirective contained fastcgi_cache_valid @@ -295,14 +280,7 @@ syn keyword ngxDirective contained gzip_types syn keyword ngxDirective contained gzip_vary syn keyword ngxDirective contained gzip_window syn keyword ngxDirective contained hash -syn keyword ngxDirective contained health_check -syn keyword ngxDirective contained health_check_timeout -syn keyword ngxDirective contained hls -syn keyword ngxDirective contained hls_buffers -syn keyword ngxDirective contained hls_forward_args -syn keyword ngxDirective contained hls_fragment -syn keyword ngxDirective contained hls_mp4_buffer_size -syn keyword ngxDirective contained hls_mp4_max_buffer_size +syn keyword ngxDirective contained http2 syn keyword ngxDirective contained http2_body_preread_size syn keyword ngxDirective contained http2_chunk_size syn keyword ngxDirective contained http2_max_concurrent_pushes @@ -312,6 +290,10 @@ syn keyword ngxDirective contained http2_push syn keyword ngxDirective contained http2_push_preload syn keyword ngxDirective contained http2_recv_buffer_size syn keyword ngxDirective contained http2_streams_index_size +syn keyword ngxDirective contained http3 +syn keyword ngxDirective contained http3_hq +syn keyword ngxDirective contained http3_max_concurrent_streams +syn keyword ngxDirective contained http3_stream_buffer_size syn keyword ngxDirective contained if_modified_since syn keyword ngxDirective contained ignore_invalid_headers syn keyword ngxDirective contained image_filter @@ -342,21 +324,20 @@ syn keyword ngxDirective contained js_filter syn keyword ngxDirective contained js_header_filter syn keyword ngxDirective contained js_import syn keyword ngxDirective contained js_path +syn keyword ngxDirective contained js_preload_object syn keyword ngxDirective contained js_preread syn keyword ngxDirective contained js_set +syn keyword ngxDirective contained js_shared_dict_zone syn keyword ngxDirective contained js_var syn keyword ngxDirective contained keepalive syn keyword ngxDirective contained keepalive_disable syn keyword ngxDirective contained keepalive_requests syn keyword ngxDirective contained keepalive_time syn keyword ngxDirective contained keepalive_timeout -syn keyword ngxDirective contained keyval -syn keyword ngxDirective contained keyval_zone syn keyword ngxDirective contained kqueue_changes syn keyword ngxDirective contained kqueue_events syn keyword ngxDirective contained large_client_header_buffers syn keyword ngxDirective contained least_conn -syn keyword ngxDirective contained least_time syn keyword ngxDirective contained limit_conn syn keyword ngxDirective contained limit_conn_dry_run syn keyword ngxDirective contained limit_conn_log_level @@ -400,14 +381,11 @@ syn keyword ngxDirective contained modern_browser syn keyword ngxDirective contained modern_browser_value syn keyword ngxDirective contained mp4 syn keyword ngxDirective contained mp4_buffer_size -syn keyword ngxDirective contained mp4_limit_rate -syn keyword ngxDirective contained mp4_limit_rate_after syn keyword ngxDirective contained mp4_max_buffer_size syn keyword ngxDirective contained mp4_start_key_frame syn keyword ngxDirective contained msie_padding syn keyword ngxDirective contained msie_refresh syn keyword ngxDirective contained multi_accept -syn keyword ngxDirective contained ntlm syn keyword ngxDirective contained open_file_cache syn keyword ngxDirective contained open_file_cache_errors syn keyword ngxDirective contained open_file_cache_events @@ -450,7 +428,6 @@ syn keyword ngxDirective contained proxy_cache_max_range_offset syn keyword ngxDirective contained proxy_cache_methods syn keyword ngxDirective contained proxy_cache_min_uses syn keyword ngxDirective contained proxy_cache_path -syn keyword ngxDirective contained proxy_cache_purge syn keyword ngxDirective contained proxy_cache_revalidate syn keyword ngxDirective contained proxy_cache_use_stale syn keyword ngxDirective contained proxy_cache_valid @@ -488,7 +465,6 @@ syn keyword ngxDirective contained proxy_requests syn keyword ngxDirective contained proxy_responses syn keyword ngxDirective contained proxy_send_lowat syn keyword ngxDirective contained proxy_send_timeout -syn keyword ngxDirective contained proxy_session_drop syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_header syn keyword ngxDirective contained proxy_smtp_auth @@ -513,7 +489,11 @@ syn keyword ngxDirective contained proxy_temp_file_write_size syn keyword ngxDirective contained proxy_temp_path syn keyword ngxDirective contained proxy_timeout syn keyword ngxDirective contained proxy_upload_rate -syn keyword ngxDirective contained queue +syn keyword ngxDirective contained quic_active_connection_id_limit +syn keyword ngxDirective contained quic_bpf +syn keyword ngxDirective contained quic_gso +syn keyword ngxDirective contained quic_host_key +syn keyword ngxDirective contained quic_retry syn keyword ngxDirective contained random syn keyword ngxDirective contained random_index syn keyword ngxDirective contained read_ahead @@ -544,7 +524,6 @@ syn keyword ngxDirective contained scgi_cache_max_range_offset syn keyword ngxDirective contained scgi_cache_methods syn keyword ngxDirective contained scgi_cache_min_uses syn keyword ngxDirective contained scgi_cache_path -syn keyword ngxDirective contained scgi_cache_purge syn keyword ngxDirective contained scgi_cache_revalidate syn keyword ngxDirective contained scgi_cache_use_stale syn keyword ngxDirective contained scgi_cache_valid @@ -583,9 +562,6 @@ syn keyword ngxDirective contained server_name_in_redirect syn keyword ngxDirective contained server_names_hash_bucket_size syn keyword ngxDirective contained server_names_hash_max_size syn keyword ngxDirective contained server_tokens -syn keyword ngxDirective contained session_log -syn keyword ngxDirective contained session_log_format -syn keyword ngxDirective contained session_log_zone syn keyword ngxDirective contained set_real_ip_from syn keyword ngxDirective contained slice syn keyword ngxDirective contained smtp_auth @@ -633,11 +609,6 @@ syn keyword ngxDirective contained ssl_trusted_certificate syn keyword ngxDirective contained ssl_verify_client syn keyword ngxDirective contained ssl_verify_depth syn keyword ngxDirective contained starttls -syn keyword ngxDirective contained state -syn keyword ngxDirective contained status -syn keyword ngxDirective contained status_format -syn keyword ngxDirective contained status_zone -syn keyword ngxDirective contained sticky syn keyword ngxDirective contained stub_status syn keyword ngxDirective contained sub_filter syn keyword ngxDirective contained sub_filter_last_modified @@ -680,7 +651,6 @@ syn keyword ngxDirective contained uwsgi_cache_max_range_offset syn keyword ngxDirective contained uwsgi_cache_methods syn keyword ngxDirective contained uwsgi_cache_min_uses syn keyword ngxDirective contained uwsgi_cache_path -syn keyword ngxDirective contained uwsgi_cache_purge syn keyword ngxDirective contained uwsgi_cache_revalidate syn keyword ngxDirective contained uwsgi_cache_use_stale syn keyword ngxDirective contained uwsgi_cache_valid @@ -744,6 +714,62 @@ syn keyword ngxDirective contained xslt_string_param syn keyword ngxDirective contained xslt_stylesheet syn keyword ngxDirective contained xslt_types syn keyword ngxDirective contained zone + +" nginx-plus commercial extensions directives + +syn keyword ngxDirectiveBlock contained match +syn keyword ngxDirectiveBlock contained otel_exporter + +syn keyword ngxDirective contained api +syn keyword ngxDirective contained auth_jwt +syn keyword ngxDirective contained auth_jwt_claim_set +syn keyword ngxDirective contained auth_jwt_header_set +syn keyword ngxDirective contained auth_jwt_key_cache +syn keyword ngxDirective contained auth_jwt_key_file +syn keyword ngxDirective contained auth_jwt_key_request +syn keyword ngxDirective contained auth_jwt_leeway +syn keyword ngxDirective contained auth_jwt_require +syn keyword ngxDirective contained auth_jwt_type +syn keyword ngxDirective contained f4f +syn keyword ngxDirective contained f4f_buffer_size +syn keyword ngxDirective contained fastcgi_cache_purge +syn keyword ngxDirective contained health_check +syn keyword ngxDirective contained health_check_timeout +syn keyword ngxDirective contained hls +syn keyword ngxDirective contained hls_buffers +syn keyword ngxDirective contained hls_forward_args +syn keyword ngxDirective contained hls_fragment +syn keyword ngxDirective contained hls_mp4_buffer_size +syn keyword ngxDirective contained hls_mp4_max_buffer_size +syn keyword ngxDirective contained internal_redirect +syn keyword ngxDirective contained keyval +syn keyword ngxDirective contained keyval_zone +syn keyword ngxDirective contained least_time +syn keyword ngxDirective contained mp4_limit_rate +syn keyword ngxDirective contained mp4_limit_rate_after +syn keyword ngxDirective contained mqtt +syn keyword ngxDirective contained mqtt_preread +syn keyword ngxDirective contained mqtt_rewrite_buffer_size +syn keyword ngxDirective contained mqtt_set_connect +syn keyword ngxDirective contained ntlm +syn keyword ngxDirective contained otel_service_name +syn keyword ngxDirective contained otel_span_attr +syn keyword ngxDirective contained otel_span_name +syn keyword ngxDirective contained otel_trace +syn keyword ngxDirective contained otel_trace_context +syn keyword ngxDirective contained proxy_cache_purge +syn keyword ngxDirective contained proxy_session_drop +syn keyword ngxDirective contained queue +syn keyword ngxDirective contained scgi_cache_purge +syn keyword ngxDirective contained session_log +syn keyword ngxDirective contained session_log_format +syn keyword ngxDirective contained session_log_zone +syn keyword ngxDirective contained state +syn keyword ngxDirective contained status +syn keyword ngxDirective contained status_format +syn keyword ngxDirective contained status_zone +syn keyword ngxDirective contained sticky +syn keyword ngxDirective contained uwsgi_cache_purge syn keyword ngxDirective contained zone_sync syn keyword ngxDirective contained zone_sync_buffers syn keyword ngxDirective contained zone_sync_connect_retry_interval @@ -766,7 +792,6 @@ syn keyword ngxDirective contained zone_sync_ssl_verify syn keyword ngxDirective contained zone_sync_ssl_verify_depth syn keyword ngxDirective contained zone_sync_timeout - " 3rd party modules list taken from " https://github.com/freebsd/freebsd-ports/blob/main/www/nginx-devel/Makefile.extmod " ---------------------------------------------------------------------------------- @@ -837,52 +862,6 @@ syn keyword ngxDirectiveThirdParty contained brotli_window " https://github.com/torden/ngx_cache_purge syn keyword ngxDirectiveThirdParty contained cache_purge_response_type -" https://github.com/nginx-clojure/nginx-clojure -syn keyword ngxDirectiveThirdParty contained access_handler_code -syn keyword ngxDirectiveThirdParty contained access_handler_name -syn keyword ngxDirectiveThirdParty contained access_handler_property -syn keyword ngxDirectiveThirdParty contained access_handler_type -syn keyword ngxDirectiveThirdParty contained always_read_body -syn keyword ngxDirectiveThirdParty contained auto_upgrade_ws -syn keyword ngxDirectiveThirdParty contained body_filter_code -syn keyword ngxDirectiveThirdParty contained body_filter_name -syn keyword ngxDirectiveThirdParty contained body_filter_property -syn keyword ngxDirectiveThirdParty contained body_filter_type -syn keyword ngxDirectiveThirdParty contained content_handler_code -syn keyword ngxDirectiveThirdParty contained content_handler_name -syn keyword ngxDirectiveThirdParty contained content_handler_property -syn keyword ngxDirectiveThirdParty contained content_handler_type -syn keyword ngxDirectiveThirdParty contained handler_code -syn keyword ngxDirectiveThirdParty contained handler_name -syn keyword ngxDirectiveThirdParty contained handler_type -syn keyword ngxDirectiveThirdParty contained handlers_lazy_init -syn keyword ngxDirectiveThirdParty contained header_filter_code -syn keyword ngxDirectiveThirdParty contained header_filter_name -syn keyword ngxDirectiveThirdParty contained header_filter_property -syn keyword ngxDirectiveThirdParty contained header_filter_type -syn keyword ngxDirectiveThirdParty contained jvm_classpath -syn keyword ngxDirectiveThirdParty contained jvm_classpath_check -syn keyword ngxDirectiveThirdParty contained jvm_exit_handler_code -syn keyword ngxDirectiveThirdParty contained jvm_exit_handler_name -syn keyword ngxDirectiveThirdParty contained jvm_handler_type -syn keyword ngxDirectiveThirdParty contained jvm_init_handler_code -syn keyword ngxDirectiveThirdParty contained jvm_init_handler_name -syn keyword ngxDirectiveThirdParty contained jvm_options -syn keyword ngxDirectiveThirdParty contained jvm_path -syn keyword ngxDirectiveThirdParty contained jvm_var -syn keyword ngxDirectiveThirdParty contained jvm_workers -syn keyword ngxDirectiveThirdParty contained log_handler_code -syn keyword ngxDirectiveThirdParty contained log_handler_name -syn keyword ngxDirectiveThirdParty contained log_handler_property -syn keyword ngxDirectiveThirdParty contained log_handler_type -syn keyword ngxDirectiveThirdParty contained max_balanced_tcp_connections -syn keyword ngxDirectiveThirdParty contained rewrite_handler_code -syn keyword ngxDirectiveThirdParty contained rewrite_handler_name -syn keyword ngxDirectiveThirdParty contained rewrite_handler_property -syn keyword ngxDirectiveThirdParty contained rewrite_handler_type -syn keyword ngxDirectiveThirdParty contained shared_map -syn keyword ngxDirectiveThirdParty contained write_page_size - " https://github.com/AirisX/nginx_cookie_flag_module syn keyword ngxDirectiveThirdParty contained set_cookie_flag @@ -932,29 +911,6 @@ syn keyword ngxDirectiveThirdParty contained dns_update syn keyword ngxDirectiveThirdParty contained dynamic_state_file syn keyword ngxDirectiveThirdParty contained dynamic_upstream -" https://github.com/ZigzagAK/ngx_dynamic_healthcheck -syn keyword ngxDirectiveThirdParty contained check -syn keyword ngxDirectiveThirdParty contained check_disable_host -syn keyword ngxDirectiveThirdParty contained check_exclude_host -syn keyword ngxDirectiveThirdParty contained check_persistent -syn keyword ngxDirectiveThirdParty contained check_request_body -syn keyword ngxDirectiveThirdParty contained check_request_headers -syn keyword ngxDirectiveThirdParty contained check_request_uri -syn keyword ngxDirectiveThirdParty contained check_response_body -syn keyword ngxDirectiveThirdParty contained check_response_codes -syn keyword ngxDirectiveThirdParty contained healthcheck -syn keyword ngxDirectiveThirdParty contained healthcheck_buffer_size -syn keyword ngxDirectiveThirdParty contained healthcheck_disable_host -syn keyword ngxDirectiveThirdParty contained healthcheck_get -syn keyword ngxDirectiveThirdParty contained healthcheck_persistent -syn keyword ngxDirectiveThirdParty contained healthcheck_request_body -syn keyword ngxDirectiveThirdParty contained healthcheck_request_headers -syn keyword ngxDirectiveThirdParty contained healthcheck_request_uri -syn keyword ngxDirectiveThirdParty contained healthcheck_response_body -syn keyword ngxDirectiveThirdParty contained healthcheck_response_codes -syn keyword ngxDirectiveThirdParty contained healthcheck_status -syn keyword ngxDirectiveThirdParty contained healthcheck_update - " https://github.com/openresty/encrypted-session-nginx-module syn keyword ngxDirectiveThirdParty contained encrypted_session_expires syn keyword ngxDirectiveThirdParty contained encrypted_session_iv @@ -1004,6 +960,7 @@ syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local syn keyword ngxDirectiveThirdParty contained auth_gss_realm syn keyword ngxDirectiveThirdParty contained auth_gss_service_ccache syn keyword ngxDirectiveThirdParty contained auth_gss_service_name +syn keyword ngxDirectiveThirdParty contained auth_gss_zone_name " https://github.com/kvspb/nginx-auth-ldap syn keyword ngxDirectiveThirdParty contained auth_ldap @@ -1033,6 +990,7 @@ syn keyword ngxDirectiveThirdParty contained eval_subrequest_in_memory " https://github.com/aperezdc/ngx-fancyindex syn keyword ngxDirectiveThirdParty contained fancyindex +syn keyword ngxDirectiveThirdParty contained fancyindex_case_sensitive syn keyword ngxDirectiveThirdParty contained fancyindex_css_href syn keyword ngxDirectiveThirdParty contained fancyindex_default_sort syn keyword ngxDirectiveThirdParty contained fancyindex_directories_first @@ -1121,6 +1079,7 @@ syn keyword ngxDirectiveThirdParty contained nchan_publisher_upstream_request syn keyword ngxDirectiveThirdParty contained nchan_pubsub syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location +syn keyword ngxDirectiveThirdParty contained nchan_redis_accurate_subscriber_count syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_backoff syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_jitter @@ -1138,6 +1097,11 @@ syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_discovered_ip_range_blacklist syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_keepalive_backoff +syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_keepalive_jitter +syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_keepalive_max +syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_keepalive_min +syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_keepalive_safety_margin syn keyword ngxDirectiveThirdParty contained nchan_redis_load_scripts_unconditionally syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace syn keyword ngxDirectiveThirdParty contained nchan_redis_node_connect_timeout @@ -1173,6 +1137,9 @@ syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_server_name syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate_path syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_verify_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_upstream_stats +syn keyword ngxDirectiveThirdParty contained nchan_redis_upstream_stats_disconnected_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_upstream_stats_enabled syn keyword ngxDirectiveThirdParty contained nchan_redis_url syn keyword ngxDirectiveThirdParty contained nchan_redis_username syn keyword ngxDirectiveThirdParty contained nchan_redis_wait_after_connecting @@ -1323,6 +1290,7 @@ syn keyword ngxDirectiveThirdParty contained upload_progress_jsonp_parameter syn keyword ngxDirectiveThirdParty contained upload_progress_template " https://github.com/yaoweibin/nginx_upstream_check_module +syn keyword ngxDirectiveThirdParty contained check syn keyword ngxDirectiveThirdParty contained check_fastcgi_param syn keyword ngxDirectiveThirdParty contained check_http_expect_alive syn keyword ngxDirectiveThirdParty contained check_http_send @@ -1335,6 +1303,7 @@ syn keyword ngxDirectiveThirdParty contained fair syn keyword ngxDirectiveThirdParty contained upstream_fair_shm_size " https://github.com/ayty-adrianomartins/nginx-sticky-module-ng +syn keyword ngxDirectiveThirdParty contained sticky_hide_cookie syn keyword ngxDirectiveThirdParty contained sticky_no_fallback " https://github.com/Novetta/nginx-video-thumbextractor-module @@ -1421,6 +1390,8 @@ syn keyword ngxDirectiveThirdParty contained lua_socket_pool_size syn keyword ngxDirectiveThirdParty contained lua_socket_read_timeout syn keyword ngxDirectiveThirdParty contained lua_socket_send_lowat syn keyword ngxDirectiveThirdParty contained lua_socket_send_timeout +syn keyword ngxDirectiveThirdParty contained lua_ssl_certificate +syn keyword ngxDirectiveThirdParty contained lua_ssl_certificate_key syn keyword ngxDirectiveThirdParty contained lua_ssl_ciphers syn keyword ngxDirectiveThirdParty contained lua_ssl_conf_command syn keyword ngxDirectiveThirdParty contained lua_ssl_crl @@ -1834,16 +1805,6 @@ syn keyword ngxDirectiveThirdParty contained slowfs_cache_purge syn keyword ngxDirectiveThirdParty contained slowfs_cache_valid syn keyword ngxDirectiveThirdParty contained slowfs_temp_path -" https://github.com/kawakibi/ngx_small_light -syn keyword ngxDirectiveThirdParty contained small_light -syn keyword ngxDirectiveThirdParty contained small_light_buffer -syn keyword ngxDirectiveThirdParty contained small_light_getparam_mode -syn keyword ngxDirectiveThirdParty contained small_light_imlib2_temp_dir -syn keyword ngxDirectiveThirdParty contained small_light_material_dir -syn keyword ngxDirectiveThirdParty contained small_light_pattern_define -syn keyword ngxDirectiveThirdParty contained small_light_radius_max -syn keyword ngxDirectiveThirdParty contained small_light_sigma_max - " https://github.com/openresty/srcache-nginx-module syn keyword ngxDirectiveThirdParty contained srcache_buffer syn keyword ngxDirectiveThirdParty contained srcache_default_expire @@ -1980,6 +1941,14 @@ syn keyword ngxDirectiveThirdParty contained websockify_pass syn keyword ngxDirectiveThirdParty contained websockify_read_timeout syn keyword ngxDirectiveThirdParty contained websockify_send_timeout +" https://github.com/vozlt/nginx-module-sts +syn keyword ngxDirectiveThirdParty contained stream_server_traffic_status +syn keyword ngxDirectiveThirdParty contained stream_server_traffic_status_average_method +syn keyword ngxDirectiveThirdParty contained stream_server_traffic_status_display +syn keyword ngxDirectiveThirdParty contained stream_server_traffic_status_display_format +syn keyword ngxDirectiveThirdParty contained stream_server_traffic_status_display_jsonp +syn keyword ngxDirectiveThirdParty contained stream_server_traffic_status_zone + " highlight hi def link ngxComment Comment diff --git a/src/core/nginx.c b/src/core/nginx.c index 48a20e9..0deb27b 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -13,6 +13,7 @@ static void ngx_show_version_info(void); static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); static void ngx_cleanup_environment(void *data); +static void ngx_cleanup_environment_variable(void *data); static ngx_int_t ngx_get_options(int argc, char *const *argv); static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv); @@ -518,7 +519,8 @@ ngx_add_inherited_sockets(ngx_cycle_t *cycle) char ** ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last) { - char **p, **env; + char **p, **env, *str; + size_t len; ngx_str_t *var; ngx_uint_t i, n; ngx_core_conf_t *ccf; @@ -600,7 +602,31 @@ tz_found: for (i = 0; i < ccf->env.nelts; i++) { if (var[i].data[var[i].len] == '=') { - env[n++] = (char *) var[i].data; + + if (last) { + env[n++] = (char *) var[i].data; + continue; + } + + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { + return NULL; + } + + len = ngx_strlen(var[i].data) + 1; + + str = ngx_alloc(len, cycle->log); + if (str == NULL) { + return NULL; + } + + ngx_memcpy(str, var[i].data, len); + + cln->handler = ngx_cleanup_environment_variable; + cln->data = str; + + env[n++] = str; + continue; } @@ -645,6 +671,29 @@ ngx_cleanup_environment(void *data) } +static void +ngx_cleanup_environment_variable(void *data) +{ + char *var = data; + + char **p; + + for (p = environ; *p; p++) { + + /* + * if an environment variable is still used, as it happens on exit, + * the only option is to leak it + */ + + if (*p == var) { + return; + } + } + + ngx_free(var); +} + + ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { @@ -680,6 +729,9 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { + if (ls[i].ignore) { + continue; + } p = ngx_sprintf(p, "%ud;", ls[i].fd); } diff --git a/src/core/nginx.h b/src/core/nginx.h index 832baaa..7ef5cfb 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1024000 -#define NGINX_VERSION "1.24.0" +#define nginx_version 1026000 +#define NGINX_VERSION "1.26.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_bpf.c b/src/core/ngx_bpf.c new file mode 100644 index 0000000..363a02c --- /dev/null +++ b/src/core/ngx_bpf.c @@ -0,0 +1,143 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + +#define NGX_BPF_LOGBUF_SIZE (16 * 1024) + + +static ngx_inline int +ngx_bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size) +{ + return syscall(__NR_bpf, cmd, attr, size); +} + + +void +ngx_bpf_program_link(ngx_bpf_program_t *program, const char *symbol, int fd) +{ + ngx_uint_t i; + ngx_bpf_reloc_t *rl; + + rl = program->relocs; + + for (i = 0; i < program->nrelocs; i++) { + if (ngx_strcmp(rl[i].name, symbol) == 0) { + program->ins[rl[i].offset].src_reg = 1; + program->ins[rl[i].offset].imm = fd; + } + } +} + + +int +ngx_bpf_load_program(ngx_log_t *log, ngx_bpf_program_t *program) +{ + int fd; + union bpf_attr attr; +#if (NGX_DEBUG) + char buf[NGX_BPF_LOGBUF_SIZE]; +#endif + + ngx_memzero(&attr, sizeof(union bpf_attr)); + + attr.license = (uintptr_t) program->license; + attr.prog_type = program->type; + attr.insns = (uintptr_t) program->ins; + attr.insn_cnt = program->nins; + +#if (NGX_DEBUG) + /* for verifier errors */ + attr.log_buf = (uintptr_t) buf; + attr.log_size = NGX_BPF_LOGBUF_SIZE; + attr.log_level = 1; +#endif + + fd = ngx_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + if (fd < 0) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "failed to load BPF program"); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "bpf verifier: %s", buf); + + return -1; + } + + return fd; +} + + +int +ngx_bpf_map_create(ngx_log_t *log, enum bpf_map_type type, int key_size, + int value_size, int max_entries, uint32_t map_flags) +{ + int fd; + union bpf_attr attr; + + ngx_memzero(&attr, sizeof(union bpf_attr)); + + attr.map_type = type; + attr.key_size = key_size; + attr.value_size = value_size; + attr.max_entries = max_entries; + attr.map_flags = map_flags; + + fd = ngx_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); + if (fd < 0) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "failed to create BPF map"); + return NGX_ERROR; + } + + return fd; +} + + +int +ngx_bpf_map_update(int fd, const void *key, const void *value, uint64_t flags) +{ + union bpf_attr attr; + + ngx_memzero(&attr, sizeof(union bpf_attr)); + + attr.map_fd = fd; + attr.key = (uintptr_t) key; + attr.value = (uintptr_t) value; + attr.flags = flags; + + return ngx_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); +} + + +int +ngx_bpf_map_delete(int fd, const void *key) +{ + union bpf_attr attr; + + ngx_memzero(&attr, sizeof(union bpf_attr)); + + attr.map_fd = fd; + attr.key = (uintptr_t) key; + + return ngx_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr)); +} + + +int +ngx_bpf_map_lookup(int fd, const void *key, void *value) +{ + union bpf_attr attr; + + ngx_memzero(&attr, sizeof(union bpf_attr)); + + attr.map_fd = fd; + attr.key = (uintptr_t) key; + attr.value = (uintptr_t) value; + + return ngx_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); +} diff --git a/src/core/ngx_bpf.h b/src/core/ngx_bpf.h new file mode 100644 index 0000000..f62a36e --- /dev/null +++ b/src/core/ngx_bpf.h @@ -0,0 +1,43 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_BPF_H_INCLUDED_ +#define _NGX_BPF_H_INCLUDED_ + + +#include +#include + +#include + + +typedef struct { + char *name; + int offset; +} ngx_bpf_reloc_t; + +typedef struct { + char *license; + enum bpf_prog_type type; + struct bpf_insn *ins; + size_t nins; + ngx_bpf_reloc_t *relocs; + size_t nrelocs; +} ngx_bpf_program_t; + + +void ngx_bpf_program_link(ngx_bpf_program_t *program, const char *symbol, + int fd); +int ngx_bpf_load_program(ngx_log_t *log, ngx_bpf_program_t *program); + +int ngx_bpf_map_create(ngx_log_t *log, enum bpf_map_type type, int key_size, + int value_size, int max_entries, uint32_t map_flags); +int ngx_bpf_map_update(int fd, const void *key, const void *value, + uint64_t flags); +int ngx_bpf_map_delete(int fd, const void *key); +int ngx_bpf_map_lookup(int fd, const void *key, void *value); + +#endif /* _NGX_BPF_H_INCLUDED_ */ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 3682345..75809d9 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1013,6 +1013,78 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) } } +#endif + +#if (NGX_HAVE_IP_MTU_DISCOVER) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET) { + value = IP_PMTUDISC_DO; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_MTU_DISCOVER, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_MTU_DISCOVER) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#elif (NGX_HAVE_IP_DONTFRAG) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET) { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_DONTFRAG, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_DONTFRAG) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif + +#if (NGX_HAVE_INET6) + +#if (NGX_HAVE_IPV6_MTU_DISCOVER) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET6) { + value = IPV6_PMTUDISC_DO; + + if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_MTU_DISCOVER) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#elif (NGX_HAVE_IP_DONTFRAG) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET6) { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_DONTFRAG, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_DONTFRAG) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif + #endif } @@ -1037,6 +1109,12 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle) ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { +#if (NGX_QUIC) + if (ls[i].quic) { + continue; + } +#endif + c = ls[i].connection; if (c) { @@ -1505,6 +1583,10 @@ ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) } #endif + if (err == NGX_EMSGSIZE && c->log_error == NGX_ERROR_IGNORE_EMSGSIZE) { + return 0; + } + if (err == 0 || err == NGX_ECONNRESET #if (NGX_WIN32) @@ -1522,6 +1604,7 @@ ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) { switch (c->log_error) { + case NGX_ERROR_IGNORE_EMSGSIZE: case NGX_ERROR_IGNORE_EINVAL: case NGX_ERROR_IGNORE_ECONNRESET: case NGX_ERROR_INFO: diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 36e1be2..84dd804 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -73,6 +73,7 @@ struct ngx_listening_s { unsigned reuseport:1; unsigned add_reuseport:1; unsigned keepalive:2; + unsigned quic:1; unsigned deferred_accept:1; unsigned delete_deferred:1; @@ -96,7 +97,8 @@ typedef enum { NGX_ERROR_ERR, NGX_ERROR_INFO, NGX_ERROR_IGNORE_ECONNRESET, - NGX_ERROR_IGNORE_EINVAL + NGX_ERROR_IGNORE_EINVAL, + NGX_ERROR_IGNORE_EMSGSIZE } ngx_connection_log_error_e; @@ -147,6 +149,10 @@ struct ngx_connection_s { ngx_proxy_protocol_t *proxy_protocol; +#if (NGX_QUIC || NGX_COMPAT) + ngx_quic_stream_t *quic; +#endif + #if (NGX_SSL || NGX_COMPAT) ngx_ssl_connection_t *ssl; #endif diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 7ecdca0..88db7dc 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -27,6 +27,7 @@ typedef struct ngx_connection_s ngx_connection_t; typedef struct ngx_thread_task_s ngx_thread_task_t; typedef struct ngx_ssl_s ngx_ssl_t; typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t; +typedef struct ngx_quic_stream_s ngx_quic_stream_t; typedef struct ngx_ssl_connection_s ngx_ssl_connection_t; typedef struct ngx_udp_connection_s ngx_udp_connection_t; @@ -82,6 +83,9 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #if (NGX_OPENSSL) #include +#if (NGX_QUIC) +#include +#endif #endif #include #include @@ -91,6 +95,9 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include +#if (NGX_HAVE_BPF) +#include +#endif #define LF (u_char) '\n' diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 4228504..acb2ef4 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -507,7 +507,7 @@ ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs) p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index 6fb4554..a415cd6 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -107,7 +107,12 @@ #endif #define NGX_MODULE_SIGNATURE_17 "0" + +#if (NGX_QUIC || NGX_COMPAT) +#define NGX_MODULE_SIGNATURE_18 "1" +#else #define NGX_MODULE_SIGNATURE_18 "0" +#endif #if (NGX_HAVE_OPENAT) #define NGX_MODULE_SIGNATURE_19 "1" diff --git a/src/core/ngx_queue.c b/src/core/ngx_queue.c index 3cacaf3..3d1d589 100644 --- a/src/core/ngx_queue.c +++ b/src/core/ngx_queue.c @@ -9,6 +9,10 @@ #include +static void ngx_queue_merge(ngx_queue_t *queue, ngx_queue_t *tail, + ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)); + + /* * find the middle queue element if the queue has odd number of elements * or the first element of the queue's second part otherwise @@ -45,13 +49,13 @@ ngx_queue_middle(ngx_queue_t *queue) } -/* the stable insertion sort */ +/* the stable merge sort */ void ngx_queue_sort(ngx_queue_t *queue, ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)) { - ngx_queue_t *q, *prev, *next; + ngx_queue_t *q, tail; q = ngx_queue_head(queue); @@ -59,22 +63,44 @@ ngx_queue_sort(ngx_queue_t *queue, return; } - for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) { + q = ngx_queue_middle(queue); - prev = ngx_queue_prev(q); - next = ngx_queue_next(q); + ngx_queue_split(queue, q, &tail); - ngx_queue_remove(q); + ngx_queue_sort(queue, cmp); + ngx_queue_sort(&tail, cmp); - do { - if (cmp(prev, q) <= 0) { - break; - } + ngx_queue_merge(queue, &tail, cmp); +} - prev = ngx_queue_prev(prev); - } while (prev != ngx_queue_sentinel(queue)); +static void +ngx_queue_merge(ngx_queue_t *queue, ngx_queue_t *tail, + ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)) +{ + ngx_queue_t *q1, *q2; - ngx_queue_insert_after(prev, q); + q1 = ngx_queue_head(queue); + q2 = ngx_queue_head(tail); + + for ( ;; ) { + if (q1 == ngx_queue_sentinel(queue)) { + ngx_queue_add(queue, tail); + break; + } + + if (q2 == ngx_queue_sentinel(tail)) { + break; + } + + if (cmp(q1, q2) <= 0) { + q1 = ngx_queue_next(q1); + continue; + } + + ngx_queue_remove(q2); + ngx_queue_insert_before(q1, q2); + + q2 = ngx_queue_head(tail); } } diff --git a/src/core/ngx_queue.h b/src/core/ngx_queue.h index 038bf12..0f82f17 100644 --- a/src/core/ngx_queue.h +++ b/src/core/ngx_queue.h @@ -47,6 +47,9 @@ struct ngx_queue_s { (h)->prev = x +#define ngx_queue_insert_before ngx_queue_insert_tail + + #define ngx_queue_head(h) \ (h)->next diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index bebf3b6..5b13c5d 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -600,6 +600,8 @@ ngx_regex_cleanup(void *data) * the new cycle, these will be re-allocated. */ + ngx_regex_malloc_init(NULL); + if (ngx_regex_compile_context) { pcre2_compile_context_free(ngx_regex_compile_context); ngx_regex_compile_context = NULL; @@ -611,6 +613,8 @@ ngx_regex_cleanup(void *data) ngx_regex_match_data_size = 0; } + ngx_regex_malloc_done(); + #endif } @@ -706,9 +710,6 @@ ngx_regex_module_init(ngx_cycle_t *cycle) ngx_regex_malloc_done(); ngx_regex_studies = NULL; -#if (NGX_PCRE2) - ngx_regex_compile_context = NULL; -#endif return NGX_OK; } @@ -732,14 +733,14 @@ ngx_regex_create_conf(ngx_cycle_t *cycle) return NULL; } - cln->handler = ngx_regex_cleanup; - cln->data = rcf; - rcf->studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); if (rcf->studies == NULL) { return NULL; } + cln->handler = ngx_regex_cleanup; + cln->data = rcf; + ngx_regex_studies = rcf->studies; return rcf; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index d81547a..ef525d9 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -267,6 +267,18 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) { +#if (NGX_QUIC) + + ngx_connection_t *c; + + c = rev->data; + + if (c->quic) { + return NGX_OK; + } + +#endif + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue, epoll */ @@ -337,9 +349,15 @@ ngx_handle_write_event(ngx_event_t *wev, size_t lowat) { ngx_connection_t *c; - if (lowat) { - c = wev->data; + c = wev->data; +#if (NGX_QUIC) + if (c->quic) { + return NGX_OK; + } +#endif + + if (lowat) { if (ngx_send_lowat(c, lowat) == NGX_ERROR) { return NGX_ERROR; } @@ -873,8 +891,16 @@ ngx_event_process_init(ngx_cycle_t *cycle) #else - rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept - : ngx_event_recvmsg; + if (c->type == SOCK_STREAM) { + rev->handler = ngx_event_accept; + +#if (NGX_QUIC) + } else if (ls[i].quic) { + rev->handler = ngx_quic_recvmsg; +#endif + } else { + rev->handler = ngx_event_recvmsg; + } #if (NGX_HAVE_REUSEPORT) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 104e8da..89f277f 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -33,9 +33,6 @@ static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, #ifdef SSL_READ_EARLY_DATA_SUCCESS static ngx_int_t ngx_ssl_try_early_data(ngx_connection_t *c); #endif -#if (NGX_DEBUG) -static void ngx_ssl_handshake_log(ngx_connection_t *c); -#endif static void ngx_ssl_handshake_handler(ngx_event_t *ev); #ifdef SSL_READ_EARLY_DATA_SUCCESS static ssize_t ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf, @@ -143,13 +140,42 @@ int ngx_ssl_stapling_index; ngx_int_t ngx_ssl_init(ngx_log_t *log) { -#if OPENSSL_VERSION_NUMBER >= 0x10100003L +#if (OPENSSL_INIT_LOAD_CONFIG && !defined LIBRESSL_VERSION_NUMBER) - if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) { + uint64_t opts; + OPENSSL_INIT_SETTINGS *init; + + opts = OPENSSL_INIT_LOAD_CONFIG; + +#if (NGX_OPENSSL_NO_CONFIG) + + if (getenv("OPENSSL_CONF") == NULL) { + opts = OPENSSL_INIT_NO_LOAD_CONFIG; + } + +#endif + + init = OPENSSL_INIT_new(); + if (init == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_INIT_new() failed"); + return NGX_ERROR; + } + +#ifndef OPENSSL_NO_STDIO + if (OPENSSL_INIT_set_config_appname(init, "nginx") == 0) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "OPENSSL_INIT_set_config_appname() failed"); + return NGX_ERROR; + } +#endif + + if (OPENSSL_init_ssl(opts, init) == 0) { ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed"); return NGX_ERROR; } + OPENSSL_INIT_free(init); + /* * OPENSSL_init_ssl() may leave errors in the error queue * while returning success @@ -159,7 +185,15 @@ ngx_ssl_init(ngx_log_t *log) #else - OPENSSL_config(NULL); +#if (NGX_OPENSSL_NO_CONFIG) + + if (getenv("OPENSSL_CONF") == NULL) { + OPENSSL_no_config(); + } + +#endif + + OPENSSL_config("nginx"); SSL_library_init(); SSL_load_error_strings(); @@ -1071,7 +1105,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) BIO *rbio, *wbio; ngx_connection_t *c; -#ifndef SSL_OP_NO_RENEGOTIATION +#if (!defined SSL_OP_NO_RENEGOTIATION \ + && !defined SSL_OP_NO_CLIENT_RENEGOTIATION) if ((where & SSL_CB_HANDSHAKE_START) && SSL_is_server((ngx_ssl_conn_t *) ssl_conn)) @@ -1804,9 +1839,10 @@ ngx_ssl_handshake(ngx_connection_t *c) c->read->ready = 1; c->write->ready = 1; -#ifndef SSL_OP_NO_RENEGOTIATION -#if OPENSSL_VERSION_NUMBER < 0x10100000L -#ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS +#if (!defined SSL_OP_NO_RENEGOTIATION \ + && !defined SSL_OP_NO_CLIENT_RENEGOTIATION \ + && defined SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS \ + && OPENSSL_VERSION_NUMBER < 0x10100000L) /* initial handshake done, disable renegotiation (CVE-2009-3555) */ if (c->ssl->connection->s3 && SSL_is_server(c->ssl->connection)) { @@ -1814,8 +1850,6 @@ ngx_ssl_handshake(ngx_connection_t *c) } #endif -#endif -#endif #if (defined BIO_get_ktls_send && !NGX_WIN32) @@ -2052,7 +2086,7 @@ ngx_ssl_try_early_data(ngx_connection_t *c) #if (NGX_DEBUG) -static void +void ngx_ssl_handshake_log(ngx_connection_t *c) { char buf[129], *s, *d; @@ -2449,7 +2483,8 @@ ngx_ssl_handle_recv(ngx_connection_t *c, int n) int sslerr; ngx_err_t err; -#ifndef SSL_OP_NO_RENEGOTIATION +#if (!defined SSL_OP_NO_RENEGOTIATION \ + && !defined SSL_OP_NO_CLIENT_RENEGOTIATION) if (c->ssl->renegotiation) { /* @@ -3202,6 +3237,13 @@ ngx_ssl_shutdown(ngx_connection_t *c) ngx_err_t err; ngx_uint_t tries; +#if (NGX_QUIC) + if (c->quic) { + /* QUIC streams inherit SSL object */ + return NGX_OK; + } +#endif + rc = NGX_OK; ngx_ssl_ocsp_cleanup(c); @@ -5145,6 +5187,9 @@ ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } curves = ngx_palloc(pool, n * sizeof(int)); + if (curves == NULL) { + return NGX_ERROR; + } n = SSL_get1_curves(c->ssl->connection, curves); len = 0; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 860ea26..ebb2c35 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -24,6 +24,14 @@ #include #endif #include +#if (NGX_QUIC) +#ifdef OPENSSL_IS_BORINGSSL +#include +#include +#else +#include +#endif +#endif #include #ifndef OPENSSL_NO_OCSP #include @@ -37,7 +45,7 @@ #if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L) #undef OPENSSL_VERSION_NUMBER -#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL) +#if (LIBRESSL_VERSION_NUMBER >= 0x3050000fL) #define OPENSSL_VERSION_NUMBER 0x1010000fL #else #define OPENSSL_VERSION_NUMBER 0x1000107fL @@ -302,6 +310,9 @@ ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); +#if (NGX_DEBUG) +void ngx_ssl_handshake_log(ngx_connection_t *c); +#endif ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit); diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index e3fa8c4..e9bb835 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -893,7 +893,7 @@ ngx_ssl_ocsp_validate(ngx_connection_t *c) ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD; ocsp->conf = ocf; -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L ocsp->certs = SSL_get0_verified_chain(c->ssl->connection); diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index 54412e1..d774903 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -57,7 +57,9 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) do_write = 1; } - if (p->upstream->fd != (ngx_socket_t) -1) { + if (p->upstream + && p->upstream->fd != (ngx_socket_t) -1) + { rev = p->upstream->read; flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0; @@ -108,7 +110,9 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ngx_msec_t delay; ngx_chain_t *chain, *cl, *ln; - if (p->upstream_eof || p->upstream_error || p->upstream_done) { + if (p->upstream_eof || p->upstream_error || p->upstream_done + || p->upstream == NULL) + { return NGX_OK; } diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index d7a94c7..43fa621 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -12,13 +12,6 @@ #if !(NGX_WIN32) -struct ngx_udp_connection_s { - ngx_rbtree_node_t node; - ngx_connection_t *connection; - ngx_buf_t *buffer; -}; - - static void ngx_close_accepted_udp_connection(ngx_connection_t *c); static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size); @@ -424,8 +417,8 @@ ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, udpt = (ngx_udp_connection_t *) temp; ct = udpt->connection; - rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen, - ct->sockaddr, ct->socklen, 1); + rc = ngx_memn2cmp(udp->key.data, udpt->key.data, + udp->key.len, udpt->key.len); if (rc == 0 && c->listening->wildcard) { rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, @@ -478,6 +471,8 @@ ngx_insert_udp_connection(ngx_connection_t *c) ngx_crc32_final(hash); udp->node.key = hash; + udp->key.data = (u_char *) c->sockaddr; + udp->key.len = c->socklen; cln = ngx_pool_cleanup_add(c->pool, 0); if (cln == NULL) { diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h index 51ca665..e5ddf1b 100644 --- a/src/event/ngx_event_udp.h +++ b/src/event/ngx_event_udp.h @@ -23,6 +23,14 @@ #endif +struct ngx_udp_connection_s { + ngx_rbtree_node_t node; + ngx_connection_t *connection; + ngx_buf_t *buffer; + ngx_str_t key; +}; + + #if (NGX_HAVE_ADDRINFO_CMSG) typedef union { diff --git a/src/event/quic/bpf/bpfgen.sh b/src/event/quic/bpf/bpfgen.sh new file mode 100644 index 0000000..78cbdac --- /dev/null +++ b/src/event/quic/bpf/bpfgen.sh @@ -0,0 +1,113 @@ +#!/bin/bash + +export LANG=C + +set -e + +if [ $# -lt 1 ]; then + echo "Usage: PROGNAME=foo LICENSE=bar $0 " + exit 1 +fi + + +self=$0 +filename=$1 +funcname=$PROGNAME + +generate_head() +{ + cat << END +/* AUTO-GENERATED, DO NOT EDIT. */ + +#include +#include + +#include "ngx_bpf.h" + + +END +} + +generate_tail() +{ + cat << END + +ngx_bpf_program_t $PROGNAME = { + .relocs = bpf_reloc_prog_$funcname, + .nrelocs = sizeof(bpf_reloc_prog_$funcname) + / sizeof(bpf_reloc_prog_$funcname[0]), + .ins = bpf_insn_prog_$funcname, + .nins = sizeof(bpf_insn_prog_$funcname) + / sizeof(bpf_insn_prog_$funcname[0]), + .license = "$LICENSE", + .type = BPF_PROG_TYPE_SK_REUSEPORT, +}; + +END +} + +process_relocations() +{ + echo "static ngx_bpf_reloc_t bpf_reloc_prog_$funcname[] = {" + + objdump -r $filename | awk '{ + + if (enabled && $NF > 0) { + off = strtonum(sprintf("0x%s", $1)); + name = $3; + + printf(" { \"%s\", %d },\n", name, off/8); + } + + if ($1 == "OFFSET") { + enabled=1; + } +}' + echo "};" + echo +} + +process_section() +{ + echo "static struct bpf_insn bpf_insn_prog_$funcname[] = {" + echo " /* opcode dst src offset imm */" + + section_info=$(objdump -h $filename --section=$funcname | grep "1 $funcname") + + # dd doesn't know hex + length=$(printf "%d" 0x$(echo $section_info | cut -d ' ' -f3)) + offset=$(printf "%d" 0x$(echo $section_info | cut -d ' ' -f6)) + + for ins in $(dd if="$filename" bs=1 count=$length skip=$offset status=none | xxd -p -c 8) + do + opcode=0x${ins:0:2} + srcdst=0x${ins:2:2} + + # bytes are dumped in LE order + offset=0x${ins:6:2}${ins:4:2} # short + immedi=0x${ins:14:2}${ins:12:2}${ins:10:2}${ins:8:2} # int + + dst="$(($srcdst & 0xF))" + src="$(($srcdst & 0xF0))" + src="$(($src >> 4))" + + opcode=$(printf "0x%x" $opcode) + dst=$(printf "BPF_REG_%d" $dst) + src=$(printf "BPF_REG_%d" $src) + offset=$(printf "%d" $offset) + immedi=$(printf "0x%x" $immedi) + + printf " { %4s, %11s, %11s, (int16_t) %6s, %10s },\n" $opcode $dst $src $offset $immedi + done + +cat << END +}; + +END +} + +generate_head +process_relocations +process_section +generate_tail + diff --git a/src/event/quic/bpf/makefile b/src/event/quic/bpf/makefile new file mode 100644 index 0000000..b4d758f --- /dev/null +++ b/src/event/quic/bpf/makefile @@ -0,0 +1,30 @@ +CFLAGS=-O2 -Wall + +LICENSE=BSD + +PROGNAME=ngx_quic_reuseport_helper +RESULT=ngx_event_quic_bpf_code +DEST=../$(RESULT).c + +all: $(RESULT) + +$(RESULT): $(PROGNAME).o + LICENSE=$(LICENSE) PROGNAME=$(PROGNAME) bash ./bpfgen.sh $< > $@ + +DEFS=-DPROGNAME=\"$(PROGNAME)\" \ + -DLICENSE_$(LICENSE) \ + -DLICENSE=\"$(LICENSE)\" \ + +$(PROGNAME).o: $(PROGNAME).c + clang $(CFLAGS) $(DEFS) -target bpf -c $< -o $@ + +install: $(RESULT) + cp $(RESULT) $(DEST) + +clean: + @rm -f $(RESULT) *.o + +debug: $(PROGNAME).o + llvm-objdump -S -no-show-raw-insn $< + +.DELETE_ON_ERROR: diff --git a/src/event/quic/bpf/ngx_quic_reuseport_helper.c b/src/event/quic/bpf/ngx_quic_reuseport_helper.c new file mode 100644 index 0000000..999e760 --- /dev/null +++ b/src/event/quic/bpf/ngx_quic_reuseport_helper.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +/* + * the bpf_helpers.h is not included into linux-headers, only available + * with kernel sources in "tools/lib/bpf/bpf_helpers.h" or in libbpf. + */ +#include + + +#if !defined(SEC) +#define SEC(NAME) __attribute__((section(NAME), used)) +#endif + + +#if defined(LICENSE_GPL) + +/* + * To see debug: + * + * echo 1 > /sys/kernel/debug/tracing/events/bpf_trace/enable + * cat /sys/kernel/debug/tracing/trace_pipe + * echo 0 > /sys/kernel/debug/tracing/events/bpf_trace/enable + */ + +#define debugmsg(fmt, ...) \ +do { \ + char __buf[] = fmt; \ + bpf_trace_printk(__buf, sizeof(__buf), ##__VA_ARGS__); \ +} while (0) + +#else + +#define debugmsg(fmt, ...) + +#endif + +char _license[] SEC("license") = LICENSE; + +/*****************************************************************************/ + +#define NGX_QUIC_PKT_LONG 0x80 /* header form */ +#define NGX_QUIC_SERVER_CID_LEN 20 + + +#define advance_data(nbytes) \ + offset += nbytes; \ + if (start + offset > end) { \ + debugmsg("cannot read %ld bytes at offset %ld", nbytes, offset); \ + goto failed; \ + } \ + data = start + offset - 1; + + +#define ngx_quic_parse_uint64(p) \ + (((__u64)(p)[0] << 56) | \ + ((__u64)(p)[1] << 48) | \ + ((__u64)(p)[2] << 40) | \ + ((__u64)(p)[3] << 32) | \ + ((__u64)(p)[4] << 24) | \ + ((__u64)(p)[5] << 16) | \ + ((__u64)(p)[6] << 8) | \ + ((__u64)(p)[7])) + +/* + * actual map object is created by the "bpf" system call, + * all pointers to this variable are replaced by the bpf loader + */ +struct bpf_map_def SEC("maps") ngx_quic_sockmap; + + +SEC(PROGNAME) +int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx) +{ + int rc; + __u64 key; + size_t len, offset; + unsigned char *start, *end, *data, *dcid; + + start = ctx->data; + end = (unsigned char *) ctx->data_end; + offset = 0; + + advance_data(sizeof(struct udphdr)); /* data at UDP header */ + advance_data(1); /* data at QUIC flags */ + + if (data[0] & NGX_QUIC_PKT_LONG) { + + advance_data(4); /* data at QUIC version */ + advance_data(1); /* data at DCID len */ + + len = data[0]; /* read DCID length */ + + if (len < 8) { + /* it's useless to search for key in such short DCID */ + return SK_PASS; + } + + } else { + len = NGX_QUIC_SERVER_CID_LEN; + } + + dcid = &data[1]; + advance_data(len); /* we expect the packet to have full DCID */ + + /* make verifier happy */ + if (dcid + sizeof(__u64) > end) { + goto failed; + } + + key = ngx_quic_parse_uint64(dcid); + + rc = bpf_sk_select_reuseport(ctx, &ngx_quic_sockmap, &key, 0); + + switch (rc) { + case 0: + debugmsg("nginx quic socket selected by key 0x%llx", key); + return SK_PASS; + + /* kernel returns positive error numbers, errno.h defines positive */ + case -ENOENT: + debugmsg("nginx quic default route for key 0x%llx", key); + /* let the default reuseport logic decide which socket to choose */ + return SK_PASS; + + default: + debugmsg("nginx quic bpf_sk_select_reuseport err: %d key 0x%llx", + rc, key); + goto failed; + } + +failed: + /* + * SK_DROP will generate ICMP, but we may want to process "invalid" packet + * in userspace quic to investigate further and finally react properly + * (maybe ignore, maybe send something in response or close connection) + */ + return SK_PASS; +} diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c new file mode 100644 index 0000000..e4690f7 --- /dev/null +++ b/src/event/quic/ngx_event_quic.c @@ -0,0 +1,1452 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c, + ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); +static ngx_int_t ngx_quic_handle_stateless_reset(ngx_connection_t *c, + ngx_quic_header_t *pkt); +static void ngx_quic_input_handler(ngx_event_t *rev); +static void ngx_quic_close_handler(ngx_event_t *ev); + +static ngx_int_t ngx_quic_handle_datagram(ngx_connection_t *c, ngx_buf_t *b, + ngx_quic_conf_t *conf); +static ngx_int_t ngx_quic_handle_packet(ngx_connection_t *c, + ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); +static ngx_int_t ngx_quic_handle_payload(ngx_connection_t *c, + ngx_quic_header_t *pkt); +static ngx_int_t ngx_quic_check_csid(ngx_quic_connection_t *qc, + ngx_quic_header_t *pkt); +static ngx_int_t ngx_quic_handle_frames(ngx_connection_t *c, + ngx_quic_header_t *pkt); + +static void ngx_quic_push_handler(ngx_event_t *ev); + + +static ngx_core_module_t ngx_quic_module_ctx = { + ngx_string("quic"), + NULL, + NULL +}; + + +ngx_module_t ngx_quic_module = { + NGX_MODULE_V1, + &ngx_quic_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_CORE_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 +}; + + +#if (NGX_DEBUG) + +void +ngx_quic_connstate_dbg(ngx_connection_t *c) +{ + u_char *p, *last; + ngx_quic_connection_t *qc; + u_char buf[NGX_MAX_ERROR_STR]; + + p = buf; + last = p + sizeof(buf); + + qc = ngx_quic_get_connection(c); + + p = ngx_slprintf(p, last, "state:"); + + if (qc) { + + if (qc->error != (ngx_uint_t) -1) { + p = ngx_slprintf(p, last, "%s", qc->error_app ? " app" : ""); + p = ngx_slprintf(p, last, " error:%ui", qc->error); + + if (qc->error_reason) { + p = ngx_slprintf(p, last, " \"%s\"", qc->error_reason); + } + } + + p = ngx_slprintf(p, last, "%s", qc->shutdown ? " shutdown" : ""); + p = ngx_slprintf(p, last, "%s", qc->closing ? " closing" : ""); + p = ngx_slprintf(p, last, "%s", qc->draining ? " draining" : ""); + p = ngx_slprintf(p, last, "%s", qc->key_phase ? " kp" : ""); + + } else { + p = ngx_slprintf(p, last, " early"); + } + + if (c->read->timer_set) { + p = ngx_slprintf(p, last, + qc && qc->send_timer_set ? " send:%M" : " read:%M", + c->read->timer.key - ngx_current_msec); + } + + if (qc) { + + if (qc->push.timer_set) { + p = ngx_slprintf(p, last, " push:%M", + qc->push.timer.key - ngx_current_msec); + } + + if (qc->pto.timer_set) { + p = ngx_slprintf(p, last, " pto:%M", + qc->pto.timer.key - ngx_current_msec); + } + + if (qc->close.timer_set) { + p = ngx_slprintf(p, last, " close:%M", + qc->close.timer.key - ngx_current_msec); + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic %*s", p - buf, buf); +} + +#endif + + +ngx_int_t +ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp) +{ + ngx_str_t scid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + scid.data = qc->path->cid->id; + scid.len = qc->path->cid->len; + + if (scid.len != ctp->initial_scid.len + || ngx_memcmp(scid.data, ctp->initial_scid.data, scid.len) != 0) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic client initial_source_connection_id mismatch"); + return NGX_ERROR; + } + + if (ctp->max_udp_payload_size < NGX_QUIC_MIN_INITIAL_SIZE + || ctp->max_udp_payload_size > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) + { + qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; + qc->error_reason = "invalid maximum packet size"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic maximum packet size is invalid"); + return NGX_ERROR; + } + + if (ctp->active_connection_id_limit < 2) { + qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; + qc->error_reason = "invalid active_connection_id_limit"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic active_connection_id_limit is invalid"); + return NGX_ERROR; + } + + if (ctp->ack_delay_exponent > 20) { + qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; + qc->error_reason = "invalid ack_delay_exponent"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic ack_delay_exponent is invalid"); + return NGX_ERROR; + } + + if (ctp->max_ack_delay >= 16384) { + qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; + qc->error_reason = "invalid max_ack_delay"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic max_ack_delay is invalid"); + return NGX_ERROR; + } + + if (ctp->max_idle_timeout > 0 + && ctp->max_idle_timeout < qc->tp.max_idle_timeout) + { + qc->tp.max_idle_timeout = ctp->max_idle_timeout; + } + + qc->streams.server_max_streams_bidi = ctp->initial_max_streams_bidi; + qc->streams.server_max_streams_uni = ctp->initial_max_streams_uni; + + ngx_memcpy(&qc->ctp, ctp, sizeof(ngx_quic_tp_t)); + + return NGX_OK; +} + + +void +ngx_quic_run(ngx_connection_t *c, ngx_quic_conf_t *conf) +{ + ngx_int_t rc; + ngx_quic_connection_t *qc; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic run"); + + rc = ngx_quic_handle_datagram(c, c->buffer, conf); + if (rc != NGX_OK) { + ngx_quic_close_connection(c, rc); + return; + } + + /* quic connection is now created */ + qc = ngx_quic_get_connection(c); + + ngx_add_timer(c->read, qc->tp.max_idle_timeout); + + if (!qc->streams.initialized) { + ngx_add_timer(&qc->close, qc->conf->handshake_timeout); + } + + ngx_quic_connstate_dbg(c); + + c->read->handler = ngx_quic_input_handler; + + return; +} + + +static ngx_quic_connection_t * +ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf, + ngx_quic_header_t *pkt) +{ + ngx_uint_t i; + ngx_quic_tp_t *ctp; + ngx_quic_connection_t *qc; + + qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); + if (qc == NULL) { + return NULL; + } + + qc->keys = ngx_pcalloc(c->pool, sizeof(ngx_quic_keys_t)); + if (qc->keys == NULL) { + return NULL; + } + + qc->version = pkt->version; + + ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel, + ngx_quic_rbtree_insert_stream); + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + ngx_queue_init(&qc->send_ctx[i].frames); + ngx_queue_init(&qc->send_ctx[i].sending); + ngx_queue_init(&qc->send_ctx[i].sent); + qc->send_ctx[i].largest_pn = NGX_QUIC_UNSET_PN; + qc->send_ctx[i].largest_ack = NGX_QUIC_UNSET_PN; + qc->send_ctx[i].largest_range = NGX_QUIC_UNSET_PN; + qc->send_ctx[i].pending_ack = NGX_QUIC_UNSET_PN; + } + + qc->send_ctx[0].level = ssl_encryption_initial; + qc->send_ctx[1].level = ssl_encryption_handshake; + qc->send_ctx[2].level = ssl_encryption_application; + + ngx_queue_init(&qc->free_frames); + + ngx_quic_init_rtt(qc); + + qc->pto.log = c->log; + qc->pto.data = c; + qc->pto.handler = ngx_quic_pto_handler; + + qc->push.log = c->log; + qc->push.data = c; + qc->push.handler = ngx_quic_push_handler; + + qc->close.log = c->log; + qc->close.data = c; + qc->close.handler = ngx_quic_close_handler; + + qc->path_validation.log = c->log; + qc->path_validation.data = c; + qc->path_validation.handler = ngx_quic_path_handler; + + qc->key_update.log = c->log; + qc->key_update.data = c; + qc->key_update.handler = ngx_quic_keys_update; + + qc->conf = conf; + + if (ngx_quic_init_transport_params(&qc->tp, conf) != NGX_OK) { + return NULL; + } + + ctp = &qc->ctp; + + /* defaults to be used before actual client parameters are received */ + ctp->max_udp_payload_size = NGX_QUIC_MAX_UDP_PAYLOAD_SIZE; + ctp->ack_delay_exponent = NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT; + ctp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY; + ctp->active_connection_id_limit = 2; + + ngx_queue_init(&qc->streams.uninitialized); + ngx_queue_init(&qc->streams.free); + + qc->streams.recv_max_data = qc->tp.initial_max_data; + qc->streams.recv_window = qc->streams.recv_max_data; + + qc->streams.client_max_streams_uni = qc->tp.initial_max_streams_uni; + qc->streams.client_max_streams_bidi = qc->tp.initial_max_streams_bidi; + + qc->congestion.window = ngx_min(10 * qc->tp.max_udp_payload_size, + ngx_max(2 * qc->tp.max_udp_payload_size, + 14720)); + qc->congestion.ssthresh = (size_t) -1; + qc->congestion.recovery_start = ngx_current_msec; + + if (pkt->validated && pkt->retried) { + qc->tp.retry_scid.len = pkt->dcid.len; + qc->tp.retry_scid.data = ngx_pstrdup(c->pool, &pkt->dcid); + if (qc->tp.retry_scid.data == NULL) { + return NULL; + } + } + + if (ngx_quic_keys_set_initial_secret(qc->keys, &pkt->dcid, c->log) + != NGX_OK) + { + return NULL; + } + + qc->validated = pkt->validated; + + if (ngx_quic_open_sockets(c, qc, pkt) != NGX_OK) { + ngx_quic_keys_cleanup(qc->keys); + return NULL; + } + + c->idle = 1; + ngx_reusable_connection(c, 1); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic connection created"); + + return qc; +} + + +static ngx_int_t +ngx_quic_handle_stateless_reset(ngx_connection_t *c, ngx_quic_header_t *pkt) +{ + u_char *tail, ch; + ngx_uint_t i; + ngx_queue_t *q; + ngx_quic_client_id_t *cid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + /* A stateless reset uses an entire UDP datagram */ + if (!pkt->first) { + return NGX_DECLINED; + } + + tail = pkt->raw->last - NGX_QUIC_SR_TOKEN_LEN; + + for (q = ngx_queue_head(&qc->client_ids); + q != ngx_queue_sentinel(&qc->client_ids); + q = ngx_queue_next(q)) + { + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + + if (cid->seqnum == 0 || !cid->used) { + /* + * No stateless reset token in initial connection id. + * Don't accept a token from an unused connection id. + */ + continue; + } + + /* constant time comparison */ + + for (ch = 0, i = 0; i < NGX_QUIC_SR_TOKEN_LEN; i++) { + ch |= tail[i] ^ cid->sr_token[i]; + } + + if (ch == 0) { + return NGX_OK; + } + } + + return NGX_DECLINED; +} + + +static void +ngx_quic_input_handler(ngx_event_t *rev) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_connection_t *c; + ngx_quic_connection_t *qc; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, 0, "quic input handler"); + + c = rev->data; + qc = ngx_quic_get_connection(c); + + c->log->action = "handling quic input"; + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "quic client timed out"); + ngx_quic_close_connection(c, NGX_DONE); + return; + } + + if (c->close) { + c->close = 0; + + if (!ngx_exiting || !qc->streams.initialized) { + qc->error = NGX_QUIC_ERR_NO_ERROR; + qc->error_reason = "graceful shutdown"; + ngx_quic_close_connection(c, NGX_ERROR); + return; + } + + if (!qc->closing && qc->conf->shutdown) { + qc->conf->shutdown(c); + } + + return; + } + + b = c->udp->buffer; + if (b == NULL) { + return; + } + + rc = ngx_quic_handle_datagram(c, b, NULL); + + if (rc == NGX_ERROR) { + ngx_quic_close_connection(c, NGX_ERROR); + return; + } + + if (rc == NGX_DONE) { + return; + } + + /* rc == NGX_OK */ + + qc->send_timer_set = 0; + ngx_add_timer(rev, qc->tp.max_idle_timeout); + + ngx_quic_connstate_dbg(c); +} + + +void +ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc) +{ + ngx_uint_t i; + ngx_pool_t *pool; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (qc == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet rejected rc:%i, cleanup connection", rc); + goto quic_done; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic close %s rc:%i", + qc->closing ? "resumed": "initiated", rc); + + if (!qc->closing) { + + /* drop packets from retransmit queues, no ack is expected */ + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + ngx_quic_free_frames(c, &qc->send_ctx[i].frames); + ngx_quic_free_frames(c, &qc->send_ctx[i].sent); + } + + if (qc->close.timer_set) { + ngx_del_timer(&qc->close); + } + + if (rc == NGX_DONE) { + + /* + * RFC 9000, 10.1. Idle Timeout + * + * If a max_idle_timeout is specified by either endpoint in its + * transport parameters (Section 18.2), the connection is silently + * closed and its state is discarded when it remains idle + */ + + /* this case also handles some errors from ngx_quic_run() */ + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic close silent drain:%d timedout:%d", + qc->draining, c->read->timedout); + } else { + + /* + * RFC 9000, 10.2. Immediate Close + * + * An endpoint sends a CONNECTION_CLOSE frame (Section 19.19) + * to terminate the connection immediately. + */ + + if (qc->error == (ngx_uint_t) -1) { + qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; + qc->error_app = 0; + } + + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic close immediate term:%d drain:%d " + "%serror:%ui \"%s\"", + rc == NGX_ERROR ? 1 : 0, qc->draining, + qc->error_app ? "app " : "", qc->error, + qc->error_reason ? qc->error_reason : ""); + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + ctx = &qc->send_ctx[i]; + + if (!ngx_quic_keys_available(qc->keys, ctx->level, 1)) { + continue; + } + + qc->error_level = ctx->level; + (void) ngx_quic_send_cc(c); + + if (rc == NGX_OK) { + ngx_add_timer(&qc->close, 3 * ngx_quic_pto(c, ctx)); + } + } + } + + qc->closing = 1; + } + + if (rc == NGX_ERROR && qc->close.timer_set) { + /* do not wait for timer in case of fatal error */ + ngx_del_timer(&qc->close); + } + + if (ngx_quic_close_streams(c, qc) == NGX_AGAIN) { + return; + } + + if (qc->push.timer_set) { + ngx_del_timer(&qc->push); + } + + if (qc->pto.timer_set) { + ngx_del_timer(&qc->pto); + } + + if (qc->path_validation.timer_set) { + ngx_del_timer(&qc->path_validation); + } + + if (qc->push.posted) { + ngx_delete_posted_event(&qc->push); + } + + if (qc->key_update.posted) { + ngx_delete_posted_event(&qc->key_update); + } + + if (qc->close.timer_set) { + return; + } + + if (qc->close.posted) { + ngx_delete_posted_event(&qc->close); + } + + ngx_quic_close_sockets(c); + + ngx_quic_keys_cleanup(qc->keys); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic close completed"); + + /* may be tested from SSL callback during SSL shutdown */ + c->udp = NULL; + +quic_done: + + if (c->ssl) { + (void) ngx_ssl_shutdown(c); + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); +#endif + + c->destroyed = 1; + + pool = c->pool; + + ngx_close_connection(c); + + ngx_destroy_pool(pool); +} + + +void +ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, + const char *reason) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (qc->closing) { + return; + } + + qc->error = err; + qc->error_reason = reason; + qc->error_app = 1; + qc->error_ftype = 0; + + ngx_post_event(&qc->close, &ngx_posted_events); +} + + +void +ngx_quic_shutdown_connection(ngx_connection_t *c, ngx_uint_t err, + const char *reason) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + qc->shutdown = 1; + qc->shutdown_code = err; + qc->shutdown_reason = reason; + + ngx_quic_shutdown_quic(c); +} + + +static void +ngx_quic_close_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic close handler"); + + c = ev->data; + + ngx_quic_close_connection(c, NGX_OK); +} + + +static ngx_int_t +ngx_quic_handle_datagram(ngx_connection_t *c, ngx_buf_t *b, + ngx_quic_conf_t *conf) +{ + size_t size; + u_char *p, *start; + ngx_int_t rc; + ngx_uint_t good; + ngx_quic_path_t *path; + ngx_quic_header_t pkt; + ngx_quic_connection_t *qc; + + good = 0; + path = NULL; + + size = b->last - b->pos; + + p = start = b->pos; + + while (p < b->last) { + + ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); + pkt.raw = b; + pkt.data = p; + pkt.len = b->last - p; + pkt.log = c->log; + pkt.first = (p == start) ? 1 : 0; + pkt.path = path; + pkt.flags = p[0]; + pkt.raw->pos++; + + rc = ngx_quic_handle_packet(c, conf, &pkt); + +#if (NGX_DEBUG) + if (pkt.parsed) { + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet done rc:%i level:%s" + " decr:%d pn:%L perr:%ui", + rc, ngx_quic_level_name(pkt.level), + pkt.decrypted, pkt.pn, pkt.error); + } else { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet done rc:%i parse failed", rc); + } +#endif + + if (rc == NGX_ERROR || rc == NGX_DONE) { + return rc; + } + + if (rc == NGX_OK) { + good = 1; + } + + path = pkt.path; /* preserve packet path from 1st packet */ + + /* NGX_OK || NGX_DECLINED */ + + /* + * we get NGX_DECLINED when there are no keys [yet] available + * to decrypt packet. + * Instead of queueing it, we ignore it and rely on the sender's + * retransmission: + * + * RFC 9000, 12.2. Coalescing Packets + * + * For example, if decryption fails (because the keys are + * not available or for any other reason), the receiver MAY either + * discard or buffer the packet for later processing and MUST + * attempt to process the remaining packets. + * + * We also skip packets that don't match connection state + * or cannot be parsed properly. + */ + + /* b->pos is at header end, adjust by actual packet length */ + b->pos = pkt.data + pkt.len; + + p = b->pos; + } + + if (!good) { + return NGX_DONE; + } + + qc = ngx_quic_get_connection(c); + + if (qc) { + qc->received += size; + + if ((uint64_t) (c->sent + qc->received) / 8 > + (qc->streams.sent + qc->streams.recv_last) + 1048576) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic flood detected"); + + qc->error = NGX_QUIC_ERR_NO_ERROR; + qc->error_reason = "QUIC flood detected"; + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf, + ngx_quic_header_t *pkt) +{ + ngx_int_t rc; + ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + + c->log->action = "parsing quic packet"; + + rc = ngx_quic_parse_packet(pkt); + + if (rc == NGX_ERROR) { + return NGX_DECLINED; + } + + pkt->parsed = 1; + + c->log->action = "handling quic packet"; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet rx dcid len:%uz %xV", + pkt->dcid.len, &pkt->dcid); + +#if (NGX_DEBUG) + if (pkt->level != ssl_encryption_application) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet rx scid len:%uz %xV", + pkt->scid.len, &pkt->scid); + } + + if (pkt->level == ssl_encryption_initial) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic address validation token len:%uz %xV", + pkt->token.len, &pkt->token); + } +#endif + + qc = ngx_quic_get_connection(c); + + if (qc) { + + if (rc == NGX_ABORT) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic unsupported version: 0x%xD", pkt->version); + return NGX_DECLINED; + } + + if (pkt->level != ssl_encryption_application) { + + if (pkt->version != qc->version) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic version mismatch: 0x%xD", pkt->version); + return NGX_DECLINED; + } + + if (pkt->first) { + qsock = ngx_quic_get_socket(c); + + if (ngx_cmp_sockaddr(&qsock->sockaddr.sockaddr, qsock->socklen, + qc->path->sockaddr, qc->path->socklen, 1) + != NGX_OK) + { + /* packet comes from unknown path, possibly migration */ + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic too early migration attempt"); + return NGX_DONE; + } + } + + if (ngx_quic_check_csid(qc, pkt) != NGX_OK) { + return NGX_DECLINED; + } + + } + + rc = ngx_quic_handle_payload(c, pkt); + + if (rc == NGX_DECLINED && pkt->level == ssl_encryption_application) { + if (ngx_quic_handle_stateless_reset(c, pkt) == NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic stateless reset packet detected"); + + qc->draining = 1; + ngx_post_event(&qc->close, &ngx_posted_events); + + return NGX_OK; + } + } + + return rc; + } + + /* packet does not belong to a connection */ + + if (rc == NGX_ABORT) { + return ngx_quic_negotiate_version(c, pkt); + } + + if (pkt->level == ssl_encryption_application) { + return ngx_quic_send_stateless_reset(c, conf, pkt); + } + + if (pkt->level != ssl_encryption_initial) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic expected initial, got handshake"); + return NGX_ERROR; + } + + c->log->action = "handling initial packet"; + + if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) { + /* RFC 9000, 7.2. Negotiating Connection IDs */ + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic too short dcid in initial" + " packet: len:%i", pkt->dcid.len); + return NGX_ERROR; + } + + /* process retry and initialize connection IDs */ + + if (pkt->token.len) { + + rc = ngx_quic_validate_token(c, conf->av_token_key, pkt); + + if (rc == NGX_ERROR) { + /* internal error */ + return NGX_ERROR; + + } else if (rc == NGX_ABORT) { + /* token cannot be decrypted */ + return ngx_quic_send_early_cc(c, pkt, + NGX_QUIC_ERR_INVALID_TOKEN, + "cannot decrypt token"); + } else if (rc == NGX_DECLINED) { + /* token is invalid */ + + if (pkt->retried) { + /* invalid address validation token */ + return ngx_quic_send_early_cc(c, pkt, + NGX_QUIC_ERR_INVALID_TOKEN, + "invalid address validation token"); + } else if (conf->retry) { + /* invalid NEW_TOKEN */ + return ngx_quic_send_retry(c, conf, pkt); + } + } + + /* NGX_OK */ + + } else if (conf->retry) { + return ngx_quic_send_retry(c, conf, pkt); + + } else { + pkt->odcid = pkt->dcid; + } + + if (ngx_terminate || ngx_exiting) { + if (conf->retry) { + return ngx_quic_send_retry(c, conf, pkt); + } + + return NGX_ERROR; + } + + c->log->action = "creating quic connection"; + + qc = ngx_quic_new_connection(c, conf, pkt); + if (qc == NULL) { + return NGX_ERROR; + } + + return ngx_quic_handle_payload(c, pkt); +} + + +static ngx_int_t +ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt) +{ + ngx_int_t rc; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + + qc = ngx_quic_get_connection(c); + + qc->error = (ngx_uint_t) -1; + qc->error_reason = 0; + + c->log->action = "decrypting packet"; + + if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic no %s keys, ignoring packet", + ngx_quic_level_name(pkt->level)); + return NGX_DECLINED; + } + +#if !defined (OPENSSL_IS_BORINGSSL) + /* OpenSSL provides read keys for an application level before it's ready */ + + if (pkt->level == ssl_encryption_application && !c->ssl->handshaked) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic no %s keys ready, ignoring packet", + ngx_quic_level_name(pkt->level)); + return NGX_DECLINED; + } +#endif + + pkt->keys = qc->keys; + pkt->key_phase = qc->key_phase; + pkt->plaintext = buf; + + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + + rc = ngx_quic_decrypt(pkt, &ctx->largest_pn); + if (rc != NGX_OK) { + qc->error = pkt->error; + qc->error_reason = "failed to decrypt packet"; + return rc; + } + + pkt->decrypted = 1; + + c->log->action = "handling decrypted packet"; + + if (pkt->path == NULL) { + rc = ngx_quic_set_path(c, pkt); + if (rc != NGX_OK) { + return rc; + } + } + + if (c->ssl == NULL) { + if (ngx_quic_init_connection(c) != NGX_OK) { + return NGX_ERROR; + } + } + + if (pkt->level == ssl_encryption_handshake) { + /* + * RFC 9001, 4.9.1. Discarding Initial Keys + * + * The successful use of Handshake packets indicates + * that no more Initial packets need to be exchanged + */ + ngx_quic_discard_ctx(c, ssl_encryption_initial); + + if (!qc->path->validated) { + qc->path->validated = 1; + ngx_quic_path_dbg(c, "in handshake", qc->path); + ngx_post_event(&qc->push, &ngx_posted_events); + } + } + + if (qc->closing) { + /* + * RFC 9000, 10.2. Immediate Close + * + * ... delayed or reordered packets are properly discarded. + * + * In the closing state, an endpoint retains only enough information + * to generate a packet containing a CONNECTION_CLOSE frame and to + * identify packets as belonging to the connection. + */ + + qc->error_level = pkt->level; + qc->error = NGX_QUIC_ERR_NO_ERROR; + qc->error_reason = "connection is closing, packet discarded"; + qc->error_ftype = 0; + qc->error_app = 0; + + return ngx_quic_send_cc(c); + } + + pkt->received = ngx_current_msec; + + c->log->action = "handling payload"; + + if (pkt->level != ssl_encryption_application) { + return ngx_quic_handle_frames(c, pkt); + } + + if (!pkt->key_update) { + return ngx_quic_handle_frames(c, pkt); + } + + /* switch keys and generate next on Key Phase change */ + + qc->key_phase ^= 1; + ngx_quic_keys_switch(c, qc->keys); + + rc = ngx_quic_handle_frames(c, pkt); + if (rc != NGX_OK) { + return rc; + } + + ngx_post_event(&qc->key_update, &ngx_posted_events); + + return NGX_OK; +} + + +void +ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level) +{ + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_socket_t *qsock; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (!ngx_quic_keys_available(qc->keys, level, 0) + && !ngx_quic_keys_available(qc->keys, level, 1)) + { + return; + } + + ngx_quic_keys_discard(qc->keys, level); + + qc->pto_count = 0; + + ctx = ngx_quic_get_send_ctx(qc, level); + + ngx_quic_free_buffer(c, &ctx->crypto); + + while (!ngx_queue_empty(&ctx->sent)) { + q = ngx_queue_head(&ctx->sent); + ngx_queue_remove(q); + + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + ngx_quic_congestion_ack(c, f); + ngx_quic_free_frame(c, f); + } + + while (!ngx_queue_empty(&ctx->frames)) { + q = ngx_queue_head(&ctx->frames); + ngx_queue_remove(q); + + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + ngx_quic_free_frame(c, f); + } + + if (level == ssl_encryption_initial) { + /* close temporary listener with initial dcid */ + qsock = ngx_quic_find_socket(c, NGX_QUIC_UNSET_PN); + if (qsock) { + ngx_quic_close_socket(c, qsock); + } + } + + ctx->send_ack = 0; + + ngx_quic_set_lost_timer(c); +} + + +static ngx_int_t +ngx_quic_check_csid(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt) +{ + ngx_queue_t *q; + ngx_quic_client_id_t *cid; + + for (q = ngx_queue_head(&qc->client_ids); + q != ngx_queue_sentinel(&qc->client_ids); + q = ngx_queue_next(q)) + { + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + + if (pkt->scid.len == cid->len + && ngx_memcmp(pkt->scid.data, cid->id, cid->len) == 0) + { + return NGX_OK; + } + } + + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic scid"); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt) +{ + u_char *end, *p; + ssize_t len; + ngx_buf_t buf; + ngx_uint_t do_close, nonprobing; + ngx_chain_t chain; + ngx_quic_frame_t frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + p = pkt->payload.data; + end = p + pkt->payload.len; + + do_close = 0; + nonprobing = 0; + + while (p < end) { + + c->log->action = "parsing frames"; + + ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); + ngx_memzero(&buf, sizeof(ngx_buf_t)); + buf.temporary = 1; + + chain.buf = &buf; + chain.next = NULL; + frame.data = &chain; + + len = ngx_quic_parse_frame(pkt, p, end, &frame); + + if (len < 0) { + qc->error = pkt->error; + return NGX_ERROR; + } + + ngx_quic_log_frame(c->log, &frame, 0); + + c->log->action = "handling frames"; + + p += len; + + switch (frame.type) { + /* probing frames */ + case NGX_QUIC_FT_PADDING: + case NGX_QUIC_FT_PATH_CHALLENGE: + case NGX_QUIC_FT_PATH_RESPONSE: + case NGX_QUIC_FT_NEW_CONNECTION_ID: + break; + + /* non-probing frames */ + default: + nonprobing = 1; + break; + } + + switch (frame.type) { + + case NGX_QUIC_FT_ACK: + if (ngx_quic_handle_ack_frame(c, pkt, &frame) != NGX_OK) { + return NGX_ERROR; + } + + continue; + + case NGX_QUIC_FT_PADDING: + /* no action required */ + continue; + + case NGX_QUIC_FT_CONNECTION_CLOSE: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: + do_close = 1; + continue; + } + + /* got there with ack-eliciting packet */ + pkt->need_ack = 1; + + switch (frame.type) { + + case NGX_QUIC_FT_CRYPTO: + + if (ngx_quic_handle_crypto_frame(c, pkt, &frame) != NGX_OK) { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_PING: + break; + + case NGX_QUIC_FT_STREAM: + + if (ngx_quic_handle_stream_frame(c, pkt, &frame) != NGX_OK) { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_MAX_DATA: + + if (ngx_quic_handle_max_data_frame(c, &frame.u.max_data) != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_STREAMS_BLOCKED: + case NGX_QUIC_FT_STREAMS_BLOCKED2: + + if (ngx_quic_handle_streams_blocked_frame(c, pkt, + &frame.u.streams_blocked) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_DATA_BLOCKED: + + if (ngx_quic_handle_data_blocked_frame(c, pkt, + &frame.u.data_blocked) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_STREAM_DATA_BLOCKED: + + if (ngx_quic_handle_stream_data_blocked_frame(c, pkt, + &frame.u.stream_data_blocked) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_MAX_STREAM_DATA: + + if (ngx_quic_handle_max_stream_data_frame(c, pkt, + &frame.u.max_stream_data) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_RESET_STREAM: + + if (ngx_quic_handle_reset_stream_frame(c, pkt, + &frame.u.reset_stream) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_STOP_SENDING: + + if (ngx_quic_handle_stop_sending_frame(c, pkt, + &frame.u.stop_sending) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_MAX_STREAMS: + case NGX_QUIC_FT_MAX_STREAMS2: + + if (ngx_quic_handle_max_streams_frame(c, pkt, &frame.u.max_streams) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_PATH_CHALLENGE: + + if (ngx_quic_handle_path_challenge_frame(c, pkt, + &frame.u.path_challenge) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_PATH_RESPONSE: + + if (ngx_quic_handle_path_response_frame(c, &frame.u.path_response) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_NEW_CONNECTION_ID: + + if (ngx_quic_handle_new_connection_id_frame(c, &frame.u.ncid) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + case NGX_QUIC_FT_RETIRE_CONNECTION_ID: + + if (ngx_quic_handle_retire_connection_id_frame(c, + &frame.u.retire_cid) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + + default: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic missing frame handler"); + return NGX_ERROR; + } + } + + if (p != end) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic trailing garbage in payload:%ui bytes", end - p); + + qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + return NGX_ERROR; + } + + if (do_close) { + qc->draining = 1; + ngx_post_event(&qc->close, &ngx_posted_events); + } + + if (pkt->path != qc->path && nonprobing) { + + /* + * RFC 9000, 9.2. Initiating Connection Migration + * + * An endpoint can migrate a connection to a new local + * address by sending packets containing non-probing frames + * from that address. + */ + if (ngx_quic_handle_migration(c, pkt) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_quic_ack_packet(c, pkt) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_quic_push_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic push handler"); + + c = ev->data; + + if (ngx_quic_output(c) != NGX_OK) { + ngx_quic_close_connection(c, NGX_ERROR); + return; + } + + ngx_quic_connstate_dbg(c); +} + + +void +ngx_quic_shutdown_quic(ngx_connection_t *c) +{ + ngx_quic_connection_t *qc; + + if (c->reusable) { + qc = ngx_quic_get_connection(c); + ngx_quic_finalize_connection(c, qc->shutdown_code, qc->shutdown_reason); + } +} diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h new file mode 100644 index 0000000..1520167 --- /dev/null +++ b/src/event/quic/ngx_event_quic.h @@ -0,0 +1,129 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_H_INCLUDED_ +#define _NGX_EVENT_QUIC_H_INCLUDED_ + + +#include +#include + + +#define NGX_QUIC_MAX_UDP_PAYLOAD_SIZE 65527 + +#define NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT 3 +#define NGX_QUIC_DEFAULT_MAX_ACK_DELAY 25 +#define NGX_QUIC_DEFAULT_HOST_KEY_LEN 32 +#define NGX_QUIC_SR_KEY_LEN 32 +#define NGX_QUIC_AV_KEY_LEN 32 + +#define NGX_QUIC_SR_TOKEN_LEN 16 + +#define NGX_QUIC_MIN_INITIAL_SIZE 1200 + +#define NGX_QUIC_STREAM_SERVER_INITIATED 0x01 +#define NGX_QUIC_STREAM_UNIDIRECTIONAL 0x02 + + +typedef ngx_int_t (*ngx_quic_init_pt)(ngx_connection_t *c); +typedef void (*ngx_quic_shutdown_pt)(ngx_connection_t *c); + + +typedef enum { + NGX_QUIC_STREAM_SEND_READY = 0, + NGX_QUIC_STREAM_SEND_SEND, + NGX_QUIC_STREAM_SEND_DATA_SENT, + NGX_QUIC_STREAM_SEND_DATA_RECVD, + NGX_QUIC_STREAM_SEND_RESET_SENT, + NGX_QUIC_STREAM_SEND_RESET_RECVD +} ngx_quic_stream_send_state_e; + + +typedef enum { + NGX_QUIC_STREAM_RECV_RECV = 0, + NGX_QUIC_STREAM_RECV_SIZE_KNOWN, + NGX_QUIC_STREAM_RECV_DATA_RECVD, + NGX_QUIC_STREAM_RECV_DATA_READ, + NGX_QUIC_STREAM_RECV_RESET_RECVD, + NGX_QUIC_STREAM_RECV_RESET_READ +} ngx_quic_stream_recv_state_e; + + +typedef struct { + uint64_t size; + uint64_t offset; + uint64_t last_offset; + ngx_chain_t *chain; + ngx_chain_t *last_chain; +} ngx_quic_buffer_t; + + +typedef struct { + ngx_ssl_t *ssl; + + ngx_flag_t retry; + ngx_flag_t gso_enabled; + ngx_flag_t disable_active_migration; + ngx_msec_t handshake_timeout; + ngx_msec_t idle_timeout; + ngx_str_t host_key; + size_t stream_buffer_size; + ngx_uint_t max_concurrent_streams_bidi; + ngx_uint_t max_concurrent_streams_uni; + ngx_uint_t active_connection_id_limit; + ngx_int_t stream_close_code; + ngx_int_t stream_reject_code_uni; + ngx_int_t stream_reject_code_bidi; + + ngx_quic_init_pt init; + ngx_quic_shutdown_pt shutdown; + + u_char av_token_key[NGX_QUIC_AV_KEY_LEN]; + u_char sr_token_key[NGX_QUIC_SR_KEY_LEN]; +} ngx_quic_conf_t; + + +struct ngx_quic_stream_s { + ngx_rbtree_node_t node; + ngx_queue_t queue; + ngx_connection_t *parent; + ngx_connection_t *connection; + uint64_t id; + uint64_t sent; + uint64_t acked; + uint64_t send_max_data; + uint64_t send_offset; + uint64_t send_final_size; + uint64_t recv_max_data; + uint64_t recv_offset; + uint64_t recv_window; + uint64_t recv_last; + uint64_t recv_final_size; + ngx_quic_buffer_t send; + ngx_quic_buffer_t recv; + ngx_quic_stream_send_state_e send_state; + ngx_quic_stream_recv_state_e recv_state; + unsigned cancelable:1; + unsigned fin_acked:1; +}; + + +void ngx_quic_recvmsg(ngx_event_t *ev); +void ngx_quic_run(ngx_connection_t *c, ngx_quic_conf_t *conf); +ngx_connection_t *ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi); +void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, + const char *reason); +void ngx_quic_shutdown_connection(ngx_connection_t *c, ngx_uint_t err, + const char *reason); +ngx_int_t ngx_quic_reset_stream(ngx_connection_t *c, ngx_uint_t err); +ngx_int_t ngx_quic_shutdown_stream(ngx_connection_t *c, int how); +void ngx_quic_cancelable_stream(ngx_connection_t *c); +ngx_int_t ngx_quic_get_packet_dcid(ngx_log_t *log, u_char *data, size_t len, + ngx_str_t *dcid); +ngx_int_t ngx_quic_derive_key(ngx_log_t *log, const char *label, + ngx_str_t *secret, ngx_str_t *salt, u_char *out, size_t len); + +#endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c new file mode 100644 index 0000000..c7ffd44 --- /dev/null +++ b/src/event/quic/ngx_event_quic_ack.c @@ -0,0 +1,1188 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#define NGX_QUIC_MAX_ACK_GAP 2 + +/* RFC 9002, 6.1.1. Packet Threshold: kPacketThreshold */ +#define NGX_QUIC_PKT_THR 3 /* packets */ +/* RFC 9002, 6.1.2. Time Threshold: kGranularity */ +#define NGX_QUIC_TIME_GRANULARITY 1 /* ms */ + +/* RFC 9002, 7.6.1. Duration: kPersistentCongestionThreshold */ +#define NGX_QUIC_PERSISTENT_CONGESTION_THR 3 + + +/* send time of ACK'ed packets */ +typedef struct { + ngx_msec_t max_pn; + ngx_msec_t oldest; + ngx_msec_t newest; +} ngx_quic_ack_stat_t; + + +static ngx_inline ngx_msec_t ngx_quic_lost_threshold(ngx_quic_connection_t *qc); +static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, + enum ssl_encryption_level_t level, ngx_msec_t send_time); +static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, + ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max, + ngx_quic_ack_stat_t *st); +static void ngx_quic_drop_ack_ranges(ngx_connection_t *c, + ngx_quic_send_ctx_t *ctx, uint64_t pn); +static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c, + ngx_quic_ack_stat_t *st); +static ngx_msec_t ngx_quic_pcg_duration(ngx_connection_t *c); +static void ngx_quic_persistent_congestion(ngx_connection_t *c); +static void ngx_quic_congestion_lost(ngx_connection_t *c, + ngx_quic_frame_t *frame); +static void ngx_quic_lost_handler(ngx_event_t *ev); + + +/* RFC 9002, 6.1.2. Time Threshold: kTimeThreshold, kGranularity */ +static ngx_inline ngx_msec_t +ngx_quic_lost_threshold(ngx_quic_connection_t *qc) +{ + ngx_msec_t thr; + + thr = ngx_max(qc->latest_rtt, qc->avg_rtt); + thr += thr >> 3; + + return ngx_max(thr, NGX_QUIC_TIME_GRANULARITY); +} + + +ngx_int_t +ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, + ngx_quic_frame_t *f) +{ + ssize_t n; + u_char *pos, *end; + uint64_t min, max, gap, range; + ngx_uint_t i; + ngx_quic_ack_stat_t send_time; + ngx_quic_send_ctx_t *ctx; + ngx_quic_ack_frame_t *ack; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_handle_ack_frame level:%d", pkt->level); + + ack = &f->u.ack; + + /* + * RFC 9000, 19.3.1. ACK Ranges + * + * If any computed packet number is negative, an endpoint MUST + * generate a connection error of type FRAME_ENCODING_ERROR. + */ + + if (ack->first_range > ack->largest) { + qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic invalid first range in ack frame"); + return NGX_ERROR; + } + + min = ack->largest - ack->first_range; + max = ack->largest; + + send_time.oldest = NGX_TIMER_INFINITE; + send_time.newest = NGX_TIMER_INFINITE; + + if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time) + != NGX_OK) + { + return NGX_ERROR; + } + + /* RFC 9000, 13.2.4. Limiting Ranges by Tracking ACK Frames */ + if (ctx->largest_ack < max || ctx->largest_ack == NGX_QUIC_UNSET_PN) { + ctx->largest_ack = max; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic updated largest received ack:%uL", max); + + /* + * RFC 9002, 5.1. Generating RTT Samples + * + * An endpoint generates an RTT sample on receiving an + * ACK frame that meets the following two conditions: + * + * - the largest acknowledged packet number is newly acknowledged + * - at least one of the newly acknowledged packets was ack-eliciting. + */ + + if (send_time.max_pn != NGX_TIMER_INFINITE) { + ngx_quic_rtt_sample(c, ack, pkt->level, send_time.max_pn); + } + } + + if (f->data) { + pos = f->data->buf->pos; + end = f->data->buf->last; + + } else { + pos = NULL; + end = NULL; + } + + for (i = 0; i < ack->range_count; i++) { + + n = ngx_quic_parse_ack_range(pkt->log, pos, end, &gap, &range); + if (n == NGX_ERROR) { + return NGX_ERROR; + } + pos += n; + + if (gap + 2 > min) { + qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic invalid range:%ui in ack frame", i); + return NGX_ERROR; + } + + max = min - gap - 2; + + if (range > max) { + qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic invalid range:%ui in ack frame", i); + return NGX_ERROR; + } + + min = max - range; + + if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time) + != NGX_OK) + { + return NGX_ERROR; + } + } + + return ngx_quic_detect_lost(c, &send_time); +} + + +static void +ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, + enum ssl_encryption_level_t level, ngx_msec_t send_time) +{ + ngx_msec_t latest_rtt, ack_delay, adjusted_rtt, rttvar_sample; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + latest_rtt = ngx_current_msec - send_time; + qc->latest_rtt = latest_rtt; + + if (qc->min_rtt == NGX_TIMER_INFINITE) { + qc->min_rtt = latest_rtt; + qc->avg_rtt = latest_rtt; + qc->rttvar = latest_rtt / 2; + qc->first_rtt = ngx_current_msec; + + } else { + qc->min_rtt = ngx_min(qc->min_rtt, latest_rtt); + + ack_delay = (ack->delay << qc->ctp.ack_delay_exponent) / 1000; + + if (c->ssl->handshaked) { + ack_delay = ngx_min(ack_delay, qc->ctp.max_ack_delay); + } + + adjusted_rtt = latest_rtt; + + if (qc->min_rtt + ack_delay < latest_rtt) { + adjusted_rtt -= ack_delay; + } + + rttvar_sample = ngx_abs((ngx_msec_int_t) (qc->avg_rtt - adjusted_rtt)); + qc->rttvar += (rttvar_sample >> 2) - (qc->rttvar >> 2); + qc->avg_rtt += (adjusted_rtt >> 3) - (qc->avg_rtt >> 3); + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic rtt sample latest:%M min:%M avg:%M var:%M", + latest_rtt, qc->min_rtt, qc->avg_rtt, qc->rttvar); +} + + +static ngx_int_t +ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + uint64_t min, uint64_t max, ngx_quic_ack_stat_t *st) +{ + ngx_uint_t found; + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (ctx->level == ssl_encryption_application) { + if (ngx_quic_handle_path_mtu(c, qc->path, min, max) != NGX_OK) { + return NGX_ERROR; + } + } + + st->max_pn = NGX_TIMER_INFINITE; + found = 0; + + q = ngx_queue_head(&ctx->sent); + + while (q != ngx_queue_sentinel(&ctx->sent)) { + + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + q = ngx_queue_next(q); + + if (f->pnum > max) { + break; + } + + if (f->pnum >= min) { + ngx_quic_congestion_ack(c, f); + + switch (f->type) { + case NGX_QUIC_FT_ACK: + case NGX_QUIC_FT_ACK_ECN: + ngx_quic_drop_ack_ranges(c, ctx, f->u.ack.largest); + break; + + case NGX_QUIC_FT_STREAM: + case NGX_QUIC_FT_RESET_STREAM: + ngx_quic_handle_stream_ack(c, f); + break; + } + + if (f->pnum == max) { + st->max_pn = f->send_time; + } + + /* save earliest and latest send times of frames ack'ed */ + if (st->oldest == NGX_TIMER_INFINITE || f->send_time < st->oldest) { + st->oldest = f->send_time; + } + + if (st->newest == NGX_TIMER_INFINITE || f->send_time > st->newest) { + st->newest = f->send_time; + } + + ngx_queue_remove(&f->queue); + ngx_quic_free_frame(c, f); + found = 1; + } + } + + if (!found) { + + if (max < ctx->pnum) { + /* duplicate ACK or ACK for non-ack-eliciting frame */ + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic ACK for the packet not sent"); + + qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + qc->error_ftype = NGX_QUIC_FT_ACK; + qc->error_reason = "unknown packet number"; + + return NGX_ERROR; + } + + if (!qc->push.timer_set) { + ngx_post_event(&qc->push, &ngx_posted_events); + } + + qc->pto_count = 0; + + return NGX_OK; +} + + +void +ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f) +{ + ngx_uint_t blocked; + ngx_msec_t timer; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + + if (f->plen == 0) { + return; + } + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + + if (f->pnum < qc->rst_pnum) { + return; + } + + blocked = (cg->in_flight >= cg->window) ? 1 : 0; + + cg->in_flight -= f->plen; + + timer = f->send_time - cg->recovery_start; + + if ((ngx_msec_int_t) timer <= 0) { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion ack recovery win:%uz ss:%z if:%uz", + cg->window, cg->ssthresh, cg->in_flight); + + goto done; + } + + if (cg->window < cg->ssthresh) { + cg->window += f->plen; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion slow start win:%uz ss:%z if:%uz", + cg->window, cg->ssthresh, cg->in_flight); + + } else { + cg->window += qc->tp.max_udp_payload_size * f->plen / cg->window; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion avoidance win:%uz ss:%z if:%uz", + cg->window, cg->ssthresh, cg->in_flight); + } + + /* prevent recovery_start from wrapping */ + + timer = cg->recovery_start - ngx_current_msec + qc->tp.max_idle_timeout * 2; + + if ((ngx_msec_int_t) timer < 0) { + cg->recovery_start = ngx_current_msec - qc->tp.max_idle_timeout * 2; + } + +done: + + if (blocked && cg->in_flight < cg->window) { + ngx_post_event(&qc->push, &ngx_posted_events); + } +} + + +static void +ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + uint64_t pn) +{ + uint64_t base; + ngx_uint_t i, smallest, largest; + ngx_quic_ack_range_t *r; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_drop_ack_ranges pn:%uL largest:%uL" + " fr:%uL nranges:%ui", pn, ctx->largest_range, + ctx->first_range, ctx->nranges); + + base = ctx->largest_range; + + if (base == NGX_QUIC_UNSET_PN) { + return; + } + + if (ctx->pending_ack != NGX_QUIC_UNSET_PN && pn >= ctx->pending_ack) { + ctx->pending_ack = NGX_QUIC_UNSET_PN; + } + + largest = base; + smallest = largest - ctx->first_range; + + if (pn >= largest) { + ctx->largest_range = NGX_QUIC_UNSET_PN; + ctx->first_range = 0; + ctx->nranges = 0; + return; + } + + if (pn >= smallest) { + ctx->first_range = largest - pn - 1; + ctx->nranges = 0; + return; + } + + for (i = 0; i < ctx->nranges; i++) { + r = &ctx->ranges[i]; + + largest = smallest - r->gap - 2; + smallest = largest - r->range; + + if (pn >= largest) { + ctx->nranges = i; + return; + } + if (pn >= smallest) { + r->range = largest - pn - 1; + ctx->nranges = i + 1; + return; + } + } +} + + +static ngx_int_t +ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st) +{ + ngx_uint_t i, nlost; + ngx_msec_t now, wait, thr, oldest, newest; + ngx_queue_t *q; + ngx_quic_frame_t *start; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + now = ngx_current_msec; + thr = ngx_quic_lost_threshold(qc); + + /* send time of lost packets across all send contexts */ + oldest = NGX_TIMER_INFINITE; + newest = NGX_TIMER_INFINITE; + + nlost = 0; + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + + ctx = &qc->send_ctx[i]; + + if (ctx->largest_ack == NGX_QUIC_UNSET_PN) { + continue; + } + + while (!ngx_queue_empty(&ctx->sent)) { + + q = ngx_queue_head(&ctx->sent); + start = ngx_queue_data(q, ngx_quic_frame_t, queue); + + if (start->pnum > ctx->largest_ack) { + break; + } + + wait = start->send_time + thr - now; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic detect_lost pnum:%uL thr:%M wait:%i level:%d", + start->pnum, thr, (ngx_int_t) wait, start->level); + + if ((ngx_msec_int_t) wait > 0 + && ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR) + { + break; + } + + if (start->send_time > qc->first_rtt) { + + if (oldest == NGX_TIMER_INFINITE || start->send_time < oldest) { + oldest = start->send_time; + } + + if (newest == NGX_TIMER_INFINITE || start->send_time > newest) { + newest = start->send_time; + } + + nlost++; + } + + ngx_quic_resend_frames(c, ctx); + } + } + + + /* RFC 9002, 7.6.2. Establishing Persistent Congestion */ + + /* + * Once acknowledged, packets are no longer tracked. Thus no send time + * information is available for such packets. This limits persistent + * congestion algorithm to packets mentioned within ACK ranges of the + * latest ACK frame. + */ + + if (st && nlost >= 2 && (st->newest < oldest || st->oldest > newest)) { + + if (newest - oldest > ngx_quic_pcg_duration(c)) { + ngx_quic_persistent_congestion(c); + } + } + + ngx_quic_set_lost_timer(c); + + return NGX_OK; +} + + +static ngx_msec_t +ngx_quic_pcg_duration(ngx_connection_t *c) +{ + ngx_msec_t duration; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + duration = qc->avg_rtt; + duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY); + duration += qc->ctp.max_ack_delay; + duration *= NGX_QUIC_PERSISTENT_CONGESTION_THR; + + return duration; +} + + +static void +ngx_quic_persistent_congestion(ngx_connection_t *c) +{ + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + + cg->recovery_start = ngx_current_msec; + cg->window = qc->tp.max_udp_payload_size * 2; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic persistent congestion win:%uz", cg->window); +} + + +void +ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) +{ + uint64_t pnum; + ngx_queue_t *q; + ngx_quic_frame_t *f, *start; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + q = ngx_queue_head(&ctx->sent); + start = ngx_queue_data(q, ngx_quic_frame_t, queue); + pnum = start->pnum; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic resend packet pnum:%uL", start->pnum); + + ngx_quic_congestion_lost(c, start); + + do { + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + if (f->pnum != pnum) { + break; + } + + q = ngx_queue_next(q); + + ngx_queue_remove(&f->queue); + + switch (f->type) { + case NGX_QUIC_FT_ACK: + case NGX_QUIC_FT_ACK_ECN: + if (ctx->level == ssl_encryption_application) { + /* force generation of most recent acknowledgment */ + ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; + } + + ngx_quic_free_frame(c, f); + break; + + case NGX_QUIC_FT_PING: + case NGX_QUIC_FT_PATH_CHALLENGE: + case NGX_QUIC_FT_PATH_RESPONSE: + case NGX_QUIC_FT_CONNECTION_CLOSE: + ngx_quic_free_frame(c, f); + break; + + case NGX_QUIC_FT_MAX_DATA: + f->u.max_data.max_data = qc->streams.recv_max_data; + ngx_quic_queue_frame(qc, f); + break; + + case NGX_QUIC_FT_MAX_STREAMS: + case NGX_QUIC_FT_MAX_STREAMS2: + f->u.max_streams.limit = f->u.max_streams.bidi + ? qc->streams.client_max_streams_bidi + : qc->streams.client_max_streams_uni; + ngx_quic_queue_frame(qc, f); + break; + + case NGX_QUIC_FT_MAX_STREAM_DATA: + qs = ngx_quic_find_stream(&qc->streams.tree, + f->u.max_stream_data.id); + if (qs == NULL) { + ngx_quic_free_frame(c, f); + break; + } + + f->u.max_stream_data.limit = qs->recv_max_data; + ngx_quic_queue_frame(qc, f); + break; + + case NGX_QUIC_FT_STREAM: + qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id); + + if (qs) { + if (qs->send_state == NGX_QUIC_STREAM_SEND_RESET_SENT + || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_RECVD) + { + ngx_quic_free_frame(c, f); + break; + } + } + + /* fall through */ + + default: + ngx_queue_insert_tail(&ctx->frames, &f->queue); + } + + } while (q != ngx_queue_sentinel(&ctx->sent)); + + if (qc->closing) { + return; + } + + ngx_post_event(&qc->push, &ngx_posted_events); +} + + +static void +ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f) +{ + ngx_uint_t blocked; + ngx_msec_t timer; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + + if (f->plen == 0) { + return; + } + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + + if (f->pnum < qc->rst_pnum) { + return; + } + + blocked = (cg->in_flight >= cg->window) ? 1 : 0; + + cg->in_flight -= f->plen; + f->plen = 0; + + timer = f->send_time - cg->recovery_start; + + if ((ngx_msec_int_t) timer <= 0) { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion lost recovery win:%uz ss:%z if:%uz", + cg->window, cg->ssthresh, cg->in_flight); + + goto done; + } + + cg->recovery_start = ngx_current_msec; + cg->window /= 2; + + if (cg->window < qc->tp.max_udp_payload_size * 2) { + cg->window = qc->tp.max_udp_payload_size * 2; + } + + cg->ssthresh = cg->window; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion lost win:%uz ss:%z if:%uz", + cg->window, cg->ssthresh, cg->in_flight); + +done: + + if (blocked && cg->in_flight < cg->window) { + ngx_post_event(&qc->push, &ngx_posted_events); + } +} + + +void +ngx_quic_set_lost_timer(ngx_connection_t *c) +{ + ngx_uint_t i; + ngx_msec_t now; + ngx_queue_t *q; + ngx_msec_int_t lost, pto, w; + ngx_quic_frame_t *f; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + now = ngx_current_msec; + + lost = -1; + pto = -1; + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + ctx = &qc->send_ctx[i]; + + if (ngx_queue_empty(&ctx->sent)) { + continue; + } + + if (ctx->largest_ack != NGX_QUIC_UNSET_PN) { + q = ngx_queue_head(&ctx->sent); + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + w = (ngx_msec_int_t) + (f->send_time + ngx_quic_lost_threshold(qc) - now); + + if (f->pnum <= ctx->largest_ack) { + if (w < 0 || ctx->largest_ack - f->pnum >= NGX_QUIC_PKT_THR) { + w = 0; + } + + if (lost == -1 || w < lost) { + lost = w; + } + } + } + + q = ngx_queue_last(&ctx->sent); + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + w = (ngx_msec_int_t) + (f->send_time + (ngx_quic_pto(c, ctx) << qc->pto_count) - now); + + if (w < 0) { + w = 0; + } + + if (pto == -1 || w < pto) { + pto = w; + } + } + + if (qc->pto.timer_set) { + ngx_del_timer(&qc->pto); + } + + if (lost != -1) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic lost timer lost:%M", lost); + + qc->pto.handler = ngx_quic_lost_handler; + ngx_add_timer(&qc->pto, lost); + return; + } + + if (pto != -1) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic lost timer pto:%M", pto); + + qc->pto.handler = ngx_quic_pto_handler; + ngx_add_timer(&qc->pto, pto); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic lost timer unset"); +} + + +ngx_msec_t +ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) +{ + ngx_msec_t duration; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + /* RFC 9002, Appendix A.8. Setting the Loss Detection Timer */ + + duration = qc->avg_rtt; + duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY); + + if (ctx->level == ssl_encryption_application && c->ssl->handshaked) { + duration += qc->ctp.max_ack_delay; + } + + return duration; +} + + +static +void ngx_quic_lost_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic lost timer"); + + c = ev->data; + + if (ngx_quic_detect_lost(c, NULL) != NGX_OK) { + ngx_quic_close_connection(c, NGX_ERROR); + return; + } + + ngx_quic_connstate_dbg(c); +} + + +void +ngx_quic_pto_handler(ngx_event_t *ev) +{ + ngx_uint_t i, n; + ngx_msec_t now; + ngx_queue_t *q; + ngx_msec_int_t w; + ngx_connection_t *c; + ngx_quic_frame_t *f; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); + + c = ev->data; + qc = ngx_quic_get_connection(c); + now = ngx_current_msec; + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + + ctx = &qc->send_ctx[i]; + + if (ngx_queue_empty(&ctx->sent)) { + continue; + } + + q = ngx_queue_last(&ctx->sent); + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + w = (ngx_msec_int_t) + (f->send_time + (ngx_quic_pto(c, ctx) << qc->pto_count) - now); + + if (f->pnum <= ctx->largest_ack + && ctx->largest_ack != NGX_QUIC_UNSET_PN) + { + continue; + } + + if (w > 0) { + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic pto %s pto_count:%ui", + ngx_quic_level_name(ctx->level), qc->pto_count); + + for (n = 0; n < 2; n++) { + + f = ngx_quic_alloc_frame(c); + if (f == NULL) { + goto failed; + } + + f->level = ctx->level; + f->type = NGX_QUIC_FT_PING; + f->ignore_congestion = 1; + + if (ngx_quic_frame_sendto(c, f, 0, qc->path) == NGX_ERROR) { + goto failed; + } + } + } + + qc->pto_count++; + + ngx_quic_set_lost_timer(c); + + ngx_quic_connstate_dbg(c); + + return; + +failed: + + ngx_quic_close_connection(c, NGX_ERROR); + return; +} + + +ngx_int_t +ngx_quic_ack_packet(ngx_connection_t *c, ngx_quic_header_t *pkt) +{ + uint64_t base, largest, smallest, gs, ge, gap, range, pn; + uint64_t prev_pending; + ngx_uint_t i, nr; + ngx_quic_send_ctx_t *ctx; + ngx_quic_ack_range_t *r; + ngx_quic_connection_t *qc; + + c->log->action = "preparing ack"; + + qc = ngx_quic_get_connection(c); + + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_ack_packet pn:%uL largest %L fr:%uL" + " nranges:%ui", pkt->pn, (int64_t) ctx->largest_range, + ctx->first_range, ctx->nranges); + + if (!ngx_quic_keys_available(qc->keys, ctx->level, 1)) { + return NGX_OK; + } + + prev_pending = ctx->pending_ack; + + if (pkt->need_ack) { + + ngx_post_event(&qc->push, &ngx_posted_events); + + if (ctx->send_ack == 0) { + ctx->ack_delay_start = ngx_current_msec; + } + + ctx->send_ack++; + + if (ctx->pending_ack == NGX_QUIC_UNSET_PN + || ctx->pending_ack < pkt->pn) + { + ctx->pending_ack = pkt->pn; + } + } + + base = ctx->largest_range; + pn = pkt->pn; + + if (base == NGX_QUIC_UNSET_PN) { + ctx->largest_range = pn; + ctx->largest_received = pkt->received; + return NGX_OK; + } + + if (base == pn) { + return NGX_OK; + } + + largest = base; + smallest = largest - ctx->first_range; + + if (pn > base) { + + if (pn - base == 1) { + ctx->first_range++; + ctx->largest_range = pn; + ctx->largest_received = pkt->received; + + return NGX_OK; + + } else { + /* new gap in front of current largest */ + + /* no place for new range, send current range as is */ + if (ctx->nranges == NGX_QUIC_MAX_RANGES) { + + if (prev_pending != NGX_QUIC_UNSET_PN) { + if (ngx_quic_send_ack(c, ctx) != NGX_OK) { + return NGX_ERROR; + } + } + + if (prev_pending == ctx->pending_ack || !pkt->need_ack) { + ctx->pending_ack = NGX_QUIC_UNSET_PN; + } + } + + gap = pn - base - 2; + range = ctx->first_range; + + ctx->first_range = 0; + ctx->largest_range = pn; + ctx->largest_received = pkt->received; + + /* packet is out of order, force send */ + if (pkt->need_ack) { + ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; + } + + i = 0; + + goto insert; + } + } + + /* pn < base, perform lookup in existing ranges */ + + /* packet is out of order */ + if (pkt->need_ack) { + ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; + } + + if (pn >= smallest && pn <= largest) { + return NGX_OK; + } + +#if (NGX_SUPPRESS_WARN) + r = NULL; +#endif + + for (i = 0; i < ctx->nranges; i++) { + r = &ctx->ranges[i]; + + ge = smallest - 1; + gs = ge - r->gap; + + if (pn >= gs && pn <= ge) { + + if (gs == ge) { + /* gap size is exactly one packet, now filled */ + + /* data moves to previous range, current is removed */ + + if (i == 0) { + ctx->first_range += r->range + 2; + + } else { + ctx->ranges[i - 1].range += r->range + 2; + } + + nr = ctx->nranges - i - 1; + if (nr) { + ngx_memmove(&ctx->ranges[i], &ctx->ranges[i + 1], + sizeof(ngx_quic_ack_range_t) * nr); + } + + ctx->nranges--; + + } else if (pn == gs) { + /* current gap shrinks from tail (current range grows) */ + r->gap--; + r->range++; + + } else if (pn == ge) { + /* current gap shrinks from head (previous range grows) */ + r->gap--; + + if (i == 0) { + ctx->first_range++; + + } else { + ctx->ranges[i - 1].range++; + } + + } else { + /* current gap is split into two parts */ + + gap = ge - pn - 1; + range = 0; + + if (ctx->nranges == NGX_QUIC_MAX_RANGES) { + if (prev_pending != NGX_QUIC_UNSET_PN) { + if (ngx_quic_send_ack(c, ctx) != NGX_OK) { + return NGX_ERROR; + } + } + + if (prev_pending == ctx->pending_ack || !pkt->need_ack) { + ctx->pending_ack = NGX_QUIC_UNSET_PN; + } + } + + r->gap = pn - gs - 1; + goto insert; + } + + return NGX_OK; + } + + largest = smallest - r->gap - 2; + smallest = largest - r->range; + + if (pn >= smallest && pn <= largest) { + /* this packet number is already known */ + return NGX_OK; + } + + } + + if (pn == smallest - 1) { + /* extend first or last range */ + + if (i == 0) { + ctx->first_range++; + + } else { + r->range++; + } + + return NGX_OK; + } + + /* nothing found, add new range at the tail */ + + if (ctx->nranges == NGX_QUIC_MAX_RANGES) { + /* packet is too old to keep it */ + + if (pkt->need_ack) { + return ngx_quic_send_ack_range(c, ctx, pn, pn); + } + + return NGX_OK; + } + + gap = smallest - 2 - pn; + range = 0; + +insert: + + if (ctx->nranges < NGX_QUIC_MAX_RANGES) { + ctx->nranges++; + } + + ngx_memmove(&ctx->ranges[i + 1], &ctx->ranges[i], + sizeof(ngx_quic_ack_range_t) * (ctx->nranges - i - 1)); + + ctx->ranges[i].gap = gap; + ctx->ranges[i].range = range; + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_generate_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) +{ + ngx_msec_t delay; + ngx_quic_connection_t *qc; + + if (!ctx->send_ack) { + return NGX_OK; + } + + if (ctx->level == ssl_encryption_application) { + + delay = ngx_current_msec - ctx->ack_delay_start; + qc = ngx_quic_get_connection(c); + + if (ngx_queue_empty(&ctx->frames) + && ctx->send_ack < NGX_QUIC_MAX_ACK_GAP + && delay < qc->tp.max_ack_delay) + { + if (!qc->push.timer_set && !qc->closing) { + ngx_add_timer(&qc->push, + qc->tp.max_ack_delay - delay); + } + + return NGX_OK; + } + } + + if (ngx_quic_send_ack(c, ctx) != NGX_OK) { + return NGX_ERROR; + } + + ctx->send_ack = 0; + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_ack.h b/src/event/quic/ngx_event_quic_ack.h new file mode 100644 index 0000000..56920c2 --- /dev/null +++ b/src/event/quic/ngx_event_quic_ack.h @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_ACK_H_INCLUDED_ +#define _NGX_EVENT_QUIC_ACK_H_INCLUDED_ + + +#include +#include + + +ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_frame_t *f); + +void ngx_quic_congestion_ack(ngx_connection_t *c, + ngx_quic_frame_t *frame); +void ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx); +void ngx_quic_set_lost_timer(ngx_connection_t *c); +void ngx_quic_pto_handler(ngx_event_t *ev); +ngx_msec_t ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx); + +ngx_int_t ngx_quic_ack_packet(ngx_connection_t *c, + ngx_quic_header_t *pkt); +ngx_int_t ngx_quic_generate_ack(ngx_connection_t *c, + ngx_quic_send_ctx_t *ctx); + +#endif /* _NGX_EVENT_QUIC_ACK_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_bpf.c b/src/event/quic/ngx_event_quic_bpf.c new file mode 100644 index 0000000..ab024ad --- /dev/null +++ b/src/event/quic/ngx_event_quic_bpf.c @@ -0,0 +1,657 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#define NGX_QUIC_BPF_VARNAME "NGINX_BPF_MAPS" +#define NGX_QUIC_BPF_VARSEP ';' +#define NGX_QUIC_BPF_ADDRSEP '#' + + +#define ngx_quic_bpf_get_conf(cycle) \ + (ngx_quic_bpf_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_quic_bpf_module) + +#define ngx_quic_bpf_get_old_conf(cycle) \ + cycle->old_cycle->conf_ctx ? ngx_quic_bpf_get_conf(cycle->old_cycle) \ + : NULL + +#define ngx_core_get_conf(cycle) \ + (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module) + + +typedef struct { + ngx_queue_t queue; + int map_fd; + + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_uint_t unused; /* unsigned unused:1; */ +} ngx_quic_sock_group_t; + + +typedef struct { + ngx_flag_t enabled; + ngx_uint_t map_size; + ngx_queue_t groups; /* of ngx_quic_sock_group_t */ +} ngx_quic_bpf_conf_t; + + +static void *ngx_quic_bpf_create_conf(ngx_cycle_t *cycle); +static ngx_int_t ngx_quic_bpf_module_init(ngx_cycle_t *cycle); + +static void ngx_quic_bpf_cleanup(void *data); +static ngx_inline void ngx_quic_bpf_close(ngx_log_t *log, int fd, + const char *name); + +static ngx_quic_sock_group_t *ngx_quic_bpf_find_group(ngx_quic_bpf_conf_t *bcf, + ngx_listening_t *ls); +static ngx_quic_sock_group_t *ngx_quic_bpf_alloc_group(ngx_cycle_t *cycle, + struct sockaddr *sa, socklen_t socklen); +static ngx_quic_sock_group_t *ngx_quic_bpf_create_group(ngx_cycle_t *cycle, + ngx_listening_t *ls); +static ngx_quic_sock_group_t *ngx_quic_bpf_get_group(ngx_cycle_t *cycle, + ngx_listening_t *ls); +static ngx_int_t ngx_quic_bpf_group_add_socket(ngx_cycle_t *cycle, + ngx_listening_t *ls); +static uint64_t ngx_quic_bpf_socket_key(ngx_fd_t fd, ngx_log_t *log); + +static ngx_int_t ngx_quic_bpf_export_maps(ngx_cycle_t *cycle); +static ngx_int_t ngx_quic_bpf_import_maps(ngx_cycle_t *cycle); + +extern ngx_bpf_program_t ngx_quic_reuseport_helper; + + +static ngx_command_t ngx_quic_bpf_commands[] = { + + { ngx_string("quic_bpf"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + 0, + offsetof(ngx_quic_bpf_conf_t, enabled), + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_quic_bpf_module_ctx = { + ngx_string("quic_bpf"), + ngx_quic_bpf_create_conf, + NULL +}; + + +ngx_module_t ngx_quic_bpf_module = { + NGX_MODULE_V1, + &ngx_quic_bpf_module_ctx, /* module context */ + ngx_quic_bpf_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + ngx_quic_bpf_module_init, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static void * +ngx_quic_bpf_create_conf(ngx_cycle_t *cycle) +{ + ngx_quic_bpf_conf_t *bcf; + + bcf = ngx_pcalloc(cycle->pool, sizeof(ngx_quic_bpf_conf_t)); + if (bcf == NULL) { + return NULL; + } + + bcf->enabled = NGX_CONF_UNSET; + bcf->map_size = NGX_CONF_UNSET_UINT; + + ngx_queue_init(&bcf->groups); + + return bcf; +} + + +static ngx_int_t +ngx_quic_bpf_module_init(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_listening_t *ls; + ngx_core_conf_t *ccf; + ngx_pool_cleanup_t *cln; + ngx_quic_bpf_conf_t *bcf; + + if (ngx_test_config) { + /* + * during config test, SO_REUSEPORT socket option is + * not set, thus making further processing meaningless + */ + return NGX_OK; + } + + ccf = ngx_core_get_conf(cycle); + bcf = ngx_quic_bpf_get_conf(cycle); + + ngx_conf_init_value(bcf->enabled, 0); + + bcf->map_size = ccf->worker_processes * 4; + + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = bcf; + cln->handler = ngx_quic_bpf_cleanup; + + if (ngx_inherited && ngx_is_init_cycle(cycle->old_cycle)) { + if (ngx_quic_bpf_import_maps(cycle) != NGX_OK) { + goto failed; + } + } + + ls = cycle->listening.elts; + + for (i = 0; i < cycle->listening.nelts; i++) { + if (ls[i].quic && ls[i].reuseport) { + if (ngx_quic_bpf_group_add_socket(cycle, &ls[i]) != NGX_OK) { + goto failed; + } + } + } + + if (ngx_quic_bpf_export_maps(cycle) != NGX_OK) { + goto failed; + } + + return NGX_OK; + +failed: + + if (ngx_is_init_cycle(cycle->old_cycle)) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "ngx_quic_bpf_module failed to initialize, check limits"); + + /* refuse to start */ + return NGX_ERROR; + } + + /* + * returning error now will lead to master process exiting immediately + * leaving worker processes orphaned, what is really unexpected. + * Instead, just issue a not about failed initialization and try + * to cleanup a bit. Still program can be already loaded to kernel + * for some reuseport groups, and there is no way to revert, so + * behaviour may be inconsistent. + */ + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "ngx_quic_bpf_module failed to initialize properly, ignored." + "please check limits and note that nginx state now " + "can be inconsistent and restart may be required"); + + return NGX_OK; +} + + +static void +ngx_quic_bpf_cleanup(void *data) +{ + ngx_quic_bpf_conf_t *bcf = (ngx_quic_bpf_conf_t *) data; + + ngx_queue_t *q; + ngx_quic_sock_group_t *grp; + + for (q = ngx_queue_head(&bcf->groups); + q != ngx_queue_sentinel(&bcf->groups); + q = ngx_queue_next(q)) + { + grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + + ngx_quic_bpf_close(ngx_cycle->log, grp->map_fd, "map"); + } +} + + +static ngx_inline void +ngx_quic_bpf_close(ngx_log_t *log, int fd, const char *name) +{ + if (close(fd) != -1) { + return; + } + + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "quic bpf close %s fd:%d failed", name, fd); +} + + +static ngx_quic_sock_group_t * +ngx_quic_bpf_find_group(ngx_quic_bpf_conf_t *bcf, ngx_listening_t *ls) +{ + ngx_queue_t *q; + ngx_quic_sock_group_t *grp; + + for (q = ngx_queue_head(&bcf->groups); + q != ngx_queue_sentinel(&bcf->groups); + q = ngx_queue_next(q)) + { + grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + + if (ngx_cmp_sockaddr(ls->sockaddr, ls->socklen, + grp->sockaddr, grp->socklen, 1) + == NGX_OK) + { + return grp; + } + } + + return NULL; +} + + +static ngx_quic_sock_group_t * +ngx_quic_bpf_alloc_group(ngx_cycle_t *cycle, struct sockaddr *sa, + socklen_t socklen) +{ + ngx_quic_bpf_conf_t *bcf; + ngx_quic_sock_group_t *grp; + + bcf = ngx_quic_bpf_get_conf(cycle); + + grp = ngx_pcalloc(cycle->pool, sizeof(ngx_quic_sock_group_t)); + if (grp == NULL) { + return NULL; + } + + grp->socklen = socklen; + grp->sockaddr = ngx_palloc(cycle->pool, socklen); + if (grp->sockaddr == NULL) { + return NULL; + } + ngx_memcpy(grp->sockaddr, sa, socklen); + + ngx_queue_insert_tail(&bcf->groups, &grp->queue); + + return grp; +} + + +static ngx_quic_sock_group_t * +ngx_quic_bpf_create_group(ngx_cycle_t *cycle, ngx_listening_t *ls) +{ + int progfd, failed, flags, rc; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_sock_group_t *grp; + + bcf = ngx_quic_bpf_get_conf(cycle); + + if (!bcf->enabled) { + return NULL; + } + + grp = ngx_quic_bpf_alloc_group(cycle, ls->sockaddr, ls->socklen); + if (grp == NULL) { + return NULL; + } + + grp->map_fd = ngx_bpf_map_create(cycle->log, BPF_MAP_TYPE_SOCKHASH, + sizeof(uint64_t), sizeof(uint64_t), + bcf->map_size, 0); + if (grp->map_fd == -1) { + goto failed; + } + + flags = fcntl(grp->map_fd, F_GETFD); + if (flags == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, errno, + "quic bpf getfd failed"); + goto failed; + } + + /* need to inherit map during binary upgrade after exec */ + flags &= ~FD_CLOEXEC; + + rc = fcntl(grp->map_fd, F_SETFD, flags); + if (rc == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, errno, + "quic bpf setfd failed"); + goto failed; + } + + ngx_bpf_program_link(&ngx_quic_reuseport_helper, + "ngx_quic_sockmap", grp->map_fd); + + progfd = ngx_bpf_load_program(cycle->log, &ngx_quic_reuseport_helper); + if (progfd < 0) { + goto failed; + } + + failed = 0; + + if (setsockopt(ls->fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, + &progfd, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "quic bpf setsockopt(SO_ATTACH_REUSEPORT_EBPF) failed"); + failed = 1; + } + + ngx_quic_bpf_close(cycle->log, progfd, "program"); + + if (failed) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf sockmap created fd:%d", grp->map_fd); + return grp; + +failed: + + if (grp->map_fd != -1) { + ngx_quic_bpf_close(cycle->log, grp->map_fd, "map"); + } + + ngx_queue_remove(&grp->queue); + + return NULL; +} + + +static ngx_quic_sock_group_t * +ngx_quic_bpf_get_group(ngx_cycle_t *cycle, ngx_listening_t *ls) +{ + ngx_quic_bpf_conf_t *bcf, *old_bcf; + ngx_quic_sock_group_t *grp, *ogrp; + + bcf = ngx_quic_bpf_get_conf(cycle); + + grp = ngx_quic_bpf_find_group(bcf, ls); + if (grp) { + return grp; + } + + old_bcf = ngx_quic_bpf_get_old_conf(cycle); + + if (old_bcf == NULL) { + return ngx_quic_bpf_create_group(cycle, ls); + } + + ogrp = ngx_quic_bpf_find_group(old_bcf, ls); + if (ogrp == NULL) { + return ngx_quic_bpf_create_group(cycle, ls); + } + + grp = ngx_quic_bpf_alloc_group(cycle, ls->sockaddr, ls->socklen); + if (grp == NULL) { + return NULL; + } + + grp->map_fd = dup(ogrp->map_fd); + if (grp->map_fd == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "quic bpf failed to duplicate bpf map descriptor"); + + ngx_queue_remove(&grp->queue); + + return NULL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf sockmap fd duplicated old:%d new:%d", + ogrp->map_fd, grp->map_fd); + + return grp; +} + + +static ngx_int_t +ngx_quic_bpf_group_add_socket(ngx_cycle_t *cycle, ngx_listening_t *ls) +{ + uint64_t cookie; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_sock_group_t *grp; + + bcf = ngx_quic_bpf_get_conf(cycle); + + grp = ngx_quic_bpf_get_group(cycle, ls); + + if (grp == NULL) { + if (!bcf->enabled) { + return NGX_OK; + } + + return NGX_ERROR; + } + + grp->unused = 0; + + cookie = ngx_quic_bpf_socket_key(ls->fd, cycle->log); + if (cookie == (uint64_t) NGX_ERROR) { + return NGX_ERROR; + } + + /* map[cookie] = socket; for use in kernel helper */ + if (ngx_bpf_map_update(grp->map_fd, &cookie, &ls->fd, BPF_ANY) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "quic bpf failed to update socket map key=%xL", cookie); + return NGX_ERROR; + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf sockmap fd:%d add socket:%d cookie:0x%xL worker:%ui", + grp->map_fd, ls->fd, cookie, ls->worker); + + /* do not inherit this socket */ + ls->ignore = 1; + + return NGX_OK; +} + + +static uint64_t +ngx_quic_bpf_socket_key(ngx_fd_t fd, ngx_log_t *log) +{ + uint64_t cookie; + socklen_t optlen; + + optlen = sizeof(cookie); + + if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &optlen) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "quic bpf getsockopt(SO_COOKIE) failed"); + + return (ngx_uint_t) NGX_ERROR; + } + + return cookie; +} + + +static ngx_int_t +ngx_quic_bpf_export_maps(ngx_cycle_t *cycle) +{ + u_char *p, *buf; + size_t len; + ngx_str_t *var; + ngx_queue_t *q; + ngx_core_conf_t *ccf; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_sock_group_t *grp; + + ccf = ngx_core_get_conf(cycle); + bcf = ngx_quic_bpf_get_conf(cycle); + + len = sizeof(NGX_QUIC_BPF_VARNAME) + 1; + + q = ngx_queue_head(&bcf->groups); + + while (q != ngx_queue_sentinel(&bcf->groups)) { + + grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + + q = ngx_queue_next(q); + + if (grp->unused) { + /* + * map was inherited, but it is not used in this configuration; + * do not pass such map further and drop the group to prevent + * interference with changes during reload + */ + + ngx_quic_bpf_close(cycle->log, grp->map_fd, "map"); + ngx_queue_remove(&grp->queue); + + continue; + } + + len += NGX_INT32_LEN + 1 + NGX_SOCKADDR_STRLEN + 1; + } + + len++; + + buf = ngx_palloc(cycle->pool, len); + if (buf == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(buf, NGX_QUIC_BPF_VARNAME "=", + sizeof(NGX_QUIC_BPF_VARNAME)); + + for (q = ngx_queue_head(&bcf->groups); + q != ngx_queue_sentinel(&bcf->groups); + q = ngx_queue_next(q)) + { + grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + + p = ngx_sprintf(p, "%ud", grp->map_fd); + + *p++ = NGX_QUIC_BPF_ADDRSEP; + + p += ngx_sock_ntop(grp->sockaddr, grp->socklen, p, + NGX_SOCKADDR_STRLEN, 1); + + *p++ = NGX_QUIC_BPF_VARSEP; + } + + *p = '\0'; + + var = ngx_array_push(&ccf->env); + if (var == NULL) { + return NGX_ERROR; + } + + var->data = buf; + var->len = sizeof(NGX_QUIC_BPF_VARNAME) - 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_bpf_import_maps(ngx_cycle_t *cycle) +{ + int s; + u_char *inherited, *p, *v; + ngx_uint_t in_fd; + ngx_addr_t tmp; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_sock_group_t *grp; + + inherited = (u_char *) getenv(NGX_QUIC_BPF_VARNAME); + + if (inherited == NULL) { + return NGX_OK; + } + + bcf = ngx_quic_bpf_get_conf(cycle); + +#if (NGX_SUPPRESS_WARN) + s = -1; +#endif + + in_fd = 1; + + for (p = inherited, v = p; *p; p++) { + + switch (*p) { + + case NGX_QUIC_BPF_ADDRSEP: + + if (!in_fd) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "quic bpf failed to parse inherited env"); + return NGX_ERROR; + } + in_fd = 0; + + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "quic bpf failed to parse inherited map fd"); + return NGX_ERROR; + } + + v = p + 1; + break; + + case NGX_QUIC_BPF_VARSEP: + + if (in_fd) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "quic bpf failed to parse inherited env"); + return NGX_ERROR; + } + in_fd = 1; + + grp = ngx_pcalloc(cycle->pool, + sizeof(ngx_quic_sock_group_t)); + if (grp == NULL) { + return NGX_ERROR; + } + + grp->map_fd = s; + + if (ngx_parse_addr_port(cycle->pool, &tmp, v, p - v) + != NGX_OK) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "quic bpf failed to parse inherited" + " address '%*s'", p - v , v); + + ngx_quic_bpf_close(cycle->log, s, "inherited map"); + + return NGX_ERROR; + } + + grp->sockaddr = tmp.sockaddr; + grp->socklen = tmp.socklen; + + grp->unused = 1; + + ngx_queue_insert_tail(&bcf->groups, &grp->queue); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf sockmap inherited with " + "fd:%d address:%*s", + grp->map_fd, p - v, v); + v = p + 1; + break; + + default: + break; + } + } + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_bpf_code.c b/src/event/quic/ngx_event_quic_bpf_code.c new file mode 100644 index 0000000..5c9dea1 --- /dev/null +++ b/src/event/quic/ngx_event_quic_bpf_code.c @@ -0,0 +1,88 @@ +/* AUTO-GENERATED, DO NOT EDIT. */ + +#include +#include + +#include "ngx_bpf.h" + + +static ngx_bpf_reloc_t bpf_reloc_prog_ngx_quic_reuseport_helper[] = { + { "ngx_quic_sockmap", 55 }, +}; + +static struct bpf_insn bpf_insn_prog_ngx_quic_reuseport_helper[] = { + /* opcode dst src offset imm */ + { 0x79, BPF_REG_4, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0x79, BPF_REG_3, BPF_REG_1, (int16_t) 8, 0x0 }, + { 0xbf, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x2d, BPF_REG_2, BPF_REG_3, (int16_t) 54, 0x0 }, + { 0xbf, BPF_REG_5, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x9 }, + { 0x2d, BPF_REG_5, BPF_REG_3, (int16_t) 51, 0x0 }, + { 0xb7, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x14 }, + { 0xb7, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x9 }, + { 0x71, BPF_REG_6, BPF_REG_2, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_6, BPF_REG_0, (int16_t) 0, 0x38 }, + { 0xc7, BPF_REG_6, BPF_REG_0, (int16_t) 0, 0x38 }, + { 0x65, BPF_REG_6, BPF_REG_0, (int16_t) 10, 0xffffffff }, + { 0xbf, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xd }, + { 0x2d, BPF_REG_2, BPF_REG_3, (int16_t) 42, 0x0 }, + { 0xbf, BPF_REG_5, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0xe }, + { 0x2d, BPF_REG_5, BPF_REG_3, (int16_t) 39, 0x0 }, + { 0xb7, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0xe }, + { 0x71, BPF_REG_5, BPF_REG_2, (int16_t) 0, 0x0 }, + { 0xb7, BPF_REG_6, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x2d, BPF_REG_6, BPF_REG_5, (int16_t) 35, 0x0 }, + { 0xf, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0xf, BPF_REG_4, BPF_REG_5, (int16_t) 0, 0x0 }, + { 0x2d, BPF_REG_4, BPF_REG_3, (int16_t) 32, 0x0 }, + { 0xbf, BPF_REG_4, BPF_REG_2, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x9 }, + { 0x2d, BPF_REG_4, BPF_REG_3, (int16_t) 29, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 1, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x38 }, + { 0x71, BPF_REG_3, BPF_REG_2, (int16_t) 2, 0x0 }, + { 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x30 }, + { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 3, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x28 }, + { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 4, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 5, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x18 }, + { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 6, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x10 }, + { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 7, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_2, BPF_REG_2, (int16_t) 8, 0x0 }, + { 0x4f, BPF_REG_3, BPF_REG_2, (int16_t) 0, 0x0 }, + { 0x7b, BPF_REG_10, BPF_REG_3, (int16_t) 65528, 0x0 }, + { 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff8 }, + { 0x18, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x52 }, + { 0xb7, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x1 }, + { 0x95, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, +}; + + +ngx_bpf_program_t ngx_quic_reuseport_helper = { + .relocs = bpf_reloc_prog_ngx_quic_reuseport_helper, + .nrelocs = sizeof(bpf_reloc_prog_ngx_quic_reuseport_helper) + / sizeof(bpf_reloc_prog_ngx_quic_reuseport_helper[0]), + .ins = bpf_insn_prog_ngx_quic_reuseport_helper, + .nins = sizeof(bpf_insn_prog_ngx_quic_reuseport_helper) + / sizeof(bpf_insn_prog_ngx_quic_reuseport_helper[0]), + .license = "BSD", + .type = BPF_PROG_TYPE_SK_REUSEPORT, +}; diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h new file mode 100644 index 0000000..824c92b --- /dev/null +++ b/src/event/quic/ngx_event_quic_connection.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ +#define _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ + + +#include +#include +#include + + +/* #define NGX_QUIC_DEBUG_PACKETS */ /* dump packet contents */ +/* #define NGX_QUIC_DEBUG_FRAMES */ /* dump frames contents */ +/* #define NGX_QUIC_DEBUG_ALLOC */ /* log frames and bufs alloc */ +/* #define NGX_QUIC_DEBUG_CRYPTO */ + +typedef struct ngx_quic_connection_s ngx_quic_connection_t; +typedef struct ngx_quic_server_id_s ngx_quic_server_id_t; +typedef struct ngx_quic_client_id_s ngx_quic_client_id_t; +typedef struct ngx_quic_send_ctx_s ngx_quic_send_ctx_t; +typedef struct ngx_quic_socket_s ngx_quic_socket_t; +typedef struct ngx_quic_path_s ngx_quic_path_t; +typedef struct ngx_quic_keys_s ngx_quic_keys_t; + +#if (NGX_QUIC_OPENSSL_COMPAT) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* RFC 9002, 6.2.2. Handshakes and New Paths: kInitialRtt */ +#define NGX_QUIC_INITIAL_RTT 333 /* ms */ + +#define NGX_QUIC_UNSET_PN (uint64_t) -1 + +#define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1) + +/* 0-RTT and 1-RTT data exist in the same packet number space, + * so we have 3 packet number spaces: + * + * 0 - Initial + * 1 - Handshake + * 2 - 0-RTT and 1-RTT + */ +#define ngx_quic_get_send_ctx(qc, level) \ + ((level) == ssl_encryption_initial) ? &((qc)->send_ctx[0]) \ + : (((level) == ssl_encryption_handshake) ? &((qc)->send_ctx[1]) \ + : &((qc)->send_ctx[2])) + +#define ngx_quic_get_connection(c) \ + (((c)->udp) ? (((ngx_quic_socket_t *)((c)->udp))->quic) : NULL) + +#define ngx_quic_get_socket(c) ((ngx_quic_socket_t *)((c)->udp)) + +#define ngx_quic_init_rtt(qc) \ + (qc)->avg_rtt = NGX_QUIC_INITIAL_RTT; \ + (qc)->rttvar = NGX_QUIC_INITIAL_RTT / 2; \ + (qc)->min_rtt = NGX_TIMER_INFINITE; \ + (qc)->first_rtt = NGX_TIMER_INFINITE; \ + (qc)->latest_rtt = 0; + + +typedef enum { + NGX_QUIC_PATH_IDLE = 0, + NGX_QUIC_PATH_VALIDATING, + NGX_QUIC_PATH_WAITING, + NGX_QUIC_PATH_MTUD +} ngx_quic_path_state_e; + + +struct ngx_quic_client_id_s { + ngx_queue_t queue; + uint64_t seqnum; + size_t len; + u_char id[NGX_QUIC_CID_LEN_MAX]; + u_char sr_token[NGX_QUIC_SR_TOKEN_LEN]; + ngx_uint_t used; /* unsigned used:1; */ +}; + + +struct ngx_quic_server_id_s { + uint64_t seqnum; + size_t len; + u_char id[NGX_QUIC_CID_LEN_MAX]; +}; + + +struct ngx_quic_path_s { + ngx_queue_t queue; + struct sockaddr *sockaddr; + ngx_sockaddr_t sa; + socklen_t socklen; + ngx_quic_client_id_t *cid; + ngx_quic_path_state_e state; + ngx_msec_t expires; + ngx_uint_t tries; + ngx_uint_t tag; + size_t mtu; + size_t mtud; + size_t max_mtu; + off_t sent; + off_t received; + u_char challenge[2][8]; + uint64_t seqnum; + uint64_t mtu_pnum[NGX_QUIC_PATH_RETRIES]; + ngx_str_t addr_text; + u_char text[NGX_SOCKADDR_STRLEN]; + unsigned validated:1; + unsigned mtu_unvalidated:1; +}; + + +struct ngx_quic_socket_s { + ngx_udp_connection_t udp; + ngx_quic_connection_t *quic; + ngx_queue_t queue; + ngx_quic_server_id_t sid; + ngx_sockaddr_t sockaddr; + socklen_t socklen; + ngx_uint_t used; /* unsigned used:1; */ +}; + + +typedef struct { + ngx_rbtree_t tree; + ngx_rbtree_node_t sentinel; + + ngx_queue_t uninitialized; + ngx_queue_t free; + + uint64_t sent; + uint64_t recv_offset; + uint64_t recv_window; + uint64_t recv_last; + uint64_t recv_max_data; + uint64_t send_offset; + uint64_t send_max_data; + + uint64_t server_max_streams_uni; + uint64_t server_max_streams_bidi; + uint64_t server_streams_uni; + uint64_t server_streams_bidi; + + uint64_t client_max_streams_uni; + uint64_t client_max_streams_bidi; + uint64_t client_streams_uni; + uint64_t client_streams_bidi; + + ngx_uint_t initialized; + /* unsigned initialized:1; */ +} ngx_quic_streams_t; + + +typedef struct { + size_t in_flight; + size_t window; + size_t ssthresh; + ngx_msec_t recovery_start; +} ngx_quic_congestion_t; + + +/* + * RFC 9000, 12.3. Packet Numbers + * + * Conceptually, a packet number space is the context in which a packet + * can be processed and acknowledged. Initial packets can only be sent + * with Initial packet protection keys and acknowledged in packets that + * are also Initial packets. + */ +struct ngx_quic_send_ctx_s { + enum ssl_encryption_level_t level; + + ngx_quic_buffer_t crypto; + uint64_t crypto_sent; + + uint64_t pnum; /* to be sent */ + uint64_t largest_ack; /* received from peer */ + uint64_t largest_pn; /* received from peer */ + + ngx_queue_t frames; /* generated frames */ + ngx_queue_t sending; /* frames assigned to pkt */ + ngx_queue_t sent; /* frames waiting ACK */ + + uint64_t pending_ack; /* non sent ack-eliciting */ + uint64_t largest_range; + uint64_t first_range; + ngx_msec_t largest_received; + ngx_msec_t ack_delay_start; + ngx_uint_t nranges; + ngx_quic_ack_range_t ranges[NGX_QUIC_MAX_RANGES]; + ngx_uint_t send_ack; +}; + + +struct ngx_quic_connection_s { + uint32_t version; + + ngx_quic_path_t *path; + + ngx_queue_t sockets; + ngx_queue_t paths; + ngx_queue_t client_ids; + ngx_queue_t free_sockets; + ngx_queue_t free_paths; + ngx_queue_t free_client_ids; + + ngx_uint_t nsockets; + ngx_uint_t nclient_ids; + uint64_t max_retired_seqnum; + uint64_t client_seqnum; + uint64_t server_seqnum; + uint64_t path_seqnum; + + ngx_quic_tp_t tp; + ngx_quic_tp_t ctp; + + ngx_quic_send_ctx_t send_ctx[NGX_QUIC_SEND_CTX_LAST]; + + ngx_quic_keys_t *keys; + + ngx_quic_conf_t *conf; + + ngx_event_t push; + ngx_event_t pto; + ngx_event_t close; + ngx_event_t path_validation; + ngx_event_t key_update; + + ngx_msec_t last_cc; + + ngx_msec_t first_rtt; + ngx_msec_t latest_rtt; + ngx_msec_t avg_rtt; + ngx_msec_t min_rtt; + ngx_msec_t rttvar; + + ngx_uint_t pto_count; + + ngx_queue_t free_frames; + ngx_buf_t *free_bufs; + ngx_buf_t *free_shadow_bufs; + + ngx_uint_t nframes; +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_uint_t nbufs; + ngx_uint_t nshadowbufs; +#endif + +#if (NGX_QUIC_OPENSSL_COMPAT) + ngx_quic_compat_t *compat; +#endif + + ngx_quic_streams_t streams; + ngx_quic_congestion_t congestion; + + uint64_t rst_pnum; /* first on validated path */ + + off_t received; + + ngx_uint_t error; + enum ssl_encryption_level_t error_level; + ngx_uint_t error_ftype; + const char *error_reason; + + ngx_uint_t shutdown_code; + const char *shutdown_reason; + + unsigned error_app:1; + unsigned send_timer_set:1; + unsigned closing:1; + unsigned shutdown:1; + unsigned draining:1; + unsigned key_phase:1; + unsigned validated:1; + unsigned client_tp_done:1; +}; + + +ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c, + ngx_quic_tp_t *ctp); +void ngx_quic_discard_ctx(ngx_connection_t *c, + enum ssl_encryption_level_t level); +void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc); +void ngx_quic_shutdown_quic(ngx_connection_t *c); + +#if (NGX_DEBUG) +void ngx_quic_connstate_dbg(ngx_connection_t *c); +#else +#define ngx_quic_connstate_dbg(c) +#endif + +#endif /* _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_connid.c b/src/event/quic/ngx_event_quic_connid.c new file mode 100644 index 0000000..f508682 --- /dev/null +++ b/src/event/quic/ngx_event_quic_connid.c @@ -0,0 +1,502 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + +#define NGX_QUIC_MAX_SERVER_IDS 8 + + +#if (NGX_QUIC_BPF) +static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id); +#endif +static ngx_int_t ngx_quic_retire_client_id(ngx_connection_t *c, + ngx_quic_client_id_t *cid); +static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c, + ngx_quic_connection_t *qc); +static ngx_int_t ngx_quic_send_server_id(ngx_connection_t *c, + ngx_quic_server_id_t *sid); + + +ngx_int_t +ngx_quic_create_server_id(ngx_connection_t *c, u_char *id) +{ + if (RAND_bytes(id, NGX_QUIC_SERVER_CID_LEN) != 1) { + return NGX_ERROR; + } + +#if (NGX_QUIC_BPF) + if (ngx_quic_bpf_attach_id(c, id) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "quic bpf failed to generate socket key"); + /* ignore error, things still may work */ + } +#endif + + return NGX_OK; +} + + +#if (NGX_QUIC_BPF) + +static ngx_int_t +ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id) +{ + int fd; + uint64_t cookie; + socklen_t optlen; + + fd = c->listening->fd; + + optlen = sizeof(cookie); + + if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &optlen) == -1) { + ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, + "quic getsockopt(SO_COOKIE) failed"); + + return NGX_ERROR; + } + + ngx_quic_dcid_encode_key(id, cookie); + + return NGX_OK; +} + +#endif + + +ngx_int_t +ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, + ngx_quic_new_conn_id_frame_t *f) +{ + ngx_str_t id; + ngx_queue_t *q; + ngx_quic_frame_t *frame; + ngx_quic_client_id_t *cid, *item; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (f->seqnum < qc->max_retired_seqnum) { + /* + * RFC 9000, 19.15. NEW_CONNECTION_ID Frame + * + * An endpoint that receives a NEW_CONNECTION_ID frame with + * a sequence number smaller than the Retire Prior To field + * of a previously received NEW_CONNECTION_ID frame MUST send + * a corresponding RETIRE_CONNECTION_ID frame that retires + * the newly received connection ID, unless it has already + * done so for that sequence number. + */ + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID; + frame->u.retire_cid.sequence_number = f->seqnum; + + ngx_quic_queue_frame(qc, frame); + + goto retire; + } + + cid = NULL; + + for (q = ngx_queue_head(&qc->client_ids); + q != ngx_queue_sentinel(&qc->client_ids); + q = ngx_queue_next(q)) + { + item = ngx_queue_data(q, ngx_quic_client_id_t, queue); + + if (item->seqnum == f->seqnum) { + cid = item; + break; + } + } + + if (cid) { + /* + * Transmission errors, timeouts, and retransmissions might cause the + * same NEW_CONNECTION_ID frame to be received multiple times. + */ + + if (cid->len != f->len + || ngx_strncmp(cid->id, f->cid, f->len) != 0 + || ngx_strncmp(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN) != 0) + { + /* + * ..if a sequence number is used for different connection IDs, + * the endpoint MAY treat that receipt as a connection error + * of type PROTOCOL_VIOLATION. + */ + qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + qc->error_reason = "seqnum refers to different connection id/token"; + return NGX_ERROR; + } + + } else { + + id.data = f->cid; + id.len = f->len; + + if (ngx_quic_create_client_id(c, &id, f->seqnum, f->srt) == NULL) { + return NGX_ERROR; + } + } + +retire: + + if (qc->max_retired_seqnum && f->retire <= qc->max_retired_seqnum) { + /* + * Once a sender indicates a Retire Prior To value, smaller values sent + * in subsequent NEW_CONNECTION_ID frames have no effect. A receiver + * MUST ignore any Retire Prior To fields that do not increase the + * largest received Retire Prior To value. + */ + goto done; + } + + qc->max_retired_seqnum = f->retire; + + q = ngx_queue_head(&qc->client_ids); + + while (q != ngx_queue_sentinel(&qc->client_ids)) { + + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + q = ngx_queue_next(q); + + if (cid->seqnum >= f->retire) { + continue; + } + + if (ngx_quic_retire_client_id(c, cid) != NGX_OK) { + return NGX_ERROR; + } + } + +done: + + if (qc->nclient_ids > qc->tp.active_connection_id_limit) { + /* + * RFC 9000, 5.1.1. Issuing Connection IDs + * + * After processing a NEW_CONNECTION_ID frame and + * adding and retiring active connection IDs, if the number of active + * connection IDs exceeds the value advertised in its + * active_connection_id_limit transport parameter, an endpoint MUST + * close the connection with an error of type CONNECTION_ID_LIMIT_ERROR. + */ + qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR; + qc->error_reason = "too many connection ids received"; + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_retire_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid) +{ + ngx_queue_t *q; + ngx_quic_path_t *path; + ngx_quic_client_id_t *new_cid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (!cid->used) { + return ngx_quic_free_client_id(c, cid); + } + + /* we are going to retire client id which is in use */ + + q = ngx_queue_head(&qc->paths); + + while (q != ngx_queue_sentinel(&qc->paths)) { + + path = ngx_queue_data(q, ngx_quic_path_t, queue); + q = ngx_queue_next(q); + + if (path->cid != cid) { + continue; + } + + if (path == qc->path) { + /* this is the active path: update it with new CID */ + new_cid = ngx_quic_next_client_id(c); + if (new_cid == NULL) { + return NGX_ERROR; + } + + qc->path->cid = new_cid; + new_cid->used = 1; + + return ngx_quic_free_client_id(c, cid); + } + + return ngx_quic_free_path(c, path); + } + + return NGX_OK; +} + + +static ngx_quic_client_id_t * +ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc) +{ + ngx_queue_t *q; + ngx_quic_client_id_t *cid; + + if (!ngx_queue_empty(&qc->free_client_ids)) { + + q = ngx_queue_head(&qc->free_client_ids); + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + + ngx_queue_remove(&cid->queue); + + ngx_memzero(cid, sizeof(ngx_quic_client_id_t)); + + } else { + + cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t)); + if (cid == NULL) { + return NULL; + } + } + + return cid; +} + + +ngx_quic_client_id_t * +ngx_quic_create_client_id(ngx_connection_t *c, ngx_str_t *id, + uint64_t seqnum, u_char *token) +{ + ngx_quic_client_id_t *cid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + cid = ngx_quic_alloc_client_id(c, qc); + if (cid == NULL) { + return NULL; + } + + cid->seqnum = seqnum; + + cid->len = id->len; + ngx_memcpy(cid->id, id->data, id->len); + + if (token) { + ngx_memcpy(cid->sr_token, token, NGX_QUIC_SR_TOKEN_LEN); + } + + ngx_queue_insert_tail(&qc->client_ids, &cid->queue); + qc->nclient_ids++; + + if (seqnum > qc->client_seqnum) { + qc->client_seqnum = seqnum; + } + + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic cid seq:%uL received id:%uz:%xV:%*xs", + cid->seqnum, id->len, id, + (size_t) NGX_QUIC_SR_TOKEN_LEN, cid->sr_token); + + return cid; +} + + +ngx_quic_client_id_t * +ngx_quic_next_client_id(ngx_connection_t *c) +{ + ngx_queue_t *q; + ngx_quic_client_id_t *cid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + for (q = ngx_queue_head(&qc->client_ids); + q != ngx_queue_sentinel(&qc->client_ids); + q = ngx_queue_next(q)) + { + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + + if (!cid->used) { + return cid; + } + } + + return NULL; +} + + +ngx_int_t +ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, + ngx_quic_retire_cid_frame_t *f) +{ + ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (f->sequence_number >= qc->server_seqnum) { + /* + * RFC 9000, 19.16. + * + * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence + * number greater than any previously sent to the peer MUST be + * treated as a connection error of type PROTOCOL_VIOLATION. + */ + qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + qc->error_reason = "sequence number of id to retire was never issued"; + + return NGX_ERROR; + } + + qsock = ngx_quic_get_socket(c); + + if (qsock->sid.seqnum == f->sequence_number) { + + /* + * RFC 9000, 19.16. + * + * The sequence number specified in a RETIRE_CONNECTION_ID frame MUST + * NOT refer to the Destination Connection ID field of the packet in + * which the frame is contained. The peer MAY treat this as a + * connection error of type PROTOCOL_VIOLATION. + */ + + qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + qc->error_reason = "sequence number of id to retire refers DCID"; + + return NGX_ERROR; + } + + qsock = ngx_quic_find_socket(c, f->sequence_number); + if (qsock == NULL) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic socket seq:%uL is retired", qsock->sid.seqnum); + + ngx_quic_close_socket(c, qsock); + + /* restore socket count up to a limit after deletion */ + if (ngx_quic_create_sockets(c) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_create_sockets(ngx_connection_t *c) +{ + ngx_uint_t n; + ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic create sockets has:%ui max:%ui", qc->nsockets, n); + + while (qc->nsockets < n) { + + qsock = ngx_quic_create_socket(c, qc); + if (qsock == NULL) { + return NGX_ERROR; + } + + if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_quic_send_server_id(c, &qsock->sid) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_send_server_id(ngx_connection_t *c, ngx_quic_server_id_t *sid) +{ + ngx_str_t dcid; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + dcid.len = sid->len; + dcid.data = sid->id; + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID; + frame->u.ncid.seqnum = sid->seqnum; + frame->u.ncid.retire = 0; + frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN; + ngx_memcpy(frame->u.ncid.cid, sid->id, NGX_QUIC_SERVER_CID_LEN); + + if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, + frame->u.ncid.srt) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_free_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid) +{ + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID; + frame->u.retire_cid.sequence_number = cid->seqnum; + + ngx_quic_queue_frame(qc, frame); + + /* we are no longer going to use this client id */ + + ngx_queue_remove(&cid->queue); + ngx_queue_insert_head(&qc->free_client_ids, &cid->queue); + + qc->nclient_ids--; + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_connid.h b/src/event/quic/ngx_event_quic_connid.h new file mode 100644 index 0000000..33e9c65 --- /dev/null +++ b/src/event/quic/ngx_event_quic_connid.h @@ -0,0 +1,29 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_CONNID_H_INCLUDED_ +#define _NGX_EVENT_QUIC_CONNID_H_INCLUDED_ + + +#include +#include + + +ngx_int_t ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, + ngx_quic_retire_cid_frame_t *f); +ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, + ngx_quic_new_conn_id_frame_t *f); + +ngx_int_t ngx_quic_create_sockets(ngx_connection_t *c); +ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id); + +ngx_quic_client_id_t *ngx_quic_create_client_id(ngx_connection_t *c, + ngx_str_t *id, uint64_t seqnum, u_char *token); +ngx_quic_client_id_t *ngx_quic_next_client_id(ngx_connection_t *c); +ngx_int_t ngx_quic_free_client_id(ngx_connection_t *c, + ngx_quic_client_id_t *cid); + +#endif /* _NGX_EVENT_QUIC_CONNID_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c new file mode 100644 index 0000000..42b7d9f --- /dev/null +++ b/src/event/quic/ngx_event_quic_frames.c @@ -0,0 +1,894 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#define NGX_QUIC_BUFFER_SIZE 4096 + +#define ngx_quic_buf_refs(b) (b)->shadow->num +#define ngx_quic_buf_inc_refs(b) ngx_quic_buf_refs(b)++ +#define ngx_quic_buf_dec_refs(b) ngx_quic_buf_refs(b)-- +#define ngx_quic_buf_set_refs(b, v) ngx_quic_buf_refs(b) = v + + +static ngx_buf_t *ngx_quic_alloc_buf(ngx_connection_t *c); +static void ngx_quic_free_buf(ngx_connection_t *c, ngx_buf_t *b); +static ngx_buf_t *ngx_quic_clone_buf(ngx_connection_t *c, ngx_buf_t *b); +static ngx_int_t ngx_quic_split_chain(ngx_connection_t *c, ngx_chain_t *cl, + off_t offset); + + +static ngx_buf_t * +ngx_quic_alloc_buf(ngx_connection_t *c) +{ + u_char *p; + ngx_buf_t *b; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + b = qc->free_bufs; + + if (b) { + qc->free_bufs = b->shadow; + p = b->start; + + } else { + b = qc->free_shadow_bufs; + + if (b) { + qc->free_shadow_bufs = b->shadow; + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic use shadow buffer n:%ui %ui", + ++qc->nbufs, --qc->nshadowbufs); +#endif + + } else { + b = ngx_palloc(c->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NULL; + } + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic new buffer n:%ui", ++qc->nbufs); +#endif + } + + p = ngx_pnalloc(c->pool, NGX_QUIC_BUFFER_SIZE); + if (p == NULL) { + return NULL; + } + } + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic alloc buffer %p", b); +#endif + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->tag = (ngx_buf_tag_t) &ngx_quic_alloc_buf; + b->temporary = 1; + b->shadow = b; + + b->start = p; + b->pos = p; + b->last = p; + b->end = p + NGX_QUIC_BUFFER_SIZE; + + ngx_quic_buf_set_refs(b, 1); + + return b; +} + + +static void +ngx_quic_free_buf(ngx_connection_t *c, ngx_buf_t *b) +{ + ngx_buf_t *shadow; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ngx_quic_buf_dec_refs(b); + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic free buffer %p r:%ui", + b, (ngx_uint_t) ngx_quic_buf_refs(b)); +#endif + + shadow = b->shadow; + + if (ngx_quic_buf_refs(b) == 0) { + shadow->shadow = qc->free_bufs; + qc->free_bufs = shadow; + } + + if (b != shadow) { + b->shadow = qc->free_shadow_bufs; + qc->free_shadow_bufs = b; + } + +} + + +static ngx_buf_t * +ngx_quic_clone_buf(ngx_connection_t *c, ngx_buf_t *b) +{ + ngx_buf_t *nb; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + nb = qc->free_shadow_bufs; + + if (nb) { + qc->free_shadow_bufs = nb->shadow; + + } else { + nb = ngx_palloc(c->pool, sizeof(ngx_buf_t)); + if (nb == NULL) { + return NULL; + } + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic new shadow buffer n:%ui", ++qc->nshadowbufs); +#endif + } + + *nb = *b; + + ngx_quic_buf_inc_refs(b); + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic clone buffer %p %p r:%ui", + b, nb, (ngx_uint_t) ngx_quic_buf_refs(b)); +#endif + + return nb; +} + + +static ngx_int_t +ngx_quic_split_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t offset) +{ + ngx_buf_t *b, *tb; + ngx_chain_t *tail; + + b = cl->buf; + + tail = ngx_alloc_chain_link(c->pool); + if (tail == NULL) { + return NGX_ERROR; + } + + tb = ngx_quic_clone_buf(c, b); + if (tb == NULL) { + return NGX_ERROR; + } + + tail->buf = tb; + + tb->pos += offset; + + b->last = tb->pos; + b->last_buf = 0; + + tail->next = cl->next; + cl->next = tail; + + return NGX_OK; +} + + +ngx_quic_frame_t * +ngx_quic_alloc_frame(ngx_connection_t *c) +{ + ngx_queue_t *q; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (!ngx_queue_empty(&qc->free_frames)) { + + q = ngx_queue_head(&qc->free_frames); + frame = ngx_queue_data(q, ngx_quic_frame_t, queue); + + ngx_queue_remove(&frame->queue); + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic reuse frame n:%ui", qc->nframes); +#endif + + } else if (qc->nframes < 10000) { + frame = ngx_palloc(c->pool, sizeof(ngx_quic_frame_t)); + if (frame == NULL) { + return NULL; + } + + ++qc->nframes; + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic alloc frame n:%ui", qc->nframes); +#endif + + } else { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic flood detected"); + return NULL; + } + + ngx_memzero(frame, sizeof(ngx_quic_frame_t)); + + return frame; +} + + +void +ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (frame->data) { + ngx_quic_free_chain(c, frame->data); + } + + ngx_queue_insert_head(&qc->free_frames, &frame->queue); + +#ifdef NGX_QUIC_DEBUG_ALLOC + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic free frame n:%ui", qc->nframes); +#endif +} + + +void +ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in) +{ + ngx_chain_t *cl; + + while (in) { + cl = in; + in = in->next; + + ngx_quic_free_buf(c, cl->buf); + ngx_free_chain(c->pool, cl); + } +} + + +void +ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames) +{ + ngx_queue_t *q; + ngx_quic_frame_t *f; + + do { + q = ngx_queue_head(frames); + + if (q == ngx_queue_sentinel(frames)) { + break; + } + + ngx_queue_remove(q); + + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + ngx_quic_free_frame(c, f); + } while (1); +} + + +void +ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame) +{ + ngx_quic_send_ctx_t *ctx; + + ctx = ngx_quic_get_send_ctx(qc, frame->level); + + ngx_queue_insert_tail(&ctx->frames, &frame->queue); + + frame->len = ngx_quic_create_frame(NULL, frame); + /* always succeeds */ + + if (qc->closing) { + return; + } + + ngx_post_event(&qc->push, &ngx_posted_events); +} + + +ngx_int_t +ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len) +{ + size_t shrink; + ngx_chain_t *out; + ngx_quic_frame_t *nf; + ngx_quic_buffer_t qb; + ngx_quic_ordered_frame_t *of, *onf; + + switch (f->type) { + case NGX_QUIC_FT_CRYPTO: + case NGX_QUIC_FT_STREAM: + break; + + default: + return NGX_DECLINED; + } + + if ((size_t) f->len <= len) { + return NGX_OK; + } + + shrink = f->len - len; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic split frame now:%uz need:%uz shrink:%uz", + f->len, len, shrink); + + of = &f->u.ord; + + if (of->length <= shrink) { + return NGX_DECLINED; + } + + of->length -= shrink; + f->len = ngx_quic_create_frame(NULL, f); + + if ((size_t) f->len > len) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "could not split QUIC frame"); + return NGX_ERROR; + } + + ngx_memzero(&qb, sizeof(ngx_quic_buffer_t)); + qb.chain = f->data; + + out = ngx_quic_read_buffer(c, &qb, of->length); + if (out == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } + + f->data = out; + + nf = ngx_quic_alloc_frame(c); + if (nf == NULL) { + return NGX_ERROR; + } + + *nf = *f; + onf = &nf->u.ord; + onf->offset += of->length; + onf->length = shrink; + nf->len = ngx_quic_create_frame(NULL, nf); + nf->data = qb.chain; + + if (f->type == NGX_QUIC_FT_STREAM) { + f->u.stream.fin = 0; + } + + ngx_queue_insert_after(&f->queue, &nf->queue); + + return NGX_OK; +} + + +ngx_chain_t * +ngx_quic_copy_buffer(ngx_connection_t *c, u_char *data, size_t len) +{ + ngx_buf_t buf; + ngx_chain_t cl, *out; + ngx_quic_buffer_t qb; + + ngx_memzero(&buf, sizeof(ngx_buf_t)); + + buf.pos = data; + buf.last = buf.pos + len; + buf.temporary = 1; + + cl.buf = &buf; + cl.next = NULL; + + ngx_memzero(&qb, sizeof(ngx_quic_buffer_t)); + + if (ngx_quic_write_buffer(c, &qb, &cl, len, 0) == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + out = ngx_quic_read_buffer(c, &qb, len); + if (out == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + ngx_quic_free_buffer(c, &qb); + + return out; +} + + +ngx_chain_t * +ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, uint64_t limit) +{ + uint64_t n; + ngx_buf_t *b; + ngx_chain_t *out, **ll; + + out = qb->chain; + + for (ll = &out; *ll; ll = &(*ll)->next) { + b = (*ll)->buf; + + if (b->sync) { + /* hole */ + break; + } + + if (limit == 0) { + break; + } + + n = b->last - b->pos; + + if (n > limit) { + if (ngx_quic_split_chain(c, *ll, limit) != NGX_OK) { + return NGX_CHAIN_ERROR; + } + + n = limit; + } + + limit -= n; + qb->offset += n; + } + + if (qb->offset >= qb->last_offset) { + qb->last_chain = NULL; + } + + qb->chain = *ll; + *ll = NULL; + + return out; +} + + +void +ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, + uint64_t offset) +{ + size_t n; + ngx_buf_t *b; + ngx_chain_t *cl; + + while (qb->chain) { + if (qb->offset >= offset) { + break; + } + + cl = qb->chain; + b = cl->buf; + n = b->last - b->pos; + + if (qb->offset + n > offset) { + n = offset - qb->offset; + b->pos += n; + qb->offset += n; + break; + } + + qb->offset += n; + qb->chain = cl->next; + + cl->next = NULL; + ngx_quic_free_chain(c, cl); + } + + if (qb->chain == NULL) { + qb->offset = offset; + } + + if (qb->offset >= qb->last_offset) { + qb->last_chain = NULL; + } +} + + +ngx_chain_t * +ngx_quic_alloc_chain(ngx_connection_t *c) +{ + ngx_chain_t *cl; + + cl = ngx_alloc_chain_link(c->pool); + if (cl == NULL) { + return NULL; + } + + cl->buf = ngx_quic_alloc_buf(c); + if (cl->buf == NULL) { + return NULL; + } + + return cl; +} + + +ngx_chain_t * +ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, + ngx_chain_t *in, uint64_t limit, uint64_t offset) +{ + u_char *p; + uint64_t n, base; + ngx_buf_t *b; + ngx_chain_t *cl, **chain; + + if (qb->last_chain && offset >= qb->last_offset) { + base = qb->last_offset; + chain = &qb->last_chain; + + } else { + base = qb->offset; + chain = &qb->chain; + } + + while (in && limit) { + + if (offset < base) { + n = ngx_min((uint64_t) (in->buf->last - in->buf->pos), + ngx_min(base - offset, limit)); + + in->buf->pos += n; + offset += n; + limit -= n; + + if (in->buf->pos == in->buf->last) { + in = in->next; + } + + continue; + } + + cl = *chain; + + if (cl == NULL) { + cl = ngx_quic_alloc_chain(c); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + cl->buf->last = cl->buf->end; + cl->buf->sync = 1; /* hole */ + cl->next = NULL; + *chain = cl; + } + + b = cl->buf; + n = b->last - b->pos; + + if (base + n <= offset) { + base += n; + chain = &cl->next; + continue; + } + + if (b->sync && offset > base) { + if (ngx_quic_split_chain(c, cl, offset - base) != NGX_OK) { + return NGX_CHAIN_ERROR; + } + + continue; + } + + p = b->pos + (offset - base); + + while (in) { + + if (!ngx_buf_in_memory(in->buf) || in->buf->pos == in->buf->last) { + in = in->next; + continue; + } + + if (p == b->last || limit == 0) { + break; + } + + n = ngx_min(b->last - p, in->buf->last - in->buf->pos); + n = ngx_min(n, limit); + + if (b->sync) { + ngx_memcpy(p, in->buf->pos, n); + qb->size += n; + } + + p += n; + in->buf->pos += n; + offset += n; + limit -= n; + } + + if (b->sync && p == b->last) { + b->sync = 0; + continue; + } + + if (b->sync && p != b->pos) { + if (ngx_quic_split_chain(c, cl, p - b->pos) != NGX_OK) { + return NGX_CHAIN_ERROR; + } + + b->sync = 0; + } + } + + qb->last_offset = base; + qb->last_chain = *chain; + + return in; +} + + +void +ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb) +{ + ngx_quic_free_chain(c, qb->chain); + + qb->chain = NULL; +} + + +#if (NGX_DEBUG) + +void +ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx) +{ + u_char *p, *last, *pos, *end; + ssize_t n; + uint64_t gap, range, largest, smallest; + ngx_uint_t i; + u_char buf[NGX_MAX_ERROR_STR]; + + p = buf; + last = buf + sizeof(buf); + + switch (f->type) { + + case NGX_QUIC_FT_CRYPTO: + p = ngx_slprintf(p, last, "CRYPTO len:%uL off:%uL", + f->u.crypto.length, f->u.crypto.offset); + +#ifdef NGX_QUIC_DEBUG_FRAMES + { + ngx_chain_t *cl; + + p = ngx_slprintf(p, last, " data:"); + + for (cl = f->data; cl; cl = cl->next) { + p = ngx_slprintf(p, last, "%*xs", + cl->buf->last - cl->buf->pos, cl->buf->pos); + } + } +#endif + + break; + + case NGX_QUIC_FT_PADDING: + p = ngx_slprintf(p, last, "PADDING"); + break; + + case NGX_QUIC_FT_ACK: + case NGX_QUIC_FT_ACK_ECN: + + p = ngx_slprintf(p, last, "ACK n:%ui delay:%uL ", + f->u.ack.range_count, f->u.ack.delay); + + if (f->data) { + pos = f->data->buf->pos; + end = f->data->buf->last; + + } else { + pos = NULL; + end = NULL; + } + + largest = f->u.ack.largest; + smallest = f->u.ack.largest - f->u.ack.first_range; + + if (largest == smallest) { + p = ngx_slprintf(p, last, "%uL", largest); + + } else { + p = ngx_slprintf(p, last, "%uL-%uL", largest, smallest); + } + + for (i = 0; i < f->u.ack.range_count; i++) { + n = ngx_quic_parse_ack_range(log, pos, end, &gap, &range); + if (n == NGX_ERROR) { + break; + } + + pos += n; + + largest = smallest - gap - 2; + smallest = largest - range; + + if (largest == smallest) { + p = ngx_slprintf(p, last, " %uL", largest); + + } else { + p = ngx_slprintf(p, last, " %uL-%uL", largest, smallest); + } + } + + if (f->type == NGX_QUIC_FT_ACK_ECN) { + p = ngx_slprintf(p, last, " ECN counters ect0:%uL ect1:%uL ce:%uL", + f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce); + } + break; + + case NGX_QUIC_FT_PING: + p = ngx_slprintf(p, last, "PING"); + break; + + case NGX_QUIC_FT_NEW_CONNECTION_ID: + p = ngx_slprintf(p, last, + "NEW_CONNECTION_ID seq:%uL retire:%uL len:%ud", + f->u.ncid.seqnum, f->u.ncid.retire, f->u.ncid.len); + break; + + case NGX_QUIC_FT_RETIRE_CONNECTION_ID: + p = ngx_slprintf(p, last, "RETIRE_CONNECTION_ID seqnum:%uL", + f->u.retire_cid.sequence_number); + break; + + case NGX_QUIC_FT_CONNECTION_CLOSE: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: + p = ngx_slprintf(p, last, "CONNECTION_CLOSE%s err:%ui", + f->type == NGX_QUIC_FT_CONNECTION_CLOSE ? "" : "_APP", + f->u.close.error_code); + + if (f->u.close.reason.len) { + p = ngx_slprintf(p, last, " %V", &f->u.close.reason); + } + + if (f->type == NGX_QUIC_FT_CONNECTION_CLOSE) { + p = ngx_slprintf(p, last, " ft:%ui", f->u.close.frame_type); + } + + break; + + case NGX_QUIC_FT_STREAM: + p = ngx_slprintf(p, last, "STREAM id:0x%xL", f->u.stream.stream_id); + + if (f->u.stream.off) { + p = ngx_slprintf(p, last, " off:%uL", f->u.stream.offset); + } + + if (f->u.stream.len) { + p = ngx_slprintf(p, last, " len:%uL", f->u.stream.length); + } + + if (f->u.stream.fin) { + p = ngx_slprintf(p, last, " fin:1"); + } + +#ifdef NGX_QUIC_DEBUG_FRAMES + { + ngx_chain_t *cl; + + p = ngx_slprintf(p, last, " data:"); + + for (cl = f->data; cl; cl = cl->next) { + p = ngx_slprintf(p, last, "%*xs", + cl->buf->last - cl->buf->pos, cl->buf->pos); + } + } +#endif + + break; + + case NGX_QUIC_FT_MAX_DATA: + p = ngx_slprintf(p, last, "MAX_DATA max_data:%uL on recv", + f->u.max_data.max_data); + break; + + case NGX_QUIC_FT_RESET_STREAM: + p = ngx_slprintf(p, last, "RESET_STREAM" + " id:0x%xL error_code:0x%xL final_size:0x%xL", + f->u.reset_stream.id, f->u.reset_stream.error_code, + f->u.reset_stream.final_size); + break; + + case NGX_QUIC_FT_STOP_SENDING: + p = ngx_slprintf(p, last, "STOP_SENDING id:0x%xL err:0x%xL", + f->u.stop_sending.id, f->u.stop_sending.error_code); + break; + + case NGX_QUIC_FT_STREAMS_BLOCKED: + case NGX_QUIC_FT_STREAMS_BLOCKED2: + p = ngx_slprintf(p, last, "STREAMS_BLOCKED limit:%uL bidi:%ui", + f->u.streams_blocked.limit, f->u.streams_blocked.bidi); + break; + + case NGX_QUIC_FT_MAX_STREAMS: + case NGX_QUIC_FT_MAX_STREAMS2: + p = ngx_slprintf(p, last, "MAX_STREAMS limit:%uL bidi:%ui", + f->u.max_streams.limit, f->u.max_streams.bidi); + break; + + case NGX_QUIC_FT_MAX_STREAM_DATA: + p = ngx_slprintf(p, last, "MAX_STREAM_DATA id:0x%xL limit:%uL", + f->u.max_stream_data.id, f->u.max_stream_data.limit); + break; + + + case NGX_QUIC_FT_DATA_BLOCKED: + p = ngx_slprintf(p, last, "DATA_BLOCKED limit:%uL", + f->u.data_blocked.limit); + break; + + case NGX_QUIC_FT_STREAM_DATA_BLOCKED: + p = ngx_slprintf(p, last, "STREAM_DATA_BLOCKED id:0x%xL limit:%uL", + f->u.stream_data_blocked.id, + f->u.stream_data_blocked.limit); + break; + + case NGX_QUIC_FT_PATH_CHALLENGE: + p = ngx_slprintf(p, last, "PATH_CHALLENGE data:0x%*xs", + sizeof(f->u.path_challenge.data), + f->u.path_challenge.data); + break; + + case NGX_QUIC_FT_PATH_RESPONSE: + p = ngx_slprintf(p, last, "PATH_RESPONSE data:0x%*xs", + sizeof(f->u.path_challenge.data), + f->u.path_challenge.data); + break; + + case NGX_QUIC_FT_NEW_TOKEN: + p = ngx_slprintf(p, last, "NEW_TOKEN"); + +#ifdef NGX_QUIC_DEBUG_FRAMES + { + ngx_chain_t *cl; + + p = ngx_slprintf(p, last, " token:"); + + for (cl = f->data; cl; cl = cl->next) { + p = ngx_slprintf(p, last, "%*xs", + cl->buf->last - cl->buf->pos, cl->buf->pos); + } + } +#endif + + break; + + case NGX_QUIC_FT_HANDSHAKE_DONE: + p = ngx_slprintf(p, last, "HANDSHAKE DONE"); + break; + + default: + p = ngx_slprintf(p, last, "unknown type 0x%xi", f->type); + break; + } + + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, log, 0, "quic frame %s %s:%uL %*s", + tx ? "tx" : "rx", ngx_quic_level_name(f->level), f->pnum, + p - buf, buf); +} + +#endif diff --git a/src/event/quic/ngx_event_quic_frames.h b/src/event/quic/ngx_event_quic_frames.h new file mode 100644 index 0000000..2d55af9 --- /dev/null +++ b/src/event/quic/ngx_event_quic_frames.h @@ -0,0 +1,45 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_FRAMES_H_INCLUDED_ +#define _NGX_EVENT_QUIC_FRAMES_H_INCLUDED_ + + +#include +#include + + +typedef ngx_int_t (*ngx_quic_frame_handler_pt)(ngx_connection_t *c, + ngx_quic_frame_t *frame, void *data); + + +ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c); +void ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame); +void ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames); +void ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame); +ngx_int_t ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, + size_t len); + +ngx_chain_t *ngx_quic_alloc_chain(ngx_connection_t *c); +void ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in); + +ngx_chain_t *ngx_quic_copy_buffer(ngx_connection_t *c, u_char *data, + size_t len); +ngx_chain_t *ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, + uint64_t limit); +ngx_chain_t *ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, + ngx_chain_t *in, uint64_t limit, uint64_t offset); +void ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, + uint64_t offset); +void ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb); + +#if (NGX_DEBUG) +void ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx); +#else +#define ngx_quic_log_frame(log, f, tx) +#endif + +#endif /* _NGX_EVENT_QUIC_FRAMES_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_migration.c b/src/event/quic/ngx_event_quic_migration.c new file mode 100644 index 0000000..2d1467e --- /dev/null +++ b/src/event/quic/ngx_event_quic_migration.c @@ -0,0 +1,1003 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#define NGX_QUIC_PATH_MTU_DELAY 100 +#define NGX_QUIC_PATH_MTU_PRECISION 16 + + +static void ngx_quic_set_connection_path(ngx_connection_t *c, + ngx_quic_path_t *path); +static ngx_int_t ngx_quic_validate_path(ngx_connection_t *c, + ngx_quic_path_t *path); +static ngx_int_t ngx_quic_send_path_challenge(ngx_connection_t *c, + ngx_quic_path_t *path); +static void ngx_quic_set_path_timer(ngx_connection_t *c); +static ngx_int_t ngx_quic_expire_path_validation(ngx_connection_t *c, + ngx_quic_path_t *path); +static ngx_int_t ngx_quic_expire_path_mtu_delay(ngx_connection_t *c, + ngx_quic_path_t *path); +static ngx_int_t ngx_quic_expire_path_mtu_discovery(ngx_connection_t *c, + ngx_quic_path_t *path); +static ngx_quic_path_t *ngx_quic_get_path(ngx_connection_t *c, ngx_uint_t tag); +static ngx_int_t ngx_quic_send_path_mtu_probe(ngx_connection_t *c, + ngx_quic_path_t *path); + + +ngx_int_t +ngx_quic_handle_path_challenge_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_path_challenge_frame_t *f) +{ + size_t min; + ngx_quic_frame_t *fp; + ngx_quic_connection_t *qc; + + if (pkt->level != ssl_encryption_application || pkt->path_challenged) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ignoring PATH_CHALLENGE"); + return NGX_OK; + } + + pkt->path_challenged = 1; + + qc = ngx_quic_get_connection(c); + + fp = ngx_quic_alloc_frame(c); + if (fp == NULL) { + return NGX_ERROR; + } + + fp->level = ssl_encryption_application; + fp->type = NGX_QUIC_FT_PATH_RESPONSE; + fp->u.path_response = *f; + + /* + * RFC 9000, 8.2.2. Path Validation Responses + * + * A PATH_RESPONSE frame MUST be sent on the network path where the + * PATH_CHALLENGE frame was received. + */ + + /* + * An endpoint MUST expand datagrams that contain a PATH_RESPONSE frame + * to at least the smallest allowed maximum datagram size of 1200 bytes. + * ... + * However, an endpoint MUST NOT expand the datagram containing the + * PATH_RESPONSE if the resulting data exceeds the anti-amplification limit. + */ + + min = (ngx_quic_path_limit(c, pkt->path, 1200) < 1200) ? 0 : 1200; + + if (ngx_quic_frame_sendto(c, fp, min, pkt->path) == NGX_ERROR) { + return NGX_ERROR; + } + + if (pkt->path == qc->path) { + /* + * RFC 9000, 9.3.3. Off-Path Packet Forwarding + * + * An endpoint that receives a PATH_CHALLENGE on an active path SHOULD + * send a non-probing packet in response. + */ + + fp = ngx_quic_alloc_frame(c); + if (fp == NULL) { + return NGX_ERROR; + } + + fp->level = ssl_encryption_application; + fp->type = NGX_QUIC_FT_PING; + + ngx_quic_queue_frame(qc, fp); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_path_response_frame(ngx_connection_t *c, + ngx_quic_path_challenge_frame_t *f) +{ + ngx_uint_t rst; + ngx_queue_t *q; + ngx_quic_path_t *path, *prev; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + /* + * RFC 9000, 8.2.3. Successful Path Validation + * + * A PATH_RESPONSE frame received on any network path validates the path + * on which the PATH_CHALLENGE was sent. + */ + + for (q = ngx_queue_head(&qc->paths); + q != ngx_queue_sentinel(&qc->paths); + q = ngx_queue_next(q)) + { + path = ngx_queue_data(q, ngx_quic_path_t, queue); + + if (path->state != NGX_QUIC_PATH_VALIDATING) { + continue; + } + + if (ngx_memcmp(path->challenge[0], f->data, sizeof(f->data)) == 0 + || ngx_memcmp(path->challenge[1], f->data, sizeof(f->data)) == 0) + { + goto valid; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stale PATH_RESPONSE ignored"); + + return NGX_OK; + +valid: + + /* + * RFC 9000, 9.4. Loss Detection and Congestion Control + * + * On confirming a peer's ownership of its new address, + * an endpoint MUST immediately reset the congestion controller + * and round-trip time estimator for the new path to initial values + * unless the only change in the peer's address is its port number. + */ + + rst = 1; + + prev = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP); + + if (prev != NULL) { + + if (ngx_cmp_sockaddr(prev->sockaddr, prev->socklen, + path->sockaddr, path->socklen, 0) + == NGX_OK) + { + /* address did not change */ + rst = 0; + + path->mtu = prev->mtu; + path->max_mtu = prev->max_mtu; + path->mtu_unvalidated = 0; + } + } + + if (rst) { + /* prevent old path packets contribution to congestion control */ + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + qc->rst_pnum = ctx->pnum; + + ngx_memzero(&qc->congestion, sizeof(ngx_quic_congestion_t)); + + qc->congestion.window = ngx_min(10 * qc->tp.max_udp_payload_size, + ngx_max(2 * qc->tp.max_udp_payload_size, + 14720)); + qc->congestion.ssthresh = (size_t) -1; + qc->congestion.recovery_start = ngx_current_msec; + + ngx_quic_init_rtt(qc); + } + + path->validated = 1; + + if (path->mtu_unvalidated) { + path->mtu_unvalidated = 0; + return ngx_quic_validate_path(c, path); + } + + /* + * RFC 9000, 9.3. Responding to Connection Migration + * + * After verifying a new client address, the server SHOULD + * send new address validation tokens (Section 8) to the client. + */ + + if (ngx_quic_send_new_token(c, path) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic path seq:%uL addr:%V successfully validated", + path->seqnum, &path->addr_text); + + ngx_quic_path_dbg(c, "is validated", path); + + ngx_quic_discover_path_mtu(c, path); + + return NGX_OK; +} + + +ngx_quic_path_t * +ngx_quic_new_path(ngx_connection_t *c, + struct sockaddr *sockaddr, socklen_t socklen, ngx_quic_client_id_t *cid) +{ + ngx_queue_t *q; + ngx_quic_path_t *path; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (!ngx_queue_empty(&qc->free_paths)) { + + q = ngx_queue_head(&qc->free_paths); + path = ngx_queue_data(q, ngx_quic_path_t, queue); + + ngx_queue_remove(&path->queue); + + ngx_memzero(path, sizeof(ngx_quic_path_t)); + + } else { + + path = ngx_pcalloc(c->pool, sizeof(ngx_quic_path_t)); + if (path == NULL) { + return NULL; + } + } + + ngx_queue_insert_tail(&qc->paths, &path->queue); + + path->cid = cid; + cid->used = 1; + + path->seqnum = qc->path_seqnum++; + + path->sockaddr = &path->sa.sockaddr; + path->socklen = socklen; + ngx_memcpy(path->sockaddr, sockaddr, socklen); + + path->addr_text.data = path->text; + path->addr_text.len = ngx_sock_ntop(sockaddr, socklen, path->text, + NGX_SOCKADDR_STRLEN, 1); + + path->mtu = NGX_QUIC_MIN_INITIAL_SIZE; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL created addr:%V", + path->seqnum, &path->addr_text); + return path; +} + + +static ngx_quic_path_t * +ngx_quic_get_path(ngx_connection_t *c, ngx_uint_t tag) +{ + ngx_queue_t *q; + ngx_quic_path_t *path; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + for (q = ngx_queue_head(&qc->paths); + q != ngx_queue_sentinel(&qc->paths); + q = ngx_queue_next(q)) + { + path = ngx_queue_data(q, ngx_quic_path_t, queue); + + if (path->tag == tag) { + return path; + } + } + + return NULL; +} + + +ngx_int_t +ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt) +{ + off_t len; + ngx_queue_t *q; + ngx_quic_path_t *path, *probe; + ngx_quic_socket_t *qsock; + ngx_quic_send_ctx_t *ctx; + ngx_quic_client_id_t *cid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + qsock = ngx_quic_get_socket(c); + + len = pkt->raw->last - pkt->raw->start; + + if (c->udp->buffer == NULL) { + /* first ever packet in connection, path already exists */ + path = qc->path; + goto update; + } + + probe = NULL; + + for (q = ngx_queue_head(&qc->paths); + q != ngx_queue_sentinel(&qc->paths); + q = ngx_queue_next(q)) + { + path = ngx_queue_data(q, ngx_quic_path_t, queue); + + if (ngx_cmp_sockaddr(&qsock->sockaddr.sockaddr, qsock->socklen, + path->sockaddr, path->socklen, 1) + == NGX_OK) + { + goto update; + } + + if (path->tag == NGX_QUIC_PATH_PROBE) { + probe = path; + } + } + + /* packet from new path, drop current probe, if any */ + + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + + /* + * only accept highest-numbered packets to prevent connection id + * exhaustion by excessive probing packets from unknown paths + */ + if (pkt->pn != ctx->largest_pn) { + return NGX_DONE; + } + + if (probe && ngx_quic_free_path(c, probe) != NGX_OK) { + return NGX_ERROR; + } + + /* new path requires new client id */ + cid = ngx_quic_next_client_id(c); + if (cid == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic no available client ids for new path"); + /* stop processing of this datagram */ + return NGX_DONE; + } + + path = ngx_quic_new_path(c, &qsock->sockaddr.sockaddr, qsock->socklen, cid); + if (path == NULL) { + return NGX_ERROR; + } + + path->tag = NGX_QUIC_PATH_PROBE; + + /* + * client arrived using new path and previously seen DCID, + * this indicates NAT rebinding (or bad client) + */ + if (qsock->used) { + pkt->rebound = 1; + } + +update: + + qsock->used = 1; + pkt->path = path; + + /* TODO: this may be too late in some cases; + * for example, if error happens during decrypt(), we cannot + * send CC, if error happens in 1st packet, due to amplification + * limit, because path->received = 0 + * + * should we account garbage as received or only decrypting packets? + */ + path->received += len; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet len:%O via sock seq:%L path seq:%uL", + len, (int64_t) qsock->sid.seqnum, path->seqnum); + ngx_quic_path_dbg(c, "status", path); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_free_path(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ngx_queue_remove(&path->queue); + ngx_queue_insert_head(&qc->free_paths, &path->queue); + + /* + * invalidate CID that is no longer usable for any other path; + * this also requests new CIDs from client + */ + if (path->cid) { + if (ngx_quic_free_client_id(c, path->cid) != NGX_OK) { + return NGX_ERROR; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL addr:%V retired", + path->seqnum, &path->addr_text); + + return NGX_OK; +} + + +static void +ngx_quic_set_connection_path(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_memcpy(c->sockaddr, path->sockaddr, path->socklen); + c->socklen = path->socklen; + + if (c->addr_text.data) { + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, + c->listening->addr_text_max_len, 0); + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic send path set to seq:%uL addr:%V", + path->seqnum, &path->addr_text); +} + + +ngx_int_t +ngx_quic_handle_migration(ngx_connection_t *c, ngx_quic_header_t *pkt) +{ + ngx_quic_path_t *next, *bkp; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + /* got non-probing packet via non-active path */ + + qc = ngx_quic_get_connection(c); + + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + + /* + * RFC 9000, 9.3. Responding to Connection Migration + * + * An endpoint only changes the address to which it sends packets in + * response to the highest-numbered non-probing packet. + */ + if (pkt->pn != ctx->largest_pn) { + return NGX_OK; + } + + next = pkt->path; + + /* + * RFC 9000, 9.3.3: + * + * In response to an apparent migration, endpoints MUST validate the + * previously active path using a PATH_CHALLENGE frame. + */ + if (pkt->rebound) { + + /* NAT rebinding: client uses new path with old SID */ + if (ngx_quic_validate_path(c, qc->path) != NGX_OK) { + return NGX_ERROR; + } + } + + if (qc->path->validated) { + + if (next->tag != NGX_QUIC_PATH_BACKUP) { + /* can delete backup path, if any */ + bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP); + + if (bkp && ngx_quic_free_path(c, bkp) != NGX_OK) { + return NGX_ERROR; + } + } + + qc->path->tag = NGX_QUIC_PATH_BACKUP; + ngx_quic_path_dbg(c, "is now backup", qc->path); + + } else { + if (ngx_quic_free_path(c, qc->path) != NGX_OK) { + return NGX_ERROR; + } + } + + /* switch active path to migrated */ + qc->path = next; + qc->path->tag = NGX_QUIC_PATH_ACTIVE; + + ngx_quic_set_connection_path(c, next); + + if (!next->validated && next->state != NGX_QUIC_PATH_VALIDATING) { + if (ngx_quic_validate_path(c, next) != NGX_OK) { + return NGX_ERROR; + } + } + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic migrated to path seq:%uL addr:%V", + qc->path->seqnum, &qc->path->addr_text); + + ngx_quic_path_dbg(c, "is now active", qc->path); + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_validate_path(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_msec_t pto; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic initiated validation of path seq:%uL", path->seqnum); + + path->tries = 0; + + if (RAND_bytes((u_char *) path->challenge, sizeof(path->challenge)) != 1) { + return NGX_ERROR; + } + + (void) ngx_quic_send_path_challenge(c, path); + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + pto = ngx_max(ngx_quic_pto(c, ctx), 1000); + + path->expires = ngx_current_msec + pto; + path->state = NGX_QUIC_PATH_VALIDATING; + + ngx_quic_set_path_timer(c); + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_send_path_challenge(ngx_connection_t *c, ngx_quic_path_t *path) +{ + size_t min; + ngx_uint_t n; + ngx_quic_frame_t *frame; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL send path_challenge tries:%ui", + path->seqnum, path->tries); + + for (n = 0; n < 2; n++) { + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_PATH_CHALLENGE; + + ngx_memcpy(frame->u.path_challenge.data, path->challenge[n], 8); + + /* + * RFC 9000, 8.2.1. Initiating Path Validation + * + * An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame + * to at least the smallest allowed maximum datagram size of 1200 bytes, + * unless the anti-amplification limit for the path does not permit + * sending a datagram of this size. + */ + + if (path->mtu_unvalidated + || ngx_quic_path_limit(c, path, 1200) < 1200) + { + min = 0; + path->mtu_unvalidated = 1; + + } else { + min = 1200; + } + + if (ngx_quic_frame_sendto(c, frame, min, path) == NGX_ERROR) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +void +ngx_quic_discover_path_mtu(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (path->max_mtu) { + if (path->max_mtu - path->mtu <= NGX_QUIC_PATH_MTU_PRECISION) { + path->state = NGX_QUIC_PATH_IDLE; + ngx_quic_set_path_timer(c); + return; + } + + path->mtud = (path->mtu + path->max_mtu) / 2; + + } else { + path->mtud = path->mtu * 2; + + if (path->mtud >= qc->ctp.max_udp_payload_size) { + path->mtud = qc->ctp.max_udp_payload_size; + path->max_mtu = qc->ctp.max_udp_payload_size; + } + } + + path->state = NGX_QUIC_PATH_WAITING; + path->expires = ngx_current_msec + NGX_QUIC_PATH_MTU_DELAY; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL schedule mtu:%uz", + path->seqnum, path->mtud); + + ngx_quic_set_path_timer(c); +} + + +static void +ngx_quic_set_path_timer(ngx_connection_t *c) +{ + ngx_msec_t now; + ngx_queue_t *q; + ngx_msec_int_t left, next; + ngx_quic_path_t *path; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + now = ngx_current_msec; + next = -1; + + for (q = ngx_queue_head(&qc->paths); + q != ngx_queue_sentinel(&qc->paths); + q = ngx_queue_next(q)) + { + path = ngx_queue_data(q, ngx_quic_path_t, queue); + + if (path->state == NGX_QUIC_PATH_IDLE) { + continue; + } + + left = path->expires - now; + left = ngx_max(left, 1); + + if (next == -1 || left < next) { + next = left; + } + } + + if (next != -1) { + ngx_add_timer(&qc->path_validation, next); + + } else if (qc->path_validation.timer_set) { + ngx_del_timer(&qc->path_validation); + } +} + + +void +ngx_quic_path_handler(ngx_event_t *ev) +{ + ngx_msec_t now; + ngx_queue_t *q; + ngx_msec_int_t left; + ngx_quic_path_t *path; + ngx_connection_t *c; + ngx_quic_connection_t *qc; + + c = ev->data; + qc = ngx_quic_get_connection(c); + + now = ngx_current_msec; + + q = ngx_queue_head(&qc->paths); + + while (q != ngx_queue_sentinel(&qc->paths)) { + + path = ngx_queue_data(q, ngx_quic_path_t, queue); + q = ngx_queue_next(q); + + if (path->state == NGX_QUIC_PATH_IDLE) { + continue; + } + + left = path->expires - now; + + if (left > 0) { + continue; + } + + switch (path->state) { + case NGX_QUIC_PATH_VALIDATING: + if (ngx_quic_expire_path_validation(c, path) != NGX_OK) { + goto failed; + } + + break; + + case NGX_QUIC_PATH_WAITING: + if (ngx_quic_expire_path_mtu_delay(c, path) != NGX_OK) { + goto failed; + } + + break; + + case NGX_QUIC_PATH_MTUD: + if (ngx_quic_expire_path_mtu_discovery(c, path) != NGX_OK) { + goto failed; + } + + break; + + default: + break; + } + } + + ngx_quic_set_path_timer(c); + + return; + +failed: + + ngx_quic_close_connection(c, NGX_ERROR); +} + + +static ngx_int_t +ngx_quic_expire_path_validation(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_msec_int_t pto; + ngx_quic_path_t *bkp; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + + if (++path->tries < NGX_QUIC_PATH_RETRIES) { + pto = ngx_max(ngx_quic_pto(c, ctx), 1000) << path->tries; + path->expires = ngx_current_msec + pto; + + (void) ngx_quic_send_path_challenge(c, path); + + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL validation failed", path->seqnum); + + /* found expired path */ + + path->validated = 0; + + + /* RFC 9000, 9.3.2. On-Path Address Spoofing + * + * To protect the connection from failing due to such a spurious + * migration, an endpoint MUST revert to using the last validated + * peer address when validation of a new peer address fails. + */ + + if (qc->path == path) { + /* active path validation failed */ + + bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP); + + if (bkp == NULL) { + qc->error = NGX_QUIC_ERR_NO_VIABLE_PATH; + qc->error_reason = "no viable path"; + return NGX_ERROR; + } + + qc->path = bkp; + qc->path->tag = NGX_QUIC_PATH_ACTIVE; + + ngx_quic_set_connection_path(c, qc->path); + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic path seq:%uL addr:%V is restored from backup", + qc->path->seqnum, &qc->path->addr_text); + + ngx_quic_path_dbg(c, "is active", qc->path); + } + + return ngx_quic_free_path(c, path); +} + + +static ngx_int_t +ngx_quic_expire_path_mtu_delay(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_int_t rc; + ngx_uint_t i; + ngx_msec_t pto; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + + path->tries = 0; + + for ( ;; ) { + + for (i = 0; i < NGX_QUIC_PATH_RETRIES; i++) { + path->mtu_pnum[i] = NGX_QUIC_UNSET_PN; + } + + rc = ngx_quic_send_path_mtu_probe(c, path); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + pto = ngx_quic_pto(c, ctx); + path->expires = ngx_current_msec + pto; + path->state = NGX_QUIC_PATH_MTUD; + return NGX_OK; + } + + /* rc == NGX_DECLINED */ + + path->max_mtu = path->mtud; + + if (path->max_mtu - path->mtu <= NGX_QUIC_PATH_MTU_PRECISION) { + path->state = NGX_QUIC_PATH_IDLE; + return NGX_OK; + } + + path->mtud = (path->mtu + path->max_mtu) / 2; + } +} + + +static ngx_int_t +ngx_quic_expire_path_mtu_discovery(ngx_connection_t *c, ngx_quic_path_t *path) +{ + ngx_int_t rc; + ngx_msec_int_t pto; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + + if (++path->tries < NGX_QUIC_PATH_RETRIES) { + rc = ngx_quic_send_path_mtu_probe(c, path); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + pto = ngx_quic_pto(c, ctx) << path->tries; + path->expires = ngx_current_msec + pto; + return NGX_OK; + } + + /* rc == NGX_DECLINED */ + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL expired mtu:%uz", + path->seqnum, path->mtud); + + path->max_mtu = path->mtud; + + ngx_quic_discover_path_mtu(c, path); + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_send_path_mtu_probe(ngx_connection_t *c, ngx_quic_path_t *path) +{ + size_t mtu; + uint64_t pnum; + ngx_int_t rc; + ngx_uint_t log_error; + ngx_quic_frame_t *frame; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_PING; + + qc = ngx_quic_get_connection(c); + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + pnum = ctx->pnum; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL send probe " + "mtu:%uz pnum:%uL tries:%ui", + path->seqnum, path->mtud, ctx->pnum, path->tries); + + log_error = c->log_error; + c->log_error = NGX_ERROR_IGNORE_EMSGSIZE; + + mtu = path->mtu; + path->mtu = path->mtud; + + rc = ngx_quic_frame_sendto(c, frame, path->mtud, path); + + path->mtu = mtu; + c->log_error = log_error; + + if (rc == NGX_OK) { + path->mtu_pnum[path->tries] = pnum; + return NGX_OK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL rejected mtu:%uz", + path->seqnum, path->mtud); + + if (rc == NGX_ERROR) { + if (c->write->error) { + c->write->error = 0; + return NGX_DECLINED; + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_path_mtu(ngx_connection_t *c, ngx_quic_path_t *path, + uint64_t min, uint64_t max) +{ + uint64_t pnum; + ngx_uint_t i; + + if (path->state != NGX_QUIC_PATH_MTUD) { + return NGX_OK; + } + + for (i = 0; i < NGX_QUIC_PATH_RETRIES; i++) { + pnum = path->mtu_pnum[i]; + + if (pnum == NGX_QUIC_UNSET_PN) { + continue; + } + + if (pnum < min || pnum > max) { + continue; + } + + path->mtu = path->mtud; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic path seq:%uL ack mtu:%uz", + path->seqnum, path->mtu); + + ngx_quic_discover_path_mtu(c, path); + + break; + } + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_migration.h b/src/event/quic/ngx_event_quic_migration.h new file mode 100644 index 0000000..270c572 --- /dev/null +++ b/src/event/quic/ngx_event_quic_migration.h @@ -0,0 +1,45 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_MIGRATION_H_INCLUDED_ +#define _NGX_EVENT_QUIC_MIGRATION_H_INCLUDED_ + + +#include +#include + +#define NGX_QUIC_PATH_RETRIES 3 + +#define NGX_QUIC_PATH_PROBE 0 +#define NGX_QUIC_PATH_ACTIVE 1 +#define NGX_QUIC_PATH_BACKUP 2 + +#define ngx_quic_path_dbg(c, msg, path) \ + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, \ + "quic path seq:%uL %s tx:%O rx:%O valid:%d st:%d mtu:%uz", \ + path->seqnum, msg, path->sent, path->received, \ + path->validated, path->state, path->mtu); + +ngx_int_t ngx_quic_handle_path_challenge_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_path_challenge_frame_t *f); +ngx_int_t ngx_quic_handle_path_response_frame(ngx_connection_t *c, + ngx_quic_path_challenge_frame_t *f); + +ngx_quic_path_t *ngx_quic_new_path(ngx_connection_t *c, + struct sockaddr *sockaddr, socklen_t socklen, ngx_quic_client_id_t *cid); +ngx_int_t ngx_quic_free_path(ngx_connection_t *c, ngx_quic_path_t *path); + +ngx_int_t ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt); +ngx_int_t ngx_quic_handle_migration(ngx_connection_t *c, + ngx_quic_header_t *pkt); + +void ngx_quic_path_handler(ngx_event_t *ev); + +void ngx_quic_discover_path_mtu(ngx_connection_t *c, ngx_quic_path_t *path); +ngx_int_t ngx_quic_handle_path_mtu(ngx_connection_t *c, + ngx_quic_path_t *path, uint64_t min, uint64_t max); + +#endif /* _NGX_EVENT_QUIC_MIGRATION_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_openssl_compat.c b/src/event/quic/ngx_event_quic_openssl_compat.c new file mode 100644 index 0000000..c7412e8 --- /dev/null +++ b/src/event/quic/ngx_event_quic_openssl_compat.c @@ -0,0 +1,651 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#if (NGX_QUIC_OPENSSL_COMPAT) + +#define NGX_QUIC_COMPAT_RECORD_SIZE 1024 + +#define NGX_QUIC_COMPAT_SSL_TP_EXT 0x39 + +#define NGX_QUIC_COMPAT_CLIENT_HANDSHAKE "CLIENT_HANDSHAKE_TRAFFIC_SECRET" +#define NGX_QUIC_COMPAT_SERVER_HANDSHAKE "SERVER_HANDSHAKE_TRAFFIC_SECRET" +#define NGX_QUIC_COMPAT_CLIENT_APPLICATION "CLIENT_TRAFFIC_SECRET_0" +#define NGX_QUIC_COMPAT_SERVER_APPLICATION "SERVER_TRAFFIC_SECRET_0" + + +typedef struct { + ngx_quic_secret_t secret; + ngx_uint_t cipher; +} ngx_quic_compat_keys_t; + + +typedef struct { + ngx_log_t *log; + + u_char type; + ngx_str_t payload; + uint64_t number; + ngx_quic_compat_keys_t *keys; + + enum ssl_encryption_level_t level; +} ngx_quic_compat_record_t; + + +struct ngx_quic_compat_s { + const SSL_QUIC_METHOD *method; + + enum ssl_encryption_level_t write_level; + + uint64_t read_record; + ngx_quic_compat_keys_t keys; + + ngx_str_t tp; + ngx_str_t ctp; +}; + + +static void ngx_quic_compat_keylog_callback(const SSL *ssl, const char *line); +static ngx_int_t ngx_quic_compat_set_encryption_secret(ngx_connection_t *c, + ngx_quic_compat_keys_t *keys, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len); +static void ngx_quic_compat_cleanup_encryption_secret(void *data); +static int ngx_quic_compat_add_transport_params_callback(SSL *ssl, + unsigned int ext_type, unsigned int context, const unsigned char **out, + size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg); +static int ngx_quic_compat_parse_transport_params_callback(SSL *ssl, + unsigned int ext_type, unsigned int context, const unsigned char *in, + size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg); +static void ngx_quic_compat_message_callback(int write_p, int version, + int content_type, const void *buf, size_t len, SSL *ssl, void *arg); +static size_t ngx_quic_compat_create_header(ngx_quic_compat_record_t *rec, + u_char *out, ngx_uint_t plain); +static ngx_int_t ngx_quic_compat_create_record(ngx_quic_compat_record_t *rec, + ngx_str_t *res); + + +ngx_int_t +ngx_quic_compat_init(ngx_conf_t *cf, SSL_CTX *ctx) +{ + SSL_CTX_set_keylog_callback(ctx, ngx_quic_compat_keylog_callback); + + if (SSL_CTX_has_client_custom_ext(ctx, NGX_QUIC_COMPAT_SSL_TP_EXT)) { + return NGX_OK; + } + + if (SSL_CTX_add_custom_ext(ctx, NGX_QUIC_COMPAT_SSL_TP_EXT, + SSL_EXT_CLIENT_HELLO + |SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, + ngx_quic_compat_add_transport_params_callback, + NULL, + NULL, + ngx_quic_compat_parse_transport_params_callback, + NULL) + == 0) + { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_add_custom_ext() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_quic_compat_keylog_callback(const SSL *ssl, const char *line) +{ + u_char ch, *p, *start, value; + size_t n; + ngx_uint_t write; + const SSL_CIPHER *cipher; + ngx_quic_compat_t *com; + ngx_connection_t *c; + ngx_quic_connection_t *qc; + enum ssl_encryption_level_t level; + u_char secret[EVP_MAX_MD_SIZE]; + + c = ngx_ssl_get_connection(ssl); + if (c->type != SOCK_DGRAM) { + return; + } + + p = (u_char *) line; + + for (start = p; *p && *p != ' '; p++); + + n = p - start; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat secret %*s", n, start); + + if (n == sizeof(NGX_QUIC_COMPAT_CLIENT_HANDSHAKE) - 1 + && ngx_strncmp(start, NGX_QUIC_COMPAT_CLIENT_HANDSHAKE, n) == 0) + { + level = ssl_encryption_handshake; + write = 0; + + } else if (n == sizeof(NGX_QUIC_COMPAT_SERVER_HANDSHAKE) - 1 + && ngx_strncmp(start, NGX_QUIC_COMPAT_SERVER_HANDSHAKE, n) == 0) + { + level = ssl_encryption_handshake; + write = 1; + + } else if (n == sizeof(NGX_QUIC_COMPAT_CLIENT_APPLICATION) - 1 + && ngx_strncmp(start, NGX_QUIC_COMPAT_CLIENT_APPLICATION, n) + == 0) + { + level = ssl_encryption_application; + write = 0; + + } else if (n == sizeof(NGX_QUIC_COMPAT_SERVER_APPLICATION) - 1 + && ngx_strncmp(start, NGX_QUIC_COMPAT_SERVER_APPLICATION, n) + == 0) + { + level = ssl_encryption_application; + write = 1; + + } else { + return; + } + + if (*p++ == '\0') { + return; + } + + for ( /* void */ ; *p && *p != ' '; p++); + + if (*p++ == '\0') { + return; + } + + for (n = 0, start = p; *p; p++) { + ch = *p; + + if (ch >= '0' && ch <= '9') { + value = ch - '0'; + goto next; + } + + ch = (u_char) (ch | 0x20); + + if (ch >= 'a' && ch <= 'f') { + value = ch - 'a' + 10; + goto next; + } + + ngx_log_error(NGX_LOG_EMERG, c->log, 0, + "invalid OpenSSL QUIC secret format"); + + return; + + next: + + if ((p - start) % 2) { + secret[n++] += value; + + } else { + if (n >= EVP_MAX_MD_SIZE) { + ngx_log_error(NGX_LOG_EMERG, c->log, 0, + "too big OpenSSL QUIC secret"); + return; + } + + secret[n] = (value << 4); + } + } + + qc = ngx_quic_get_connection(c); + com = qc->compat; + cipher = SSL_get_current_cipher(ssl); + + if (write) { + com->method->set_write_secret((SSL *) ssl, level, cipher, secret, n); + com->write_level = level; + + } else { + com->method->set_read_secret((SSL *) ssl, level, cipher, secret, n); + com->read_record = 0; + + (void) ngx_quic_compat_set_encryption_secret(c, &com->keys, level, + cipher, secret, n); + } + + ngx_explicit_memzero(secret, n); +} + + +static ngx_int_t +ngx_quic_compat_set_encryption_secret(ngx_connection_t *c, + ngx_quic_compat_keys_t *keys, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) +{ + ngx_int_t key_len; + ngx_str_t secret_str; + ngx_uint_t i; + ngx_quic_md_t key; + ngx_quic_hkdf_t seq[2]; + ngx_quic_secret_t *peer_secret; + ngx_quic_ciphers_t ciphers; + ngx_pool_cleanup_t *cln; + + peer_secret = &keys->secret; + + keys->cipher = SSL_CIPHER_get_id(cipher); + + key_len = ngx_quic_ciphers(keys->cipher, &ciphers); + + if (key_len == NGX_ERROR) { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); + return NGX_ERROR; + } + + key.len = key_len; + + peer_secret->iv.len = NGX_QUIC_IV_LEN; + + secret_str.len = secret_len; + secret_str.data = (u_char *) secret; + + ngx_quic_hkdf_set(&seq[0], "tls13 key", &key, &secret_str); + ngx_quic_hkdf_set(&seq[1], "tls13 iv", &peer_secret->iv, &secret_str); + + for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { + if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, c->log) != NGX_OK) { + return NGX_ERROR; + } + } + + /* register cleanup handler once */ + + if (peer_secret->ctx) { + ngx_quic_crypto_cleanup(peer_secret); + + } else { + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_quic_compat_cleanup_encryption_secret; + cln->data = peer_secret; + } + + if (ngx_quic_crypto_init(ciphers.c, peer_secret, &key, 1, c->log) + == NGX_ERROR) + { + return NGX_ERROR; + } + + ngx_explicit_memzero(key.data, key.len); + + return NGX_OK; +} + + +static void +ngx_quic_compat_cleanup_encryption_secret(void *data) +{ + ngx_quic_secret_t *secret = data; + + ngx_quic_crypto_cleanup(secret); +} + + +static int +ngx_quic_compat_add_transport_params_callback(SSL *ssl, unsigned int ext_type, + unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, + size_t chainidx, int *al, void *add_arg) +{ + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection(ssl); + if (c->type != SOCK_DGRAM) { + return 0; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat add transport params"); + + qc = ngx_quic_get_connection(c); + com = qc->compat; + + *out = com->tp.data; + *outlen = com->tp.len; + + return 1; +} + + +static int +ngx_quic_compat_parse_transport_params_callback(SSL *ssl, unsigned int ext_type, + unsigned int context, const unsigned char *in, size_t inlen, X509 *x, + size_t chainidx, int *al, void *parse_arg) +{ + u_char *p; + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection(ssl); + if (c->type != SOCK_DGRAM) { + return 0; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat parse transport params"); + + qc = ngx_quic_get_connection(c); + com = qc->compat; + + p = ngx_pnalloc(c->pool, inlen); + if (p == NULL) { + return 0; + } + + ngx_memcpy(p, in, inlen); + + com->ctp.data = p; + com->ctp.len = inlen; + + return 1; +} + + +int +SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) +{ + BIO *rbio, *wbio; + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection(ssl); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic compat set method"); + + qc = ngx_quic_get_connection(c); + + qc->compat = ngx_pcalloc(c->pool, sizeof(ngx_quic_compat_t)); + if (qc->compat == NULL) { + return 0; + } + + com = qc->compat; + com->method = quic_method; + + rbio = BIO_new(BIO_s_mem()); + if (rbio == NULL) { + return 0; + } + + wbio = BIO_new(BIO_s_null()); + if (wbio == NULL) { + return 0; + } + + SSL_set_bio(ssl, rbio, wbio); + + SSL_set_msg_callback(ssl, ngx_quic_compat_message_callback); + + /* early data is not supported */ + SSL_set_max_early_data(ssl, 0); + + return 1; +} + + +static void +ngx_quic_compat_message_callback(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg) +{ + ngx_uint_t alert; + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + enum ssl_encryption_level_t level; + + if (!write_p) { + return; + } + + c = ngx_ssl_get_connection(ssl); + qc = ngx_quic_get_connection(c); + + if (qc == NULL) { + /* closing */ + return; + } + + com = qc->compat; + level = com->write_level; + + switch (content_type) { + + case SSL3_RT_HANDSHAKE: + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat tx %s len:%uz ", + ngx_quic_level_name(level), len); + + if (com->method->add_handshake_data(ssl, level, buf, len) != 1) { + goto failed; + } + + break; + + case SSL3_RT_ALERT: + if (len >= 2) { + alert = ((u_char *) buf)[1]; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat %s alert:%ui len:%uz ", + ngx_quic_level_name(level), alert, len); + + if (com->method->send_alert(ssl, level, alert) != 1) { + goto failed; + } + } + + break; + } + + return; + +failed: + + ngx_post_event(&qc->close, &ngx_posted_events); +} + + +int +SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level, + const uint8_t *data, size_t len) +{ + BIO *rbio; + size_t n; + u_char *p; + ngx_str_t res; + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + ngx_quic_compat_record_t rec; + u_char in[NGX_QUIC_COMPAT_RECORD_SIZE + 1]; + u_char out[NGX_QUIC_COMPAT_RECORD_SIZE + 1 + + SSL3_RT_HEADER_LENGTH + + NGX_QUIC_TAG_LEN]; + + c = ngx_ssl_get_connection(ssl); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic compat rx %s len:%uz", + ngx_quic_level_name(level), len); + + qc = ngx_quic_get_connection(c); + com = qc->compat; + rbio = SSL_get_rbio(ssl); + + while (len) { + ngx_memzero(&rec, sizeof(ngx_quic_compat_record_t)); + + rec.type = SSL3_RT_HANDSHAKE; + rec.log = c->log; + rec.number = com->read_record++; + rec.keys = &com->keys; + rec.level = level; + + if (level == ssl_encryption_initial) { + n = ngx_min(len, 65535); + + rec.payload.len = n; + rec.payload.data = (u_char *) data; + + ngx_quic_compat_create_header(&rec, out, 1); + + BIO_write(rbio, out, SSL3_RT_HEADER_LENGTH); + BIO_write(rbio, data, n); + +#if defined(NGX_QUIC_DEBUG_CRYPTO) && defined(NGX_QUIC_DEBUG_PACKETS) + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat record len:%uz %*xs%*xs", + n + SSL3_RT_HEADER_LENGTH, + (size_t) SSL3_RT_HEADER_LENGTH, out, n, data); +#endif + + } else { + n = ngx_min(len, NGX_QUIC_COMPAT_RECORD_SIZE); + + p = ngx_cpymem(in, data, n); + *p++ = SSL3_RT_HANDSHAKE; + + rec.payload.len = p - in; + rec.payload.data = in; + + res.data = out; + + if (ngx_quic_compat_create_record(&rec, &res) != NGX_OK) { + return 0; + } + +#if defined(NGX_QUIC_DEBUG_CRYPTO) && defined(NGX_QUIC_DEBUG_PACKETS) + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic compat record len:%uz %xV", res.len, &res); +#endif + + BIO_write(rbio, res.data, res.len); + } + + data += n; + len -= n; + } + + return 1; +} + + +static size_t +ngx_quic_compat_create_header(ngx_quic_compat_record_t *rec, u_char *out, + ngx_uint_t plain) +{ + u_char type; + size_t len; + + len = rec->payload.len; + + if (plain) { + type = rec->type; + + } else { + type = SSL3_RT_APPLICATION_DATA; + len += NGX_QUIC_TAG_LEN; + } + + out[0] = type; + out[1] = 0x03; + out[2] = 0x03; + out[3] = (len >> 8); + out[4] = len; + + return 5; +} + + +static ngx_int_t +ngx_quic_compat_create_record(ngx_quic_compat_record_t *rec, ngx_str_t *res) +{ + ngx_str_t ad, out; + ngx_quic_secret_t *secret; + u_char nonce[NGX_QUIC_IV_LEN]; + + ad.data = res->data; + ad.len = ngx_quic_compat_create_header(rec, ad.data, 0); + + out.len = rec->payload.len + NGX_QUIC_TAG_LEN; + out.data = res->data + ad.len; + +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, rec->log, 0, + "quic compat ad len:%uz %xV", ad.len, &ad); +#endif + + secret = &rec->keys->secret; + + ngx_memcpy(nonce, secret->iv.data, secret->iv.len); + ngx_quic_compute_nonce(nonce, sizeof(nonce), rec->number); + + if (ngx_quic_crypto_seal(secret, &out, nonce, &rec->payload, &ad, rec->log) + != NGX_OK) + { + return NGX_ERROR; + } + + res->len = ad.len + out.len; + + return NGX_OK; +} + + +int +SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, + size_t params_len) +{ + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection(ssl); + qc = ngx_quic_get_connection(c); + com = qc->compat; + + com->tp.len = params_len; + com->tp.data = (u_char *) params; + + return 1; +} + + +void +SSL_get_peer_quic_transport_params(const SSL *ssl, const uint8_t **out_params, + size_t *out_params_len) +{ + ngx_connection_t *c; + ngx_quic_compat_t *com; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection(ssl); + qc = ngx_quic_get_connection(c); + com = qc->compat; + + *out_params = com->ctp.data; + *out_params_len = com->ctp.len; +} + +#endif /* NGX_QUIC_OPENSSL_COMPAT */ diff --git a/src/event/quic/ngx_event_quic_openssl_compat.h b/src/event/quic/ngx_event_quic_openssl_compat.h new file mode 100644 index 0000000..77cc3cb --- /dev/null +++ b/src/event/quic/ngx_event_quic_openssl_compat.h @@ -0,0 +1,59 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_OPENSSL_COMPAT_H_INCLUDED_ +#define _NGX_EVENT_QUIC_OPENSSL_COMPAT_H_INCLUDED_ + +#if defined SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION \ + || defined LIBRESSL_VERSION_NUMBER +#undef NGX_QUIC_OPENSSL_COMPAT +#else + + +#include +#include + + +typedef struct ngx_quic_compat_s ngx_quic_compat_t; + + +enum ssl_encryption_level_t { + ssl_encryption_initial = 0, + ssl_encryption_early_data, + ssl_encryption_handshake, + ssl_encryption_application +}; + + +typedef struct ssl_quic_method_st { + int (*set_read_secret)(SSL *ssl, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, + const uint8_t *rsecret, size_t secret_len); + int (*set_write_secret)(SSL *ssl, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, + const uint8_t *wsecret, size_t secret_len); + int (*add_handshake_data)(SSL *ssl, enum ssl_encryption_level_t level, + const uint8_t *data, size_t len); + int (*flush_flight)(SSL *ssl); + int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, + uint8_t alert); +} SSL_QUIC_METHOD; + + +ngx_int_t ngx_quic_compat_init(ngx_conf_t *cf, SSL_CTX *ctx); + +int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); +int SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level, + const uint8_t *data, size_t len); +int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, + size_t params_len); +void SSL_get_peer_quic_transport_params(const SSL *ssl, + const uint8_t **out_params, size_t *out_params_len); + + +#endif /* TLSEXT_TYPE_quic_transport_parameters */ + +#endif /* _NGX_EVENT_QUIC_OPENSSL_COMPAT_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c new file mode 100644 index 0000000..ce6aaab --- /dev/null +++ b/src/event/quic/ngx_event_quic_output.c @@ -0,0 +1,1319 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#define NGX_QUIC_MAX_UDP_SEGMENT_BUF 65487 /* 65K - IPv6 header */ +#define NGX_QUIC_MAX_SEGMENTS 64 /* UDP_MAX_SEGMENTS */ + +#define NGX_QUIC_RETRY_TOKEN_LIFETIME 3 /* seconds */ +#define NGX_QUIC_NEW_TOKEN_LIFETIME 600 /* seconds */ +#define NGX_QUIC_RETRY_BUFFER_SIZE 256 + /* 1 flags + 4 version + 3 x (1 + 20) s/o/dcid + itag + token(64) */ + +/* + * RFC 9000, 10.3. Stateless Reset + * + * Endpoints MUST discard packets that are too small to be valid QUIC + * packets. With the set of AEAD functions defined in [QUIC-TLS], + * short header packets that are smaller than 21 bytes are never valid. + */ +#define NGX_QUIC_MIN_PKT_LEN 21 + +#define NGX_QUIC_MIN_SR_PACKET 43 /* 5 rand + 16 srt + 22 padding */ +#define NGX_QUIC_MAX_SR_PACKET 1200 + +#define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */ + +#define NGX_QUIC_SOCKET_RETRY_DELAY 10 /* ms, for NGX_AGAIN on write */ + + +#define ngx_quic_log_packet(log, pkt) \ + ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0, \ + "quic packet tx %s bytes:%ui need_ack:%d" \ + " number:%L encoded nl:%d trunc:0x%xD", \ + ngx_quic_level_name((pkt)->level), (pkt)->payload.len, \ + (pkt)->need_ack, (pkt)->number, (pkt)->num_len, \ + (pkt)->trunc); + + +static ngx_int_t ngx_quic_create_datagrams(ngx_connection_t *c); +static void ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx); +static void ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + uint64_t pnum); +#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) +static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c); +static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c); +static ssize_t ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, + size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment); +#endif +static ssize_t ngx_quic_output_packet(ngx_connection_t *c, + ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); +static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + ngx_quic_header_t *pkt, ngx_quic_path_t *path); +static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); +static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, + struct sockaddr *sockaddr, socklen_t socklen); +static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, + ngx_quic_send_ctx_t *ctx); + + +ngx_int_t +ngx_quic_output(ngx_connection_t *c) +{ + size_t in_flight; + ngx_int_t rc; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + + c->log->action = "sending frames"; + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + + in_flight = cg->in_flight; + +#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) + if (ngx_quic_allow_segmentation(c)) { + rc = ngx_quic_create_segments(c); + } else +#endif + { + rc = ngx_quic_create_datagrams(c); + } + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + if (in_flight == cg->in_flight || qc->closing) { + /* no ack-eliciting data was sent or we are done */ + return NGX_OK; + } + + if (!qc->send_timer_set) { + qc->send_timer_set = 1; + ngx_add_timer(c->read, qc->tp.max_idle_timeout); + } + + ngx_quic_set_lost_timer(c); + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_create_datagrams(ngx_connection_t *c) +{ + size_t len, min; + ssize_t n; + u_char *p; + uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST]; + ngx_uint_t i, pad; + ngx_quic_path_t *path; + ngx_quic_send_ctx_t *ctx; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + path = qc->path; + + while (cg->in_flight < cg->window) { + + p = dst; + + len = ngx_quic_path_limit(c, path, path->mtu); + + pad = ngx_quic_get_padding_level(c); + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + + ctx = &qc->send_ctx[i]; + + preserved_pnum[i] = ctx->pnum; + + if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { + return NGX_ERROR; + } + + min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE) + ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0; + + if (min > len) { + /* padding can't be applied - avoid sending the packet */ + + while (i-- > 0) { + ctx = &qc->send_ctx[i]; + ngx_quic_revert_send(c, ctx, preserved_pnum[i]); + } + + return NGX_OK; + } + + n = ngx_quic_output_packet(c, ctx, p, len, min); + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + p += n; + len -= n; + } + + len = p - dst; + if (len == 0) { + break; + } + + n = ngx_quic_send(c, dst, len, path->sockaddr, path->socklen); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n == NGX_AGAIN) { + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + ngx_quic_revert_send(c, &qc->send_ctx[i], preserved_pnum[i]); + } + + ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY); + break; + } + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + ngx_quic_commit_send(c, &qc->send_ctx[i]); + } + + path->sent += len; + } + + return NGX_OK; +} + + +static void +ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) +{ + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + cg = &qc->congestion; + + while (!ngx_queue_empty(&ctx->sending)) { + + q = ngx_queue_head(&ctx->sending); + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + ngx_queue_remove(q); + + if (f->pkt_need_ack && !qc->closing) { + ngx_queue_insert_tail(&ctx->sent, q); + + cg->in_flight += f->plen; + + } else { + ngx_quic_free_frame(c, f); + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion send if:%uz", cg->in_flight); +} + + +static void +ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + uint64_t pnum) +{ + ngx_queue_t *q; + + while (!ngx_queue_empty(&ctx->sending)) { + + q = ngx_queue_last(&ctx->sending); + ngx_queue_remove(q); + ngx_queue_insert_head(&ctx->frames, q); + } + + ctx->pnum = pnum; +} + + +#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) + +static ngx_uint_t +ngx_quic_allow_segmentation(ngx_connection_t *c) +{ + size_t bytes, len; + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (!qc->conf->gso_enabled) { + return 0; + } + + if (!qc->path->validated) { + /* don't even try to be faster on non-validated paths */ + return 0; + } + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); + if (!ngx_queue_empty(&ctx->frames)) { + return 0; + } + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); + if (!ngx_queue_empty(&ctx->frames)) { + return 0; + } + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + + bytes = 0; + len = ngx_min(qc->path->mtu, NGX_QUIC_MAX_UDP_SEGMENT_BUF); + + for (q = ngx_queue_head(&ctx->frames); + q != ngx_queue_sentinel(&ctx->frames); + q = ngx_queue_next(q)) + { + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + bytes += f->len; + + if (bytes > len * 3) { + /* require at least ~3 full packets to batch */ + return 1; + } + } + + return 0; +} + + +static ngx_int_t +ngx_quic_create_segments(ngx_connection_t *c) +{ + size_t len, segsize; + ssize_t n; + u_char *p, *end; + uint64_t preserved_pnum; + ngx_uint_t nseg; + ngx_quic_path_t *path; + ngx_quic_send_ctx_t *ctx; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + path = qc->path; + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); + + if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { + return NGX_ERROR; + } + + segsize = ngx_min(path->mtu, NGX_QUIC_MAX_UDP_SEGMENT_BUF); + p = dst; + end = dst + sizeof(dst); + + nseg = 0; + + preserved_pnum = ctx->pnum; + + for ( ;; ) { + + len = ngx_min(segsize, (size_t) (end - p)); + + if (len && cg->in_flight + (p - dst) < cg->window) { + + n = ngx_quic_output_packet(c, ctx, p, len, len); + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n) { + p += n; + nseg++; + } + + } else { + n = 0; + } + + if (p == dst) { + break; + } + + if (n == 0 || nseg == NGX_QUIC_MAX_SEGMENTS) { + n = ngx_quic_send_segments(c, dst, p - dst, path->sockaddr, + path->socklen, segsize); + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n == NGX_AGAIN) { + ngx_quic_revert_send(c, ctx, preserved_pnum); + + ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY); + break; + } + + ngx_quic_commit_send(c, ctx); + + path->sent += n; + + p = dst; + nseg = 0; + preserved_pnum = ctx->pnum; + } + } + + return NGX_OK; +} + + +static ssize_t +ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, size_t len, + struct sockaddr *sockaddr, socklen_t socklen, size_t segment) +{ + size_t clen; + ssize_t n; + uint16_t *valp; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; + +#if (NGX_HAVE_ADDRINFO_CMSG) + char msg_control[CMSG_SPACE(sizeof(uint16_t)) + + CMSG_SPACE(sizeof(ngx_addrinfo_t))]; +#else + char msg_control[CMSG_SPACE(sizeof(uint16_t))]; +#endif + + ngx_memzero(&msg, sizeof(struct msghdr)); + ngx_memzero(msg_control, sizeof(msg_control)); + + iov.iov_len = len; + iov.iov_base = buf; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_name = sockaddr; + msg.msg_namelen = socklen; + + msg.msg_control = msg_control; + msg.msg_controllen = sizeof(msg_control); + + cmsg = CMSG_FIRSTHDR(&msg); + + cmsg->cmsg_level = SOL_UDP; + cmsg->cmsg_type = UDP_SEGMENT; + cmsg->cmsg_len = CMSG_LEN(sizeof(uint16_t)); + + clen = CMSG_SPACE(sizeof(uint16_t)); + + valp = (void *) CMSG_DATA(cmsg); + *valp = segment; + +#if (NGX_HAVE_ADDRINFO_CMSG) + if (c->listening && c->listening->wildcard && c->local_sockaddr) { + cmsg = CMSG_NXTHDR(&msg, cmsg); + clen += ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr); + } +#endif + + msg.msg_controllen = clen; + + n = ngx_sendmsg(c, &msg, 0); + if (n < 0) { + return n; + } + + c->sent += n; + + return n; +} + +#endif + + + +static ngx_uint_t +ngx_quic_get_padding_level(ngx_connection_t *c) +{ + ngx_uint_t i; + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + + /* + * RFC 9000, 14.1. Initial Datagram Size + * + * Similarly, a server MUST expand the payload of all UDP datagrams + * carrying ack-eliciting Initial packets to at least the smallest + * allowed maximum datagram size of 1200 bytes. + */ + + qc = ngx_quic_get_connection(c); + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); + + for (q = ngx_queue_head(&ctx->frames); + q != ngx_queue_sentinel(&ctx->frames); + q = ngx_queue_next(q)) + { + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + if (f->need_ack) { + for (i = 0; i + 1 < NGX_QUIC_SEND_CTX_LAST; i++) { + ctx = &qc->send_ctx[i + 1]; + + if (ngx_queue_empty(&ctx->frames)) { + break; + } + } + + return i; + } + } + + return NGX_QUIC_SEND_CTX_LAST; +} + + +static ssize_t +ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + u_char *data, size_t max, size_t min) +{ + size_t len, pad, min_payload, max_payload; + u_char *p; + ssize_t flen; + ngx_str_t res; + ngx_int_t rc; + ngx_uint_t nframes; + ngx_msec_t now; + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_header_t pkt; + ngx_quic_connection_t *qc; + static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + + if (ngx_queue_empty(&ctx->frames)) { + return 0; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic output %s packet max:%uz min:%uz", + ngx_quic_level_name(ctx->level), max, min); + + qc = ngx_quic_get_connection(c); + + if (!ngx_quic_keys_available(qc->keys, ctx->level, 1)) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "quic %s write keys discarded", + ngx_quic_level_name(ctx->level)); + + while (!ngx_queue_empty(&ctx->frames)) { + q = ngx_queue_head(&ctx->frames); + ngx_queue_remove(q); + + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + ngx_quic_free_frame(c, f); + } + + return 0; + } + + ngx_quic_init_packet(c, ctx, &pkt, qc->path); + + min_payload = ngx_quic_payload_size(&pkt, min); + max_payload = ngx_quic_payload_size(&pkt, max); + + /* RFC 9001, 5.4.2. Header Protection Sample */ + pad = 4 - pkt.num_len; + min_payload = ngx_max(min_payload, pad); + + if (min_payload > max_payload) { + return 0; + } + + now = ngx_current_msec; + nframes = 0; + p = src; + len = 0; + + for (q = ngx_queue_head(&ctx->frames); + q != ngx_queue_sentinel(&ctx->frames); + q = ngx_queue_next(q)) + { + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + if (len >= max_payload) { + break; + } + + if (len + f->len > max_payload) { + rc = ngx_quic_split_frame(c, f, max_payload - len); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + break; + } + } + + if (f->need_ack) { + pkt.need_ack = 1; + } + + f->pnum = ctx->pnum; + f->send_time = now; + f->plen = 0; + + ngx_quic_log_frame(c->log, f, 1); + + flen = ngx_quic_create_frame(p, f); + if (flen == -1) { + return NGX_ERROR; + } + + len += flen; + p += flen; + + nframes++; + } + + if (nframes == 0) { + return 0; + } + + if (len < min_payload) { + ngx_memset(p, NGX_QUIC_FT_PADDING, min_payload - len); + len = min_payload; + } + + pkt.payload.data = src; + pkt.payload.len = len; + + res.data = data; + + ngx_quic_log_packet(c->log, &pkt); + + if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { + return NGX_ERROR; + } + + ctx->pnum++; + + if (pkt.need_ack) { + q = ngx_queue_head(&ctx->frames); + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + f->plen = res.len; + } + + while (nframes--) { + q = ngx_queue_head(&ctx->frames); + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + f->pkt_need_ack = pkt.need_ack; + + ngx_queue_remove(q); + ngx_queue_insert_tail(&ctx->sending, q); + } + + return res.len; +} + + +static void +ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + ngx_quic_header_t *pkt, ngx_quic_path_t *path) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ngx_memzero(pkt, sizeof(ngx_quic_header_t)); + + pkt->flags = NGX_QUIC_PKT_FIXED_BIT; + + if (ctx->level == ssl_encryption_initial) { + pkt->flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; + + } else if (ctx->level == ssl_encryption_handshake) { + pkt->flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE; + + } else { + if (qc->key_phase) { + pkt->flags |= NGX_QUIC_PKT_KPHASE; + } + } + + pkt->dcid.data = path->cid->id; + pkt->dcid.len = path->cid->len; + + pkt->scid = qc->tp.initial_scid; + + pkt->version = qc->version; + pkt->log = c->log; + pkt->level = ctx->level; + + pkt->keys = qc->keys; + + ngx_quic_set_packet_number(pkt, ctx); +} + + +static ssize_t +ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, + struct sockaddr *sockaddr, socklen_t socklen) +{ + ssize_t n; + struct iovec iov; + struct msghdr msg; +#if (NGX_HAVE_ADDRINFO_CMSG) + struct cmsghdr *cmsg; + char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; +#endif + + ngx_memzero(&msg, sizeof(struct msghdr)); + + iov.iov_len = len; + iov.iov_base = buf; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_name = sockaddr; + msg.msg_namelen = socklen; + +#if (NGX_HAVE_ADDRINFO_CMSG) + if (c->listening && c->listening->wildcard && c->local_sockaddr) { + + msg.msg_control = msg_control; + msg.msg_controllen = sizeof(msg_control); + ngx_memzero(msg_control, sizeof(msg_control)); + + cmsg = CMSG_FIRSTHDR(&msg); + + msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr); + } +#endif + + n = ngx_sendmsg(c, &msg, 0); + if (n < 0) { + return n; + } + + c->sent += n; + + return n; +} + + +static void +ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx) +{ + uint64_t delta; + + delta = ctx->pnum - ctx->largest_ack; + pkt->number = ctx->pnum; + + if (delta <= 0x7F) { + pkt->num_len = 1; + pkt->trunc = ctx->pnum & 0xff; + + } else if (delta <= 0x7FFF) { + pkt->num_len = 2; + pkt->flags |= 0x1; + pkt->trunc = ctx->pnum & 0xffff; + + } else if (delta <= 0x7FFFFF) { + pkt->num_len = 3; + pkt->flags |= 0x2; + pkt->trunc = ctx->pnum & 0xffffff; + + } else { + pkt->num_len = 4; + pkt->flags |= 0x3; + pkt->trunc = ctx->pnum & 0xffffffff; + } +} + + +ngx_int_t +ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt) +{ + size_t len; + ngx_quic_header_t pkt; + static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sending version negotiation packet"); + + pkt.log = c->log; + pkt.flags = NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_FIXED_BIT; + pkt.dcid = inpkt->scid; + pkt.scid = inpkt->dcid; + + len = ngx_quic_create_version_negotiation(&pkt, buf); + +#ifdef NGX_QUIC_DEBUG_PACKETS + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic vnego packet to send len:%uz %*xs", len, len, buf); +#endif + + (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen); + + return NGX_DONE; +} + + +ngx_int_t +ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf, + ngx_quic_header_t *pkt) +{ + u_char *token; + size_t len, max; + uint16_t rndbytes; + u_char buf[NGX_QUIC_MAX_SR_PACKET]; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic handle stateless reset output"); + + if (pkt->len <= NGX_QUIC_MIN_PKT_LEN) { + return NGX_DECLINED; + } + + if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) { + len = pkt->len - 1; + + } else { + max = ngx_min(NGX_QUIC_MAX_SR_PACKET, pkt->len * 3); + + if (RAND_bytes((u_char *) &rndbytes, sizeof(rndbytes)) != 1) { + return NGX_ERROR; + } + + len = (rndbytes % (max - NGX_QUIC_MIN_SR_PACKET + 1)) + + NGX_QUIC_MIN_SR_PACKET; + } + + if (RAND_bytes(buf, len - NGX_QUIC_SR_TOKEN_LEN) != 1) { + return NGX_ERROR; + } + + buf[0] &= ~NGX_QUIC_PKT_LONG; + buf[0] |= NGX_QUIC_PKT_FIXED_BIT; + + token = &buf[len - NGX_QUIC_SR_TOKEN_LEN]; + + if (ngx_quic_new_sr_token(c, &pkt->dcid, conf->sr_token_key, token) + != NGX_OK) + { + return NGX_ERROR; + } + + (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen); + + return NGX_DECLINED; +} + + +ngx_int_t +ngx_quic_send_cc(ngx_connection_t *c) +{ + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (qc->draining) { + return NGX_OK; + } + + if (qc->closing + && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL) + { + /* dot not send CC too often */ + return NGX_OK; + } + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = qc->error_level; + frame->type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP + : NGX_QUIC_FT_CONNECTION_CLOSE; + frame->u.close.error_code = qc->error; + frame->u.close.frame_type = qc->error_ftype; + + if (qc->error_reason) { + frame->u.close.reason.len = ngx_strlen(qc->error_reason); + frame->u.close.reason.data = (u_char *) qc->error_reason; + } + + frame->ignore_congestion = 1; + + qc->last_cc = ngx_current_msec; + + return ngx_quic_frame_sendto(c, frame, 0, qc->path); +} + + +ngx_int_t +ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt, + ngx_uint_t err, const char *reason) +{ + ssize_t len; + ngx_str_t res; + ngx_quic_keys_t keys; + ngx_quic_frame_t frame; + ngx_quic_header_t pkt; + + static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + + ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); + ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); + + frame.level = inpkt->level; + frame.type = NGX_QUIC_FT_CONNECTION_CLOSE; + frame.u.close.error_code = err; + + frame.u.close.reason.data = (u_char *) reason; + frame.u.close.reason.len = ngx_strlen(reason); + + ngx_quic_log_frame(c->log, &frame, 1); + + len = ngx_quic_create_frame(NULL, &frame); + if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) { + return NGX_ERROR; + } + + len = ngx_quic_create_frame(src, &frame); + if (len == -1) { + return NGX_ERROR; + } + + ngx_memzero(&keys, sizeof(ngx_quic_keys_t)); + + pkt.keys = &keys; + + if (ngx_quic_keys_set_initial_secret(pkt.keys, &inpkt->dcid, c->log) + != NGX_OK) + { + return NGX_ERROR; + } + + pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG + | NGX_QUIC_PKT_INITIAL; + + pkt.num_len = 1; + /* + * pkt.num = 0; + * pkt.trunc = 0; + */ + + pkt.version = inpkt->version; + pkt.log = c->log; + pkt.level = inpkt->level; + pkt.dcid = inpkt->scid; + pkt.scid = inpkt->dcid; + pkt.payload.data = src; + pkt.payload.len = len; + + res.data = dst; + + ngx_quic_log_packet(c->log, &pkt); + + if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { + ngx_quic_keys_cleanup(pkt.keys); + return NGX_ERROR; + } + + if (ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen) < 0) { + ngx_quic_keys_cleanup(pkt.keys); + return NGX_ERROR; + } + + ngx_quic_keys_cleanup(pkt.keys); + + return NGX_DONE; +} + + +ngx_int_t +ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf, + ngx_quic_header_t *inpkt) +{ + time_t expires; + ssize_t len; + ngx_str_t res, token; + ngx_quic_header_t pkt; + + u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; + u_char dcid[NGX_QUIC_SERVER_CID_LEN]; + u_char tbuf[NGX_QUIC_TOKEN_BUF_SIZE]; + + expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME; + + token.data = tbuf; + token.len = NGX_QUIC_TOKEN_BUF_SIZE; + + if (ngx_quic_new_token(c->log, c->sockaddr, c->socklen, conf->av_token_key, + &token, &inpkt->dcid, expires, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); + pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY; + pkt.version = inpkt->version; + pkt.log = c->log; + + pkt.odcid = inpkt->dcid; + pkt.dcid = inpkt->scid; + + /* TODO: generate routable dcid */ + if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) { + return NGX_ERROR; + } + + pkt.scid.len = NGX_QUIC_SERVER_CID_LEN; + pkt.scid.data = dcid; + + pkt.token = token; + + res.data = buf; + + if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { + return NGX_ERROR; + } + +#ifdef NGX_QUIC_DEBUG_PACKETS + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic packet to send len:%uz %xV", res.len, &res); +#endif + + len = ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen); + if (len < 0) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic retry packet sent to %xV", &pkt.dcid); + + /* + * RFC 9000, 17.2.5.1. Sending a Retry Packet + * + * A server MUST NOT send more than one Retry + * packet in response to a single UDP datagram. + * NGX_DONE will stop quic_input() from processing further + */ + return NGX_DONE; +} + + +ngx_int_t +ngx_quic_send_new_token(ngx_connection_t *c, ngx_quic_path_t *path) +{ + time_t expires; + ngx_str_t token; + ngx_chain_t *out; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + u_char tbuf[NGX_QUIC_TOKEN_BUF_SIZE]; + + qc = ngx_quic_get_connection(c); + + expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME; + + token.data = tbuf; + token.len = NGX_QUIC_TOKEN_BUF_SIZE; + + if (ngx_quic_new_token(c->log, path->sockaddr, path->socklen, + qc->conf->av_token_key, &token, NULL, expires, 0) + != NGX_OK) + { + return NGX_ERROR; + } + + out = ngx_quic_copy_buffer(c, token.data, token.len); + if (out == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_NEW_TOKEN; + frame->data = out; + frame->u.token.length = token.len; + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) +{ + size_t len, left; + uint64_t ack_delay; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t *cl, **ll; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ack_delay = ngx_current_msec - ctx->largest_received; + ack_delay *= 1000; + ack_delay >>= qc->tp.ack_delay_exponent; + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + ll = &frame->data; + b = NULL; + + for (i = 0; i < ctx->nranges; i++) { + len = ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap, + ctx->ranges[i].range); + + left = b ? b->end - b->last : 0; + + if (left < len) { + cl = ngx_quic_alloc_chain(c); + if (cl == NULL) { + return NGX_ERROR; + } + + *ll = cl; + ll = &cl->next; + + b = cl->buf; + left = b->end - b->last; + + if (left < len) { + return NGX_ERROR; + } + } + + b->last += ngx_quic_create_ack_range(b->last, ctx->ranges[i].gap, + ctx->ranges[i].range); + + frame->u.ack.ranges_length += len; + } + + *ll = NULL; + + frame->level = ctx->level; + frame->type = NGX_QUIC_FT_ACK; + frame->u.ack.largest = ctx->largest_range; + frame->u.ack.delay = ack_delay; + frame->u.ack.range_count = ctx->nranges; + frame->u.ack.first_range = ctx->first_range; + frame->len = ngx_quic_create_frame(NULL, frame); + + ngx_queue_insert_head(&ctx->frames, &frame->queue); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, + uint64_t smallest, uint64_t largest) +{ + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ctx->level; + frame->type = NGX_QUIC_FT_ACK; + frame->u.ack.largest = largest; + frame->u.ack.delay = 0; + frame->u.ack.range_count = 0; + frame->u.ack.first_range = largest - smallest; + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame, + size_t min, ngx_quic_path_t *path) +{ + size_t max, max_payload, min_payload, pad; + ssize_t len, sent; + ngx_str_t res; + ngx_msec_t now; + ngx_quic_header_t pkt; + ngx_quic_send_ctx_t *ctx; + ngx_quic_congestion_t *cg; + ngx_quic_connection_t *qc; + + static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + + qc = ngx_quic_get_connection(c); + cg = &qc->congestion; + ctx = ngx_quic_get_send_ctx(qc, frame->level); + + now = ngx_current_msec; + + max = ngx_quic_path_limit(c, path, path->mtu); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic sendto %s packet max:%uz min:%uz", + ngx_quic_level_name(ctx->level), max, min); + + if (cg->in_flight >= cg->window && !frame->ignore_congestion) { + ngx_quic_free_frame(c, frame); + return NGX_AGAIN; + } + + ngx_quic_init_packet(c, ctx, &pkt, path); + + min_payload = ngx_quic_payload_size(&pkt, min); + max_payload = ngx_quic_payload_size(&pkt, max); + + /* RFC 9001, 5.4.2. Header Protection Sample */ + pad = 4 - pkt.num_len; + min_payload = ngx_max(min_payload, pad); + + if (min_payload > max_payload) { + ngx_quic_free_frame(c, frame); + return NGX_AGAIN; + } + +#if (NGX_DEBUG) + frame->pnum = pkt.number; +#endif + + ngx_quic_log_frame(c->log, frame, 1); + + len = ngx_quic_create_frame(NULL, frame); + if ((size_t) len > max_payload) { + ngx_quic_free_frame(c, frame); + return NGX_AGAIN; + } + + len = ngx_quic_create_frame(src, frame); + if (len == -1) { + ngx_quic_free_frame(c, frame); + return NGX_ERROR; + } + + if (len < (ssize_t) min_payload) { + ngx_memset(src + len, NGX_QUIC_FT_PADDING, min_payload - len); + len = min_payload; + } + + pkt.payload.data = src; + pkt.payload.len = len; + + res.data = dst; + + ngx_quic_log_packet(c->log, &pkt); + + if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { + ngx_quic_free_frame(c, frame); + return NGX_ERROR; + } + + frame->pnum = ctx->pnum; + frame->send_time = now; + frame->plen = res.len; + + ctx->pnum++; + + sent = ngx_quic_send(c, res.data, res.len, path->sockaddr, path->socklen); + if (sent < 0) { + ngx_quic_free_frame(c, frame); + return sent; + } + + path->sent += sent; + + if (frame->need_ack && !qc->closing) { + ngx_queue_insert_tail(&ctx->sent, &frame->queue); + + cg->in_flight += frame->plen; + + } else { + ngx_quic_free_frame(c, frame); + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic congestion send if:%uz", cg->in_flight); + + if (!qc->send_timer_set) { + qc->send_timer_set = 1; + ngx_add_timer(c->read, qc->tp.max_idle_timeout); + } + + ngx_quic_set_lost_timer(c); + + return NGX_OK; +} + + +size_t +ngx_quic_path_limit(ngx_connection_t *c, ngx_quic_path_t *path, size_t size) +{ + off_t max; + + if (!path->validated) { + max = path->received * 3; + max = (path->sent >= max) ? 0 : max - path->sent; + + if ((off_t) size > max) { + return max; + } + } + + return size; +} diff --git a/src/event/quic/ngx_event_quic_output.h b/src/event/quic/ngx_event_quic_output.h new file mode 100644 index 0000000..52d8a37 --- /dev/null +++ b/src/event/quic/ngx_event_quic_output.h @@ -0,0 +1,40 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_OUTPUT_H_INCLUDED_ +#define _NGX_EVENT_QUIC_OUTPUT_H_INCLUDED_ + + +#include +#include + + +ngx_int_t ngx_quic_output(ngx_connection_t *c); + +ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c, + ngx_quic_header_t *inpkt); + +ngx_int_t ngx_quic_send_stateless_reset(ngx_connection_t *c, + ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); +ngx_int_t ngx_quic_send_cc(ngx_connection_t *c); +ngx_int_t ngx_quic_send_early_cc(ngx_connection_t *c, + ngx_quic_header_t *inpkt, ngx_uint_t err, const char *reason); + +ngx_int_t ngx_quic_send_retry(ngx_connection_t *c, + ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); +ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c, ngx_quic_path_t *path); + +ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, + ngx_quic_send_ctx_t *ctx); +ngx_int_t ngx_quic_send_ack_range(ngx_connection_t *c, + ngx_quic_send_ctx_t *ctx, uint64_t smallest, uint64_t largest); + +ngx_int_t ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame, + size_t min, ngx_quic_path_t *path); +size_t ngx_quic_path_limit(ngx_connection_t *c, ngx_quic_path_t *path, + size_t size); + +#endif /* _NGX_EVENT_QUIC_OUTPUT_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_protection.c b/src/event/quic/ngx_event_quic_protection.c new file mode 100644 index 0000000..8223626 --- /dev/null +++ b/src/event/quic/ngx_event_quic_protection.c @@ -0,0 +1,1243 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +/* RFC 9001, 5.4.1. Header Protection Application: 5-byte mask */ +#define NGX_QUIC_HP_LEN 5 + +#define NGX_QUIC_AES_128_KEY_LEN 16 + +#define NGX_QUIC_INITIAL_CIPHER TLS1_3_CK_AES_128_GCM_SHA256 + + +static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len, + const EVP_MD *digest, const u_char *prk, size_t prk_len, + const u_char *info, size_t info_len); +static ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len, + const EVP_MD *digest, const u_char *secret, size_t secret_len, + const u_char *salt, size_t salt_len); + +static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask, + uint64_t *largest_pn); + +static ngx_int_t ngx_quic_crypto_open(ngx_quic_secret_t *s, ngx_str_t *out, + u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); +#ifndef OPENSSL_IS_BORINGSSL +static ngx_int_t ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out, + u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); +#endif + +static ngx_int_t ngx_quic_crypto_hp_init(const EVP_CIPHER *cipher, + ngx_quic_secret_t *s, ngx_log_t *log); +static ngx_int_t ngx_quic_crypto_hp(ngx_quic_secret_t *s, + u_char *out, u_char *in, ngx_log_t *log); +static void ngx_quic_crypto_hp_cleanup(ngx_quic_secret_t *s); + +static ngx_int_t ngx_quic_create_packet(ngx_quic_header_t *pkt, + ngx_str_t *res); +static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, + ngx_str_t *res); + + +ngx_int_t +ngx_quic_ciphers(ngx_uint_t id, ngx_quic_ciphers_t *ciphers) +{ + ngx_int_t len; + + switch (id) { + + case TLS1_3_CK_AES_128_GCM_SHA256: +#ifdef OPENSSL_IS_BORINGSSL + ciphers->c = EVP_aead_aes_128_gcm(); +#else + ciphers->c = EVP_aes_128_gcm(); +#endif + ciphers->hp = EVP_aes_128_ctr(); + ciphers->d = EVP_sha256(); + len = 16; + break; + + case TLS1_3_CK_AES_256_GCM_SHA384: +#ifdef OPENSSL_IS_BORINGSSL + ciphers->c = EVP_aead_aes_256_gcm(); +#else + ciphers->c = EVP_aes_256_gcm(); +#endif + ciphers->hp = EVP_aes_256_ctr(); + ciphers->d = EVP_sha384(); + len = 32; + break; + + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: +#ifdef OPENSSL_IS_BORINGSSL + ciphers->c = EVP_aead_chacha20_poly1305(); +#else + ciphers->c = EVP_chacha20_poly1305(); +#endif +#ifdef OPENSSL_IS_BORINGSSL + ciphers->hp = (const EVP_CIPHER *) EVP_aead_chacha20_poly1305(); +#else + ciphers->hp = EVP_chacha20(); +#endif + ciphers->d = EVP_sha256(); + len = 32; + break; + +#ifndef OPENSSL_IS_BORINGSSL + case TLS1_3_CK_AES_128_CCM_SHA256: + ciphers->c = EVP_aes_128_ccm(); + ciphers->hp = EVP_aes_128_ctr(); + ciphers->d = EVP_sha256(); + len = 16; + break; +#endif + + default: + return NGX_ERROR; + } + + return len; +} + + +ngx_int_t +ngx_quic_keys_set_initial_secret(ngx_quic_keys_t *keys, ngx_str_t *secret, + ngx_log_t *log) +{ + size_t is_len; + uint8_t is[SHA256_DIGEST_LENGTH]; + ngx_str_t iss; + ngx_uint_t i; + const EVP_MD *digest; + ngx_quic_md_t client_key, server_key; + ngx_quic_hkdf_t seq[8]; + ngx_quic_secret_t *client, *server; + ngx_quic_ciphers_t ciphers; + + static const uint8_t salt[20] = + "\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17" + "\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb\x7f\x0a"; + + client = &keys->secrets[ssl_encryption_initial].client; + server = &keys->secrets[ssl_encryption_initial].server; + + /* + * RFC 9001, section 5. Packet Protection + * + * Initial packets use AEAD_AES_128_GCM. The hash function + * for HKDF when deriving initial secrets and keys is SHA-256. + */ + + digest = EVP_sha256(); + is_len = SHA256_DIGEST_LENGTH; + + if (ngx_hkdf_extract(is, &is_len, digest, secret->data, secret->len, + salt, sizeof(salt)) + != NGX_OK) + { + return NGX_ERROR; + } + + iss.len = is_len; + iss.data = is; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0, + "quic ngx_quic_set_initial_secret"); +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, + "quic salt len:%uz %*xs", sizeof(salt), sizeof(salt), salt); + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, + "quic initial secret len:%uz %*xs", is_len, is_len, is); +#endif + + client->secret.len = SHA256_DIGEST_LENGTH; + server->secret.len = SHA256_DIGEST_LENGTH; + + client_key.len = NGX_QUIC_AES_128_KEY_LEN; + server_key.len = NGX_QUIC_AES_128_KEY_LEN; + + client->hp.len = NGX_QUIC_AES_128_KEY_LEN; + server->hp.len = NGX_QUIC_AES_128_KEY_LEN; + + client->iv.len = NGX_QUIC_IV_LEN; + server->iv.len = NGX_QUIC_IV_LEN; + + /* labels per RFC 9001, 5.1. Packet Protection Keys */ + ngx_quic_hkdf_set(&seq[0], "tls13 client in", &client->secret, &iss); + ngx_quic_hkdf_set(&seq[1], "tls13 quic key", &client_key, &client->secret); + ngx_quic_hkdf_set(&seq[2], "tls13 quic iv", &client->iv, &client->secret); + ngx_quic_hkdf_set(&seq[3], "tls13 quic hp", &client->hp, &client->secret); + ngx_quic_hkdf_set(&seq[4], "tls13 server in", &server->secret, &iss); + ngx_quic_hkdf_set(&seq[5], "tls13 quic key", &server_key, &server->secret); + ngx_quic_hkdf_set(&seq[6], "tls13 quic iv", &server->iv, &server->secret); + ngx_quic_hkdf_set(&seq[7], "tls13 quic hp", &server->hp, &server->secret); + + for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { + if (ngx_quic_hkdf_expand(&seq[i], digest, log) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_quic_ciphers(NGX_QUIC_INITIAL_CIPHER, &ciphers) == NGX_ERROR) { + return NGX_ERROR; + } + + if (ngx_quic_crypto_init(ciphers.c, client, &client_key, 0, log) + == NGX_ERROR) + { + return NGX_ERROR; + } + + if (ngx_quic_crypto_init(ciphers.c, server, &server_key, 1, log) + == NGX_ERROR) + { + goto failed; + } + + if (ngx_quic_crypto_hp_init(ciphers.hp, client, log) == NGX_ERROR) { + goto failed; + } + + if (ngx_quic_crypto_hp_init(ciphers.hp, server, log) == NGX_ERROR) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_quic_keys_cleanup(keys); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_quic_hkdf_expand(ngx_quic_hkdf_t *h, const EVP_MD *digest, ngx_log_t *log) +{ + size_t info_len; + uint8_t *p; + uint8_t info[20]; + + info_len = 2 + 1 + h->label_len + 1; + + info[0] = 0; + info[1] = h->out_len; + info[2] = h->label_len; + + p = ngx_cpymem(&info[3], h->label, h->label_len); + *p = '\0'; + + if (ngx_hkdf_expand(h->out, h->out_len, digest, + h->prk, h->prk_len, info, info_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "ngx_hkdf_expand(%*s) failed", h->label_len, h->label); + return NGX_ERROR; + } + +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, log, 0, + "quic expand \"%*s\" len:%uz %*xs", + h->label_len, h->label, h->out_len, h->out_len, h->out); +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_hkdf_expand(u_char *out_key, size_t out_len, const EVP_MD *digest, + const uint8_t *prk, size_t prk_len, const u_char *info, size_t info_len) +{ +#ifdef OPENSSL_IS_BORINGSSL + + if (HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len) + == 0) + { + return NGX_ERROR; + } + + return NGX_OK; + +#else + + EVP_PKEY_CTX *pctx; + + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + if (pctx == NULL) { + return NGX_ERROR; + } + + if (EVP_PKEY_derive_init(pctx) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_set_hkdf_md(pctx, digest) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_set1_hkdf_key(pctx, prk, prk_len) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len) <= 0) { + goto failed; + } + + if (EVP_PKEY_derive(pctx, out_key, &out_len) <= 0) { + goto failed; + } + + EVP_PKEY_CTX_free(pctx); + + return NGX_OK; + +failed: + + EVP_PKEY_CTX_free(pctx); + + return NGX_ERROR; + +#endif +} + + +static ngx_int_t +ngx_hkdf_extract(u_char *out_key, size_t *out_len, const EVP_MD *digest, + const u_char *secret, size_t secret_len, const u_char *salt, + size_t salt_len) +{ +#ifdef OPENSSL_IS_BORINGSSL + + if (HKDF_extract(out_key, out_len, digest, secret, secret_len, salt, + salt_len) + == 0) + { + return NGX_ERROR; + } + + return NGX_OK; + +#else + + EVP_PKEY_CTX *pctx; + + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + if (pctx == NULL) { + return NGX_ERROR; + } + + if (EVP_PKEY_derive_init(pctx) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_set_hkdf_md(pctx, digest) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secret_len) <= 0) { + goto failed; + } + + if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, salt_len) <= 0) { + goto failed; + } + + if (EVP_PKEY_derive(pctx, out_key, out_len) <= 0) { + goto failed; + } + + EVP_PKEY_CTX_free(pctx); + + return NGX_OK; + +failed: + + EVP_PKEY_CTX_free(pctx); + + return NGX_ERROR; + +#endif +} + + +ngx_int_t +ngx_quic_crypto_init(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, + ngx_quic_md_t *key, ngx_int_t enc, ngx_log_t *log) +{ + +#ifdef OPENSSL_IS_BORINGSSL + EVP_AEAD_CTX *ctx; + + ctx = EVP_AEAD_CTX_new(cipher, key->data, key->len, + EVP_AEAD_DEFAULT_TAG_LENGTH); + if (ctx == NULL) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_AEAD_CTX_new() failed"); + return NGX_ERROR; + } +#else + EVP_CIPHER_CTX *ctx; + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CIPHER_CTX_new() failed"); + return NGX_ERROR; + } + + if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) != 1) { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherInit_ex() failed"); + return NGX_ERROR; + } + + if (EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE + && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, NGX_QUIC_TAG_LEN, + NULL) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_TAG) failed"); + return NGX_ERROR; + } + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, s->iv.len, NULL) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_IVLEN) failed"); + return NGX_ERROR; + } + + if (EVP_CipherInit_ex(ctx, NULL, NULL, key->data, NULL, enc) != 1) { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherInit_ex() failed"); + return NGX_ERROR; + } +#endif + + s->ctx = ctx; + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_crypto_open(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, + ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log) +{ +#ifdef OPENSSL_IS_BORINGSSL + if (EVP_AEAD_CTX_open(s->ctx, out->data, &out->len, out->len, nonce, + s->iv.len, in->data, in->len, ad->data, ad->len) + != 1) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_AEAD_CTX_open() failed"); + return NGX_ERROR; + } + + return NGX_OK; +#else + return ngx_quic_crypto_common(s, out, nonce, in, ad, log); +#endif +} + + +ngx_int_t +ngx_quic_crypto_seal(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, + ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log) +{ +#ifdef OPENSSL_IS_BORINGSSL + if (EVP_AEAD_CTX_seal(s->ctx, out->data, &out->len, out->len, nonce, + s->iv.len, in->data, in->len, ad->data, ad->len) + != 1) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_AEAD_CTX_seal() failed"); + return NGX_ERROR; + } + + return NGX_OK; +#else + return ngx_quic_crypto_common(s, out, nonce, in, ad, log); +#endif +} + + +#ifndef OPENSSL_IS_BORINGSSL + +static ngx_int_t +ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, + ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log) +{ + int len, enc; + ngx_quic_crypto_ctx_t *ctx; + + ctx = s->ctx; + enc = EVP_CIPHER_CTX_encrypting(ctx); + + if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, enc) != 1) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherInit_ex() failed"); + return NGX_ERROR; + } + + if (enc == 0) { + in->len -= NGX_QUIC_TAG_LEN; + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, NGX_QUIC_TAG_LEN, + in->data + in->len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_TAG) failed"); + return NGX_ERROR; + } + } + + if (EVP_CIPHER_mode(EVP_CIPHER_CTX_cipher(ctx)) == EVP_CIPH_CCM_MODE + && EVP_CipherUpdate(ctx, NULL, &len, NULL, in->len) != 1) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherUpdate() failed"); + return NGX_ERROR; + } + + if (EVP_CipherUpdate(ctx, NULL, &len, ad->data, ad->len) != 1) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherUpdate() failed"); + return NGX_ERROR; + } + + if (EVP_CipherUpdate(ctx, out->data, &len, in->data, in->len) != 1) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherUpdate() failed"); + return NGX_ERROR; + } + + out->len = len; + + if (EVP_CipherFinal_ex(ctx, out->data + out->len, &len) <= 0) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CipherFinal_ex failed"); + return NGX_ERROR; + } + + out->len += len; + + if (enc == 1) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, NGX_QUIC_TAG_LEN, + out->data + out->len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_GET_TAG) failed"); + return NGX_ERROR; + } + + out->len += NGX_QUIC_TAG_LEN; + } + + return NGX_OK; +} + +#endif + + +void +ngx_quic_crypto_cleanup(ngx_quic_secret_t *s) +{ + if (s->ctx) { +#ifdef OPENSSL_IS_BORINGSSL + EVP_AEAD_CTX_free(s->ctx); +#else + EVP_CIPHER_CTX_free(s->ctx); +#endif + s->ctx = NULL; + } +} + + +static ngx_int_t +ngx_quic_crypto_hp_init(const EVP_CIPHER *cipher, ngx_quic_secret_t *s, + ngx_log_t *log) +{ + EVP_CIPHER_CTX *ctx; + +#ifdef OPENSSL_IS_BORINGSSL + if (cipher == (EVP_CIPHER *) EVP_aead_chacha20_poly1305()) { + /* no EVP interface */ + s->hp_ctx = NULL; + return NGX_OK; + } +#endif + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CIPHER_CTX_new() failed"); + return NGX_ERROR; + } + + if (EVP_EncryptInit_ex(ctx, cipher, NULL, s->hp.data, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptInit_ex() failed"); + return NGX_ERROR; + } + + s->hp_ctx = ctx; + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_crypto_hp(ngx_quic_secret_t *s, u_char *out, u_char *in, + ngx_log_t *log) +{ + int outlen; + EVP_CIPHER_CTX *ctx; + u_char zero[NGX_QUIC_HP_LEN] = {0}; + + ctx = s->hp_ctx; + +#ifdef OPENSSL_IS_BORINGSSL + uint32_t cnt; + + if (ctx == NULL) { + ngx_memcpy(&cnt, in, sizeof(uint32_t)); + CRYPTO_chacha_20(out, zero, NGX_QUIC_HP_LEN, s->hp.data, &in[4], cnt); + return NGX_OK; + } +#endif + + if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, in) != 1) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptInit_ex() failed"); + return NGX_ERROR; + } + + if (!EVP_EncryptUpdate(ctx, out, &outlen, zero, NGX_QUIC_HP_LEN)) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptUpdate() failed"); + return NGX_ERROR; + } + + if (!EVP_EncryptFinal_ex(ctx, out + NGX_QUIC_HP_LEN, &outlen)) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptFinal_Ex() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_quic_crypto_hp_cleanup(ngx_quic_secret_t *s) +{ + if (s->hp_ctx) { + EVP_CIPHER_CTX_free(s->hp_ctx); + s->hp_ctx = NULL; + } +} + + +ngx_int_t +ngx_quic_keys_set_encryption_secret(ngx_log_t *log, ngx_uint_t is_write, + ngx_quic_keys_t *keys, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) +{ + ngx_int_t key_len; + ngx_str_t secret_str; + ngx_uint_t i; + ngx_quic_md_t key; + ngx_quic_hkdf_t seq[3]; + ngx_quic_secret_t *peer_secret; + ngx_quic_ciphers_t ciphers; + + peer_secret = is_write ? &keys->secrets[level].server + : &keys->secrets[level].client; + + keys->cipher = SSL_CIPHER_get_id(cipher); + + key_len = ngx_quic_ciphers(keys->cipher, &ciphers); + + if (key_len == NGX_ERROR) { + ngx_ssl_error(NGX_LOG_INFO, log, 0, "unexpected cipher"); + return NGX_ERROR; + } + + if (sizeof(peer_secret->secret.data) < secret_len) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "unexpected secret len: %uz", secret_len); + return NGX_ERROR; + } + + peer_secret->secret.len = secret_len; + ngx_memcpy(peer_secret->secret.data, secret, secret_len); + + key.len = key_len; + peer_secret->iv.len = NGX_QUIC_IV_LEN; + peer_secret->hp.len = key_len; + + secret_str.len = secret_len; + secret_str.data = (u_char *) secret; + + ngx_quic_hkdf_set(&seq[0], "tls13 quic key", &key, &secret_str); + ngx_quic_hkdf_set(&seq[1], "tls13 quic iv", &peer_secret->iv, &secret_str); + ngx_quic_hkdf_set(&seq[2], "tls13 quic hp", &peer_secret->hp, &secret_str); + + for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { + if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, log) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_quic_crypto_init(ciphers.c, peer_secret, &key, is_write, log) + == NGX_ERROR) + { + return NGX_ERROR; + } + + if (ngx_quic_crypto_hp_init(ciphers.hp, peer_secret, log) == NGX_ERROR) { + return NGX_ERROR; + } + + ngx_explicit_memzero(key.data, key.len); + + return NGX_OK; +} + + +ngx_uint_t +ngx_quic_keys_available(ngx_quic_keys_t *keys, + enum ssl_encryption_level_t level, ngx_uint_t is_write) +{ + if (is_write == 0) { + return keys->secrets[level].client.ctx != NULL; + } + + return keys->secrets[level].server.ctx != NULL; +} + + +void +ngx_quic_keys_discard(ngx_quic_keys_t *keys, + enum ssl_encryption_level_t level) +{ + ngx_quic_secret_t *client, *server; + + client = &keys->secrets[level].client; + server = &keys->secrets[level].server; + + ngx_quic_crypto_cleanup(client); + ngx_quic_crypto_cleanup(server); + + ngx_quic_crypto_hp_cleanup(client); + ngx_quic_crypto_hp_cleanup(server); + + ngx_explicit_memzero(client->secret.data, client->secret.len); + ngx_explicit_memzero(server->secret.data, server->secret.len); +} + + +void +ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys) +{ + ngx_quic_secrets_t *current, *next, tmp; + + current = &keys->secrets[ssl_encryption_application]; + next = &keys->next_key; + + ngx_quic_crypto_cleanup(¤t->client); + ngx_quic_crypto_cleanup(¤t->server); + + tmp = *current; + *current = *next; + *next = tmp; +} + + +void +ngx_quic_keys_update(ngx_event_t *ev) +{ + ngx_int_t key_len; + ngx_uint_t i; + ngx_quic_md_t client_key, server_key; + ngx_quic_hkdf_t seq[6]; + ngx_quic_keys_t *keys; + ngx_connection_t *c; + ngx_quic_ciphers_t ciphers; + ngx_quic_secrets_t *current, *next; + ngx_quic_connection_t *qc; + + c = ev->data; + qc = ngx_quic_get_connection(c); + keys = qc->keys; + + current = &keys->secrets[ssl_encryption_application]; + next = &keys->next_key; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic key update"); + + c->log->action = "updating keys"; + + key_len = ngx_quic_ciphers(keys->cipher, &ciphers); + + if (key_len == NGX_ERROR) { + goto failed; + } + + client_key.len = key_len; + server_key.len = key_len; + + next->client.secret.len = current->client.secret.len; + next->client.iv.len = NGX_QUIC_IV_LEN; + next->client.hp = current->client.hp; + next->client.hp_ctx = current->client.hp_ctx; + + next->server.secret.len = current->server.secret.len; + next->server.iv.len = NGX_QUIC_IV_LEN; + next->server.hp = current->server.hp; + next->server.hp_ctx = current->server.hp_ctx; + + ngx_quic_hkdf_set(&seq[0], "tls13 quic ku", + &next->client.secret, ¤t->client.secret); + ngx_quic_hkdf_set(&seq[1], "tls13 quic key", + &client_key, &next->client.secret); + ngx_quic_hkdf_set(&seq[2], "tls13 quic iv", + &next->client.iv, &next->client.secret); + ngx_quic_hkdf_set(&seq[3], "tls13 quic ku", + &next->server.secret, ¤t->server.secret); + ngx_quic_hkdf_set(&seq[4], "tls13 quic key", + &server_key, &next->server.secret); + ngx_quic_hkdf_set(&seq[5], "tls13 quic iv", + &next->server.iv, &next->server.secret); + + for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { + if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, c->log) != NGX_OK) { + goto failed; + } + } + + if (ngx_quic_crypto_init(ciphers.c, &next->client, &client_key, 0, c->log) + == NGX_ERROR) + { + goto failed; + } + + if (ngx_quic_crypto_init(ciphers.c, &next->server, &server_key, 1, c->log) + == NGX_ERROR) + { + goto failed; + } + + ngx_explicit_memzero(current->client.secret.data, + current->client.secret.len); + ngx_explicit_memzero(current->server.secret.data, + current->server.secret.len); + + ngx_explicit_memzero(client_key.data, client_key.len); + ngx_explicit_memzero(server_key.data, server_key.len); + + return; + +failed: + + ngx_quic_close_connection(c, NGX_ERROR); +} + + +void +ngx_quic_keys_cleanup(ngx_quic_keys_t *keys) +{ + ngx_uint_t i; + ngx_quic_secrets_t *next; + + for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) { + ngx_quic_keys_discard(keys, i); + } + + next = &keys->next_key; + + ngx_quic_crypto_cleanup(&next->client); + ngx_quic_crypto_cleanup(&next->server); + + ngx_explicit_memzero(next->client.secret.data, + next->client.secret.len); + ngx_explicit_memzero(next->server.secret.data, + next->server.secret.len); +} + + +static ngx_int_t +ngx_quic_create_packet(ngx_quic_header_t *pkt, ngx_str_t *res) +{ + u_char *pnp, *sample; + ngx_str_t ad, out; + ngx_uint_t i; + ngx_quic_secret_t *secret; + u_char nonce[NGX_QUIC_IV_LEN], mask[NGX_QUIC_HP_LEN]; + + ad.data = res->data; + ad.len = ngx_quic_create_header(pkt, ad.data, &pnp); + + out.len = pkt->payload.len + NGX_QUIC_TAG_LEN; + out.data = res->data + ad.len; + +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic ad len:%uz %xV", ad.len, &ad); +#endif + + secret = &pkt->keys->secrets[pkt->level].server; + + ngx_memcpy(nonce, secret->iv.data, secret->iv.len); + ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number); + + if (ngx_quic_crypto_seal(secret, &out, nonce, &pkt->payload, &ad, pkt->log) + != NGX_OK) + { + return NGX_ERROR; + } + + sample = &out.data[4 - pkt->num_len]; + if (ngx_quic_crypto_hp(secret, mask, sample, pkt->log) != NGX_OK) { + return NGX_ERROR; + } + + /* RFC 9001, 5.4.1. Header Protection Application */ + ad.data[0] ^= mask[0] & ngx_quic_pkt_hp_mask(pkt->flags); + + for (i = 0; i < pkt->num_len; i++) { + pnp[i] ^= mask[i + 1]; + } + + res->len = ad.len + out.len; + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, ngx_str_t *res) +{ + u_char *start; + ngx_str_t ad, itag; + ngx_quic_md_t key; + ngx_quic_secret_t secret; + ngx_quic_ciphers_t ciphers; + + /* 5.8. Retry Packet Integrity */ + static u_char key_data[16] = + "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e"; + static u_char nonce[NGX_QUIC_IV_LEN] = + "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb"; + static ngx_str_t in = ngx_string(""); + + ad.data = res->data; + ad.len = ngx_quic_create_retry_itag(pkt, ad.data, &start); + + itag.data = ad.data + ad.len; + itag.len = NGX_QUIC_TAG_LEN; + +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic retry itag len:%uz %xV", ad.len, &ad); +#endif + + if (ngx_quic_ciphers(NGX_QUIC_INITIAL_CIPHER, &ciphers) == NGX_ERROR) { + return NGX_ERROR; + } + + key.len = sizeof(key_data); + ngx_memcpy(key.data, key_data, sizeof(key_data)); + secret.iv.len = NGX_QUIC_IV_LEN; + + if (ngx_quic_crypto_init(ciphers.c, &secret, &key, 1, pkt->log) + == NGX_ERROR) + { + return NGX_ERROR; + } + + if (ngx_quic_crypto_seal(&secret, &itag, nonce, &in, &ad, pkt->log) + != NGX_OK) + { + ngx_quic_crypto_cleanup(&secret); + return NGX_ERROR; + } + + ngx_quic_crypto_cleanup(&secret); + + res->len = itag.data + itag.len - start; + res->data = start; + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_derive_key(ngx_log_t *log, const char *label, ngx_str_t *secret, + ngx_str_t *salt, u_char *out, size_t len) +{ + size_t is_len, info_len; + uint8_t *p; + const EVP_MD *digest; + + uint8_t is[SHA256_DIGEST_LENGTH]; + uint8_t info[20]; + + digest = EVP_sha256(); + is_len = SHA256_DIGEST_LENGTH; + + if (ngx_hkdf_extract(is, &is_len, digest, secret->data, secret->len, + salt->data, salt->len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "ngx_hkdf_extract(%s) failed", label); + return NGX_ERROR; + } + + info[0] = 0; + info[1] = len; + info[2] = ngx_strlen(label); + + info_len = 2 + 1 + info[2] + 1; + + if (info_len >= 20) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "ngx_quic_create_key label \"%s\" too long", label); + return NGX_ERROR; + } + + p = ngx_cpymem(&info[3], label, info[2]); + *p = '\0'; + + if (ngx_hkdf_expand(out, len, digest, is, is_len, info, info_len) != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "ngx_hkdf_expand(%s) failed", label); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static uint64_t +ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask, + uint64_t *largest_pn) +{ + u_char *p; + uint64_t truncated_pn, expected_pn, candidate_pn; + uint64_t pn_nbits, pn_win, pn_hwin, pn_mask; + + pn_nbits = ngx_min(len * 8, 62); + + p = *pos; + truncated_pn = *p++ ^ *mask++; + + while (--len) { + truncated_pn = (truncated_pn << 8) + (*p++ ^ *mask++); + } + + *pos = p; + + expected_pn = *largest_pn + 1; + pn_win = 1ULL << pn_nbits; + pn_hwin = pn_win / 2; + pn_mask = pn_win - 1; + + candidate_pn = (expected_pn & ~pn_mask) | truncated_pn; + + if ((int64_t) candidate_pn <= (int64_t) (expected_pn - pn_hwin) + && candidate_pn < (1ULL << 62) - pn_win) + { + candidate_pn += pn_win; + + } else if (candidate_pn > expected_pn + pn_hwin + && candidate_pn >= pn_win) + { + candidate_pn -= pn_win; + } + + *largest_pn = ngx_max((int64_t) *largest_pn, (int64_t) candidate_pn); + + return candidate_pn; +} + + +void +ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn) +{ + nonce[len - 8] ^= (pn >> 56) & 0x3f; + nonce[len - 7] ^= (pn >> 48) & 0xff; + nonce[len - 6] ^= (pn >> 40) & 0xff; + nonce[len - 5] ^= (pn >> 32) & 0xff; + nonce[len - 4] ^= (pn >> 24) & 0xff; + nonce[len - 3] ^= (pn >> 16) & 0xff; + nonce[len - 2] ^= (pn >> 8) & 0xff; + nonce[len - 1] ^= pn & 0xff; +} + + +ngx_int_t +ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_str_t *res) +{ + if (ngx_quic_pkt_retry(pkt->flags)) { + return ngx_quic_create_retry_packet(pkt, res); + } + + return ngx_quic_create_packet(pkt, res); +} + + +ngx_int_t +ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn) +{ + u_char *p, *sample; + size_t len; + uint64_t pn, lpn; + ngx_int_t pnl; + ngx_str_t in, ad; + ngx_uint_t key_phase; + ngx_quic_secret_t *secret; + uint8_t nonce[NGX_QUIC_IV_LEN], mask[NGX_QUIC_HP_LEN]; + + secret = &pkt->keys->secrets[pkt->level].client; + + p = pkt->raw->pos; + len = pkt->data + pkt->len - p; + + /* + * RFC 9001, 5.4.2. Header Protection Sample + * 5.4.3. AES-Based Header Protection + * 5.4.4. ChaCha20-Based Header Protection + * + * the Packet Number field is assumed to be 4 bytes long + * AES and ChaCha20 algorithms sample 16 bytes + */ + + if (len < NGX_QUIC_TAG_LEN + 4) { + return NGX_DECLINED; + } + + sample = p + 4; + + /* header protection */ + + if (ngx_quic_crypto_hp(secret, mask, sample, pkt->log) != NGX_OK) { + return NGX_DECLINED; + } + + pkt->flags ^= mask[0] & ngx_quic_pkt_hp_mask(pkt->flags); + + if (ngx_quic_short_pkt(pkt->flags)) { + key_phase = (pkt->flags & NGX_QUIC_PKT_KPHASE) != 0; + + if (key_phase != pkt->key_phase) { + if (pkt->keys->next_key.client.ctx != NULL) { + secret = &pkt->keys->next_key.client; + pkt->key_update = 1; + + } else { + /* + * RFC 9001, 6.3. Timing of Receive Key Generation. + * + * Trial decryption to avoid timing side-channel. + */ + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic next key missing"); + } + } + } + + lpn = *largest_pn; + + pnl = (pkt->flags & 0x03) + 1; + pn = ngx_quic_parse_pn(&p, pnl, &mask[1], &lpn); + + pkt->pn = pn; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic packet rx clearflags:%xd", pkt->flags); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic packet rx number:%uL len:%xi", pn, pnl); + + /* packet protection */ + + in.data = p; + in.len = len - pnl; + + ad.len = p - pkt->data; + ad.data = pkt->plaintext; + + ngx_memcpy(ad.data, pkt->data, ad.len); + ad.data[0] = pkt->flags; + + do { + ad.data[ad.len - pnl] = pn >> (8 * (pnl - 1)) % 256; + } while (--pnl); + + ngx_memcpy(nonce, secret->iv.data, secret->iv.len); + ngx_quic_compute_nonce(nonce, sizeof(nonce), pn); + +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic ad len:%uz %xV", ad.len, &ad); +#endif + + pkt->payload.len = in.len - NGX_QUIC_TAG_LEN; + pkt->payload.data = pkt->plaintext + ad.len; + + if (ngx_quic_crypto_open(secret, &pkt->payload, nonce, &in, &ad, pkt->log) + != NGX_OK) + { + return NGX_DECLINED; + } + + if (pkt->payload.len == 0) { + /* + * RFC 9000, 12.4. Frames and Frame Types + * + * An endpoint MUST treat receipt of a packet containing no + * frames as a connection error of type PROTOCOL_VIOLATION. + */ + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic zero-length packet"); + pkt->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + return NGX_ERROR; + } + + if (pkt->flags & ngx_quic_pkt_rb_mask(pkt->flags)) { + /* + * RFC 9000, Reserved Bits + * + * An endpoint MUST treat receipt of a packet that has + * a non-zero value for these bits, after removing both + * packet and header protection, as a connection error + * of type PROTOCOL_VIOLATION. + */ + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic reserved bit set in packet"); + pkt->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + return NGX_ERROR; + } + +#if defined(NGX_QUIC_DEBUG_CRYPTO) && defined(NGX_QUIC_DEBUG_PACKETS) + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic packet payload len:%uz %xV", + pkt->payload.len, &pkt->payload); +#endif + + *largest_pn = lpn; + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_protection.h b/src/event/quic/ngx_event_quic_protection.h new file mode 100644 index 0000000..34cfee6 --- /dev/null +++ b/src/event/quic/ngx_event_quic_protection.h @@ -0,0 +1,120 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ +#define _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ + + +#include +#include + +#include + + +#define NGX_QUIC_ENCRYPTION_LAST ((ssl_encryption_application) + 1) + +/* RFC 5116, 5.1/5.3 and RFC 8439, 2.3/2.5 for all supported ciphers */ +#define NGX_QUIC_IV_LEN 12 +#define NGX_QUIC_TAG_LEN 16 + +/* largest hash used in TLS is SHA-384 */ +#define NGX_QUIC_MAX_MD_SIZE 48 + + +#ifdef OPENSSL_IS_BORINGSSL +#define ngx_quic_cipher_t EVP_AEAD +#define ngx_quic_crypto_ctx_t EVP_AEAD_CTX +#else +#define ngx_quic_cipher_t EVP_CIPHER +#define ngx_quic_crypto_ctx_t EVP_CIPHER_CTX +#endif + + +typedef struct { + size_t len; + u_char data[NGX_QUIC_MAX_MD_SIZE]; +} ngx_quic_md_t; + + +typedef struct { + size_t len; + u_char data[NGX_QUIC_IV_LEN]; +} ngx_quic_iv_t; + + +typedef struct { + ngx_quic_md_t secret; + ngx_quic_iv_t iv; + ngx_quic_md_t hp; + ngx_quic_crypto_ctx_t *ctx; + EVP_CIPHER_CTX *hp_ctx; +} ngx_quic_secret_t; + + +typedef struct { + ngx_quic_secret_t client; + ngx_quic_secret_t server; +} ngx_quic_secrets_t; + + +struct ngx_quic_keys_s { + ngx_quic_secrets_t secrets[NGX_QUIC_ENCRYPTION_LAST]; + ngx_quic_secrets_t next_key; + ngx_uint_t cipher; +}; + + +typedef struct { + const ngx_quic_cipher_t *c; + const EVP_CIPHER *hp; + const EVP_MD *d; +} ngx_quic_ciphers_t; + + +typedef struct { + size_t out_len; + u_char *out; + + size_t prk_len; + const uint8_t *prk; + + size_t label_len; + const u_char *label; +} ngx_quic_hkdf_t; + +#define ngx_quic_hkdf_set(seq, _label, _out, _prk) \ + (seq)->out_len = (_out)->len; (seq)->out = (_out)->data; \ + (seq)->prk_len = (_prk)->len, (seq)->prk = (_prk)->data, \ + (seq)->label_len = (sizeof(_label) - 1); (seq)->label = (u_char *)(_label); + + +ngx_int_t ngx_quic_keys_set_initial_secret(ngx_quic_keys_t *keys, + ngx_str_t *secret, ngx_log_t *log); +ngx_int_t ngx_quic_keys_set_encryption_secret(ngx_log_t *log, + ngx_uint_t is_write, ngx_quic_keys_t *keys, + enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, + const uint8_t *secret, size_t secret_len); +ngx_uint_t ngx_quic_keys_available(ngx_quic_keys_t *keys, + enum ssl_encryption_level_t level, ngx_uint_t is_write); +void ngx_quic_keys_discard(ngx_quic_keys_t *keys, + enum ssl_encryption_level_t level); +void ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys); +void ngx_quic_keys_update(ngx_event_t *ev); +void ngx_quic_keys_cleanup(ngx_quic_keys_t *keys); +ngx_int_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_str_t *res); +ngx_int_t ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn); +void ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn); +ngx_int_t ngx_quic_ciphers(ngx_uint_t id, ngx_quic_ciphers_t *ciphers); +ngx_int_t ngx_quic_crypto_init(const ngx_quic_cipher_t *cipher, + ngx_quic_secret_t *s, ngx_quic_md_t *key, ngx_int_t enc, ngx_log_t *log); +ngx_int_t ngx_quic_crypto_seal(ngx_quic_secret_t *s, ngx_str_t *out, + u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); +void ngx_quic_crypto_cleanup(ngx_quic_secret_t *s); +ngx_int_t ngx_quic_hkdf_expand(ngx_quic_hkdf_t *hkdf, const EVP_MD *digest, + ngx_log_t *log); + + +#endif /* _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_socket.c b/src/event/quic/ngx_event_quic_socket.c new file mode 100644 index 0000000..c2bc822 --- /dev/null +++ b/src/event/quic/ngx_event_quic_socket.c @@ -0,0 +1,237 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +ngx_int_t +ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_header_t *pkt) +{ + ngx_quic_socket_t *qsock, *tmp; + ngx_quic_client_id_t *cid; + + /* + * qc->path = NULL + * + * qc->nclient_ids = 0 + * qc->nsockets = 0 + * qc->max_retired_seqnum = 0 + * qc->client_seqnum = 0 + */ + + ngx_queue_init(&qc->sockets); + ngx_queue_init(&qc->free_sockets); + + ngx_queue_init(&qc->paths); + ngx_queue_init(&qc->free_paths); + + ngx_queue_init(&qc->client_ids); + ngx_queue_init(&qc->free_client_ids); + + qc->tp.original_dcid.len = pkt->odcid.len; + qc->tp.original_dcid.data = ngx_pstrdup(c->pool, &pkt->odcid); + if (qc->tp.original_dcid.data == NULL) { + return NGX_ERROR; + } + + /* socket to use for further processing (id auto-generated) */ + qsock = ngx_quic_create_socket(c, qc); + if (qsock == NULL) { + return NGX_ERROR; + } + + /* socket is listening at new server id */ + if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { + return NGX_ERROR; + } + + qsock->used = 1; + + qc->tp.initial_scid.len = qsock->sid.len; + qc->tp.initial_scid.data = ngx_pnalloc(c->pool, qsock->sid.len); + if (qc->tp.initial_scid.data == NULL) { + goto failed; + } + ngx_memcpy(qc->tp.initial_scid.data, qsock->sid.id, qsock->sid.len); + + /* for all packets except first, this is set at udp layer */ + c->udp = &qsock->udp; + + /* ngx_quic_get_connection(c) macro is now usable */ + + /* we have a client identified by scid */ + cid = ngx_quic_create_client_id(c, &pkt->scid, 0, NULL); + if (cid == NULL) { + goto failed; + } + + /* path of the first packet is our initial active path */ + qc->path = ngx_quic_new_path(c, c->sockaddr, c->socklen, cid); + if (qc->path == NULL) { + goto failed; + } + + qc->path->tag = NGX_QUIC_PATH_ACTIVE; + + if (pkt->validated) { + qc->path->validated = 1; + } + + ngx_quic_path_dbg(c, "set active", qc->path); + + tmp = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); + if (tmp == NULL) { + goto failed; + } + + tmp->sid.seqnum = NGX_QUIC_UNSET_PN; /* temporary socket */ + + ngx_memcpy(tmp->sid.id, pkt->dcid.data, pkt->dcid.len); + tmp->sid.len = pkt->dcid.len; + + if (ngx_quic_listen(c, qc, tmp) != NGX_OK) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); + c->udp = NULL; + + return NGX_ERROR; +} + + +ngx_quic_socket_t * +ngx_quic_create_socket(ngx_connection_t *c, ngx_quic_connection_t *qc) +{ + ngx_queue_t *q; + ngx_quic_socket_t *sock; + + if (!ngx_queue_empty(&qc->free_sockets)) { + + q = ngx_queue_head(&qc->free_sockets); + sock = ngx_queue_data(q, ngx_quic_socket_t, queue); + + ngx_queue_remove(&sock->queue); + + ngx_memzero(sock, sizeof(ngx_quic_socket_t)); + + } else { + + sock = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); + if (sock == NULL) { + return NULL; + } + } + + sock->sid.len = NGX_QUIC_SERVER_CID_LEN; + if (ngx_quic_create_server_id(c, sock->sid.id) != NGX_OK) { + return NULL; + } + + sock->sid.seqnum = qc->server_seqnum++; + + return sock; +} + + +void +ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ngx_queue_remove(&qsock->queue); + ngx_queue_insert_head(&qc->free_sockets, &qsock->queue); + + ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); + qc->nsockets--; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic socket seq:%L closed nsock:%ui", + (int64_t) qsock->sid.seqnum, qc->nsockets); +} + + +ngx_int_t +ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_socket_t *qsock) +{ + ngx_str_t id; + ngx_quic_server_id_t *sid; + + sid = &qsock->sid; + + id.data = sid->id; + id.len = sid->len; + + qsock->udp.connection = c; + qsock->udp.node.key = ngx_crc32_long(id.data, id.len); + qsock->udp.key = id; + + ngx_rbtree_insert(&c->listening->rbtree, &qsock->udp.node); + + ngx_queue_insert_tail(&qc->sockets, &qsock->queue); + + qc->nsockets++; + qsock->quic = qc; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic socket seq:%L listening at sid:%xV nsock:%ui", + (int64_t) sid->seqnum, &id, qc->nsockets); + + return NGX_OK; +} + + +void +ngx_quic_close_sockets(ngx_connection_t *c) +{ + ngx_queue_t *q; + ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + while (!ngx_queue_empty(&qc->sockets)) { + q = ngx_queue_head(&qc->sockets); + qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); + + ngx_quic_close_socket(c, qsock); + } +} + + +ngx_quic_socket_t * +ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum) +{ + ngx_queue_t *q; + ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + for (q = ngx_queue_head(&qc->sockets); + q != ngx_queue_sentinel(&qc->sockets); + q = ngx_queue_next(q)) + { + qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); + + if (qsock->sid.seqnum == seqnum) { + return qsock; + } + } + + return NULL; +} diff --git a/src/event/quic/ngx_event_quic_socket.h b/src/event/quic/ngx_event_quic_socket.h new file mode 100644 index 0000000..68ecc06 --- /dev/null +++ b/src/event/quic/ngx_event_quic_socket.h @@ -0,0 +1,28 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_SOCKET_H_INCLUDED_ +#define _NGX_EVENT_QUIC_SOCKET_H_INCLUDED_ + + +#include +#include + + +ngx_int_t ngx_quic_open_sockets(ngx_connection_t *c, + ngx_quic_connection_t *qc, ngx_quic_header_t *pkt); +void ngx_quic_close_sockets(ngx_connection_t *c); + +ngx_quic_socket_t *ngx_quic_create_socket(ngx_connection_t *c, + ngx_quic_connection_t *qc); +ngx_int_t ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_socket_t *qsock); +void ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock); + +ngx_quic_socket_t *ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum); + + +#endif /* _NGX_EVENT_QUIC_SOCKET_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c new file mode 100644 index 0000000..7872783 --- /dev/null +++ b/src/event/quic/ngx_event_quic_ssl.c @@ -0,0 +1,590 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#if defined OPENSSL_IS_BORINGSSL \ + || defined LIBRESSL_VERSION_NUMBER \ + || NGX_QUIC_OPENSSL_COMPAT +#define NGX_QUIC_BORINGSSL_API 1 +#endif + + +/* + * RFC 9000, 7.5. Cryptographic Message Buffering + * + * Implementations MUST support buffering at least 4096 bytes of data + */ +#define NGX_QUIC_MAX_BUFFERED 65535 + + +#if (NGX_QUIC_BORINGSSL_API) +static int ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, + const uint8_t *secret, size_t secret_len); +static int ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, + const uint8_t *secret, size_t secret_len); +#else +static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len); +#endif + +static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const uint8_t *data, size_t len); +static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); +static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, uint8_t alert); +static ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data, + enum ssl_encryption_level_t level); + + +#if (NGX_QUIC_BORINGSSL_API) + +static int +ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, + const uint8_t *rsecret, size_t secret_len) +{ + ngx_connection_t *c; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + qc = ngx_quic_get_connection(c); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_set_read_secret() level:%d", level); +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic read secret len:%uz %*xs", secret_len, + secret_len, rsecret); +#endif + + if (ngx_quic_keys_set_encryption_secret(c->log, 0, qc->keys, level, + cipher, rsecret, secret_len) + != NGX_OK) + { + return 0; + } + + return 1; +} + + +static int +ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, + const uint8_t *wsecret, size_t secret_len) +{ + ngx_connection_t *c; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + qc = ngx_quic_get_connection(c); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_set_write_secret() level:%d", level); +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic write secret len:%uz %*xs", secret_len, + secret_len, wsecret); +#endif + + if (ngx_quic_keys_set_encryption_secret(c->log, 1, qc->keys, level, + cipher, wsecret, secret_len) + != NGX_OK) + { + return 0; + } + + return 1; +} + +#else + +static int +ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const uint8_t *rsecret, + const uint8_t *wsecret, size_t secret_len) +{ + ngx_connection_t *c; + const SSL_CIPHER *cipher; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + qc = ngx_quic_get_connection(c); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_set_encryption_secrets() level:%d", level); +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic read secret len:%uz %*xs", secret_len, + secret_len, rsecret); +#endif + + cipher = SSL_get_current_cipher(ssl_conn); + + if (ngx_quic_keys_set_encryption_secret(c->log, 0, qc->keys, level, + cipher, rsecret, secret_len) + != NGX_OK) + { + return 0; + } + + if (level == ssl_encryption_early_data) { + return 1; + } + +#ifdef NGX_QUIC_DEBUG_CRYPTO + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic write secret len:%uz %*xs", secret_len, + secret_len, wsecret); +#endif + + if (ngx_quic_keys_set_encryption_secret(c->log, 1, qc->keys, level, + cipher, wsecret, secret_len) + != NGX_OK) + { + return 0; + } + + return 1; +} + +#endif + + +static int +ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, + enum ssl_encryption_level_t level, const uint8_t *data, size_t len) +{ + u_char *p, *end; + size_t client_params_len; + ngx_chain_t *out; + const uint8_t *client_params; + ngx_quic_tp_t ctp; + ngx_quic_frame_t *frame; + ngx_connection_t *c; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) + unsigned int alpn_len; + const unsigned char *alpn_data; +#endif + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + qc = ngx_quic_get_connection(c); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_add_handshake_data"); + + if (!qc->client_tp_done) { + /* + * things to do once during handshake: check ALPN and transport + * parameters; we want to break handshake if something is wrong + * here; + */ + +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) + + SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len); + + if (alpn_len == 0) { + qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL); + qc->error_reason = "unsupported protocol in ALPN extension"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic unsupported protocol in ALPN extension"); + return 0; + } + +#endif + + SSL_get_peer_quic_transport_params(ssl_conn, &client_params, + &client_params_len); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic SSL_get_peer_quic_transport_params():" + " params_len:%ui", client_params_len); + + if (client_params_len == 0) { + /* RFC 9001, 8.2. QUIC Transport Parameters Extension */ + qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION); + qc->error_reason = "missing transport parameters"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "missing transport parameters"); + return 0; + } + + p = (u_char *) client_params; + end = p + client_params_len; + + /* defaults for parameters not sent by client */ + ngx_memcpy(&ctp, &qc->ctp, sizeof(ngx_quic_tp_t)); + + if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) + != NGX_OK) + { + qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; + qc->error_reason = "failed to process transport parameters"; + + return 0; + } + + if (ngx_quic_apply_transport_params(c, &ctp) != NGX_OK) { + return 0; + } + + qc->client_tp_done = 1; + } + + ctx = ngx_quic_get_send_ctx(qc, level); + + out = ngx_quic_copy_buffer(c, (u_char *) data, len); + if (out == NGX_CHAIN_ERROR) { + return 0; + } + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return 0; + } + + frame->data = out; + frame->level = level; + frame->type = NGX_QUIC_FT_CRYPTO; + frame->u.crypto.offset = ctx->crypto_sent; + frame->u.crypto.length = len; + + ctx->crypto_sent += len; + + ngx_quic_queue_frame(qc, frame); + + return 1; +} + + +static int +ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn) +{ +#if (NGX_DEBUG) + ngx_connection_t *c; + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_flush_flight()"); +#endif + return 1; +} + + +static int +ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, + uint8_t alert) +{ + ngx_connection_t *c; + ngx_quic_connection_t *qc; + + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic ngx_quic_send_alert() level:%s alert:%d", + ngx_quic_level_name(level), (int) alert); + + /* already closed on regular shutdown */ + + qc = ngx_quic_get_connection(c); + if (qc == NULL) { + return 1; + } + + qc->error = NGX_QUIC_ERR_CRYPTO(alert); + qc->error_reason = "handshake failed"; + + return 1; +} + + +ngx_int_t +ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, + ngx_quic_frame_t *frame) +{ + uint64_t last; + ngx_chain_t *cl; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + ngx_quic_crypto_frame_t *f; + + qc = ngx_quic_get_connection(c); + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + f = &frame->u.crypto; + + /* no overflow since both values are 62-bit */ + last = f->offset + f->length; + + if (last > ctx->crypto.offset + NGX_QUIC_MAX_BUFFERED) { + qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; + return NGX_ERROR; + } + + if (last <= ctx->crypto.offset) { + if (pkt->level == ssl_encryption_initial) { + /* speeding up handshake completion */ + + if (!ngx_queue_empty(&ctx->sent)) { + ngx_quic_resend_frames(c, ctx); + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); + while (!ngx_queue_empty(&ctx->sent)) { + ngx_quic_resend_frames(c, ctx); + } + } + } + + return NGX_OK; + } + + if (f->offset == ctx->crypto.offset) { + if (ngx_quic_crypto_input(c, frame->data, pkt->level) != NGX_OK) { + return NGX_ERROR; + } + + ngx_quic_skip_buffer(c, &ctx->crypto, last); + + } else { + if (ngx_quic_write_buffer(c, &ctx->crypto, frame->data, f->length, + f->offset) + == NGX_CHAIN_ERROR) + { + return NGX_ERROR; + } + } + + cl = ngx_quic_read_buffer(c, &ctx->crypto, (uint64_t) -1); + + if (cl) { + if (ngx_quic_crypto_input(c, cl, pkt->level) != NGX_OK) { + return NGX_ERROR; + } + + ngx_quic_free_chain(c, cl); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data, + enum ssl_encryption_level_t level) +{ + int n, sslerr; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_ssl_conn_t *ssl_conn; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + ssl_conn = c->ssl->connection; + + for (cl = data; cl; cl = cl->next) { + b = cl->buf; + + if (!SSL_provide_quic_data(ssl_conn, level, b->pos, b->last - b->pos)) { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "SSL_provide_quic_data() failed"); + return NGX_ERROR; + } + } + + n = SSL_do_handshake(ssl_conn); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); + + if (n <= 0) { + sslerr = SSL_get_error(ssl_conn, n); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", + sslerr); + + if (sslerr != SSL_ERROR_WANT_READ) { + + if (c->ssl->handshake_rejected) { + ngx_connection_error(c, 0, "handshake rejected"); + ERR_clear_error(); + + return NGX_ERROR; + } + + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); + return NGX_ERROR; + } + } + + if (n <= 0 || SSL_in_init(ssl_conn)) { + if (ngx_quic_keys_available(qc->keys, ssl_encryption_early_data, 0) + && qc->client_tp_done) + { + if (ngx_quic_init_streams(c) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; + } + +#if (NGX_DEBUG) + ngx_ssl_handshake_log(c); +#endif + + c->ssl->handshaked = 1; + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_HANDSHAKE_DONE; + ngx_quic_queue_frame(qc, frame); + + if (qc->conf->retry) { + if (ngx_quic_send_new_token(c, qc->path) != NGX_OK) { + return NGX_ERROR; + } + } + + /* + * RFC 9001, 9.5. Header Protection Timing Side Channels + * + * Generating next keys before a key update is received. + */ + + ngx_post_event(&qc->key_update, &ngx_posted_events); + + /* + * RFC 9001, 4.9.2. Discarding Handshake Keys + * + * An endpoint MUST discard its Handshake keys + * when the TLS handshake is confirmed. + */ + ngx_quic_discard_ctx(c, ssl_encryption_handshake); + + ngx_quic_discover_path_mtu(c, qc->path); + + /* start accepting clients on negotiated number of server ids */ + if (ngx_quic_create_sockets(c) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_quic_init_streams(c) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_init_connection(ngx_connection_t *c) +{ + u_char *p; + size_t clen; + ssize_t len; + ngx_str_t dcid; + ngx_ssl_conn_t *ssl_conn; + ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + static SSL_QUIC_METHOD quic_method; + + qc = ngx_quic_get_connection(c); + + if (ngx_ssl_create_connection(qc->conf->ssl, c, 0) != NGX_OK) { + return NGX_ERROR; + } + + c->ssl->no_wait_shutdown = 1; + + ssl_conn = c->ssl->connection; + + if (!quic_method.send_alert) { +#if (NGX_QUIC_BORINGSSL_API) + quic_method.set_read_secret = ngx_quic_set_read_secret; + quic_method.set_write_secret = ngx_quic_set_write_secret; +#else + quic_method.set_encryption_secrets = ngx_quic_set_encryption_secrets; +#endif + quic_method.add_handshake_data = ngx_quic_add_handshake_data; + quic_method.flush_flight = ngx_quic_flush_flight; + quic_method.send_alert = ngx_quic_send_alert; + } + + if (SSL_set_quic_method(ssl_conn, &quic_method) == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic SSL_set_quic_method() failed"); + return NGX_ERROR; + } + +#ifdef OPENSSL_INFO_QUIC + if (SSL_CTX_get_max_early_data(qc->conf->ssl->ctx)) { + SSL_set_quic_early_data_enabled(ssl_conn, 1); + } +#endif + + qsock = ngx_quic_get_socket(c); + + dcid.data = qsock->sid.id; + dcid.len = qsock->sid.len; + + if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, qc->tp.sr_token) + != NGX_OK) + { + return NGX_ERROR; + } + + len = ngx_quic_create_transport_params(NULL, NULL, &qc->tp, &clen); + /* always succeeds */ + + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_quic_create_transport_params(p, p + len, &qc->tp, NULL); + if (len < 0) { + return NGX_ERROR; + } + +#ifdef NGX_QUIC_DEBUG_PACKETS + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic transport parameters len:%uz %*xs", len, len, p); +#endif + + if (SSL_set_quic_transport_params(ssl_conn, p, len) == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic SSL_set_quic_transport_params() failed"); + return NGX_ERROR; + } + +#ifdef OPENSSL_IS_BORINGSSL + if (SSL_set_quic_early_data_context(ssl_conn, p, clen) == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic SSL_set_quic_early_data_context() failed"); + return NGX_ERROR; + } +#endif + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_ssl.h b/src/event/quic/ngx_event_quic_ssl.h new file mode 100644 index 0000000..ee0aa07 --- /dev/null +++ b/src/event/quic/ngx_event_quic_ssl.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_SSL_H_INCLUDED_ +#define _NGX_EVENT_QUIC_SSL_H_INCLUDED_ + + +#include +#include + +ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); + +ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); + +#endif /* _NGX_EVENT_QUIC_SSL_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c new file mode 100644 index 0000000..178b805 --- /dev/null +++ b/src/event/quic/ngx_event_quic_streams.c @@ -0,0 +1,1820 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#define NGX_QUIC_STREAM_GONE (void *) -1 + + +static ngx_int_t ngx_quic_do_reset_stream(ngx_quic_stream_t *qs, + ngx_uint_t err); +static ngx_int_t ngx_quic_shutdown_stream_send(ngx_connection_t *c); +static ngx_int_t ngx_quic_shutdown_stream_recv(ngx_connection_t *c); +static ngx_quic_stream_t *ngx_quic_get_stream(ngx_connection_t *c, uint64_t id); +static ngx_int_t ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id); +static void ngx_quic_init_stream_handler(ngx_event_t *ev); +static void ngx_quic_init_streams_handler(ngx_connection_t *c); +static ngx_int_t ngx_quic_do_init_streams(ngx_connection_t *c); +static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c, + uint64_t id); +static void ngx_quic_empty_handler(ngx_event_t *ev); +static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, + size_t size); +static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, + size_t size); +static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, + ngx_chain_t *in, off_t limit); +static ngx_int_t ngx_quic_stream_flush(ngx_quic_stream_t *qs); +static void ngx_quic_stream_cleanup_handler(void *data); +static ngx_int_t ngx_quic_close_stream(ngx_quic_stream_t *qs); +static ngx_int_t ngx_quic_can_shutdown(ngx_connection_t *c); +static ngx_int_t ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last); +static ngx_int_t ngx_quic_update_flow(ngx_quic_stream_t *qs, uint64_t last); +static ngx_int_t ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs); +static ngx_int_t ngx_quic_update_max_data(ngx_connection_t *c); +static void ngx_quic_set_event(ngx_event_t *ev); + + +ngx_connection_t * +ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi) +{ + uint64_t id; + ngx_connection_t *pc, *sc; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + pc = c->quic ? c->quic->parent : c; + qc = ngx_quic_get_connection(pc); + + if (qc->closing) { + return NULL; + } + + if (bidi) { + if (qc->streams.server_streams_bidi + >= qc->streams.server_max_streams_bidi) + { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic too many server bidi streams:%uL", + qc->streams.server_streams_bidi); + return NULL; + } + + id = (qc->streams.server_streams_bidi << 2) + | NGX_QUIC_STREAM_SERVER_INITIATED; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic creating server bidi stream" + " streams:%uL max:%uL id:0x%xL", + qc->streams.server_streams_bidi, + qc->streams.server_max_streams_bidi, id); + + qc->streams.server_streams_bidi++; + + } else { + if (qc->streams.server_streams_uni + >= qc->streams.server_max_streams_uni) + { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic too many server uni streams:%uL", + qc->streams.server_streams_uni); + return NULL; + } + + id = (qc->streams.server_streams_uni << 2) + | NGX_QUIC_STREAM_SERVER_INITIATED + | NGX_QUIC_STREAM_UNIDIRECTIONAL; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic creating server uni stream" + " streams:%uL max:%uL id:0x%xL", + qc->streams.server_streams_uni, + qc->streams.server_max_streams_uni, id); + + qc->streams.server_streams_uni++; + } + + qs = ngx_quic_create_stream(pc, id); + if (qs == NULL) { + return NULL; + } + + sc = qs->connection; + + sc->write->active = 1; + sc->write->ready = 1; + + if (bidi) { + sc->read->active = 1; + } + + return sc; +} + + +void +ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_quic_stream_t *qn, *qnt; + + for ( ;; ) { + qn = (ngx_quic_stream_t *) node; + qnt = (ngx_quic_stream_t *) temp; + + p = (qn->id < qnt->id) ? &temp->left : &temp->right; + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +ngx_quic_stream_t * +ngx_quic_find_stream(ngx_rbtree_t *rbtree, uint64_t id) +{ + ngx_rbtree_node_t *node, *sentinel; + ngx_quic_stream_t *qn; + + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + qn = (ngx_quic_stream_t *) node; + + if (id == qn->id) { + return qn; + } + + node = (id < qn->id) ? node->left : node->right; + } + + return NULL; +} + + +ngx_int_t +ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) +{ + ngx_pool_t *pool; + ngx_queue_t *q; + ngx_rbtree_t *tree; + ngx_connection_t *sc; + ngx_rbtree_node_t *node; + ngx_quic_stream_t *qs; + + while (!ngx_queue_empty(&qc->streams.uninitialized)) { + q = ngx_queue_head(&qc->streams.uninitialized); + ngx_queue_remove(q); + + qs = ngx_queue_data(q, ngx_quic_stream_t, queue); + pool = qs->connection->pool; + + ngx_close_connection(qs->connection); + ngx_destroy_pool(pool); + } + + tree = &qc->streams.tree; + + if (tree->root == tree->sentinel) { + return NGX_OK; + } + + node = ngx_rbtree_min(tree->root, tree->sentinel); + + while (node) { + qs = (ngx_quic_stream_t *) node; + node = ngx_rbtree_next(tree, node); + sc = qs->connection; + + qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD; + qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT; + + if (sc == NULL) { + ngx_quic_close_stream(qs); + continue; + } + + sc->read->error = 1; + sc->write->error = 1; + + ngx_quic_set_event(sc->read); + ngx_quic_set_event(sc->write); + + sc->close = 1; + sc->read->handler(sc->read); + } + + if (tree->root == tree->sentinel) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic connection has active streams"); + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_quic_reset_stream(ngx_connection_t *c, ngx_uint_t err) +{ + return ngx_quic_do_reset_stream(c->quic, err); +} + + +static ngx_int_t +ngx_quic_do_reset_stream(ngx_quic_stream_t *qs, ngx_uint_t err) +{ + ngx_connection_t *pc; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + if (qs->send_state == NGX_QUIC_STREAM_SEND_DATA_RECVD + || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_SENT + || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_RECVD) + { + return NGX_OK; + } + + qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT; + qs->send_final_size = qs->send_offset; + + if (qs->connection) { + qs->connection->write->error = 1; + } + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL reset", qs->id); + + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_RESET_STREAM; + frame->u.reset_stream.id = qs->id; + frame->u.reset_stream.error_code = err; + frame->u.reset_stream.final_size = qs->send_offset; + + ngx_quic_queue_frame(qc, frame); + + ngx_quic_free_buffer(pc, &qs->send); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_shutdown_stream(ngx_connection_t *c, int how) +{ + if (how == NGX_RDWR_SHUTDOWN || how == NGX_WRITE_SHUTDOWN) { + if (ngx_quic_shutdown_stream_send(c) != NGX_OK) { + return NGX_ERROR; + } + } + + if (how == NGX_RDWR_SHUTDOWN || how == NGX_READ_SHUTDOWN) { + if (ngx_quic_shutdown_stream_recv(c) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_shutdown_stream_send(ngx_connection_t *c) +{ + ngx_quic_stream_t *qs; + + qs = c->quic; + + if (qs->send_state != NGX_QUIC_STREAM_SEND_READY + && qs->send_state != NGX_QUIC_STREAM_SEND_SEND) + { + return NGX_OK; + } + + qs->send_state = NGX_QUIC_STREAM_SEND_SEND; + qs->send_final_size = c->sent; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, qs->parent->log, 0, + "quic stream id:0x%xL send shutdown", qs->id); + + return ngx_quic_stream_flush(qs); +} + + +static ngx_int_t +ngx_quic_shutdown_stream_recv(ngx_connection_t *c) +{ + ngx_connection_t *pc; + ngx_quic_frame_t *frame; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qs = c->quic; + + if (qs->recv_state != NGX_QUIC_STREAM_RECV_RECV + && qs->recv_state != NGX_QUIC_STREAM_RECV_SIZE_KNOWN) + { + return NGX_OK; + } + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (qc->conf->stream_close_code == 0) { + return NGX_OK; + } + + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL recv shutdown", qs->id); + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_STOP_SENDING; + frame->u.stop_sending.id = qs->id; + frame->u.stop_sending.error_code = qc->conf->stream_close_code; + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +static ngx_quic_stream_t * +ngx_quic_get_stream(ngx_connection_t *c, uint64_t id) +{ + uint64_t min_id; + ngx_event_t *rev; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + qs = ngx_quic_find_stream(&qc->streams.tree, id); + + if (qs) { + return qs; + } + + if (qc->shutdown || qc->closing) { + return NGX_QUIC_STREAM_GONE; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL is missing", id); + + if (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { + + if (id & NGX_QUIC_STREAM_SERVER_INITIATED) { + if ((id >> 2) < qc->streams.server_streams_uni) { + return NGX_QUIC_STREAM_GONE; + } + + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NULL; + } + + if ((id >> 2) < qc->streams.client_streams_uni) { + return NGX_QUIC_STREAM_GONE; + } + + if ((id >> 2) >= qc->streams.client_max_streams_uni) { + qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; + return NULL; + } + + min_id = (qc->streams.client_streams_uni << 2) + | NGX_QUIC_STREAM_UNIDIRECTIONAL; + qc->streams.client_streams_uni = (id >> 2) + 1; + + } else { + + if (id & NGX_QUIC_STREAM_SERVER_INITIATED) { + if ((id >> 2) < qc->streams.server_streams_bidi) { + return NGX_QUIC_STREAM_GONE; + } + + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NULL; + } + + if ((id >> 2) < qc->streams.client_streams_bidi) { + return NGX_QUIC_STREAM_GONE; + } + + if ((id >> 2) >= qc->streams.client_max_streams_bidi) { + qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; + return NULL; + } + + min_id = (qc->streams.client_streams_bidi << 2); + qc->streams.client_streams_bidi = (id >> 2) + 1; + } + + /* + * RFC 9000, 2.1. Stream Types and Identifiers + * + * successive streams of each type are created with numerically increasing + * stream IDs. A stream ID that is used out of order results in all + * streams of that type with lower-numbered stream IDs also being opened. + */ + +#if (NGX_SUPPRESS_WARN) + qs = NULL; +#endif + + for ( /* void */ ; min_id <= id; min_id += 0x04) { + + qs = ngx_quic_create_stream(c, min_id); + + if (qs == NULL) { + if (ngx_quic_reject_stream(c, min_id) != NGX_OK) { + return NULL; + } + + continue; + } + + ngx_queue_insert_tail(&qc->streams.uninitialized, &qs->queue); + + rev = qs->connection->read; + rev->handler = ngx_quic_init_stream_handler; + + if (qc->streams.initialized) { + ngx_post_event(rev, &ngx_posted_events); + + if (qc->push.posted) { + /* + * The posted stream can produce output immediately. + * By postponing the push event, we coalesce the stream + * output with queued frames in one UDP datagram. + */ + + ngx_delete_posted_event(&qc->push); + ngx_post_event(&qc->push, &ngx_posted_events); + } + } + } + + if (qs == NULL) { + return NGX_QUIC_STREAM_GONE; + } + + return qs; +} + + +static ngx_int_t +ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id) +{ + uint64_t code; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + code = (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) + ? qc->conf->stream_reject_code_uni + : qc->conf->stream_reject_code_bidi; + + if (code == 0) { + return NGX_DECLINED; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL reject err:0x%xL", id, code); + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_RESET_STREAM; + frame->u.reset_stream.id = id; + frame->u.reset_stream.error_code = code; + frame->u.reset_stream.final_size = 0; + + ngx_quic_queue_frame(qc, frame); + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_STOP_SENDING; + frame->u.stop_sending.id = id; + frame->u.stop_sending.error_code = code; + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +static void +ngx_quic_init_stream_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_quic_stream_t *qs; + + c = ev->data; + qs = c->quic; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic init stream"); + + if ((qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { + c->write->active = 1; + c->write->ready = 1; + } + + c->read->active = 1; + + ngx_queue_remove(&qs->queue); + + c->listening->handler(c); +} + + +ngx_int_t +ngx_quic_init_streams(ngx_connection_t *c) +{ + ngx_int_t rc; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (qc->streams.initialized) { + return NGX_OK; + } + + rc = ngx_ssl_ocsp_validate(c); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + c->ssl->handler = ngx_quic_init_streams_handler; + return NGX_OK; + } + + return ngx_quic_do_init_streams(c); +} + + +static void +ngx_quic_init_streams_handler(ngx_connection_t *c) +{ + if (ngx_quic_do_init_streams(c) != NGX_OK) { + ngx_quic_close_connection(c, NGX_ERROR); + } +} + + +static ngx_int_t +ngx_quic_do_init_streams(ngx_connection_t *c) +{ + ngx_queue_t *q; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic init streams"); + + qc = ngx_quic_get_connection(c); + + if (qc->conf->init) { + if (qc->conf->init(c) != NGX_OK) { + return NGX_ERROR; + } + } + + for (q = ngx_queue_head(&qc->streams.uninitialized); + q != ngx_queue_sentinel(&qc->streams.uninitialized); + q = ngx_queue_next(q)) + { + qs = ngx_queue_data(q, ngx_quic_stream_t, queue); + ngx_post_event(qs->connection->read, &ngx_posted_events); + } + + qc->streams.initialized = 1; + + if (!qc->closing && qc->close.timer_set) { + ngx_del_timer(&qc->close); + } + + return NGX_OK; +} + + +static ngx_quic_stream_t * +ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) +{ + ngx_str_t addr_text; + ngx_log_t *log; + ngx_pool_t *pool; + ngx_uint_t reusable; + ngx_queue_t *q; + struct sockaddr *sockaddr; + ngx_connection_t *sc; + ngx_quic_stream_t *qs; + ngx_pool_cleanup_t *cln; + ngx_quic_connection_t *qc; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL create", id); + + qc = ngx_quic_get_connection(c); + + if (!ngx_queue_empty(&qc->streams.free)) { + q = ngx_queue_head(&qc->streams.free); + qs = ngx_queue_data(q, ngx_quic_stream_t, queue); + ngx_queue_remove(&qs->queue); + + } else { + /* + * the number of streams is limited by transport + * parameters and application requirements + */ + + qs = ngx_palloc(c->pool, sizeof(ngx_quic_stream_t)); + if (qs == NULL) { + return NULL; + } + } + + ngx_memzero(qs, sizeof(ngx_quic_stream_t)); + + qs->node.key = id; + qs->parent = c; + qs->id = id; + qs->send_final_size = (uint64_t) -1; + qs->recv_final_size = (uint64_t) -1; + + pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log); + if (pool == NULL) { + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + + log = ngx_palloc(pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + + *log = *c->log; + pool->log = log; + + sockaddr = ngx_palloc(pool, c->socklen); + if (sockaddr == NULL) { + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + + ngx_memcpy(sockaddr, c->sockaddr, c->socklen); + + if (c->addr_text.data) { + addr_text.data = ngx_pnalloc(pool, c->addr_text.len); + if (addr_text.data == NULL) { + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + + ngx_memcpy(addr_text.data, c->addr_text.data, c->addr_text.len); + addr_text.len = c->addr_text.len; + + } else { + addr_text.len = 0; + addr_text.data = NULL; + } + + reusable = c->reusable; + ngx_reusable_connection(c, 0); + + sc = ngx_get_connection(c->fd, log); + if (sc == NULL) { + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + ngx_reusable_connection(c, reusable); + return NULL; + } + + qs->connection = sc; + + sc->quic = qs; + sc->shared = 1; + sc->type = SOCK_STREAM; + sc->pool = pool; + sc->ssl = c->ssl; + sc->sockaddr = sockaddr; + sc->socklen = c->socklen; + sc->listening = c->listening; + sc->addr_text = addr_text; + sc->local_sockaddr = c->local_sockaddr; + sc->local_socklen = c->local_socklen; + sc->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + sc->start_time = c->start_time; + sc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; + + sc->recv = ngx_quic_stream_recv; + sc->send = ngx_quic_stream_send; + sc->send_chain = ngx_quic_stream_send_chain; + + sc->read->log = log; + sc->write->log = log; + + sc->read->handler = ngx_quic_empty_handler; + sc->write->handler = ngx_quic_empty_handler; + + log->connection = sc->number; + + if (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { + if (id & NGX_QUIC_STREAM_SERVER_INITIATED) { + qs->send_max_data = qc->ctp.initial_max_stream_data_uni; + qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_READ; + qs->send_state = NGX_QUIC_STREAM_SEND_READY; + + } else { + qs->recv_max_data = qc->tp.initial_max_stream_data_uni; + qs->recv_state = NGX_QUIC_STREAM_RECV_RECV; + qs->send_state = NGX_QUIC_STREAM_SEND_DATA_RECVD; + } + + } else { + if (id & NGX_QUIC_STREAM_SERVER_INITIATED) { + qs->send_max_data = qc->ctp.initial_max_stream_data_bidi_remote; + qs->recv_max_data = qc->tp.initial_max_stream_data_bidi_local; + + } else { + qs->send_max_data = qc->ctp.initial_max_stream_data_bidi_local; + qs->recv_max_data = qc->tp.initial_max_stream_data_bidi_remote; + } + + qs->recv_state = NGX_QUIC_STREAM_RECV_RECV; + qs->send_state = NGX_QUIC_STREAM_SEND_READY; + } + + qs->recv_window = qs->recv_max_data; + + cln = ngx_pool_cleanup_add(pool, 0); + if (cln == NULL) { + ngx_close_connection(sc); + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + ngx_reusable_connection(c, reusable); + return NULL; + } + + cln->handler = ngx_quic_stream_cleanup_handler; + cln->data = sc; + + ngx_rbtree_insert(&qc->streams.tree, &qs->node); + + return qs; +} + + +void +ngx_quic_cancelable_stream(ngx_connection_t *c) +{ + ngx_connection_t *pc; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qs = c->quic; + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (!qs->cancelable) { + qs->cancelable = 1; + + if (ngx_quic_can_shutdown(pc) == NGX_OK) { + ngx_reusable_connection(pc, 1); + + if (qc->shutdown) { + ngx_quic_shutdown_quic(pc); + } + } + } +} + + +static void +ngx_quic_empty_handler(ngx_event_t *ev) +{ +} + + +static ssize_t +ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t len; + ngx_buf_t *b; + ngx_chain_t *cl, *in; + ngx_event_t *rev; + ngx_connection_t *pc; + ngx_quic_stream_t *qs; + + qs = c->quic; + pc = qs->parent; + rev = c->read; + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_RESET_RECVD + || qs->recv_state == NGX_QUIC_STREAM_RECV_RESET_READ) + { + qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_READ; + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL recv buf:%uz", qs->id, size); + + if (size == 0) { + return 0; + } + + in = ngx_quic_read_buffer(pc, &qs->recv, size); + if (in == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } + + len = 0; + + for (cl = in; cl; cl = cl->next) { + b = cl->buf; + len += b->last - b->pos; + buf = ngx_cpymem(buf, b->pos, b->last - b->pos); + } + + ngx_quic_free_chain(pc, in); + + if (len == 0) { + rev->ready = 0; + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_DATA_RECVD + && qs->recv_offset == qs->recv_final_size) + { + qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_READ; + } + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_DATA_READ) { + rev->eof = 1; + return 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL recv() not ready", qs->id); + return NGX_AGAIN; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL recv len:%z", qs->id, len); + + if (ngx_quic_update_flow(qs, qs->recv_offset + len) != NGX_OK) { + return NGX_ERROR; + } + + return len; +} + + +static ssize_t +ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, size_t size) +{ + ngx_buf_t b; + ngx_chain_t cl; + + ngx_memzero(&b, sizeof(ngx_buf_t)); + + b.memory = 1; + b.pos = buf; + b.last = buf + size; + + cl.buf = &b; + cl.next = NULL; + + if (ngx_quic_stream_send_chain(c, &cl, 0) == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } + + if (b.pos == buf) { + return NGX_AGAIN; + } + + return b.pos - buf; +} + + +static ngx_chain_t * +ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + uint64_t n, flow; + ngx_event_t *wev; + ngx_connection_t *pc; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qs = c->quic; + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + wev = c->write; + + if (qs->send_state != NGX_QUIC_STREAM_SEND_READY + && qs->send_state != NGX_QUIC_STREAM_SEND_SEND) + { + wev->error = 1; + return NGX_CHAIN_ERROR; + } + + qs->send_state = NGX_QUIC_STREAM_SEND_SEND; + + flow = qs->acked + qc->conf->stream_buffer_size - qs->sent; + + if (flow == 0) { + wev->ready = 0; + return in; + } + + if (limit == 0 || limit > (off_t) flow) { + limit = flow; + } + + n = qs->send.size; + + in = ngx_quic_write_buffer(pc, &qs->send, in, limit, qs->sent); + if (in == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + n = qs->send.size - n; + c->sent += n; + qs->sent += n; + qc->streams.sent += n; + + if (flow == n) { + wev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic send_chain sent:%uL", n); + + if (ngx_quic_stream_flush(qs) != NGX_OK) { + return NGX_CHAIN_ERROR; + } + + return in; +} + + +static ngx_int_t +ngx_quic_stream_flush(ngx_quic_stream_t *qs) +{ + off_t limit, len; + ngx_uint_t last; + ngx_chain_t *out; + ngx_quic_frame_t *frame; + ngx_connection_t *pc; + ngx_quic_connection_t *qc; + + if (qs->send_state != NGX_QUIC_STREAM_SEND_SEND) { + return NGX_OK; + } + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (qc->streams.send_max_data == 0) { + qc->streams.send_max_data = qc->ctp.initial_max_data; + } + + limit = ngx_min(qc->streams.send_max_data - qc->streams.send_offset, + qs->send_max_data - qs->send_offset); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL flush limit:%O", qs->id, limit); + + len = qs->send.offset; + + out = ngx_quic_read_buffer(pc, &qs->send, limit); + if (out == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } + + len = qs->send.offset - len; + last = 0; + + if (qs->send_final_size != (uint64_t) -1 + && qs->send_final_size == qs->send.offset) + { + qs->send_state = NGX_QUIC_STREAM_SEND_DATA_SENT; + last = 1; + } + + if (len == 0 && !last) { + return NGX_OK; + } + + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_STREAM; + frame->data = out; + + frame->u.stream.off = 1; + frame->u.stream.len = 1; + frame->u.stream.fin = last; + + frame->u.stream.stream_id = qs->id; + frame->u.stream.offset = qs->send_offset; + frame->u.stream.length = len; + + ngx_quic_queue_frame(qc, frame); + + qs->send_offset += len; + qc->streams.send_offset += len; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL flush len:%O last:%ui", + qs->id, len, last); + + if (qs->connection == NULL) { + return ngx_quic_close_stream(qs); + } + + return NGX_OK; +} + + +static void +ngx_quic_stream_cleanup_handler(void *data) +{ + ngx_connection_t *c = data; + + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qs = c->quic; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, qs->parent->log, 0, + "quic stream id:0x%xL cleanup", qs->id); + + if (ngx_quic_shutdown_stream(c, NGX_RDWR_SHUTDOWN) != NGX_OK) { + qs->connection = NULL; + goto failed; + } + + qs->connection = NULL; + + if (ngx_quic_close_stream(qs) != NGX_OK) { + goto failed; + } + + return; + +failed: + + qc = ngx_quic_get_connection(qs->parent); + qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; + + ngx_post_event(&qc->close, &ngx_posted_events); +} + + +static ngx_int_t +ngx_quic_close_stream(ngx_quic_stream_t *qs) +{ + ngx_connection_t *pc; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (!qc->closing) { + /* make sure everything is sent and final size is received */ + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_RECV) { + return NGX_OK; + } + + if (qs->send_state != NGX_QUIC_STREAM_SEND_DATA_RECVD + && qs->send_state != NGX_QUIC_STREAM_SEND_RESET_RECVD) + { + return NGX_OK; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL close", qs->id); + + ngx_quic_free_buffer(pc, &qs->send); + ngx_quic_free_buffer(pc, &qs->recv); + + ngx_rbtree_delete(&qc->streams.tree, &qs->node); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + + if (qc->closing) { + /* schedule handler call to continue ngx_quic_close_connection() */ + ngx_post_event(&qc->close, &ngx_posted_events); + return NGX_OK; + } + + if (!pc->reusable && ngx_quic_can_shutdown(pc) == NGX_OK) { + ngx_reusable_connection(pc, 1); + } + + if (qc->shutdown) { + ngx_quic_shutdown_quic(pc); + return NGX_OK; + } + + if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) { + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_MAX_STREAMS; + + if (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { + frame->u.max_streams.limit = ++qc->streams.client_max_streams_uni; + frame->u.max_streams.bidi = 0; + + } else { + frame->u.max_streams.limit = ++qc->streams.client_max_streams_bidi; + frame->u.max_streams.bidi = 1; + } + + ngx_quic_queue_frame(qc, frame); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_can_shutdown(ngx_connection_t *c) +{ + ngx_rbtree_t *tree; + ngx_rbtree_node_t *node; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + tree = &qc->streams.tree; + + if (tree->root != tree->sentinel) { + for (node = ngx_rbtree_min(tree->root, tree->sentinel); + node; + node = ngx_rbtree_next(tree, node)) + { + qs = (ngx_quic_stream_t *) node; + + if (!qs->cancelable) { + return NGX_DECLINED; + } + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, + ngx_quic_frame_t *frame) +{ + uint64_t last; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + ngx_quic_stream_frame_t *f; + + qc = ngx_quic_get_connection(c); + f = &frame->u.stream; + + if ((f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) + && (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED)) + { + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NGX_ERROR; + } + + /* no overflow since both values are 62-bit */ + last = f->offset + f->length; + + qs = ngx_quic_get_stream(c, f->stream_id); + + if (qs == NULL) { + return NGX_ERROR; + } + + if (qs == NGX_QUIC_STREAM_GONE) { + return NGX_OK; + } + + if (qs->recv_state != NGX_QUIC_STREAM_RECV_RECV + && qs->recv_state != NGX_QUIC_STREAM_RECV_SIZE_KNOWN) + { + return NGX_OK; + } + + if (ngx_quic_control_flow(qs, last) != NGX_OK) { + return NGX_ERROR; + } + + if (qs->recv_final_size != (uint64_t) -1 && last > qs->recv_final_size) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + if (last < qs->recv_offset) { + return NGX_OK; + } + + if (f->fin) { + if (qs->recv_final_size != (uint64_t) -1 && qs->recv_final_size != last) + { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + if (qs->recv_last > last) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + qs->recv_final_size = last; + qs->recv_state = NGX_QUIC_STREAM_RECV_SIZE_KNOWN; + } + + if (ngx_quic_write_buffer(c, &qs->recv, frame->data, f->length, f->offset) + == NGX_CHAIN_ERROR) + { + return NGX_ERROR; + } + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_SIZE_KNOWN + && qs->recv.size == qs->recv_final_size) + { + qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_RECVD; + } + + if (qs->connection == NULL) { + return ngx_quic_close_stream(qs); + } + + if (f->offset <= qs->recv_offset) { + ngx_quic_set_event(qs->connection->read); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_max_data_frame(ngx_connection_t *c, + ngx_quic_max_data_frame_t *f) +{ + ngx_rbtree_t *tree; + ngx_rbtree_node_t *node; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + tree = &qc->streams.tree; + + if (f->max_data <= qc->streams.send_max_data) { + return NGX_OK; + } + + if (tree->root == tree->sentinel + || qc->streams.send_offset < qc->streams.send_max_data) + { + /* not blocked on MAX_DATA */ + qc->streams.send_max_data = f->max_data; + return NGX_OK; + } + + qc->streams.send_max_data = f->max_data; + node = ngx_rbtree_min(tree->root, tree->sentinel); + + while (node && qc->streams.send_offset < qc->streams.send_max_data) { + + qs = (ngx_quic_stream_t *) node; + node = ngx_rbtree_next(tree, node); + + if (ngx_quic_stream_flush(qs) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_streams_blocked_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_streams_blocked_frame_t *f) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_data_blocked_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_data_blocked_frame_t *f) +{ + return ngx_quic_update_max_data(c); +} + + +ngx_int_t +ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_stream_data_blocked_frame_t *f) +{ + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) + && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED)) + { + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NGX_ERROR; + } + + qs = ngx_quic_get_stream(c, f->id); + + if (qs == NULL) { + return NGX_ERROR; + } + + if (qs == NGX_QUIC_STREAM_GONE) { + return NGX_OK; + } + + return ngx_quic_update_max_stream_data(qs); +} + + +ngx_int_t +ngx_quic_handle_max_stream_data_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_stream_data_frame_t *f) +{ + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) + && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) + { + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NGX_ERROR; + } + + qs = ngx_quic_get_stream(c, f->id); + + if (qs == NULL) { + return NGX_ERROR; + } + + if (qs == NGX_QUIC_STREAM_GONE) { + return NGX_OK; + } + + if (f->limit <= qs->send_max_data) { + return NGX_OK; + } + + if (qs->send_offset < qs->send_max_data) { + /* not blocked on MAX_STREAM_DATA */ + qs->send_max_data = f->limit; + return NGX_OK; + } + + qs->send_max_data = f->limit; + + return ngx_quic_stream_flush(qs); +} + + +ngx_int_t +ngx_quic_handle_reset_stream_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_reset_stream_frame_t *f) +{ + ngx_event_t *rev; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) + && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED)) + { + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NGX_ERROR; + } + + qs = ngx_quic_get_stream(c, f->id); + + if (qs == NULL) { + return NGX_ERROR; + } + + if (qs == NGX_QUIC_STREAM_GONE) { + return NGX_OK; + } + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_RESET_RECVD + || qs->recv_state == NGX_QUIC_STREAM_RECV_RESET_READ) + { + return NGX_OK; + } + + qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD; + + if (ngx_quic_control_flow(qs, f->final_size) != NGX_OK) { + return NGX_ERROR; + } + + if (qs->recv_final_size != (uint64_t) -1 + && qs->recv_final_size != f->final_size) + { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + if (qs->recv_last > f->final_size) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + qs->recv_final_size = f->final_size; + + if (ngx_quic_update_flow(qs, qs->recv_final_size) != NGX_OK) { + return NGX_ERROR; + } + + if (qs->connection == NULL) { + return ngx_quic_close_stream(qs); + } + + rev = qs->connection->read; + rev->error = 1; + + ngx_quic_set_event(rev); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_stop_sending_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f) +{ + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) + && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) + { + qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; + return NGX_ERROR; + } + + qs = ngx_quic_get_stream(c, f->id); + + if (qs == NULL) { + return NGX_ERROR; + } + + if (qs == NGX_QUIC_STREAM_GONE) { + return NGX_OK; + } + + if (ngx_quic_do_reset_stream(qs, f->error_code) != NGX_OK) { + return NGX_ERROR; + } + + if (qs->connection == NULL) { + return ngx_quic_close_stream(qs); + } + + ngx_quic_set_event(qs->connection->write); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_handle_max_streams_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f) +{ + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + if (f->bidi) { + if (qc->streams.server_max_streams_bidi < f->limit) { + qc->streams.server_max_streams_bidi = f->limit; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic max_streams_bidi:%uL", f->limit); + } + + } else { + if (qc->streams.server_max_streams_uni < f->limit) { + qc->streams.server_max_streams_uni = f->limit; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic max_streams_uni:%uL", f->limit); + } + } + + return NGX_OK; +} + + +void +ngx_quic_handle_stream_ack(ngx_connection_t *c, ngx_quic_frame_t *f) +{ + uint64_t acked; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + switch (f->type) { + + case NGX_QUIC_FT_RESET_STREAM: + + qs = ngx_quic_find_stream(&qc->streams.tree, f->u.reset_stream.id); + if (qs == NULL) { + return; + } + + qs->send_state = NGX_QUIC_STREAM_SEND_RESET_RECVD; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL ack reset final_size:%uL", + qs->id, f->u.reset_stream.final_size); + + break; + + case NGX_QUIC_FT_STREAM: + + qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id); + if (qs == NULL) { + return; + } + + acked = qs->acked; + qs->acked += f->u.stream.length; + + if (f->u.stream.fin) { + qs->fin_acked = 1; + } + + if (qs->send_state == NGX_QUIC_STREAM_SEND_DATA_SENT + && qs->acked == qs->sent && qs->fin_acked) + { + qs->send_state = NGX_QUIC_STREAM_SEND_DATA_RECVD; + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL ack len:%uL fin:%d unacked:%uL", + qs->id, f->u.stream.length, f->u.stream.fin, + qs->sent - qs->acked); + + if (qs->connection + && qs->sent - acked == qc->conf->stream_buffer_size + && f->u.stream.length > 0) + { + ngx_quic_set_event(qs->connection->write); + } + + break; + + default: + return; + } + + if (qs->connection == NULL) { + ngx_quic_close_stream(qs); + } +} + + +static ngx_int_t +ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last) +{ + uint64_t len; + ngx_connection_t *pc; + ngx_quic_connection_t *qc; + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (last <= qs->recv_last) { + return NGX_OK; + } + + len = last - qs->recv_last; + + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL flow control msd:%uL/%uL md:%uL/%uL", + qs->id, last, qs->recv_max_data, qc->streams.recv_last + len, + qc->streams.recv_max_data); + + qs->recv_last += len; + + if (qs->recv_state == NGX_QUIC_STREAM_RECV_RECV + && qs->recv_last > qs->recv_max_data) + { + qc->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; + return NGX_ERROR; + } + + qc->streams.recv_last += len; + + if (qc->streams.recv_last > qc->streams.recv_max_data) { + qc->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_update_flow(ngx_quic_stream_t *qs, uint64_t last) +{ + uint64_t len; + ngx_connection_t *pc; + ngx_quic_connection_t *qc; + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (last <= qs->recv_offset) { + return NGX_OK; + } + + len = last - qs->recv_offset; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL flow update %uL", qs->id, last); + + qs->recv_offset += len; + + if (qs->recv_max_data <= qs->recv_offset + qs->recv_window / 2) { + if (ngx_quic_update_max_stream_data(qs) != NGX_OK) { + return NGX_ERROR; + } + } + + qc->streams.recv_offset += len; + + if (qc->streams.recv_max_data + <= qc->streams.recv_offset + qc->streams.recv_window / 2) + { + if (ngx_quic_update_max_data(pc) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs) +{ + uint64_t recv_max_data; + ngx_connection_t *pc; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + + if (qs->recv_state != NGX_QUIC_STREAM_RECV_RECV) { + return NGX_OK; + } + + recv_max_data = qs->recv_offset + qs->recv_window; + + if (qs->recv_max_data == recv_max_data) { + return NGX_OK; + } + + qs->recv_max_data = recv_max_data; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL flow update msd:%uL", + qs->id, qs->recv_max_data); + + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_MAX_STREAM_DATA; + frame->u.max_stream_data.id = qs->id; + frame->u.max_stream_data.limit = qs->recv_max_data; + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_update_max_data(ngx_connection_t *c) +{ + uint64_t recv_max_data; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + recv_max_data = qc->streams.recv_offset + qc->streams.recv_window; + + if (qc->streams.recv_max_data == recv_max_data) { + return NGX_OK; + } + + qc->streams.recv_max_data = recv_max_data; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic flow update md:%uL", qc->streams.recv_max_data); + + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_MAX_DATA; + frame->u.max_data.max_data = qc->streams.recv_max_data; + + ngx_quic_queue_frame(qc, frame); + + return NGX_OK; +} + + +static void +ngx_quic_set_event(ngx_event_t *ev) +{ + ev->ready = 1; + + if (ev->active) { + ngx_post_event(ev, &ngx_posted_events); + } +} diff --git a/src/event/quic/ngx_event_quic_streams.h b/src/event/quic/ngx_event_quic_streams.h new file mode 100644 index 0000000..fb6dbbd --- /dev/null +++ b/src/event/quic/ngx_event_quic_streams.h @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_STREAMS_H_INCLUDED_ +#define _NGX_EVENT_QUIC_STREAMS_H_INCLUDED_ + + +#include +#include + + +ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); +void ngx_quic_handle_stream_ack(ngx_connection_t *c, + ngx_quic_frame_t *f); +ngx_int_t ngx_quic_handle_max_data_frame(ngx_connection_t *c, + ngx_quic_max_data_frame_t *f); +ngx_int_t ngx_quic_handle_streams_blocked_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_streams_blocked_frame_t *f); +ngx_int_t ngx_quic_handle_data_blocked_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_data_blocked_frame_t *f); +ngx_int_t ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_stream_data_blocked_frame_t *f); +ngx_int_t ngx_quic_handle_max_stream_data_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_stream_data_frame_t *f); +ngx_int_t ngx_quic_handle_reset_stream_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_reset_stream_frame_t *f); +ngx_int_t ngx_quic_handle_stop_sending_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f); +ngx_int_t ngx_quic_handle_max_streams_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f); + +ngx_int_t ngx_quic_init_streams(ngx_connection_t *c); +void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, + uint64_t id); +ngx_int_t ngx_quic_close_streams(ngx_connection_t *c, + ngx_quic_connection_t *qc); + +#endif /* _NGX_EVENT_QUIC_STREAMS_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_tokens.c b/src/event/quic/ngx_event_quic_tokens.c new file mode 100644 index 0000000..c1da0d4 --- /dev/null +++ b/src/event/quic/ngx_event_quic_tokens.c @@ -0,0 +1,309 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include +#include + + +static void ngx_quic_address_hash(struct sockaddr *sockaddr, socklen_t socklen, + ngx_uint_t no_port, u_char buf[20]); + + +ngx_int_t +ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret, + u_char *token) +{ + ngx_str_t tmp; + + tmp.data = secret; + tmp.len = NGX_QUIC_SR_KEY_LEN; + + if (ngx_quic_derive_key(c->log, "sr_token_key", &tmp, cid, token, + NGX_QUIC_SR_TOKEN_LEN) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stateless reset token %*xs", + (size_t) NGX_QUIC_SR_TOKEN_LEN, token); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_new_token(ngx_log_t *log, struct sockaddr *sockaddr, + socklen_t socklen, u_char *key, ngx_str_t *token, ngx_str_t *odcid, + time_t exp, ngx_uint_t is_retry) +{ + int len, iv_len; + u_char *p, *iv; + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *cipher; + + u_char in[NGX_QUIC_MAX_TOKEN_SIZE]; + + ngx_quic_address_hash(sockaddr, socklen, !is_retry, in); + + p = in + 20; + + p = ngx_cpymem(p, &exp, sizeof(time_t)); + + *p++ = is_retry ? 1 : 0; + + if (odcid) { + *p++ = odcid->len; + p = ngx_cpymem(p, odcid->data, odcid->len); + + } else { + *p++ = 0; + } + + len = p - in; + + cipher = EVP_aes_256_gcm(); + iv_len = NGX_QUIC_AES_256_GCM_IV_LEN; + + if ((size_t) (iv_len + len + NGX_QUIC_AES_256_GCM_TAG_LEN) > token->len) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "quic token buffer is too small"); + return NGX_ERROR; + } + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + return NGX_ERROR; + } + + iv = token->data; + + if (RAND_bytes(iv, iv_len) <= 0 + || !EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv)) + { + EVP_CIPHER_CTX_free(ctx); + return NGX_ERROR; + } + + token->len = iv_len; + + if (EVP_EncryptUpdate(ctx, token->data + token->len, &len, in, len) != 1) { + EVP_CIPHER_CTX_free(ctx); + return NGX_ERROR; + } + + token->len += len; + + if (EVP_EncryptFinal_ex(ctx, token->data + token->len, &len) <= 0) { + EVP_CIPHER_CTX_free(ctx); + return NGX_ERROR; + } + + token->len += len; + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, + NGX_QUIC_AES_256_GCM_TAG_LEN, + token->data + token->len) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + return NGX_ERROR; + } + + token->len += NGX_QUIC_AES_256_GCM_TAG_LEN; + + EVP_CIPHER_CTX_free(ctx); + +#ifdef NGX_QUIC_DEBUG_PACKETS + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, + "quic new token len:%uz %xV", token->len, token); +#endif + + return NGX_OK; +} + + +static void +ngx_quic_address_hash(struct sockaddr *sockaddr, socklen_t socklen, + ngx_uint_t no_port, u_char buf[20]) +{ + size_t len; + u_char *data; + ngx_sha1_t sha1; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + len = (size_t) socklen; + data = (u_char *) sockaddr; + + if (no_port) { + switch (sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sockaddr; + + len = sizeof(struct in6_addr); + data = sin6->sin6_addr.s6_addr; + + break; +#endif + + case AF_INET: + sin = (struct sockaddr_in *) sockaddr; + + len = sizeof(in_addr_t); + data = (u_char *) &sin->sin_addr; + + break; + } + } + + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, data, len); + ngx_sha1_final(buf, &sha1); +} + + +ngx_int_t +ngx_quic_validate_token(ngx_connection_t *c, u_char *key, + ngx_quic_header_t *pkt) +{ + int len, tlen, iv_len; + u_char *iv, *p; + time_t now, exp; + size_t total; + ngx_str_t odcid; + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *cipher; + + u_char addr_hash[20]; + u_char tdec[NGX_QUIC_MAX_TOKEN_SIZE]; + +#if NGX_SUPPRESS_WARN + ngx_str_null(&odcid); +#endif + + /* Retry token or NEW_TOKEN in a previous connection */ + + cipher = EVP_aes_256_gcm(); + iv = pkt->token.data; + iv_len = NGX_QUIC_AES_256_GCM_IV_LEN; + + /* sanity checks */ + + if (pkt->token.len < (size_t) iv_len + NGX_QUIC_AES_256_GCM_TAG_LEN) { + goto garbage; + } + + if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE + + NGX_QUIC_AES_256_GCM_TAG_LEN) + { + goto garbage; + } + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + return NGX_ERROR; + } + + if (!EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) { + EVP_CIPHER_CTX_free(ctx); + return NGX_ERROR; + } + + p = pkt->token.data + iv_len; + len = pkt->token.len - iv_len - NGX_QUIC_AES_256_GCM_TAG_LEN; + + if (EVP_DecryptUpdate(ctx, tdec, &tlen, p, len) != 1) { + EVP_CIPHER_CTX_free(ctx); + goto garbage; + } + total = tlen; + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + NGX_QUIC_AES_256_GCM_TAG_LEN, p + len) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + goto garbage; + } + + if (EVP_DecryptFinal_ex(ctx, tdec + tlen, &tlen) <= 0) { + EVP_CIPHER_CTX_free(ctx); + goto garbage; + } + total += tlen; + + EVP_CIPHER_CTX_free(ctx); + + if (total < (20 + sizeof(time_t) + 2)) { + goto garbage; + } + + p = tdec + 20; + + ngx_memcpy(&exp, p, sizeof(time_t)); + p += sizeof(time_t); + + pkt->retried = (*p++ == 1); + + ngx_quic_address_hash(c->sockaddr, c->socklen, !pkt->retried, addr_hash); + + if (ngx_memcmp(tdec, addr_hash, 20) != 0) { + goto bad_token; + } + + odcid.len = *p++; + if (odcid.len) { + if (odcid.len > NGX_QUIC_MAX_CID_LEN) { + goto bad_token; + } + + if ((size_t)(tdec + total - p) < odcid.len) { + goto bad_token; + } + + odcid.data = p; + } + + now = ngx_time(); + + if (now > exp) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token"); + return NGX_DECLINED; + } + + if (odcid.len) { + pkt->odcid.len = odcid.len; + pkt->odcid.data = pkt->odcid_buf; + ngx_memcpy(pkt->odcid.data, odcid.data, odcid.len); + + } else { + pkt->odcid = pkt->dcid; + } + + pkt->validated = 1; + + return NGX_OK; + +garbage: + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic garbage token"); + + return NGX_ABORT; + +bad_token: + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token"); + + return NGX_DECLINED; +} diff --git a/src/event/quic/ngx_event_quic_tokens.h b/src/event/quic/ngx_event_quic_tokens.h new file mode 100644 index 0000000..ee3fe5b --- /dev/null +++ b/src/event/quic/ngx_event_quic_tokens.h @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_TOKENS_H_INCLUDED_ +#define _NGX_EVENT_QUIC_TOKENS_H_INCLUDED_ + + +#include +#include + + +#define NGX_QUIC_MAX_TOKEN_SIZE 64 + /* SHA-1(addr)=20 + sizeof(time_t) + retry(1) + odcid.len(1) + odcid */ + +#define NGX_QUIC_AES_256_GCM_IV_LEN 12 +#define NGX_QUIC_AES_256_GCM_TAG_LEN 16 + +#define NGX_QUIC_TOKEN_BUF_SIZE (NGX_QUIC_AES_256_GCM_IV_LEN \ + + NGX_QUIC_MAX_TOKEN_SIZE \ + + NGX_QUIC_AES_256_GCM_TAG_LEN) + + +ngx_int_t ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, + u_char *secret, u_char *token); +ngx_int_t ngx_quic_new_token(ngx_log_t *log, struct sockaddr *sockaddr, + socklen_t socklen, u_char *key, ngx_str_t *token, ngx_str_t *odcid, + time_t expires, ngx_uint_t is_retry); +ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, + u_char *key, ngx_quic_header_t *pkt); + +#endif /* _NGX_EVENT_QUIC_TOKENS_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c new file mode 100644 index 0000000..19670a6 --- /dev/null +++ b/src/event/quic/ngx_event_quic_transport.c @@ -0,0 +1,2202 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +#define NGX_QUIC_LONG_DCID_LEN_OFFSET 5 +#define NGX_QUIC_LONG_DCID_OFFSET 6 +#define NGX_QUIC_SHORT_DCID_OFFSET 1 + +#define NGX_QUIC_STREAM_FRAME_FIN 0x01 +#define NGX_QUIC_STREAM_FRAME_LEN 0x02 +#define NGX_QUIC_STREAM_FRAME_OFF 0x04 + + +#if (NGX_HAVE_NONALIGNED) + +#define ngx_quic_parse_uint16(p) ntohs(*(uint16_t *) (p)) +#define ngx_quic_parse_uint32(p) ntohl(*(uint32_t *) (p)) + +#define ngx_quic_write_uint16 ngx_quic_write_uint16_aligned +#define ngx_quic_write_uint32 ngx_quic_write_uint32_aligned + +#else + +#define ngx_quic_parse_uint16(p) ((p)[0] << 8 | (p)[1]) +#define ngx_quic_parse_uint32(p) \ + ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) + +#define ngx_quic_write_uint16(p, s) \ + ((p)[0] = (u_char) ((s) >> 8), \ + (p)[1] = (u_char) (s), \ + (p) + sizeof(uint16_t)) + +#define ngx_quic_write_uint32(p, s) \ + ((p)[0] = (u_char) ((s) >> 24), \ + (p)[1] = (u_char) ((s) >> 16), \ + (p)[2] = (u_char) ((s) >> 8), \ + (p)[3] = (u_char) (s), \ + (p) + sizeof(uint32_t)) + +#endif + +#define ngx_quic_write_uint64(p, s) \ + ((p)[0] = (u_char) ((s) >> 56), \ + (p)[1] = (u_char) ((s) >> 48), \ + (p)[2] = (u_char) ((s) >> 40), \ + (p)[3] = (u_char) ((s) >> 32), \ + (p)[4] = (u_char) ((s) >> 24), \ + (p)[5] = (u_char) ((s) >> 16), \ + (p)[6] = (u_char) ((s) >> 8), \ + (p)[7] = (u_char) (s), \ + (p) + sizeof(uint64_t)) + +#define ngx_quic_write_uint24(p, s) \ + ((p)[0] = (u_char) ((s) >> 16), \ + (p)[1] = (u_char) ((s) >> 8), \ + (p)[2] = (u_char) (s), \ + (p) + 3) + +#define ngx_quic_write_uint16_aligned(p, s) \ + (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t)) + +#define ngx_quic_write_uint32_aligned(p, s) \ + (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t)) + +#define ngx_quic_build_int_set(p, value, len, bits) \ + (*(p)++ = ((value >> ((len) * 8)) & 0xff) | ((bits) << 6)) + + +static u_char *ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out); +static ngx_uint_t ngx_quic_varint_len(uint64_t value); +static void ngx_quic_build_int(u_char **pos, uint64_t value); + +static u_char *ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value); +static u_char *ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value); +static u_char *ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len, + u_char **out); +static u_char *ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len, + u_char *dst); + +static ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt, + size_t dcid_len); +static ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt); +static ngx_int_t ngx_quic_supported_version(uint32_t version); +static ngx_int_t ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt); + +static size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out, + u_char **pnp); +static size_t ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out, + u_char **pnp); + +static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt, + ngx_uint_t frame_type); +static size_t ngx_quic_create_ping(u_char *p); +static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack, + ngx_chain_t *ranges); +static size_t ngx_quic_create_reset_stream(u_char *p, + ngx_quic_reset_stream_frame_t *rs); +static size_t ngx_quic_create_stop_sending(u_char *p, + ngx_quic_stop_sending_frame_t *ss); +static size_t ngx_quic_create_crypto(u_char *p, + ngx_quic_crypto_frame_t *crypto, ngx_chain_t *data); +static size_t ngx_quic_create_hs_done(u_char *p); +static size_t ngx_quic_create_new_token(u_char *p, + ngx_quic_new_token_frame_t *token, ngx_chain_t *data); +static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf, + ngx_chain_t *data); +static size_t ngx_quic_create_max_streams(u_char *p, + ngx_quic_max_streams_frame_t *ms); +static size_t ngx_quic_create_max_stream_data(u_char *p, + ngx_quic_max_stream_data_frame_t *ms); +static size_t ngx_quic_create_max_data(u_char *p, + ngx_quic_max_data_frame_t *md); +static size_t ngx_quic_create_path_challenge(u_char *p, + ngx_quic_path_challenge_frame_t *pc); +static size_t ngx_quic_create_path_response(u_char *p, + ngx_quic_path_challenge_frame_t *pc); +static size_t ngx_quic_create_new_connection_id(u_char *p, + ngx_quic_new_conn_id_frame_t *rcid); +static size_t ngx_quic_create_retire_connection_id(u_char *p, + ngx_quic_retire_cid_frame_t *rcid); +static size_t ngx_quic_create_close(u_char *p, ngx_quic_frame_t *f); + +static ngx_int_t ngx_quic_parse_transport_param(u_char *p, u_char *end, + uint16_t id, ngx_quic_tp_t *dst); + + +uint32_t ngx_quic_versions[] = { + /* QUICv1 */ + 0x00000001, +}; + +#define NGX_QUIC_NVERSIONS \ + (sizeof(ngx_quic_versions) / sizeof(ngx_quic_versions[0])) + + +static ngx_inline u_char * +ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out) +{ + u_char *p; + uint64_t value; + ngx_uint_t len; + + if (pos >= end) { + return NULL; + } + + p = pos; + len = 1 << (*p >> 6); + + value = *p++ & 0x3f; + + if ((size_t)(end - p) < (len - 1)) { + return NULL; + } + + while (--len) { + value = (value << 8) + *p++; + } + + *out = value; + + return p; +} + + +static ngx_inline u_char * +ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value) +{ + if ((size_t)(end - pos) < 1) { + return NULL; + } + + *value = *pos; + + return pos + 1; +} + + +static ngx_inline u_char * +ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value) +{ + if ((size_t)(end - pos) < sizeof(uint32_t)) { + return NULL; + } + + *value = ngx_quic_parse_uint32(pos); + + return pos + sizeof(uint32_t); +} + + +static ngx_inline u_char * +ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len, u_char **out) +{ + if ((size_t)(end - pos) < len) { + return NULL; + } + + *out = pos; + + return pos + len; +} + + +static u_char * +ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len, u_char *dst) +{ + if ((size_t)(end - pos) < len) { + return NULL; + } + + ngx_memcpy(dst, pos, len); + + return pos + len; +} + + +static ngx_inline ngx_uint_t +ngx_quic_varint_len(uint64_t value) +{ + if (value < (1 << 6)) { + return 1; + } + + if (value < (1 << 14)) { + return 2; + } + + if (value < (1 << 30)) { + return 4; + } + + return 8; +} + + +static ngx_inline void +ngx_quic_build_int(u_char **pos, uint64_t value) +{ + u_char *p; + + p = *pos; + + if (value < (1 << 6)) { + ngx_quic_build_int_set(p, value, 0, 0); + + } else if (value < (1 << 14)) { + ngx_quic_build_int_set(p, value, 1, 1); + ngx_quic_build_int_set(p, value, 0, 0); + + } else if (value < (1 << 30)) { + ngx_quic_build_int_set(p, value, 3, 2); + ngx_quic_build_int_set(p, value, 2, 0); + ngx_quic_build_int_set(p, value, 1, 0); + ngx_quic_build_int_set(p, value, 0, 0); + + } else { + ngx_quic_build_int_set(p, value, 7, 3); + ngx_quic_build_int_set(p, value, 6, 0); + ngx_quic_build_int_set(p, value, 5, 0); + ngx_quic_build_int_set(p, value, 4, 0); + ngx_quic_build_int_set(p, value, 3, 0); + ngx_quic_build_int_set(p, value, 2, 0); + ngx_quic_build_int_set(p, value, 1, 0); + ngx_quic_build_int_set(p, value, 0, 0); + } + + *pos = p; +} + + +ngx_int_t +ngx_quic_parse_packet(ngx_quic_header_t *pkt) +{ + if (!ngx_quic_long_pkt(pkt->flags)) { + pkt->level = ssl_encryption_application; + + if (ngx_quic_parse_short_header(pkt, NGX_QUIC_SERVER_CID_LEN) != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; + } + + if (ngx_quic_parse_long_header(pkt) != NGX_OK) { + return NGX_ERROR; + } + + if (!ngx_quic_supported_version(pkt->version)) { + return NGX_ABORT; + } + + if (ngx_quic_parse_long_header_v1(pkt) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_parse_short_header(ngx_quic_header_t *pkt, size_t dcid_len) +{ + u_char *p, *end; + + p = pkt->raw->pos; + end = pkt->data + pkt->len; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic packet rx short flags:%xd", pkt->flags); + + if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set"); + return NGX_ERROR; + } + + pkt->dcid.len = dcid_len; + + p = ngx_quic_read_bytes(p, end, dcid_len, &pkt->dcid.data); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet is too small to read dcid"); + return NGX_ERROR; + } + + pkt->raw->pos = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_parse_long_header(ngx_quic_header_t *pkt) +{ + u_char *p, *end; + uint8_t idlen; + + p = pkt->raw->pos; + end = pkt->data + pkt->len; + + p = ngx_quic_read_uint32(p, end, &pkt->version); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet is too small to read version"); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic packet rx long flags:%xd version:%xD", + pkt->flags, pkt->version); + + if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set"); + return NGX_ERROR; + } + + p = ngx_quic_read_uint8(p, end, &idlen); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet is too small to read dcid len"); + return NGX_ERROR; + } + + if (idlen > NGX_QUIC_CID_LEN_MAX) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet dcid is too long"); + return NGX_ERROR; + } + + pkt->dcid.len = idlen; + + p = ngx_quic_read_bytes(p, end, idlen, &pkt->dcid.data); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet is too small to read dcid"); + return NGX_ERROR; + } + + p = ngx_quic_read_uint8(p, end, &idlen); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet is too small to read scid len"); + return NGX_ERROR; + } + + if (idlen > NGX_QUIC_CID_LEN_MAX) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet scid is too long"); + return NGX_ERROR; + } + + pkt->scid.len = idlen; + + p = ngx_quic_read_bytes(p, end, idlen, &pkt->scid.data); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet is too small to read scid"); + return NGX_ERROR; + } + + pkt->raw->pos = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_quic_supported_version(uint32_t version) +{ + ngx_uint_t i; + + for (i = 0; i < NGX_QUIC_NVERSIONS; i++) { + if (ngx_quic_versions[i] == version) { + return 1; + } + } + + return 0; +} + + +static ngx_int_t +ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt) +{ + u_char *p, *end; + uint64_t varint; + + p = pkt->raw->pos; + end = pkt->raw->last; + + pkt->log->action = "parsing quic long header"; + + if (ngx_quic_pkt_in(pkt->flags)) { + + if (pkt->len < NGX_QUIC_MIN_INITIAL_SIZE) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic UDP datagram is too small for initial packet"); + return NGX_DECLINED; + } + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic failed to parse token length"); + return NGX_ERROR; + } + + pkt->token.len = varint; + + p = ngx_quic_read_bytes(p, end, pkt->token.len, &pkt->token.data); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic packet too small to read token data"); + return NGX_ERROR; + } + + pkt->level = ssl_encryption_initial; + + } else if (ngx_quic_pkt_zrtt(pkt->flags)) { + pkt->level = ssl_encryption_early_data; + + } else if (ngx_quic_pkt_hs(pkt->flags)) { + pkt->level = ssl_encryption_handshake; + + } else { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic bad packet type"); + return NGX_DECLINED; + } + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic bad packet length"); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic packet rx %s len:%uL", + ngx_quic_level_name(pkt->level), varint); + + if (varint > (uint64_t) ((pkt->data + pkt->len) - p)) { + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic truncated %s packet", + ngx_quic_level_name(pkt->level)); + return NGX_ERROR; + } + + pkt->raw->pos = p; + pkt->len = p + varint - pkt->data; + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_get_packet_dcid(ngx_log_t *log, u_char *data, size_t n, + ngx_str_t *dcid) +{ + size_t len, offset; + + if (n == 0) { + goto failed; + } + + if (ngx_quic_long_pkt(*data)) { + if (n < NGX_QUIC_LONG_DCID_LEN_OFFSET + 1) { + goto failed; + } + + len = data[NGX_QUIC_LONG_DCID_LEN_OFFSET]; + offset = NGX_QUIC_LONG_DCID_OFFSET; + + } else { + len = NGX_QUIC_SERVER_CID_LEN; + offset = NGX_QUIC_SHORT_DCID_OFFSET; + } + + if (n < len + offset) { + goto failed; + } + + dcid->len = len; + dcid->data = &data[offset]; + + return NGX_OK; + +failed: + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0, "quic malformed packet"); + + return NGX_ERROR; +} + + +size_t +ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out) +{ + u_char *p, *start; + ngx_uint_t i; + + p = start = out; + + *p++ = pkt->flags; + + /* + * The Version field of a Version Negotiation packet + * MUST be set to 0x00000000 + */ + p = ngx_quic_write_uint32(p, 0); + + *p++ = pkt->dcid.len; + p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len); + + *p++ = pkt->scid.len; + p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len); + + for (i = 0; i < NGX_QUIC_NVERSIONS; i++) { + p = ngx_quic_write_uint32(p, ngx_quic_versions[i]); + } + + return p - start; +} + + +/* returns the amount of payload quic packet of "pkt_len" size may fit or 0 */ +size_t +ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len) +{ + size_t len; + + if (ngx_quic_short_pkt(pkt->flags)) { + + len = 1 + pkt->dcid.len + pkt->num_len + NGX_QUIC_TAG_LEN; + if (len > pkt_len) { + return 0; + } + + return pkt_len - len; + } + + /* flags, version, dcid and scid with lengths and zero-length token */ + len = 5 + 2 + pkt->dcid.len + pkt->scid.len + + (pkt->level == ssl_encryption_initial ? 1 : 0); + + if (len > pkt_len) { + return 0; + } + + /* (pkt_len - len) is 'remainder' packet length (see RFC 9000, 17.2) */ + len += ngx_quic_varint_len(pkt_len - len) + + pkt->num_len + NGX_QUIC_TAG_LEN; + + if (len > pkt_len) { + return 0; + } + + return pkt_len - len; +} + + +size_t +ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, u_char **pnp) +{ + return ngx_quic_short_pkt(pkt->flags) + ? ngx_quic_create_short_header(pkt, out, pnp) + : ngx_quic_create_long_header(pkt, out, pnp); +} + + +static size_t +ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out, + u_char **pnp) +{ + size_t rem_len; + u_char *p, *start; + + rem_len = pkt->num_len + pkt->payload.len + NGX_QUIC_TAG_LEN; + + if (out == NULL) { + return 5 + 2 + pkt->dcid.len + pkt->scid.len + + ngx_quic_varint_len(rem_len) + pkt->num_len + + (pkt->level == ssl_encryption_initial ? 1 : 0); + } + + p = start = out; + + *p++ = pkt->flags; + + p = ngx_quic_write_uint32(p, pkt->version); + + *p++ = pkt->dcid.len; + p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len); + + *p++ = pkt->scid.len; + p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len); + + if (pkt->level == ssl_encryption_initial) { + ngx_quic_build_int(&p, 0); + } + + ngx_quic_build_int(&p, rem_len); + + *pnp = p; + + switch (pkt->num_len) { + case 1: + *p++ = pkt->trunc; + break; + case 2: + p = ngx_quic_write_uint16(p, pkt->trunc); + break; + case 3: + p = ngx_quic_write_uint24(p, pkt->trunc); + break; + case 4: + p = ngx_quic_write_uint32(p, pkt->trunc); + break; + } + + return p - start; +} + + +static size_t +ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out, + u_char **pnp) +{ + u_char *p, *start; + + if (out == NULL) { + return 1 + pkt->dcid.len + pkt->num_len; + } + + p = start = out; + + *p++ = pkt->flags; + + p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len); + + *pnp = p; + + switch (pkt->num_len) { + case 1: + *p++ = pkt->trunc; + break; + case 2: + p = ngx_quic_write_uint16(p, pkt->trunc); + break; + case 3: + p = ngx_quic_write_uint24(p, pkt->trunc); + break; + case 4: + p = ngx_quic_write_uint32(p, pkt->trunc); + break; + } + + return p - start; +} + + +size_t +ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out, + u_char **start) +{ + u_char *p; + + p = out; + + *p++ = pkt->odcid.len; + p = ngx_cpymem(p, pkt->odcid.data, pkt->odcid.len); + + *start = p; + + *p++ = 0xff; + + p = ngx_quic_write_uint32(p, pkt->version); + + *p++ = pkt->dcid.len; + p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len); + + *p++ = pkt->scid.len; + p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len); + + p = ngx_cpymem(p, pkt->token.data, pkt->token.len); + + return p - out; +} + + +ssize_t +ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end, + ngx_quic_frame_t *f) +{ + u_char *p; + uint64_t varint; + ngx_buf_t *b; + ngx_uint_t i; + + b = f->data->buf; + + p = start; + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic failed to obtain quic frame type"); + return NGX_ERROR; + } + + if (varint > NGX_QUIC_FT_LAST) { + pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic unknown frame type 0x%xL", varint); + return NGX_ERROR; + } + + f->type = varint; + + if (ngx_quic_frame_allowed(pkt, f->type) != NGX_OK) { + pkt->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; + return NGX_ERROR; + } + + switch (f->type) { + + case NGX_QUIC_FT_CRYPTO: + + p = ngx_quic_parse_int(p, end, &f->u.crypto.offset); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.crypto.length); + if (p == NULL) { + goto error; + } + + p = ngx_quic_read_bytes(p, end, f->u.crypto.length, &b->pos); + if (p == NULL) { + goto error; + } + + b->last = p; + + break; + + case NGX_QUIC_FT_PADDING: + + while (p < end && *p == NGX_QUIC_FT_PADDING) { + p++; + } + + break; + + case NGX_QUIC_FT_ACK: + case NGX_QUIC_FT_ACK_ECN: + + p = ngx_quic_parse_int(p, end, &f->u.ack.largest); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.ack.delay); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.ack.range_count); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.ack.first_range); + if (p == NULL) { + goto error; + } + + b->pos = p; + + /* process all ranges to get bounds, values are ignored */ + for (i = 0; i < f->u.ack.range_count; i++) { + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + goto error; + } + } + + b->last = p; + + f->u.ack.ranges_length = b->last - b->pos; + + if (f->type == NGX_QUIC_FT_ACK_ECN) { + + p = ngx_quic_parse_int(p, end, &f->u.ack.ect0); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.ack.ect1); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.ack.ce); + if (p == NULL) { + goto error; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0, + "quic ACK ECN counters ect0:%uL ect1:%uL ce:%uL", + f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce); + } + + break; + + case NGX_QUIC_FT_PING: + break; + + case NGX_QUIC_FT_NEW_CONNECTION_ID: + + p = ngx_quic_parse_int(p, end, &f->u.ncid.seqnum); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.ncid.retire); + if (p == NULL) { + goto error; + } + + if (f->u.ncid.retire > f->u.ncid.seqnum) { + goto error; + } + + p = ngx_quic_read_uint8(p, end, &f->u.ncid.len); + if (p == NULL) { + goto error; + } + + if (f->u.ncid.len < 1 || f->u.ncid.len > NGX_QUIC_CID_LEN_MAX) { + goto error; + } + + p = ngx_quic_copy_bytes(p, end, f->u.ncid.len, f->u.ncid.cid); + if (p == NULL) { + goto error; + } + + p = ngx_quic_copy_bytes(p, end, NGX_QUIC_SR_TOKEN_LEN, f->u.ncid.srt); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_RETIRE_CONNECTION_ID: + + p = ngx_quic_parse_int(p, end, &f->u.retire_cid.sequence_number); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_CONNECTION_CLOSE: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: + + p = ngx_quic_parse_int(p, end, &f->u.close.error_code); + if (p == NULL) { + goto error; + } + + if (f->type == NGX_QUIC_FT_CONNECTION_CLOSE) { + p = ngx_quic_parse_int(p, end, &f->u.close.frame_type); + if (p == NULL) { + goto error; + } + } + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + goto error; + } + + f->u.close.reason.len = varint; + + p = ngx_quic_read_bytes(p, end, f->u.close.reason.len, + &f->u.close.reason.data); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_STREAM: + case NGX_QUIC_FT_STREAM1: + case NGX_QUIC_FT_STREAM2: + case NGX_QUIC_FT_STREAM3: + case NGX_QUIC_FT_STREAM4: + case NGX_QUIC_FT_STREAM5: + case NGX_QUIC_FT_STREAM6: + case NGX_QUIC_FT_STREAM7: + + f->u.stream.fin = (f->type & NGX_QUIC_STREAM_FRAME_FIN) ? 1 : 0; + + p = ngx_quic_parse_int(p, end, &f->u.stream.stream_id); + if (p == NULL) { + goto error; + } + + if (f->type & NGX_QUIC_STREAM_FRAME_OFF) { + f->u.stream.off = 1; + + p = ngx_quic_parse_int(p, end, &f->u.stream.offset); + if (p == NULL) { + goto error; + } + + } else { + f->u.stream.off = 0; + f->u.stream.offset = 0; + } + + if (f->type & NGX_QUIC_STREAM_FRAME_LEN) { + f->u.stream.len = 1; + + p = ngx_quic_parse_int(p, end, &f->u.stream.length); + if (p == NULL) { + goto error; + } + + } else { + f->u.stream.len = 0; + f->u.stream.length = end - p; /* up to packet end */ + } + + p = ngx_quic_read_bytes(p, end, f->u.stream.length, &b->pos); + if (p == NULL) { + goto error; + } + + b->last = p; + + f->type = NGX_QUIC_FT_STREAM; + break; + + case NGX_QUIC_FT_MAX_DATA: + + p = ngx_quic_parse_int(p, end, &f->u.max_data.max_data); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_RESET_STREAM: + + p = ngx_quic_parse_int(p, end, &f->u.reset_stream.id); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.reset_stream.error_code); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.reset_stream.final_size); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_STOP_SENDING: + + p = ngx_quic_parse_int(p, end, &f->u.stop_sending.id); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.stop_sending.error_code); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_STREAMS_BLOCKED: + case NGX_QUIC_FT_STREAMS_BLOCKED2: + + p = ngx_quic_parse_int(p, end, &f->u.streams_blocked.limit); + if (p == NULL) { + goto error; + } + + if (f->u.streams_blocked.limit > 0x1000000000000000) { + goto error; + } + + f->u.streams_blocked.bidi = + (f->type == NGX_QUIC_FT_STREAMS_BLOCKED) ? 1 : 0; + break; + + case NGX_QUIC_FT_MAX_STREAMS: + case NGX_QUIC_FT_MAX_STREAMS2: + + p = ngx_quic_parse_int(p, end, &f->u.max_streams.limit); + if (p == NULL) { + goto error; + } + + if (f->u.max_streams.limit > 0x1000000000000000) { + goto error; + } + + f->u.max_streams.bidi = (f->type == NGX_QUIC_FT_MAX_STREAMS) ? 1 : 0; + + break; + + case NGX_QUIC_FT_MAX_STREAM_DATA: + + p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.id); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.limit); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_DATA_BLOCKED: + + p = ngx_quic_parse_int(p, end, &f->u.data_blocked.limit); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_STREAM_DATA_BLOCKED: + + p = ngx_quic_parse_int(p, end, &f->u.stream_data_blocked.id); + if (p == NULL) { + goto error; + } + + p = ngx_quic_parse_int(p, end, &f->u.stream_data_blocked.limit); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_PATH_CHALLENGE: + + p = ngx_quic_copy_bytes(p, end, 8, f->u.path_challenge.data); + if (p == NULL) { + goto error; + } + + break; + + case NGX_QUIC_FT_PATH_RESPONSE: + + p = ngx_quic_copy_bytes(p, end, 8, f->u.path_response.data); + if (p == NULL) { + goto error; + } + + break; + + default: + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic unknown frame type 0x%xi", f->type); + return NGX_ERROR; + } + + f->level = pkt->level; +#if (NGX_DEBUG) + f->pnum = pkt->pn; +#endif + + return p - start; + +error: + + pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; + + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic failed to parse frame type:0x%xi", f->type); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_quic_frame_allowed(ngx_quic_header_t *pkt, ngx_uint_t frame_type) +{ + uint8_t ptype; + + /* + * RFC 9000, 12.4. Frames and Frame Types: Table 3 + * + * Frame permissions per packet: 4 bits: IH01 + */ + static uint8_t ngx_quic_frame_masks[] = { + /* PADDING */ 0xF, + /* PING */ 0xF, + /* ACK */ 0xD, + /* ACK_ECN */ 0xD, + /* RESET_STREAM */ 0x3, + /* STOP_SENDING */ 0x3, + /* CRYPTO */ 0xD, + /* NEW_TOKEN */ 0x0, /* only sent by server */ + /* STREAM */ 0x3, + /* STREAM1 */ 0x3, + /* STREAM2 */ 0x3, + /* STREAM3 */ 0x3, + /* STREAM4 */ 0x3, + /* STREAM5 */ 0x3, + /* STREAM6 */ 0x3, + /* STREAM7 */ 0x3, + /* MAX_DATA */ 0x3, + /* MAX_STREAM_DATA */ 0x3, + /* MAX_STREAMS */ 0x3, + /* MAX_STREAMS2 */ 0x3, + /* DATA_BLOCKED */ 0x3, + /* STREAM_DATA_BLOCKED */ 0x3, + /* STREAMS_BLOCKED */ 0x3, + /* STREAMS_BLOCKED2 */ 0x3, + /* NEW_CONNECTION_ID */ 0x3, + /* RETIRE_CONNECTION_ID */ 0x3, + /* PATH_CHALLENGE */ 0x3, + /* PATH_RESPONSE */ 0x1, + /* CONNECTION_CLOSE */ 0xF, + /* CONNECTION_CLOSE2 */ 0x3, + /* HANDSHAKE_DONE */ 0x0, /* only sent by server */ + }; + + if (ngx_quic_long_pkt(pkt->flags)) { + + if (ngx_quic_pkt_in(pkt->flags)) { + ptype = 8; /* initial */ + + } else if (ngx_quic_pkt_hs(pkt->flags)) { + ptype = 4; /* handshake */ + + } else { + ptype = 2; /* zero-rtt */ + } + + } else { + ptype = 1; /* application data */ + } + + if (ptype & ngx_quic_frame_masks[frame_type]) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, pkt->log, 0, + "quic frame type 0x%xi is not " + "allowed in packet with flags 0x%xd", + frame_type, pkt->flags); + + return NGX_DECLINED; +} + + +ssize_t +ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, u_char *end, + uint64_t *gap, uint64_t *range) +{ + u_char *p; + + p = start; + + p = ngx_quic_parse_int(p, end, gap); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse ack frame gap"); + return NGX_ERROR; + } + + p = ngx_quic_parse_int(p, end, range); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse ack frame range"); + return NGX_ERROR; + } + + return p - start; +} + + +size_t +ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(gap); + len += ngx_quic_varint_len(range); + return len; + } + + start = p; + + ngx_quic_build_int(&p, gap); + ngx_quic_build_int(&p, range); + + return p - start; +} + + +ssize_t +ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f) +{ + /* + * RFC 9002, 2. Conventions and Definitions + * + * Ack-eliciting frames: All frames other than ACK, PADDING, and + * CONNECTION_CLOSE are considered ack-eliciting. + */ + f->need_ack = 1; + + switch (f->type) { + case NGX_QUIC_FT_PING: + return ngx_quic_create_ping(p); + + case NGX_QUIC_FT_ACK: + f->need_ack = 0; + return ngx_quic_create_ack(p, &f->u.ack, f->data); + + case NGX_QUIC_FT_RESET_STREAM: + return ngx_quic_create_reset_stream(p, &f->u.reset_stream); + + case NGX_QUIC_FT_STOP_SENDING: + return ngx_quic_create_stop_sending(p, &f->u.stop_sending); + + case NGX_QUIC_FT_CRYPTO: + return ngx_quic_create_crypto(p, &f->u.crypto, f->data); + + case NGX_QUIC_FT_HANDSHAKE_DONE: + return ngx_quic_create_hs_done(p); + + case NGX_QUIC_FT_NEW_TOKEN: + return ngx_quic_create_new_token(p, &f->u.token, f->data); + + case NGX_QUIC_FT_STREAM: + return ngx_quic_create_stream(p, &f->u.stream, f->data); + + case NGX_QUIC_FT_CONNECTION_CLOSE: + case NGX_QUIC_FT_CONNECTION_CLOSE_APP: + f->need_ack = 0; + return ngx_quic_create_close(p, f); + + case NGX_QUIC_FT_MAX_STREAMS: + return ngx_quic_create_max_streams(p, &f->u.max_streams); + + case NGX_QUIC_FT_MAX_STREAM_DATA: + return ngx_quic_create_max_stream_data(p, &f->u.max_stream_data); + + case NGX_QUIC_FT_MAX_DATA: + return ngx_quic_create_max_data(p, &f->u.max_data); + + case NGX_QUIC_FT_PATH_CHALLENGE: + return ngx_quic_create_path_challenge(p, &f->u.path_challenge); + + case NGX_QUIC_FT_PATH_RESPONSE: + return ngx_quic_create_path_response(p, &f->u.path_response); + + case NGX_QUIC_FT_NEW_CONNECTION_ID: + return ngx_quic_create_new_connection_id(p, &f->u.ncid); + + case NGX_QUIC_FT_RETIRE_CONNECTION_ID: + return ngx_quic_create_retire_connection_id(p, &f->u.retire_cid); + + default: + /* BUG: unsupported frame type generated */ + return NGX_ERROR; + } +} + + +static size_t +ngx_quic_create_ping(u_char *p) +{ + u_char *start; + + if (p == NULL) { + return ngx_quic_varint_len(NGX_QUIC_FT_PING); + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_PING); + + return p - start; +} + + +static size_t +ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack, ngx_chain_t *ranges) +{ + size_t len; + u_char *start; + ngx_buf_t *b; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_ACK); + len += ngx_quic_varint_len(ack->largest); + len += ngx_quic_varint_len(ack->delay); + len += ngx_quic_varint_len(ack->range_count); + len += ngx_quic_varint_len(ack->first_range); + len += ack->ranges_length; + + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_ACK); + ngx_quic_build_int(&p, ack->largest); + ngx_quic_build_int(&p, ack->delay); + ngx_quic_build_int(&p, ack->range_count); + ngx_quic_build_int(&p, ack->first_range); + + while (ranges) { + b = ranges->buf; + p = ngx_cpymem(p, b->pos, b->last - b->pos); + ranges = ranges->next; + } + + return p - start; +} + + +static size_t +ngx_quic_create_reset_stream(u_char *p, ngx_quic_reset_stream_frame_t *rs) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_RESET_STREAM); + len += ngx_quic_varint_len(rs->id); + len += ngx_quic_varint_len(rs->error_code); + len += ngx_quic_varint_len(rs->final_size); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_RESET_STREAM); + ngx_quic_build_int(&p, rs->id); + ngx_quic_build_int(&p, rs->error_code); + ngx_quic_build_int(&p, rs->final_size); + + return p - start; +} + + +static size_t +ngx_quic_create_stop_sending(u_char *p, ngx_quic_stop_sending_frame_t *ss) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_STOP_SENDING); + len += ngx_quic_varint_len(ss->id); + len += ngx_quic_varint_len(ss->error_code); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_STOP_SENDING); + ngx_quic_build_int(&p, ss->id); + ngx_quic_build_int(&p, ss->error_code); + + return p - start; +} + + +static size_t +ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto, + ngx_chain_t *data) +{ + size_t len; + u_char *start; + ngx_buf_t *b; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_CRYPTO); + len += ngx_quic_varint_len(crypto->offset); + len += ngx_quic_varint_len(crypto->length); + len += crypto->length; + + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO); + ngx_quic_build_int(&p, crypto->offset); + ngx_quic_build_int(&p, crypto->length); + + while (data) { + b = data->buf; + p = ngx_cpymem(p, b->pos, b->last - b->pos); + data = data->next; + } + + return p - start; +} + + +static size_t +ngx_quic_create_hs_done(u_char *p) +{ + u_char *start; + + if (p == NULL) { + return ngx_quic_varint_len(NGX_QUIC_FT_HANDSHAKE_DONE); + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_HANDSHAKE_DONE); + + return p - start; +} + + +static size_t +ngx_quic_create_new_token(u_char *p, ngx_quic_new_token_frame_t *token, + ngx_chain_t *data) +{ + size_t len; + u_char *start; + ngx_buf_t *b; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_TOKEN); + len += ngx_quic_varint_len(token->length); + len += token->length; + + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_TOKEN); + ngx_quic_build_int(&p, token->length); + + while (data) { + b = data->buf; + p = ngx_cpymem(p, b->pos, b->last - b->pos); + data = data->next; + } + + return p - start; +} + + +static size_t +ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf, + ngx_chain_t *data) +{ + size_t len; + u_char *start, type; + ngx_buf_t *b; + + type = NGX_QUIC_FT_STREAM; + + if (sf->off) { + type |= NGX_QUIC_STREAM_FRAME_OFF; + } + + if (sf->len) { + type |= NGX_QUIC_STREAM_FRAME_LEN; + } + + if (sf->fin) { + type |= NGX_QUIC_STREAM_FRAME_FIN; + } + + if (p == NULL) { + len = ngx_quic_varint_len(type); + len += ngx_quic_varint_len(sf->stream_id); + + if (sf->off) { + len += ngx_quic_varint_len(sf->offset); + } + + if (sf->len) { + len += ngx_quic_varint_len(sf->length); + } + + len += sf->length; + + return len; + } + + start = p; + + ngx_quic_build_int(&p, type); + ngx_quic_build_int(&p, sf->stream_id); + + if (sf->off) { + ngx_quic_build_int(&p, sf->offset); + } + + if (sf->len) { + ngx_quic_build_int(&p, sf->length); + } + + while (data) { + b = data->buf; + p = ngx_cpymem(p, b->pos, b->last - b->pos); + data = data->next; + } + + return p - start; +} + + +static size_t +ngx_quic_create_max_streams(u_char *p, ngx_quic_max_streams_frame_t *ms) +{ + size_t len; + u_char *start; + ngx_uint_t type; + + type = ms->bidi ? NGX_QUIC_FT_MAX_STREAMS : NGX_QUIC_FT_MAX_STREAMS2; + + if (p == NULL) { + len = ngx_quic_varint_len(type); + len += ngx_quic_varint_len(ms->limit); + return len; + } + + start = p; + + ngx_quic_build_int(&p, type); + ngx_quic_build_int(&p, ms->limit); + + return p - start; +} + + +static ngx_int_t +ngx_quic_parse_transport_param(u_char *p, u_char *end, uint16_t id, + ngx_quic_tp_t *dst) +{ + uint64_t varint; + ngx_str_t str; + + varint = 0; + ngx_str_null(&str); + + switch (id) { + + case NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION: + /* zero-length option */ + if (end - p != 0) { + return NGX_ERROR; + } + dst->disable_active_migration = 1; + return NGX_OK; + + case NGX_QUIC_TP_MAX_IDLE_TIMEOUT: + case NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE: + case NGX_QUIC_TP_INITIAL_MAX_DATA: + case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: + case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: + case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI: + case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI: + case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI: + case NGX_QUIC_TP_ACK_DELAY_EXPONENT: + case NGX_QUIC_TP_MAX_ACK_DELAY: + case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT: + + p = ngx_quic_parse_int(p, end, &varint); + if (p == NULL) { + return NGX_ERROR; + } + break; + + case NGX_QUIC_TP_INITIAL_SCID: + + str.len = end - p; + str.data = p; + break; + + default: + return NGX_DECLINED; + } + + switch (id) { + + case NGX_QUIC_TP_MAX_IDLE_TIMEOUT: + dst->max_idle_timeout = varint; + break; + + case NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE: + dst->max_udp_payload_size = varint; + break; + + case NGX_QUIC_TP_INITIAL_MAX_DATA: + dst->initial_max_data = varint; + break; + + case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: + dst->initial_max_stream_data_bidi_local = varint; + break; + + case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: + dst->initial_max_stream_data_bidi_remote = varint; + break; + + case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI: + dst->initial_max_stream_data_uni = varint; + break; + + case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI: + dst->initial_max_streams_bidi = varint; + break; + + case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI: + dst->initial_max_streams_uni = varint; + break; + + case NGX_QUIC_TP_ACK_DELAY_EXPONENT: + dst->ack_delay_exponent = varint; + break; + + case NGX_QUIC_TP_MAX_ACK_DELAY: + dst->max_ack_delay = varint; + break; + + case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT: + dst->active_connection_id_limit = varint; + break; + + case NGX_QUIC_TP_INITIAL_SCID: + dst->initial_scid = str; + break; + + default: + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp, + ngx_log_t *log) +{ + uint64_t id, len; + ngx_int_t rc; + + while (p < end) { + p = ngx_quic_parse_int(p, end, &id); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse transport param id"); + return NGX_ERROR; + } + + switch (id) { + case NGX_QUIC_TP_ORIGINAL_DCID: + case NGX_QUIC_TP_PREFERRED_ADDRESS: + case NGX_QUIC_TP_RETRY_SCID: + case NGX_QUIC_TP_SR_TOKEN: + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic client sent forbidden transport param" + " id:0x%xL", id); + return NGX_ERROR; + } + + p = ngx_quic_parse_int(p, end, &len); + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse" + " transport param id:0x%xL length", id); + return NGX_ERROR; + } + + rc = ngx_quic_parse_transport_param(p, p + len, id, tp); + + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse" + " transport param id:0x%xL data", id); + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic %s transport param id:0x%xL, skipped", + (id % 31 == 27) ? "reserved" : "unknown", id); + } + + p += len; + } + + if (p != end) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic trailing garbage in" + " transport parameters: bytes:%ui", + end - p); + return NGX_ERROR; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0, + "quic transport parameters parsed ok"); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp disable active migration: %ui", + tp->disable_active_migration); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "quic tp idle_timeout:%ui", + tp->max_idle_timeout); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp max_udp_payload_size:%ui", + tp->max_udp_payload_size); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "quic tp max_data:%ui", + tp->initial_max_data); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp max_stream_data_bidi_local:%ui", + tp->initial_max_stream_data_bidi_local); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp max_stream_data_bidi_remote:%ui", + tp->initial_max_stream_data_bidi_remote); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp max_stream_data_uni:%ui", + tp->initial_max_stream_data_uni); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp initial_max_streams_bidi:%ui", + tp->initial_max_streams_bidi); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp initial_max_streams_uni:%ui", + tp->initial_max_streams_uni); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp ack_delay_exponent:%ui", + tp->ack_delay_exponent); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "quic tp max_ack_delay:%ui", + tp->max_ack_delay); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp active_connection_id_limit:%ui", + tp->active_connection_id_limit); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, + "quic tp initial source_connection_id len:%uz %xV", + tp->initial_scid.len, &tp->initial_scid); + + return NGX_OK; +} + + +static size_t +ngx_quic_create_max_stream_data(u_char *p, ngx_quic_max_stream_data_frame_t *ms) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_MAX_STREAM_DATA); + len += ngx_quic_varint_len(ms->id); + len += ngx_quic_varint_len(ms->limit); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_MAX_STREAM_DATA); + ngx_quic_build_int(&p, ms->id); + ngx_quic_build_int(&p, ms->limit); + + return p - start; +} + + +static size_t +ngx_quic_create_max_data(u_char *p, ngx_quic_max_data_frame_t *md) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_MAX_DATA); + len += ngx_quic_varint_len(md->max_data); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_MAX_DATA); + ngx_quic_build_int(&p, md->max_data); + + return p - start; +} + + +static size_t +ngx_quic_create_path_challenge(u_char *p, ngx_quic_path_challenge_frame_t *pc) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_PATH_CHALLENGE); + len += sizeof(pc->data); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_PATH_CHALLENGE); + p = ngx_cpymem(p, &pc->data, sizeof(pc->data)); + + return p - start; +} + + +static size_t +ngx_quic_create_path_response(u_char *p, ngx_quic_path_challenge_frame_t *pc) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_PATH_RESPONSE); + len += sizeof(pc->data); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_PATH_RESPONSE); + p = ngx_cpymem(p, &pc->data, sizeof(pc->data)); + + return p - start; +} + + +static size_t +ngx_quic_create_new_connection_id(u_char *p, ngx_quic_new_conn_id_frame_t *ncid) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_CONNECTION_ID); + len += ngx_quic_varint_len(ncid->seqnum); + len += ngx_quic_varint_len(ncid->retire); + len++; + len += ncid->len; + len += NGX_QUIC_SR_TOKEN_LEN; + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_CONNECTION_ID); + ngx_quic_build_int(&p, ncid->seqnum); + ngx_quic_build_int(&p, ncid->retire); + *p++ = ncid->len; + p = ngx_cpymem(p, ncid->cid, ncid->len); + p = ngx_cpymem(p, ncid->srt, NGX_QUIC_SR_TOKEN_LEN); + + return p - start; +} + + +static size_t +ngx_quic_create_retire_connection_id(u_char *p, + ngx_quic_retire_cid_frame_t *rcid) +{ + size_t len; + u_char *start; + + if (p == NULL) { + len = ngx_quic_varint_len(NGX_QUIC_FT_RETIRE_CONNECTION_ID); + len += ngx_quic_varint_len(rcid->sequence_number); + return len; + } + + start = p; + + ngx_quic_build_int(&p, NGX_QUIC_FT_RETIRE_CONNECTION_ID); + ngx_quic_build_int(&p, rcid->sequence_number); + + return p - start; +} + + +ngx_int_t +ngx_quic_init_transport_params(ngx_quic_tp_t *tp, ngx_quic_conf_t *qcf) +{ + ngx_uint_t nstreams; + + ngx_memzero(tp, sizeof(ngx_quic_tp_t)); + + /* + * set by ngx_memzero(): + * + * tp->disable_active_migration = 0; + * tp->original_dcid = { 0, NULL }; + * tp->initial_scid = { 0, NULL }; + * tp->retry_scid = { 0, NULL }; + * tp->sr_token = { 0 } + * tp->sr_enabled = 0 + * tp->preferred_address = NULL + */ + + tp->max_idle_timeout = qcf->idle_timeout; + + tp->max_udp_payload_size = NGX_QUIC_MAX_UDP_PAYLOAD_SIZE; + + nstreams = qcf->max_concurrent_streams_bidi + + qcf->max_concurrent_streams_uni; + + tp->initial_max_data = nstreams * qcf->stream_buffer_size; + tp->initial_max_stream_data_bidi_local = qcf->stream_buffer_size; + tp->initial_max_stream_data_bidi_remote = qcf->stream_buffer_size; + tp->initial_max_stream_data_uni = qcf->stream_buffer_size; + + tp->initial_max_streams_bidi = qcf->max_concurrent_streams_bidi; + tp->initial_max_streams_uni = qcf->max_concurrent_streams_uni; + + tp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY; + tp->ack_delay_exponent = NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT; + + tp->active_connection_id_limit = qcf->active_connection_id_limit; + tp->disable_active_migration = qcf->disable_active_migration; + + return NGX_OK; +} + + +ssize_t +ngx_quic_create_transport_params(u_char *pos, u_char *end, ngx_quic_tp_t *tp, + size_t *clen) +{ + u_char *p; + size_t len; + +#define ngx_quic_tp_len(id, value) \ + ngx_quic_varint_len(id) \ + + ngx_quic_varint_len(value) \ + + ngx_quic_varint_len(ngx_quic_varint_len(value)) + +#define ngx_quic_tp_vint(id, value) \ + do { \ + ngx_quic_build_int(&p, id); \ + ngx_quic_build_int(&p, ngx_quic_varint_len(value)); \ + ngx_quic_build_int(&p, value); \ + } while (0) + +#define ngx_quic_tp_strlen(id, value) \ + ngx_quic_varint_len(id) \ + + ngx_quic_varint_len(value.len) \ + + value.len + +#define ngx_quic_tp_str(id, value) \ + do { \ + ngx_quic_build_int(&p, id); \ + ngx_quic_build_int(&p, value.len); \ + p = ngx_cpymem(p, value.data, value.len); \ + } while (0) + + len = ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_DATA, tp->initial_max_data); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI, + tp->initial_max_streams_uni); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI, + tp->initial_max_streams_bidi); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, + tp->initial_max_stream_data_bidi_local); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, + tp->initial_max_stream_data_bidi_remote); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI, + tp->initial_max_stream_data_uni); + + len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_IDLE_TIMEOUT, + tp->max_idle_timeout); + + len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE, + tp->max_udp_payload_size); + + if (tp->disable_active_migration) { + len += ngx_quic_varint_len(NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION); + len += ngx_quic_varint_len(0); + } + + len += ngx_quic_tp_len(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT, + tp->active_connection_id_limit); + + /* transport parameters listed above will be saved in 0-RTT context */ + if (clen) { + *clen = len; + } + + len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_ACK_DELAY, + tp->max_ack_delay); + + len += ngx_quic_tp_len(NGX_QUIC_TP_ACK_DELAY_EXPONENT, + tp->ack_delay_exponent); + + len += ngx_quic_tp_strlen(NGX_QUIC_TP_ORIGINAL_DCID, tp->original_dcid); + len += ngx_quic_tp_strlen(NGX_QUIC_TP_INITIAL_SCID, tp->initial_scid); + + if (tp->retry_scid.len) { + len += ngx_quic_tp_strlen(NGX_QUIC_TP_RETRY_SCID, tp->retry_scid); + } + + len += ngx_quic_varint_len(NGX_QUIC_TP_SR_TOKEN); + len += ngx_quic_varint_len(NGX_QUIC_SR_TOKEN_LEN); + len += NGX_QUIC_SR_TOKEN_LEN; + + if (pos == NULL) { + return len; + } + + p = pos; + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_DATA, + tp->initial_max_data); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI, + tp->initial_max_streams_uni); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI, + tp->initial_max_streams_bidi); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, + tp->initial_max_stream_data_bidi_local); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, + tp->initial_max_stream_data_bidi_remote); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI, + tp->initial_max_stream_data_uni); + + ngx_quic_tp_vint(NGX_QUIC_TP_MAX_IDLE_TIMEOUT, + tp->max_idle_timeout); + + ngx_quic_tp_vint(NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE, + tp->max_udp_payload_size); + + if (tp->disable_active_migration) { + ngx_quic_build_int(&p, NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION); + ngx_quic_build_int(&p, 0); + } + + ngx_quic_tp_vint(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT, + tp->active_connection_id_limit); + + ngx_quic_tp_vint(NGX_QUIC_TP_MAX_ACK_DELAY, + tp->max_ack_delay); + + ngx_quic_tp_vint(NGX_QUIC_TP_ACK_DELAY_EXPONENT, + tp->ack_delay_exponent); + + ngx_quic_tp_str(NGX_QUIC_TP_ORIGINAL_DCID, tp->original_dcid); + ngx_quic_tp_str(NGX_QUIC_TP_INITIAL_SCID, tp->initial_scid); + + if (tp->retry_scid.len) { + ngx_quic_tp_str(NGX_QUIC_TP_RETRY_SCID, tp->retry_scid); + } + + ngx_quic_build_int(&p, NGX_QUIC_TP_SR_TOKEN); + ngx_quic_build_int(&p, NGX_QUIC_SR_TOKEN_LEN); + p = ngx_cpymem(p, tp->sr_token, NGX_QUIC_SR_TOKEN_LEN); + + return p - pos; +} + + +static size_t +ngx_quic_create_close(u_char *p, ngx_quic_frame_t *f) +{ + size_t len; + u_char *start; + ngx_quic_close_frame_t *cl; + + cl = &f->u.close; + + if (p == NULL) { + len = ngx_quic_varint_len(f->type); + len += ngx_quic_varint_len(cl->error_code); + + if (f->type != NGX_QUIC_FT_CONNECTION_CLOSE_APP) { + len += ngx_quic_varint_len(cl->frame_type); + } + + len += ngx_quic_varint_len(cl->reason.len); + len += cl->reason.len; + + return len; + } + + start = p; + + ngx_quic_build_int(&p, f->type); + ngx_quic_build_int(&p, cl->error_code); + + if (f->type != NGX_QUIC_FT_CONNECTION_CLOSE_APP) { + ngx_quic_build_int(&p, cl->frame_type); + } + + ngx_quic_build_int(&p, cl->reason.len); + p = ngx_cpymem(p, cl->reason.data, cl->reason.len); + + return p - start; +} + + +void +ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key) +{ + (void) ngx_quic_write_uint64(dcid, key); +} diff --git a/src/event/quic/ngx_event_quic_transport.h b/src/event/quic/ngx_event_quic_transport.h new file mode 100644 index 0000000..3e32039 --- /dev/null +++ b/src/event/quic/ngx_event_quic_transport.h @@ -0,0 +1,397 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ +#define _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ + + +#include +#include + + +/* + * RFC 9000, 17.2. Long Header Packets + * 17.3. Short Header Packets + * + * QUIC flags in first byte + */ +#define NGX_QUIC_PKT_LONG 0x80 /* header form */ +#define NGX_QUIC_PKT_FIXED_BIT 0x40 +#define NGX_QUIC_PKT_TYPE 0x30 /* in long packet */ +#define NGX_QUIC_PKT_KPHASE 0x04 /* in short packet */ + +#define ngx_quic_long_pkt(flags) ((flags) & NGX_QUIC_PKT_LONG) +#define ngx_quic_short_pkt(flags) (((flags) & NGX_QUIC_PKT_LONG) == 0) + +/* Long packet types */ +#define NGX_QUIC_PKT_INITIAL 0x00 +#define NGX_QUIC_PKT_ZRTT 0x10 +#define NGX_QUIC_PKT_HANDSHAKE 0x20 +#define NGX_QUIC_PKT_RETRY 0x30 + +#define ngx_quic_pkt_in(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_INITIAL) +#define ngx_quic_pkt_zrtt(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_ZRTT) +#define ngx_quic_pkt_hs(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_HANDSHAKE) +#define ngx_quic_pkt_retry(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_RETRY) + +#define ngx_quic_pkt_rb_mask(flags) \ + (ngx_quic_long_pkt(flags) ? 0x0C : 0x18) +#define ngx_quic_pkt_hp_mask(flags) \ + (ngx_quic_long_pkt(flags) ? 0x0F : 0x1F) + +#define ngx_quic_level_name(lvl) \ + (lvl == ssl_encryption_application) ? "app" \ + : (lvl == ssl_encryption_initial) ? "init" \ + : (lvl == ssl_encryption_handshake) ? "hs" : "early" + +#define NGX_QUIC_MAX_CID_LEN 20 +#define NGX_QUIC_SERVER_CID_LEN NGX_QUIC_MAX_CID_LEN + +/* 12.4. Frames and Frame Types */ +#define NGX_QUIC_FT_PADDING 0x00 +#define NGX_QUIC_FT_PING 0x01 +#define NGX_QUIC_FT_ACK 0x02 +#define NGX_QUIC_FT_ACK_ECN 0x03 +#define NGX_QUIC_FT_RESET_STREAM 0x04 +#define NGX_QUIC_FT_STOP_SENDING 0x05 +#define NGX_QUIC_FT_CRYPTO 0x06 +#define NGX_QUIC_FT_NEW_TOKEN 0x07 +#define NGX_QUIC_FT_STREAM 0x08 +#define NGX_QUIC_FT_STREAM1 0x09 +#define NGX_QUIC_FT_STREAM2 0x0A +#define NGX_QUIC_FT_STREAM3 0x0B +#define NGX_QUIC_FT_STREAM4 0x0C +#define NGX_QUIC_FT_STREAM5 0x0D +#define NGX_QUIC_FT_STREAM6 0x0E +#define NGX_QUIC_FT_STREAM7 0x0F +#define NGX_QUIC_FT_MAX_DATA 0x10 +#define NGX_QUIC_FT_MAX_STREAM_DATA 0x11 +#define NGX_QUIC_FT_MAX_STREAMS 0x12 +#define NGX_QUIC_FT_MAX_STREAMS2 0x13 +#define NGX_QUIC_FT_DATA_BLOCKED 0x14 +#define NGX_QUIC_FT_STREAM_DATA_BLOCKED 0x15 +#define NGX_QUIC_FT_STREAMS_BLOCKED 0x16 +#define NGX_QUIC_FT_STREAMS_BLOCKED2 0x17 +#define NGX_QUIC_FT_NEW_CONNECTION_ID 0x18 +#define NGX_QUIC_FT_RETIRE_CONNECTION_ID 0x19 +#define NGX_QUIC_FT_PATH_CHALLENGE 0x1A +#define NGX_QUIC_FT_PATH_RESPONSE 0x1B +#define NGX_QUIC_FT_CONNECTION_CLOSE 0x1C +#define NGX_QUIC_FT_CONNECTION_CLOSE_APP 0x1D +#define NGX_QUIC_FT_HANDSHAKE_DONE 0x1E + +#define NGX_QUIC_FT_LAST NGX_QUIC_FT_HANDSHAKE_DONE + +/* 22.5. QUIC Transport Error Codes Registry */ +#define NGX_QUIC_ERR_NO_ERROR 0x00 +#define NGX_QUIC_ERR_INTERNAL_ERROR 0x01 +#define NGX_QUIC_ERR_CONNECTION_REFUSED 0x02 +#define NGX_QUIC_ERR_FLOW_CONTROL_ERROR 0x03 +#define NGX_QUIC_ERR_STREAM_LIMIT_ERROR 0x04 +#define NGX_QUIC_ERR_STREAM_STATE_ERROR 0x05 +#define NGX_QUIC_ERR_FINAL_SIZE_ERROR 0x06 +#define NGX_QUIC_ERR_FRAME_ENCODING_ERROR 0x07 +#define NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR 0x08 +#define NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR 0x09 +#define NGX_QUIC_ERR_PROTOCOL_VIOLATION 0x0A +#define NGX_QUIC_ERR_INVALID_TOKEN 0x0B +#define NGX_QUIC_ERR_APPLICATION_ERROR 0x0C +#define NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED 0x0D +#define NGX_QUIC_ERR_KEY_UPDATE_ERROR 0x0E +#define NGX_QUIC_ERR_AEAD_LIMIT_REACHED 0x0F +#define NGX_QUIC_ERR_NO_VIABLE_PATH 0x10 + +#define NGX_QUIC_ERR_CRYPTO_ERROR 0x100 + +#define NGX_QUIC_ERR_CRYPTO(e) (NGX_QUIC_ERR_CRYPTO_ERROR + (e)) + + +/* 22.3. QUIC Transport Parameters Registry */ +#define NGX_QUIC_TP_ORIGINAL_DCID 0x00 +#define NGX_QUIC_TP_MAX_IDLE_TIMEOUT 0x01 +#define NGX_QUIC_TP_SR_TOKEN 0x02 +#define NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE 0x03 +#define NGX_QUIC_TP_INITIAL_MAX_DATA 0x04 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 0x05 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 0x06 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI 0x07 +#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI 0x08 +#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI 0x09 +#define NGX_QUIC_TP_ACK_DELAY_EXPONENT 0x0A +#define NGX_QUIC_TP_MAX_ACK_DELAY 0x0B +#define NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION 0x0C +#define NGX_QUIC_TP_PREFERRED_ADDRESS 0x0D +#define NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT 0x0E +#define NGX_QUIC_TP_INITIAL_SCID 0x0F +#define NGX_QUIC_TP_RETRY_SCID 0x10 + +#define NGX_QUIC_CID_LEN_MIN 8 +#define NGX_QUIC_CID_LEN_MAX 20 + +#define NGX_QUIC_MAX_RANGES 10 + + +typedef struct { + uint64_t gap; + uint64_t range; +} ngx_quic_ack_range_t; + + +typedef struct { + uint64_t largest; + uint64_t delay; + uint64_t range_count; + uint64_t first_range; + uint64_t ect0; + uint64_t ect1; + uint64_t ce; + uint64_t ranges_length; +} ngx_quic_ack_frame_t; + + +typedef struct { + uint64_t seqnum; + uint64_t retire; + uint8_t len; + u_char cid[NGX_QUIC_CID_LEN_MAX]; + u_char srt[NGX_QUIC_SR_TOKEN_LEN]; +} ngx_quic_new_conn_id_frame_t; + + +typedef struct { + uint64_t length; +} ngx_quic_new_token_frame_t; + +/* + * common layout for CRYPTO and STREAM frames; + * conceptually, CRYPTO frame is also a stream + * frame lacking some properties + */ +typedef struct { + uint64_t offset; + uint64_t length; +} ngx_quic_ordered_frame_t; + +typedef ngx_quic_ordered_frame_t ngx_quic_crypto_frame_t; + + +typedef struct { + /* initial fields same as in ngx_quic_ordered_frame_t */ + uint64_t offset; + uint64_t length; + + uint64_t stream_id; + unsigned off:1; + unsigned len:1; + unsigned fin:1; +} ngx_quic_stream_frame_t; + + +typedef struct { + uint64_t max_data; +} ngx_quic_max_data_frame_t; + + +typedef struct { + uint64_t error_code; + uint64_t frame_type; + ngx_str_t reason; +} ngx_quic_close_frame_t; + + +typedef struct { + uint64_t id; + uint64_t error_code; + uint64_t final_size; +} ngx_quic_reset_stream_frame_t; + + +typedef struct { + uint64_t id; + uint64_t error_code; +} ngx_quic_stop_sending_frame_t; + + +typedef struct { + uint64_t limit; + ngx_uint_t bidi; /* unsigned: bidi:1 */ +} ngx_quic_streams_blocked_frame_t; + + +typedef struct { + uint64_t limit; + ngx_uint_t bidi; /* unsigned: bidi:1 */ +} ngx_quic_max_streams_frame_t; + + +typedef struct { + uint64_t id; + uint64_t limit; +} ngx_quic_max_stream_data_frame_t; + + +typedef struct { + uint64_t limit; +} ngx_quic_data_blocked_frame_t; + + +typedef struct { + uint64_t id; + uint64_t limit; +} ngx_quic_stream_data_blocked_frame_t; + + +typedef struct { + uint64_t sequence_number; +} ngx_quic_retire_cid_frame_t; + + +typedef struct { + u_char data[8]; +} ngx_quic_path_challenge_frame_t; + + +typedef struct ngx_quic_frame_s ngx_quic_frame_t; + +struct ngx_quic_frame_s { + ngx_uint_t type; + enum ssl_encryption_level_t level; + ngx_queue_t queue; + uint64_t pnum; + size_t plen; + ngx_msec_t send_time; + ssize_t len; + unsigned need_ack:1; + unsigned pkt_need_ack:1; + unsigned ignore_congestion:1; + + ngx_chain_t *data; + union { + ngx_quic_ack_frame_t ack; + ngx_quic_crypto_frame_t crypto; + ngx_quic_ordered_frame_t ord; + ngx_quic_new_conn_id_frame_t ncid; + ngx_quic_new_token_frame_t token; + ngx_quic_stream_frame_t stream; + ngx_quic_max_data_frame_t max_data; + ngx_quic_close_frame_t close; + ngx_quic_reset_stream_frame_t reset_stream; + ngx_quic_stop_sending_frame_t stop_sending; + ngx_quic_streams_blocked_frame_t streams_blocked; + ngx_quic_max_streams_frame_t max_streams; + ngx_quic_max_stream_data_frame_t max_stream_data; + ngx_quic_data_blocked_frame_t data_blocked; + ngx_quic_stream_data_blocked_frame_t stream_data_blocked; + ngx_quic_retire_cid_frame_t retire_cid; + ngx_quic_path_challenge_frame_t path_challenge; + ngx_quic_path_challenge_frame_t path_response; + } u; +}; + + +typedef struct { + ngx_log_t *log; + ngx_quic_path_t *path; + + ngx_quic_keys_t *keys; + + ngx_msec_t received; + uint64_t number; + uint8_t num_len; + uint32_t trunc; + uint8_t flags; + uint32_t version; + ngx_str_t token; + enum ssl_encryption_level_t level; + ngx_uint_t error; + + /* filled in by parser */ + ngx_buf_t *raw; /* udp datagram */ + + u_char *data; /* quic packet */ + size_t len; + + /* cleartext fields */ + ngx_str_t odcid; /* retry packet tag */ + u_char odcid_buf[NGX_QUIC_MAX_CID_LEN]; + ngx_str_t dcid; + ngx_str_t scid; + uint64_t pn; + u_char *plaintext; + ngx_str_t payload; /* decrypted data */ + + unsigned need_ack:1; + unsigned key_phase:1; + unsigned key_update:1; + unsigned parsed:1; + unsigned decrypted:1; + unsigned validated:1; + unsigned retried:1; + unsigned first:1; + unsigned rebound:1; + unsigned path_challenged:1; +} ngx_quic_header_t; + + +typedef struct { + ngx_msec_t max_idle_timeout; + ngx_msec_t max_ack_delay; + + size_t max_udp_payload_size; + size_t initial_max_data; + size_t initial_max_stream_data_bidi_local; + size_t initial_max_stream_data_bidi_remote; + size_t initial_max_stream_data_uni; + ngx_uint_t initial_max_streams_bidi; + ngx_uint_t initial_max_streams_uni; + ngx_uint_t ack_delay_exponent; + ngx_uint_t active_connection_id_limit; + ngx_flag_t disable_active_migration; + + ngx_str_t original_dcid; + ngx_str_t initial_scid; + ngx_str_t retry_scid; + u_char sr_token[NGX_QUIC_SR_TOKEN_LEN]; + + /* TODO */ + void *preferred_address; +} ngx_quic_tp_t; + + +ngx_int_t ngx_quic_parse_packet(ngx_quic_header_t *pkt); + +size_t ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out); + +size_t ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len); + +size_t ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, + u_char **pnp); + +size_t ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out, + u_char **start); + +ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end, + ngx_quic_frame_t *frame); +ssize_t ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f); + +ssize_t ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, + u_char *end, uint64_t *gap, uint64_t *range); +size_t ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range); + +ngx_int_t ngx_quic_init_transport_params(ngx_quic_tp_t *tp, + ngx_quic_conf_t *qcf); +ngx_int_t ngx_quic_parse_transport_params(u_char *p, u_char *end, + ngx_quic_tp_t *tp, ngx_log_t *log); +ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end, + ngx_quic_tp_t *tp, size_t *clen); + +void ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key); + +#endif /* _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_udp.c b/src/event/quic/ngx_event_quic_udp.c new file mode 100644 index 0000000..15b54bc --- /dev/null +++ b/src/event/quic/ngx_event_quic_udp.c @@ -0,0 +1,420 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static void ngx_quic_close_accepted_connection(ngx_connection_t *c); +static ngx_connection_t *ngx_quic_lookup_connection(ngx_listening_t *ls, + ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen); + + +void +ngx_quic_recvmsg(ngx_event_t *ev) +{ + ssize_t n; + ngx_str_t key; + ngx_buf_t buf; + ngx_log_t *log; + ngx_err_t err; + socklen_t socklen, local_socklen; + ngx_event_t *rev, *wev; + struct iovec iov[1]; + struct msghdr msg; + ngx_sockaddr_t sa, lsa; + struct sockaddr *sockaddr, *local_sockaddr; + ngx_listening_t *ls; + ngx_event_conf_t *ecf; + ngx_connection_t *c, *lc; + ngx_quic_socket_t *qsock; + static u_char buffer[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; + +#if (NGX_HAVE_ADDRINFO_CMSG) + u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; +#endif + + if (ev->timedout) { + if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { + return; + } + + ev->timedout = 0; + } + + ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); + + if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { + ev->available = ecf->multi_accept; + } + + lc = ev->data; + ls = lc->listening; + ev->ready = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "quic recvmsg on %V, ready: %d", + &ls->addr_text, ev->available); + + do { + ngx_memzero(&msg, sizeof(struct msghdr)); + + iov[0].iov_base = (void *) buffer; + iov[0].iov_len = sizeof(buffer); + + msg.msg_name = &sa; + msg.msg_namelen = sizeof(ngx_sockaddr_t); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + +#if (NGX_HAVE_ADDRINFO_CMSG) + if (ls->wildcard) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); + + ngx_memzero(&msg_control, sizeof(msg_control)); + } +#endif + + n = recvmsg(lc->fd, &msg, 0); + + if (n == -1) { + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, + "quic recvmsg() not ready"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, err, "quic recvmsg() failed"); + + return; + } + +#if (NGX_HAVE_ADDRINFO_CMSG) + if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "quic recvmsg() truncated data"); + continue; + } +#endif + + sockaddr = msg.msg_name; + socklen = msg.msg_namelen; + + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (sockaddr->sa_family == AF_UNIX) { + struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) + || saun->sun_path[0] == '\0') + { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "unbound unix socket"); + goto next; + } + } + +#endif + + local_sockaddr = ls->sockaddr; + local_socklen = ls->socklen; + +#if (NGX_HAVE_ADDRINFO_CMSG) + + if (ls->wildcard) { + struct cmsghdr *cmsg; + + ngx_memcpy(&lsa, local_sockaddr, local_socklen); + local_sockaddr = &lsa.sockaddr; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) { + break; + } + } + } + +#endif + + if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { + goto next; + } + + c = ngx_quic_lookup_connection(ls, &key, local_sockaddr, local_socklen); + + if (c) { + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + ngx_log_handler_pt handler; + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic recvmsg: fd:%d n:%z", c->fd, n); + + c->log->handler = handler; + } +#endif + + ngx_memzero(&buf, sizeof(ngx_buf_t)); + + buf.pos = buffer; + buf.last = buffer + n; + buf.start = buf.pos; + buf.end = buffer + sizeof(buffer); + + qsock = ngx_quic_get_socket(c); + + ngx_memcpy(&qsock->sockaddr, sockaddr, socklen); + qsock->socklen = socklen; + + c->udp->buffer = &buf; + + rev = c->read; + rev->ready = 1; + rev->active = 0; + + rev->handler(rev); + + if (c->udp) { + c->udp->buffer = NULL; + } + + rev->ready = 0; + rev->active = 1; + + goto next; + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); +#endif + + ngx_accept_disabled = ngx_cycle->connection_n / 8 + - ngx_cycle->free_connection_n; + + c = ngx_get_connection(lc->fd, ev->log); + if (c == NULL) { + return; + } + + c->shared = 1; + c->type = SOCK_DGRAM; + c->socklen = socklen; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + c->pool = ngx_create_pool(ls->pool_size, ev->log); + if (c->pool == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + c->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN); + if (c->sockaddr == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + ngx_memcpy(c->sockaddr, sockaddr, socklen); + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + *log = ls->log; + + c->log = log; + c->pool->log = log; + c->listening = ls; + + if (local_sockaddr == &lsa.sockaddr) { + local_sockaddr = ngx_palloc(c->pool, local_socklen); + if (local_sockaddr == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + ngx_memcpy(local_sockaddr, &lsa, local_socklen); + } + + c->local_sockaddr = local_sockaddr; + c->local_socklen = local_socklen; + + c->buffer = ngx_create_temp_buf(c->pool, n); + if (c->buffer == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); + + rev = c->read; + wev = c->write; + + rev->active = 1; + wev->ready = 1; + + rev->log = log; + wev->log = log; + + /* + * TODO: MT: - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + * + * TODO: MP: - allocated in a shared memory + * - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + */ + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + + c->start_time = ngx_current_msec; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); +#endif + + if (ls->addr_ntop) { + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); + if (c->addr_text.data == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + 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_quic_close_accepted_connection(c); + return; + } + } + +#if (NGX_DEBUG) + { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + + ngx_debug_accepted_connection(ecf, c); + + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA quic recvmsg: %V fd:%d n:%z", + c->number, &addr, c->fd, n); + } + + } +#endif + + log->data = NULL; + log->handler = NULL; + + ls->handler(c); + + next: + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ev->available -= n; + } + + } while (ev->available); +} + + +static void +ngx_quic_close_accepted_connection(ngx_connection_t *c) +{ + ngx_free_connection(c); + + c->fd = (ngx_socket_t) -1; + + if (c->pool) { + ngx_destroy_pool(c->pool); + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); +#endif +} + + +static ngx_connection_t * +ngx_quic_lookup_connection(ngx_listening_t *ls, ngx_str_t *key, + struct sockaddr *local_sockaddr, socklen_t local_socklen) +{ + uint32_t hash; + ngx_int_t rc; + ngx_connection_t *c; + ngx_rbtree_node_t *node, *sentinel; + ngx_quic_socket_t *qsock; + + if (key->len == 0) { + return NULL; + } + + node = ls->rbtree.root; + sentinel = ls->rbtree.sentinel; + hash = ngx_crc32_long(key->data, key->len); + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + qsock = (ngx_quic_socket_t *) node; + + rc = ngx_memn2cmp(key->data, qsock->sid.id, key->len, qsock->sid.len); + + c = qsock->udp.connection; + + if (rc == 0 && ls->wildcard) { + rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, + c->local_sockaddr, c->local_socklen, 1); + } + + if (rc == 0) { + c->udp = &qsock->udp; + return c; + } + + node = (rc < 0) ? node->left : node->right; + } + + return NULL; +} diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c index 7355de9..ea75520 100644 --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -148,7 +148,7 @@ ngx_http_access_handler(ngx_http_request_t *r) p = sin6->sin6_addr.s6_addr; if (alcf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - addr = p[12] << 24; + addr = (in_addr_t) p[12] << 24; addr += p[13] << 16; addr += p[14] << 8; addr += p[15]; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 2d9a18f..b989083 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2048,7 +2048,10 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) } u->headers_in.status_n = status; - u->headers_in.status_line = *status_line; + + if (status_line->len > 3) { + u->headers_in.status_line = *status_line; + } } else if (u->headers_in.location) { u->headers_in.status_n = 302; diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index ef4e9b8..75c0397 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -199,7 +199,7 @@ ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, p = inaddr6->s6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; @@ -272,7 +272,7 @@ ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; @@ -1259,7 +1259,7 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, return gvvn->value; } - val = ngx_palloc(ctx->pool, sizeof(ngx_http_variable_value_t)); + val = ngx_pcalloc(ctx->pool, sizeof(ngx_http_variable_value_t)); if (val == NULL) { return NULL; } @@ -1271,8 +1271,6 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, } val->valid = 1; - val->no_cacheable = 0; - val->not_found = 0; gvvn = ngx_palloc(ctx->temp_pool, sizeof(ngx_http_geo_variable_value_node_t)); diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index eaf9876..5b8b11f 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -266,7 +266,7 @@ ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c index 599dd3a..11a681b 100644 --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -631,7 +631,7 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the using of the regex \"%V\" requires PCRE library", + "using regex \"%V\" requires PCRE library", name); return NGX_ERROR; diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c index 0e6d4df..ff3b687 100644 --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -489,6 +489,7 @@ ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (cf->args->nelts == 2) { + ngx_str_set(&ret->text.value, ""); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 9fc18dc..3acea87 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1153,7 +1153,10 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) } u->headers_in.status_n = status; - u->headers_in.status_line = *status_line; + + if (status_line->len > 3) { + u->headers_in.status_line = *status_line; + } } else if (u->headers_in.location) { u->headers_in.status_n = 302; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index e7601b8..0b84bd3 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -2001,7 +2001,7 @@ ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern, #else ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "the using of the regex \"%V\" in SSI requires PCRE library", + "using regex \"%V\" in SSI requires PCRE library", pattern); return NGX_HTTP_SSI_ERROR; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 4c4a598..1c92d9f 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -9,6 +9,10 @@ #include #include +#if (NGX_QUIC_OPENSSL_COMPAT) +#include +#endif + typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); @@ -39,8 +43,6 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf, ngx_http_ssl_srv_conf_t *conf); -static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, @@ -52,6 +54,10 @@ static char *ngx_http_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf); +#if (NGX_QUIC_OPENSSL_COMPAT) +static ngx_int_t ngx_http_ssl_quic_compat_init(ngx_conf_t *cf, + ngx_http_conf_addr_t *addr); +#endif static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { @@ -82,24 +88,12 @@ static ngx_conf_enum_t ngx_http_ssl_ocsp[] = { }; -static ngx_conf_deprecated_t ngx_http_ssl_deprecated = { - ngx_conf_deprecated, "ssl", "listen ... ssl" -}; - - static ngx_conf_post_t ngx_http_ssl_conf_command_post = { ngx_http_ssl_conf_command_check }; static ngx_command_t ngx_http_ssl_commands[] = { - { ngx_string("ssl"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, - ngx_http_ssl_enable, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_ssl_srv_conf_t, enable), - &ngx_http_ssl_deprecated }, - { ngx_string("ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, @@ -419,16 +413,22 @@ 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; + unsigned int srvlen; + unsigned char *srv; #if (NGX_DEBUG) - unsigned int i; + unsigned int i; +#endif +#if (NGX_HTTP_V2 || NGX_HTTP_V3) + ngx_http_connection_t *hc; #endif #if (NGX_HTTP_V2) - ngx_http_connection_t *hc; + ngx_http_v2_srv_conf_t *h2scf; #endif -#if (NGX_HTTP_V2 || NGX_DEBUG) - ngx_connection_t *c; +#if (NGX_HTTP_V3) + ngx_http_v3_srv_conf_t *h3scf; +#endif +#if (NGX_HTTP_V2 || NGX_HTTP_V3 || NGX_DEBUG) + ngx_connection_t *c; c = ngx_ssl_get_connection(ssl_conn); #endif @@ -441,17 +441,49 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, } #endif -#if (NGX_HTTP_V2) +#if (NGX_HTTP_V2 || NGX_HTTP_V3) hc = c->data; +#endif + +#if (NGX_HTTP_V3) + if (hc->addr_conf->quic) { + + h3scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); + + if (h3scf->enable && h3scf->enable_hq) { + srv = (unsigned char *) NGX_HTTP_V3_ALPN_PROTO + NGX_HTTP_V3_HQ_ALPN_PROTO; + srvlen = sizeof(NGX_HTTP_V3_ALPN_PROTO NGX_HTTP_V3_HQ_ALPN_PROTO) + - 1; + + } else if (h3scf->enable_hq) { + srv = (unsigned char *) NGX_HTTP_V3_HQ_ALPN_PROTO; + srvlen = sizeof(NGX_HTTP_V3_HQ_ALPN_PROTO) - 1; + + } else if (h3scf->enable) { + srv = (unsigned char *) NGX_HTTP_V3_ALPN_PROTO; + srvlen = sizeof(NGX_HTTP_V3_ALPN_PROTO) - 1; + + } else { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } - if (hc->addr_conf->http2) { - srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS; - srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1; } else #endif { - srv = (unsigned char *) NGX_HTTP_ALPN_PROTOS; - srvlen = sizeof(NGX_HTTP_ALPN_PROTOS) - 1; +#if (NGX_HTTP_V2) + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); + + if (h2scf->enable || hc->addr_conf->http2) { + srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1; + + } else +#endif + { + srv = (unsigned char *) NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_ALPN_PROTOS) - 1; + } } if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, @@ -579,7 +611,6 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) * sscf->stapling_responder = { 0, NULL }; */ - sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; sscf->early_data = NGX_CONF_UNSET; sscf->reject_handshake = NGX_CONF_UNSET; @@ -611,17 +642,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_pool_cleanup_t *cln; - if (conf->enable == NGX_CONF_UNSET) { - if (prev->enable == NGX_CONF_UNSET) { - conf->enable = 0; - - } else { - conf->enable = prev->enable; - conf->file = prev->file; - conf->line = prev->line; - } - } - ngx_conf_merge_value(conf->session_timeout, prev->session_timeout, 300); @@ -676,37 +696,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; - if (conf->enable) { - - if (conf->certificates) { - if (conf->certificate_keys == NULL) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined for " - "the \"ssl\" directive in %s:%ui", - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - if (conf->certificate_keys->nelts < conf->certificates->nelts) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\" and " - "the \"ssl\" directive in %s:%ui", - ((ngx_str_t *) conf->certificates->elts) - + conf->certificates->nelts - 1, - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - } else if (!conf->reject_handshake) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate\" is defined for " - "the \"ssl\" directive in %s:%ui", - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - } else if (conf->certificates) { + if (conf->certificates) { if (conf->certificate_keys == NULL || conf->certificate_keys->nelts < conf->certificates->nelts) @@ -992,26 +982,6 @@ found: } -static char * -ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_ssl_srv_conf_t *sscf = conf; - - char *rv; - - rv = ngx_conf_set_flag_slot(cf, cmd, conf); - - if (rv != NGX_CONF_OK) { - return rv; - } - - sscf->file = cf->conf_file->file.name.data; - sscf->line = cf->conf_file->line; - - return NGX_CONF_OK; -} - - static char * ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -1241,6 +1211,7 @@ static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf) { ngx_uint_t a, p, s; + const char *name; ngx_http_conf_addr_t *addr; ngx_http_conf_port_t *port; ngx_http_ssl_srv_conf_t *sscf; @@ -1290,22 +1261,44 @@ ngx_http_ssl_init(ngx_conf_t *cf) addr = port[p].addrs.elts; for (a = 0; a < port[p].addrs.nelts; a++) { - if (!addr[a].opt.ssl) { + if (!addr[a].opt.ssl && !addr[a].opt.quic) { continue; } + if (addr[a].opt.quic) { + name = "quic"; + +#if (NGX_QUIC_OPENSSL_COMPAT) + if (ngx_http_ssl_quic_compat_init(cf, &addr[a]) != NGX_OK) { + return NGX_ERROR; + } +#endif + + } else { + name = "ssl"; + } + cscf = addr[a].default_server; sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; if (sscf->certificates) { + + if (addr[a].opt.quic && !(sscf->protocols & NGX_SSL_TLSv1_3)) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "\"ssl_protocols\" must enable TLSv1.3 for " + "the \"listen ... %s\" directive in %s:%ui", + name, cscf->file_name, cscf->line); + return NGX_ERROR; + } + continue; } if (!sscf->reject_handshake) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " - "the \"listen ... ssl\" directive in %s:%ui", - cscf->file_name, cscf->line); + "the \"listen ... %s\" directive in %s:%ui", + name, cscf->file_name, cscf->line); return NGX_ERROR; } @@ -1326,8 +1319,8 @@ ngx_http_ssl_init(ngx_conf_t *cf) ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " - "the \"listen ... ssl\" directive in %s:%ui", - cscf->file_name, cscf->line); + "the \"listen ... %s\" directive in %s:%ui", + name, cscf->file_name, cscf->line); return NGX_ERROR; } } @@ -1335,3 +1328,31 @@ ngx_http_ssl_init(ngx_conf_t *cf) return NGX_OK; } + + +#if (NGX_QUIC_OPENSSL_COMPAT) + +static ngx_int_t +ngx_http_ssl_quic_compat_init(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) +{ + ngx_uint_t s; + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_core_srv_conf_t **cscfp, *cscf; + + cscfp = addr->servers.elts; + for (s = 0; s < addr->servers.nelts; s++) { + + cscf = cscfp[s]; + sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; + + if (sscf->certificates || sscf->reject_handshake) { + if (ngx_quic_compat_init(cf, sscf->ssl.ctx) != NGX_OK) { + return NGX_ERROR; + } + } + } + + return NGX_OK; +} + +#endif diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 7ab0f7e..c69c8ff 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -15,8 +15,6 @@ typedef struct { - ngx_flag_t enable; - ngx_ssl_t ssl; ngx_flag_t prefer_server_ciphers; @@ -64,9 +62,6 @@ typedef struct { ngx_flag_t stapling_verify; ngx_str_t stapling_file; ngx_str_t stapling_responder; - - u_char *file; - ngx_uint_t line; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index e4f721b..c1731ff 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1381,7 +1381,10 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) } u->headers_in.status_n = status; - u->headers_in.status_line = *status_line; + + if (status_line->len > 3) { + u->headers_in.status_line = *status_line; + } } else if (u->headers_in.location) { u->headers_in.status_n = 302; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 93e1cd4..d835f89 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1200,7 +1200,10 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, port = cmcf->ports->elts; for (i = 0; i < cmcf->ports->nelts; i++) { - if (p != port[i].port || sa->sa_family != port[i].family) { + if (p != port[i].port + || lsopt->type != port[i].type + || sa->sa_family != port[i].family) + { continue; } @@ -1217,6 +1220,7 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } port->family = sa->sa_family; + port->type = lsopt->type; port->port = p; port->addrs.elts = NULL; @@ -1237,6 +1241,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #if (NGX_HTTP_V2) ngx_uint_t http2; #endif +#if (NGX_HTTP_V3) + ngx_uint_t quic; +#endif /* * we cannot compare whole sockaddr struct's as kernel @@ -1278,6 +1285,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, protocols |= lsopt->http2 << 2; protocols_prev |= addr[i].opt.http2 << 2; #endif +#if (NGX_HTTP_V3) + quic = lsopt->quic || addr[i].opt.quic; +#endif if (lsopt->set) { @@ -1365,6 +1375,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #if (NGX_HTTP_V2) addr[i].opt.http2 = http2; #endif +#if (NGX_HTTP_V3) + addr[i].opt.quic = quic; +#endif return NGX_OK; } @@ -1831,6 +1844,7 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) } #endif + ls->type = addr->opt.type; ls->backlog = addr->opt.backlog; ls->rcvbuf = addr->opt.rcvbuf; ls->sndbuf = addr->opt.sndbuf; @@ -1866,6 +1880,12 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->reuseport = addr->opt.reuseport; #endif + ls->wildcard = addr->opt.wildcard; + +#if (NGX_HTTP_V3) + ls->quic = addr->opt.quic; +#endif + return ls; } @@ -1897,6 +1917,9 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, #endif #if (NGX_HTTP_V2) addrs[i].conf.http2 = addr[i].opt.http2; +#endif +#if (NGX_HTTP_V3) + addrs[i].conf.quic = addr[i].opt.quic; #endif addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; @@ -1962,6 +1985,9 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, #endif #if (NGX_HTTP_V2) addrs6[i].conf.http2 = addr[i].opt.http2; +#endif +#if (NGX_HTTP_V3) + addrs6[i].conf.quic = addr[i].opt.quic; #endif addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index a7f312f..e06464e 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -20,6 +20,8 @@ typedef struct ngx_http_file_cache_s ngx_http_file_cache_t; typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef struct ngx_http_chunked_s ngx_http_chunked_t; typedef struct ngx_http_v2_stream_s ngx_http_v2_stream_t; +typedef struct ngx_http_v3_parse_s ngx_http_v3_parse_t; +typedef struct ngx_http_v3_session_s ngx_http_v3_session_t; typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); @@ -38,6 +40,9 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, #if (NGX_HTTP_V2) #include #endif +#if (NGX_HTTP_V3) +#include +#endif #if (NGX_HTTP_CACHE) #include #endif @@ -124,6 +129,11 @@ void ngx_http_handler(ngx_http_request_t *r); void ngx_http_run_posted_requests(ngx_connection_t *c); ngx_int_t ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr); +ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, + ngx_str_t *host); +ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, + ngx_uint_t alloc); +void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc); void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc); void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc); @@ -167,7 +177,7 @@ ngx_uint_t ngx_http_degraded(ngx_http_request_t *); #endif -#if (NGX_HTTP_V2) +#if (NGX_HTTP_V2 || NGX_HTTP_V3) ngx_int_t ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log); size_t ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index bd3028b..8e5de2b 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -170,6 +170,8 @@ ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) file->aio->data = r; file->aio->handler = ngx_http_copy_aio_event_handler; + ngx_add_timer(&file->aio->event, 60000); + r->main->blocked++; r->aio = 1; ctx->aio = 1; @@ -192,12 +194,32 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http aio: \"%V?%V\"", &r->uri, &r->args); + if (ev->timedout) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "aio operation took too long"); + ev->timedout = 0; + return; + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + r->main->blocked--; r->aio = 0; - r->write_event_handler(r); + if (r->main->terminated) { + /* + * trigger connection event handler if the request was + * terminated + */ - ngx_http_run_posted_requests(c); + c->write->handler(c->write); + + } else { + r->write_event_handler(r); + ngx_http_run_posted_requests(c); + } } #endif @@ -264,6 +286,8 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) return NGX_ERROR; } + ngx_add_timer(&task->event, 60000); + r->main->blocked++; r->aio = 1; @@ -288,6 +312,17 @@ ngx_http_copy_thread_event_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http thread: \"%V?%V\"", &r->uri, &r->args); + if (ev->timedout) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "thread operation took too long"); + ev->timedout = 0; + return; + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + r->main->blocked--; r->aio = 0; @@ -305,11 +340,11 @@ ngx_http_copy_thread_event_handler(ngx_event_t *ev) #endif - if (r->done) { + if (r->done || r->main->terminated) { /* * trigger connection event handler if the subrequest was - * already finalized; this can happen if the handler is used - * for sendfile() in threads + * already finalized (this can happen if the handler is used + * for sendfile() in threads), or if the request was terminated */ c->write->handler(c->write); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 2140e06..033a3bf 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -3005,6 +3005,7 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) lsopt.socklen = sizeof(struct sockaddr_in); lsopt.backlog = NGX_LISTEN_BACKLOG; + lsopt.type = SOCK_STREAM; lsopt.rcvbuf = -1; lsopt.sndbuf = -1; #if (NGX_HAVE_SETFIB) @@ -3960,7 +3961,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value, size; ngx_url_t u; - ngx_uint_t n, i; + ngx_uint_t n, i, backlog; ngx_http_listen_opt_t lsopt; cscf->listen = 1; @@ -3986,6 +3987,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); lsopt.backlog = NGX_LISTEN_BACKLOG; + lsopt.type = SOCK_STREAM; lsopt.rcvbuf = -1; lsopt.sndbuf = -1; #if (NGX_HAVE_SETFIB) @@ -3998,6 +4000,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) lsopt.ipv6only = 1; #endif + backlog = 0; + for (n = 2; n < cf->args->nelts; n++) { if (ngx_strcmp(value[n].data, "default_server") == 0 @@ -4056,6 +4060,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + backlog = 1; + continue; } @@ -4174,6 +4180,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[n].data, "http2") == 0) { #if (NGX_HTTP_V2) + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"listen ... http2\" directive " + "is deprecated, use " + "the \"http2\" directive instead"); + lsopt.http2 = 1; continue; #else @@ -4184,6 +4195,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[n].data, "quic") == 0) { +#if (NGX_HTTP_V3) + lsopt.quic = 1; + lsopt.type = SOCK_DGRAM; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"quic\" parameter requires " + "ngx_http_v3_module"); + return NGX_CONF_ERROR; +#endif + } + if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[n].data[13], "on") == 0) { @@ -4285,6 +4309,50 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (lsopt.quic) { +#if (NGX_HAVE_TCP_FASTOPEN) + if (lsopt.fastopen != -1) { + return "\"fastopen\" parameter is incompatible with \"quic\""; + } +#endif + + if (backlog) { + return "\"backlog\" parameter is incompatible with \"quic\""; + } + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + if (lsopt.accept_filter) { + return "\"accept_filter\" parameter is incompatible with \"quic\""; + } +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + if (lsopt.deferred_accept) { + return "\"deferred\" parameter is incompatible with \"quic\""; + } +#endif + +#if (NGX_HTTP_SSL) + if (lsopt.ssl) { + return "\"ssl\" parameter is incompatible with \"quic\""; + } +#endif + +#if (NGX_HTTP_V2) + if (lsopt.http2) { + return "\"http2\" parameter is incompatible with \"quic\""; + } +#endif + + if (lsopt.so_keepalive) { + return "\"so_keepalive\" parameter is incompatible with \"quic\""; + } + + if (lsopt.proxy_protocol) { + return "\"proxy_protocol\" parameter is incompatible with \"quic\""; + } + } + for (n = 0; n < u.naddrs; n++) { for (i = 0; i < n; i++) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index e41bc68..765e7ff 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -75,6 +75,7 @@ typedef struct { unsigned wildcard:1; unsigned ssl:1; unsigned http2:1; + unsigned quic:1; #if (NGX_HAVE_INET6) unsigned ipv6only:1; #endif @@ -86,6 +87,7 @@ typedef struct { int backlog; int rcvbuf; int sndbuf; + int type; #if (NGX_HAVE_SETFIB) int setfib; #endif @@ -237,6 +239,7 @@ struct ngx_http_addr_conf_s { unsigned ssl:1; unsigned http2:1; + unsigned quic:1; unsigned proxy_protocol:1; }; @@ -266,6 +269,7 @@ typedef struct { typedef struct { ngx_int_t family; + ngx_int_t type; in_port_t port; ngx_array_t addrs; /* array of ngx_http_conf_addr_t */ } ngx_http_conf_port_t; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index aa5fd19..5209f00 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -14,7 +14,7 @@ static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c); static void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev); -static void ngx_http_file_cache_lock_wait(ngx_http_request_t *r, +static ngx_int_t ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); @@ -463,6 +463,7 @@ ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) static void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev) { + ngx_int_t rc; ngx_connection_t *c; ngx_http_request_t *r; @@ -474,13 +475,31 @@ ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http file cache wait: \"%V?%V\"", &r->uri, &r->args); - ngx_http_file_cache_lock_wait(r, r->cache); + rc = ngx_http_file_cache_lock_wait(r, r->cache); - ngx_http_run_posted_requests(c); + if (rc == NGX_AGAIN) { + return; + } + + r->cache->waiting = 0; + r->main->blocked--; + + if (r->main->terminated) { + /* + * trigger connection event handler if the request was + * terminated + */ + + c->write->handler(c->write); + + } else { + r->write_event_handler(r); + ngx_http_run_posted_requests(c); + } } -static void +static ngx_int_t ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c) { ngx_uint_t wait; @@ -495,7 +514,7 @@ ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c) ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "cache lock timeout"); c->lock_timeout = 0; - goto wakeup; + return NGX_OK; } cache = c->file_cache; @@ -513,14 +532,10 @@ ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c) if (wait) { ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer); - return; + return NGX_AGAIN; } -wakeup: - - c->waiting = 0; - r->main->blocked--; - r->write_event_handler(r); + return NGX_OK; } @@ -690,6 +705,8 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) c->file.aio->data = r; c->file.aio->handler = ngx_http_cache_aio_event_handler; + ngx_add_timer(&c->file.aio->event, 60000); + r->main->blocked++; r->aio = 1; @@ -737,12 +754,32 @@ ngx_http_cache_aio_event_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http file cache aio: \"%V?%V\"", &r->uri, &r->args); + if (ev->timedout) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "aio operation took too long"); + ev->timedout = 0; + return; + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + r->main->blocked--; r->aio = 0; - r->write_event_handler(r); + if (r->main->terminated) { + /* + * trigger connection event handler if the request was + * terminated + */ - ngx_http_run_posted_requests(c); + c->write->handler(c->write); + + } else { + r->write_event_handler(r); + ngx_http_run_posted_requests(c); + } } #endif @@ -786,6 +823,8 @@ ngx_http_cache_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) return NGX_ERROR; } + ngx_add_timer(&task->event, 60000); + r->main->blocked++; r->aio = 1; @@ -807,12 +846,32 @@ ngx_http_cache_thread_event_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http file cache thread: \"%V?%V\"", &r->uri, &r->args); + if (ev->timedout) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "thread operation took too long"); + ev->timedout = 0; + return; + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + r->main->blocked--; r->aio = 0; - r->write_event_handler(r); + if (r->main->terminated) { + /* + * trigger connection event handler if the request was + * terminated + */ - ngx_http_run_posted_requests(c); + c->write->handler(c->write); + + } else { + r->write_event_handler(r); + ngx_http_run_posted_requests(c); + } } #endif diff --git a/src/http/ngx_http_huff_decode.c b/src/http/ngx_http_huff_decode.c index 14b7b78..a65c3c3 100644 --- a/src/http/ngx_http_huff_decode.c +++ b/src/http/ngx_http_huff_decode.c @@ -2657,7 +2657,7 @@ ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, - "http2 huffman decoding error at state %d: " + "http huffman decoding error at state %d: " "bad code 0x%Xd", *state, ch >> 4); return NGX_ERROR; @@ -2667,7 +2667,7 @@ ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, - "http2 huffman decoding error at state %d: " + "http huffman decoding error at state %d: " "bad code 0x%Xd", *state, ch & 0xf); return NGX_ERROR; @@ -2677,7 +2677,7 @@ ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, if (last) { if (!ending) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http2 huffman decoding error: " + "http huffman decoding error: " "incomplete code 0x%Xd", ch); return NGX_ERROR; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index d4f2dae..f7e5038 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -451,19 +451,16 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) switch (ch) { case '/': - r->port_end = p; r->uri_start = p; state = sw_after_slash_in_uri; break; case '?': - r->port_end = p; r->uri_start = p; r->args_start = p + 1; r->empty_path_in_uri = 1; state = sw_uri; break; case ' ': - r->port_end = p; /* * use single "/" from request line to preserve pointers, * if request line will be copied to large client buffer diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 5e0340b..3cca57c 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -29,10 +29,6 @@ static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); -static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, - ngx_uint_t alloc); -static ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, - ngx_str_t *host); static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); @@ -50,7 +46,6 @@ static void ngx_http_keepalive_handler(ngx_event_t *ev); static void ngx_http_set_lingering_close(ngx_connection_t *c); static void ngx_http_lingering_close_handler(ngx_event_t *ev); static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); -static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); static void ngx_http_log_request(ngx_http_request_t *r); static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); @@ -323,24 +318,19 @@ ngx_http_init_connection(ngx_connection_t *c) rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; -#if (NGX_HTTP_V2) - if (hc->addr_conf->http2) { - rev->handler = ngx_http_v2_init; +#if (NGX_HTTP_V3) + if (hc->addr_conf->quic) { + ngx_http_v3_init_stream(c); + return; } #endif #if (NGX_HTTP_SSL) - { - ngx_http_ssl_srv_conf_t *sscf; - - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - - if (sscf->enable || hc->addr_conf->ssl) { + if (hc->addr_conf->ssl) { hc->ssl = 1; c->log->action = "SSL handshaking"; rev->handler = ngx_http_ssl_handshake; } - } #endif if (hc->addr_conf->proxy_protocol) { @@ -381,6 +371,9 @@ ngx_http_wait_request_handler(ngx_event_t *rev) ngx_buf_t *b; ngx_connection_t *c; ngx_http_connection_t *hc; +#if (NGX_HTTP_V2) + ngx_http_v2_srv_conf_t *h2scf; +#endif ngx_http_core_srv_conf_t *cscf; c = rev->data; @@ -427,6 +420,8 @@ ngx_http_wait_request_handler(ngx_event_t *rev) b->end = b->last + size; } + size = b->end - b->last; + n = c->recv(c, b->last, size); if (n == NGX_AGAIN) { @@ -441,12 +436,16 @@ ngx_http_wait_request_handler(ngx_event_t *rev) return; } - /* - * We are trying to not hold c->buffer's memory for an idle connection. - */ + if (b->pos == b->last) { - if (ngx_pfree(c->pool, b->start) == NGX_OK) { - b->start = NULL; + /* + * We are trying to not hold c->buffer's memory for an + * idle connection. + */ + + if (ngx_pfree(c->pool, b->start) == NGX_OK) { + b->start = NULL; + } } return; @@ -487,6 +486,29 @@ ngx_http_wait_request_handler(ngx_event_t *rev) } } +#if (NGX_HTTP_V2) + + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); + + if (!hc->ssl && (h2scf->enable || hc->addr_conf->http2)) { + + size = ngx_min(sizeof(NGX_HTTP_V2_PREFACE) - 1, + (size_t) (b->last - b->pos)); + + if (ngx_memcmp(b->pos, NGX_HTTP_V2_PREFACE, size) == 0) { + + if (size == sizeof(NGX_HTTP_V2_PREFACE) - 1) { + ngx_http_v2_init(rev); + return; + } + + ngx_post_event(rev, &ngx_posted_events); + return; + } + } + +#endif + c->log->action = "reading client request line"; ngx_reusable_connection(c, 0); @@ -806,13 +828,16 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) #if (NGX_HTTP_V2 \ && defined TLSEXT_TYPE_application_layer_protocol_negotiation) { - unsigned int len; - const unsigned char *data; - ngx_http_connection_t *hc; + unsigned int len; + const unsigned char *data; + ngx_http_connection_t *hc; + ngx_http_v2_srv_conf_t *h2scf; hc = c->data; - if (hc->addr_conf->http2) { + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); + + if (h2scf->enable || hc->addr_conf->http2) { SSL_get0_alpn_selected(c->ssl->connection, &data, &len); @@ -949,6 +974,14 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #ifdef SSL_OP_NO_RENEGOTIATION SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION); +#endif + +#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT +#if (NGX_HTTP_V3) + if (c->listening->quic) { + SSL_clear_options(ssl_conn, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + } +#endif #endif } @@ -1685,14 +1718,23 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, r->request_end = new + (r->request_end - old); } - r->method_end = new + (r->method_end - old); + if (r->method_end) { + r->method_end = new + (r->method_end - old); + } - r->uri_start = new + (r->uri_start - old); - r->uri_end = new + (r->uri_end - old); + if (r->uri_start) { + r->uri_start = new + (r->uri_start - old); + } + + if (r->uri_end) { + r->uri_end = new + (r->uri_end - old); + } if (r->schema_start) { r->schema_start = new + (r->schema_start - old); - r->schema_end = new + (r->schema_end - old); + if (r->schema_end) { + r->schema_end = new + (r->schema_end - old); + } } if (r->host_start) { @@ -1702,11 +1744,6 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, } } - if (r->port_start) { - r->port_start = new + (r->port_start - old); - r->port_end = new + (r->port_end - old); - } - if (r->uri_ext) { r->uri_ext = new + (r->uri_ext - old); } @@ -1721,9 +1758,18 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, } else { r->header_name_start = new; - r->header_name_end = new + (r->header_name_end - old); - r->header_start = new + (r->header_start - old); - r->header_end = new + (r->header_end - old); + + if (r->header_name_end) { + r->header_name_end = new + (r->header_name_end - old); + } + + if (r->header_start) { + r->header_start = new + (r->header_start - old); + } + + if (r->header_end) { + r->header_end = new + (r->header_end - old); + } } r->header_in = b; @@ -2095,7 +2141,7 @@ ngx_http_process_request(ngx_http_request_t *r) } -static ngx_int_t +ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) { u_char *h, ch; @@ -2187,7 +2233,7 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) } -static ngx_int_t +ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) { ngx_int_t rc; @@ -2648,6 +2694,8 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http terminate request count:%d", mr->count); + mr->terminated = 1; + if (rc > 0 && (mr->headers_out.status == 0 || mr->connection->sent == 0)) { mr->headers_out.status = rc; } @@ -2670,8 +2718,11 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc) if (mr->write_event_handler) { if (mr->blocked) { + r = r->connection->data; + r->connection->error = 1; r->write_event_handler = ngx_http_request_finalizer; + return; } @@ -2710,6 +2761,13 @@ ngx_http_finalize_connection(ngx_http_request_t *r) } #endif +#if (NGX_HTTP_V3) + if (r->connection->quic) { + ngx_http_close_request(r, 0); + return; + } +#endif + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->main->count != 1) { @@ -2925,6 +2983,20 @@ ngx_http_test_reading(ngx_http_request_t *r) #endif +#if (NGX_HTTP_V3) + + if (c->quic) { + if (rev->error) { + c->error = 1; + err = 0; + goto closed; + } + + return; + } + +#endif + #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -3590,7 +3662,7 @@ ngx_http_post_action(ngx_http_request_t *r) } -static void +void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_connection_t *c; @@ -3677,7 +3749,12 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) log->action = "closing request"; - if (r->connection->timedout) { + if (r->connection->timedout +#if (NGX_HTTP_V3) + && r->connection->quic == NULL +#endif + ) + { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->reset_timedout_connection) { @@ -3750,6 +3827,12 @@ ngx_http_close_connection(ngx_connection_t *c) #endif +#if (NGX_HTTP_V3) + if (c->quic) { + ngx_http_v3_reset_stream(c); + } +#endif + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 8c9eed2..65c8333 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -24,6 +24,7 @@ #define NGX_HTTP_VERSION_10 1000 #define NGX_HTTP_VERSION_11 1001 #define NGX_HTTP_VERSION_20 2000 +#define NGX_HTTP_VERSION_30 3000 #define NGX_HTTP_UNKNOWN 0x00000001 #define NGX_HTTP_GET 0x00000002 @@ -451,6 +452,7 @@ struct ngx_http_request_s { ngx_http_connection_t *http_connection; ngx_http_v2_stream_t *stream; + ngx_http_v3_parse_t *v3_parse; ngx_http_log_handler_pt log_handler; @@ -543,10 +545,12 @@ struct ngx_http_request_s { unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; + unsigned response_sent:1; unsigned expect_tested:1; unsigned root_tested:1; unsigned done:1; unsigned logged:1; + unsigned terminated:1; unsigned buffered:4; @@ -594,8 +598,6 @@ struct ngx_http_request_s { u_char *schema_end; u_char *host_start; u_char *host_end; - u_char *port_start; - u_char *port_end; unsigned http_minor:16; unsigned http_major:16; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index ad3549f..afb0423 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -92,6 +92,13 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } #endif +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30) { + rc = ngx_http_v3_read_request_body(r); + goto done; + } +#endif + preread = r->header_in->last - r->header_in->pos; if (preread) { @@ -238,6 +245,18 @@ ngx_http_read_unbuffered_request_body(ngx_http_request_t *r) } #endif +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30) { + rc = ngx_http_v3_read_unbuffered_request_body(r); + + if (rc == NGX_OK) { + r->reading_body = 0; + } + + return rc; + } +#endif + if (r->connection->read->timedout) { r->connection->timedout = 1; return NGX_HTTP_REQUEST_TIME_OUT; @@ -625,6 +644,12 @@ ngx_http_discard_request_body(ngx_http_request_t *r) } #endif +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30) { + return NGX_OK; + } +#endif + if (ngx_http_test_expect(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -920,6 +945,9 @@ ngx_http_test_expect(ngx_http_request_t *r) || r->http_version < NGX_HTTP_VERSION_11 #if (NGX_HTTP_V2) || r->stream != NULL +#endif +#if (NGX_HTTP_V3) + || r->connection->quic != NULL #endif ) { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 3ae822b..2ce9f21 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -521,6 +521,13 @@ ngx_http_upstream_init(ngx_http_request_t *r) } #endif +#if (NGX_HTTP_V3) + if (c->quic) { + ngx_http_upstream_init_request(r); + return; + } +#endif + if (c->read->timer_set) { ngx_del_timer(c->read); } @@ -1354,6 +1361,19 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, } #endif +#if (NGX_HTTP_V3) + + if (c->quic) { + if (c->write->error) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + } + + return; + } + +#endif + #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -3929,6 +3949,8 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r->aio = 1; p->aio = 1; + ngx_add_timer(&task->event, 60000); + return NGX_OK; } @@ -3947,6 +3969,17 @@ ngx_http_upstream_thread_event_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream thread: \"%V?%V\"", &r->uri, &r->args); + if (ev->timedout) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "thread operation took too long"); + ev->timedout = 0; + return; + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + r->main->blocked--; r->aio = 0; @@ -3964,11 +3997,11 @@ ngx_http_upstream_thread_event_handler(ngx_event_t *ev) #endif - if (r->done) { + if (r->done || r->main->terminated) { /* * trigger connection event handler if the subrequest was - * already finalized; this can happen if the handler is used - * for sendfile() in threads + * already finalized (this can happen if the handler is used + * for sendfile() in threads), or if the request was terminated */ c->write->handler(c->write); @@ -4541,6 +4574,10 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, u->peer.connection = NULL; + if (u->pipe) { + u->pipe->upstream = NULL; + } + if (u->pipe && u->pipe->temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 16ffda3..4f0bd0e 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -828,7 +828,7 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data, u_char sep) { size_t len; - u_char *p; + u_char *p, *end; ngx_table_elt_t *h, *th; h = *(ngx_table_elt_t **) ((char *) r + data); @@ -870,6 +870,8 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r, v->len = len; v->data = p; + end = p + len; + for (th = h; th; th = th->next) { if (th->hash == 0) { @@ -878,7 +880,7 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r, p = ngx_copy(p, th->value.data, th->value.len); - if (th->next == NULL) { + if (p == end) { break; } diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 89ab49e..9188ee9 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -240,6 +240,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) r->out = NULL; c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; + if (last) { + r->response_sent = 1; + } + return NGX_OK; } @@ -346,6 +350,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; + if (last) { + r->response_sent = 1; + } + if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) { return NGX_AGAIN; } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index ea3f27c..0f5bd3d 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -11,14 +11,6 @@ #include -typedef struct { - ngx_str_t name; - ngx_uint_t offset; - ngx_uint_t hash; - ngx_http_header_t *hh; -} ngx_http_v2_parse_header_t; - - /* errors */ #define NGX_HTTP_V2_NO_ERROR 0x0 #define NGX_HTTP_V2_PROTOCOL_ERROR 0x1 @@ -63,8 +55,6 @@ static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c); static void ngx_http_v2_lingering_close(ngx_connection_t *c); static void ngx_http_v2_lingering_close_handler(ngx_event_t *rev); -static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, - u_char *pos, u_char *end); static u_char *ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end); static u_char *ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, @@ -128,7 +118,7 @@ static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, ngx_uint_t prefix); static ngx_http_v2_stream_t *ngx_http_v2_create_stream( - ngx_http_v2_connection_t *h2c, ngx_uint_t push); + ngx_http_v2_connection_t *h2c); static ngx_http_v2_node_t *ngx_http_v2_get_node_by_id( ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t alloc); static ngx_http_v2_node_t *ngx_http_v2_get_closed_node( @@ -164,14 +154,11 @@ static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value); static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value); -static ngx_int_t ngx_http_v2_parse_header(ngx_http_request_t *r, - ngx_http_v2_parse_header_t *header, ngx_str_t *value); static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r); static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header); static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); static void ngx_http_v2_run_request(ngx_http_request_t *r); -static void ngx_http_v2_run_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, size_t size, ngx_uint_t last, ngx_uint_t flush); static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r); @@ -212,26 +199,10 @@ static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = { (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt)) -static ngx_http_v2_parse_header_t ngx_http_v2_parse_headers[] = { - { ngx_string("host"), - offsetof(ngx_http_headers_in_t, host), 0, NULL }, - - { ngx_string("accept-encoding"), - offsetof(ngx_http_headers_in_t, accept_encoding), 0, NULL }, - - { ngx_string("accept-language"), - offsetof(ngx_http_headers_in_t, accept_language), 0, NULL }, - - { ngx_string("user-agent"), - offsetof(ngx_http_headers_in_t, user_agent), 0, NULL }, - - { ngx_null_string, 0, 0, NULL } -}; - - void ngx_http_v2_init(ngx_event_t *rev) { + u_char *p, *end; ngx_connection_t *c; ngx_pool_cleanup_t *cln; ngx_http_connection_t *hc; @@ -276,7 +247,6 @@ ngx_http_v2_init(ngx_event_t *rev) h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); - h2c->concurrent_pushes = h2scf->concurrent_pushes; h2c->priority_limit = ngx_max(h2scf->concurrent_streams, 100); h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); @@ -314,8 +284,7 @@ ngx_http_v2_init(ngx_event_t *rev) return; } - h2c->state.handler = hc->proxy_protocol ? ngx_http_v2_state_proxy_protocol - : ngx_http_v2_state_preface; + h2c->state.handler = ngx_http_v2_state_preface; ngx_queue_init(&h2c->waiting); ngx_queue_init(&h2c->dependencies); @@ -335,6 +304,23 @@ ngx_http_v2_init(ngx_event_t *rev) c->idle = 1; ngx_reusable_connection(c, 0); + if (c->buffer) { + p = c->buffer->pos; + end = c->buffer->last; + + do { + p = h2c->state.handler(h2c, p, end); + + if (p == NULL) { + return; + } + + } while (p != end); + + h2c->total_bytes += p - c->buffer->pos; + c->buffer->pos = p; + } + ngx_http_v2_read_handler(rev); } @@ -361,6 +347,7 @@ ngx_http_v2_read_handler(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); h2c->blocked = 1; + h2c->new_streams = 0; if (c->close) { c->close = 0; @@ -370,7 +357,7 @@ ngx_http_v2_read_handler(ngx_event_t *rev) return; } - if (!h2c->processing && !h2c->pushing) { + if (!h2c->processing) { ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); return; } @@ -399,13 +386,11 @@ ngx_http_v2_read_handler(ngx_event_t *rev) h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); - available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE; + available = h2mcf->recv_buffer_size - NGX_HTTP_V2_STATE_BUFFER_SIZE; do { p = h2mcf->recv_buffer; - - ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE); - end = p + h2c->state.buffer_used; + end = ngx_cpymem(p, h2c->state.buffer, h2c->state.buffer_used); n = c->recv(c, end, available); @@ -413,9 +398,7 @@ ngx_http_v2_read_handler(ngx_event_t *rev) break; } - if (n == 0 - && (h2c->state.incomplete || h2c->processing || h2c->pushing)) - { + if (n == 0 && (h2c->state.incomplete || h2c->processing)) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely closed connection"); } @@ -638,7 +621,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; - if (h2c->last_out || h2c->processing || h2c->pushing) { + if (h2c->last_out || h2c->processing) { return; } @@ -846,32 +829,11 @@ ngx_http_v2_lingering_close_handler(ngx_event_t *rev) } -static u_char * -ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos, - u_char *end) -{ - ngx_log_t *log; - - log = h2c->connection->log; - log->action = "reading PROXY protocol"; - - pos = ngx_proxy_protocol_read(h2c->connection, pos, end); - - log->action = "processing HTTP/2 connection"; - - if (pos == NULL) { - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); - } - - return ngx_http_v2_state_preface(h2c, pos, end); -} - - static u_char * ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - static const u_char preface[] = "PRI * HTTP/2.0\r\n"; + static const u_char preface[] = NGX_HTTP_V2_PREFACE_START; if ((size_t) (end - pos) < sizeof(preface) - 1) { return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_preface); @@ -892,7 +854,7 @@ static u_char * ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - static const u_char preface[] = "\r\nSM\r\n\r\n"; + static const u_char preface[] = NGX_HTTP_V2_PREFACE_END; if ((size_t) (end - pos) < sizeof(preface) - 1) { return ngx_http_v2_state_save(h2c, pos, end, @@ -1321,6 +1283,14 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, goto rst_stream; } + if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent too many streams at once"); + + status = NGX_HTTP_V2_REFUSED_STREAM; + goto rst_stream; + } + if (!h2c->settings_ack && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW) @@ -1344,7 +1314,7 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->closed_nodes--; } - stream = ngx_http_v2_create_stream(h2c, 0); + stream = ngx_http_v2_create_stream(h2c); if (stream == NULL) { return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } @@ -1386,6 +1356,12 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, rst_stream: + if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent too many refused streams"); + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR); + } + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) { return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } @@ -2133,11 +2109,6 @@ ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, u_char *pos, "client canceled stream %ui", h2c->state.sid); break; - case NGX_HTTP_V2_REFUSED_STREAM: - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client refused stream %ui", h2c->state.sid); - break; - case NGX_HTTP_V2_INTERNAL_ERROR: ngx_log_error(NGX_LOG_INFO, fc->log, 0, "client terminated stream %ui due to internal error", @@ -2205,7 +2176,6 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, { ssize_t window_delta; ngx_uint_t id, value; - ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_out_frame_t *frame; window_delta = 0; @@ -2267,14 +2237,6 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_PROTOCOL_ERROR); } - h2c->push_disabled = !value; - break; - - case NGX_HTTP_V2_MAX_STREAMS_SETTING: - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); - - h2c->concurrent_pushes = ngx_min(value, h2scf->concurrent_pushes); break; case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING: @@ -2628,7 +2590,7 @@ ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } - ngx_memcpy(h2c->state.buffer, pos, NGX_HTTP_V2_STATE_BUFFER_SIZE); + ngx_memcpy(h2c->state.buffer, pos, size); h2c->state.buffer_used = size; h2c->state.handler = handler; @@ -2729,163 +2691,6 @@ ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, } -ngx_http_v2_stream_t * -ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path) -{ - ngx_int_t rc; - ngx_str_t value; - ngx_pool_t *pool; - ngx_uint_t index; - ngx_table_elt_t **h; - ngx_connection_t *fc; - ngx_http_request_t *r; - ngx_http_v2_node_t *node; - ngx_http_v2_stream_t *stream; - ngx_http_v2_srv_conf_t *h2scf; - ngx_http_v2_connection_t *h2c; - ngx_http_v2_parse_header_t *header; - - h2c = parent->connection; - - pool = ngx_create_pool(1024, h2c->connection->log); - if (pool == NULL) { - goto rst_stream; - } - - node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1); - - if (node == NULL) { - ngx_destroy_pool(pool); - goto rst_stream; - } - - stream = ngx_http_v2_create_stream(h2c, 1); - if (stream == NULL) { - - if (node->parent == NULL) { - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); - - index = ngx_http_v2_index(h2scf, h2c->last_push); - h2c->streams_index[index] = node->index; - - ngx_queue_insert_tail(&h2c->closed, &node->reuse); - h2c->closed_nodes++; - } - - ngx_destroy_pool(pool); - goto rst_stream; - } - - if (node->parent) { - ngx_queue_remove(&node->reuse); - h2c->closed_nodes--; - } - - stream->pool = pool; - - r = stream->request; - fc = r->connection; - - stream->in_closed = 1; - stream->node = node; - - node->stream = stream; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 push stream sid:%ui " - "depends on %ui excl:0 weight:16", - h2c->last_push, parent->node->id); - - node->weight = NGX_HTTP_V2_DEFAULT_WEIGHT; - ngx_http_v2_set_dependency(h2c, node, parent->node->id, 0); - - r->method_name = ngx_http_core_get_method; - r->method = NGX_HTTP_GET; - - r->schema.data = ngx_pstrdup(pool, &parent->request->schema); - if (r->schema.data == NULL) { - goto close; - } - - r->schema.len = parent->request->schema.len; - - value.data = ngx_pstrdup(pool, path); - if (value.data == NULL) { - goto close; - } - - value.len = path->len; - - rc = ngx_http_v2_parse_path(r, &value); - - if (rc != NGX_OK) { - goto error; - } - - for (header = ngx_http_v2_parse_headers; header->name.len; header++) { - h = (ngx_table_elt_t **) - ((char *) &parent->request->headers_in + header->offset); - - if (*h == NULL) { - continue; - } - - value.len = (*h)->value.len; - - value.data = ngx_pnalloc(pool, value.len + 1); - if (value.data == NULL) { - goto close; - } - - ngx_memcpy(value.data, (*h)->value.data, value.len); - value.data[value.len] = '\0'; - - rc = ngx_http_v2_parse_header(r, header, &value); - - if (rc != NGX_OK) { - goto error; - } - } - - fc->write->handler = ngx_http_v2_run_request_handler; - ngx_post_event(fc->write, &ngx_posted_events); - - return stream; - -error: - - if (rc == NGX_ABORT) { - /* header handler has already finalized request */ - ngx_http_run_posted_requests(fc); - return NULL; - } - - if (rc == NGX_DECLINED) { - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - ngx_http_run_posted_requests(fc); - return NULL; - } - -close: - - ngx_http_v2_close_stream(stream, NGX_HTTP_INTERNAL_SERVER_ERROR); - - return NULL; - -rst_stream: - - if (ngx_http_v2_send_rst_stream(h2c, h2c->last_push, - NGX_HTTP_INTERNAL_SERVER_ERROR) - != NGX_OK) - { - h2c->connection->error = 1; - } - - return NULL; -} - - static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c) { @@ -3157,7 +2962,7 @@ ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, static ngx_http_v2_stream_t * -ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) +ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) { ngx_log_t *log; ngx_event_t *rev, *wev; @@ -3212,13 +3017,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t)); log->data = ctx; - - if (push) { - log->action = "processing pushed request headers"; - - } else { - log->action = "reading client request headers"; - } + log->action = "reading client request headers"; ngx_memzero(rev, sizeof(ngx_event_t)); @@ -3290,12 +3089,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) stream->send_window = h2c->init_window; stream->recv_window = h2scf->preread_size; - if (push) { - h2c->pushing++; - - } else { - h2c->processing++; - } + h2c->processing++; h2c->priority_limit += h2scf->concurrent_streams; @@ -3717,46 +3511,42 @@ ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value) static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value) -{ - return ngx_http_v2_parse_header(r, &ngx_http_v2_parse_headers[0], value); -} - - -static ngx_int_t -ngx_http_v2_parse_header(ngx_http_request_t *r, - ngx_http_v2_parse_header_t *header, ngx_str_t *value) { ngx_table_elt_t *h; + ngx_http_header_t *hh; ngx_http_core_main_conf_t *cmcf; + static ngx_str_t host = ngx_string("host"); + h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { return NGX_ERROR; } - h->key.len = header->name.len; - h->key.data = header->name.data; - h->lowcase_key = header->name.data; + h->hash = ngx_hash(ngx_hash(ngx_hash('h', 'o'), 's'), 't'); - if (header->hh == NULL) { - header->hash = ngx_hash_key(header->name.data, header->name.len); - - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - header->hh = ngx_hash_find(&cmcf->headers_in_hash, header->hash, - h->lowcase_key, h->key.len); - if (header->hh == NULL) { - return NGX_ERROR; - } - } - - h->hash = header->hash; + h->key.len = host.len; + h->key.data = host.data; h->value.len = value->len; h->value.data = value->data; - if (header->hh->handler(r, h, header->hh->offset) != NGX_OK) { - /* header handler has already finalized request */ + h->lowcase_key = host.data; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); + + if (hh == NULL) { + return NGX_ERROR; + } + + if (hh->handler(r, h, hh->offset) != NGX_OK) { + /* + * request has been finalized already + * in ngx_http_process_host() + */ return NGX_ABORT; } @@ -3943,10 +3733,22 @@ static void ngx_http_v2_run_request(ngx_http_request_t *r) { ngx_connection_t *fc; + ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_connection_t *h2c; fc = r->connection; + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); + + if (!h2scf->enable && !r->http_connection->addr_conf->http2) { + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client attempted to request the server name " + "for which the negotiated protocol is disabled"); + + ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST); + goto failed; + } + if (ngx_http_v2_construct_request_line(r) != NGX_OK) { goto failed; } @@ -3987,22 +3789,6 @@ failed: } -static void -ngx_http_v2_run_request_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, fc->log, 0, - "http2 run request handler"); - - ngx_http_v2_run_request(r); -} - - ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r) { @@ -4606,7 +4392,6 @@ void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) { ngx_pool_t *pool; - ngx_uint_t push; ngx_event_t *ev; ngx_connection_t *fc; ngx_http_v2_node_t *node; @@ -4615,10 +4400,9 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) h2c = stream->connection; node = stream->node; - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 close stream %ui, queued %ui, " - "processing %ui, pushing %ui", - node->id, stream->queued, h2c->processing, h2c->pushing); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 close stream %ui, queued %ui, processing %ui", + node->id, stream->queued, h2c->processing); fc = stream->request->connection; @@ -4653,8 +4437,6 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) h2c->state.stream = NULL; } - push = stream->node->id % 2 == 0; - node->stream = NULL; ngx_queue_insert_tail(&h2c->closed, &node->reuse); @@ -4704,14 +4486,9 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) fc->data = h2c->free_fake_connections; h2c->free_fake_connections = fc; - if (push) { - h2c->pushing--; + h2c->processing--; - } else { - h2c->processing--; - } - - if (h2c->processing || h2c->pushing || h2c->blocked) { + if (h2c->processing || h2c->blocked) { return; } @@ -4887,7 +4664,7 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, } } - if (!h2c->processing && !h2c->pushing) { + if (!h2c->processing) { goto done; } @@ -4935,7 +4712,7 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, h2c->blocked = 0; - if (h2c->processing || h2c->pushing) { + if (h2c->processing) { c->error = 1; return; } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 4e25293..6751b30 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -24,8 +24,6 @@ #define NGX_HTTP_V2_MAX_FIELD \ (127 + (1 << (NGX_HTTP_V2_INT_OCTETS - 1) * 7) - 1) -#define NGX_HTTP_V2_STREAM_ID_SIZE 4 - #define NGX_HTTP_V2_FRAME_HEADER_SIZE 9 /* frame types */ @@ -63,6 +61,15 @@ typedef u_char *(*ngx_http_v2_handler_pt) (ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end); +typedef struct { + ngx_flag_t enable; + size_t pool_size; + ngx_uint_t concurrent_streams; + size_t preread_size; + ngx_uint_t streams_index_mask; +} ngx_http_v2_srv_conf_t; + + typedef struct { ngx_str_t name; ngx_str_t value; @@ -124,11 +131,10 @@ struct ngx_http_v2_connection_s { ngx_uint_t processing; ngx_uint_t frames; ngx_uint_t idle; + ngx_uint_t new_streams; + ngx_uint_t refused_streams; ngx_uint_t priority_limit; - ngx_uint_t pushing; - ngx_uint_t concurrent_pushes; - size_t send_window; size_t recv_window; size_t init_window; @@ -155,7 +161,6 @@ struct ngx_http_v2_connection_s { ngx_uint_t closed_nodes; ngx_uint_t last_sid; - ngx_uint_t last_push; time_t lingering_time; @@ -163,7 +168,6 @@ struct ngx_http_v2_connection_s { unsigned table_update:1; unsigned blocked:1; unsigned goaway:1; - unsigned push_disabled:1; }; @@ -293,9 +297,6 @@ void ngx_http_v2_init(ngx_event_t *rev); ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r); ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r); -ngx_http_v2_stream_t *ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, - ngx_str_t *path); - void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc); ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c); @@ -397,20 +398,25 @@ ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); #define NGX_HTTP_V2_STATUS_404_INDEX 13 #define NGX_HTTP_V2_STATUS_500_INDEX 14 -#define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16 -#define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17 #define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28 #define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31 #define NGX_HTTP_V2_DATE_INDEX 33 #define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44 #define NGX_HTTP_V2_LOCATION_INDEX 46 #define NGX_HTTP_V2_SERVER_INDEX 54 -#define NGX_HTTP_V2_USER_AGENT_INDEX 58 #define NGX_HTTP_V2_VARY_INDEX 59 +#define NGX_HTTP_V2_PREFACE_START "PRI * HTTP/2.0\r\n" +#define NGX_HTTP_V2_PREFACE_END "\r\nSM\r\n\r\n" +#define NGX_HTTP_V2_PREFACE NGX_HTTP_V2_PREFACE_START \ + NGX_HTTP_V2_PREFACE_END + u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, ngx_uint_t lower); +extern ngx_module_t ngx_http_v2_module; + + #endif /* _NGX_HTTP_V2_H_INCLUDED_ */ diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 5f8626a..1e2cafa 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -27,39 +27,8 @@ #define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 -typedef struct { - ngx_str_t name; - u_char index; - ngx_uint_t offset; -} ngx_http_v2_push_header_t; - - -static ngx_http_v2_push_header_t ngx_http_v2_push_headers[] = { - { ngx_string(":authority"), NGX_HTTP_V2_AUTHORITY_INDEX, - offsetof(ngx_http_headers_in_t, host) }, - - { ngx_string("accept-encoding"), NGX_HTTP_V2_ACCEPT_ENCODING_INDEX, - offsetof(ngx_http_headers_in_t, accept_encoding) }, - - { ngx_string("accept-language"), NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX, - offsetof(ngx_http_headers_in_t, accept_language) }, - - { ngx_string("user-agent"), NGX_HTTP_V2_USER_AGENT_INDEX, - offsetof(ngx_http_headers_in_t, user_agent) }, -}; - -#define NGX_HTTP_V2_PUSH_HEADERS \ - (sizeof(ngx_http_v2_push_headers) / sizeof(ngx_http_v2_push_header_t)) - - -static ngx_int_t ngx_http_v2_push_resources(ngx_http_request_t *r); -static ngx_int_t ngx_http_v2_push_resource(ngx_http_request_t *r, - ngx_str_t *path, ngx_str_t *binary); - static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame( ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin); -static ngx_http_v2_out_frame_t *ngx_http_v2_create_push_frame( - ngx_http_request_t *r, u_char *pos, u_char *end); static ngx_http_v2_out_frame_t *ngx_http_v2_create_trailers_frame( ngx_http_request_t *r); @@ -82,8 +51,6 @@ static ngx_inline ngx_int_t ngx_http_v2_filter_send( static ngx_int_t ngx_http_v2_headers_frame_handler( ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); -static ngx_int_t ngx_http_v2_push_frame_handler( - ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); static ngx_int_t ngx_http_v2_data_frame_handler( ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); static ngx_inline void ngx_http_v2_handle_frame( @@ -244,15 +211,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) h2c = stream->connection; - if (!h2c->push_disabled && !h2c->goaway - && stream->node->id % 2 == 1 - && r->method != NGX_HTTP_HEAD) - { - if (ngx_http_v2_push_resources(r) != NGX_OK) { - return NGX_ERROR; - } - } - len = h2c->table_update ? 1 : 0; len += status ? 1 : 1 + ngx_http_v2_literal_size("418"); @@ -653,7 +611,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) ngx_http_v2_queue_blocked_frame(h2c, frame); - stream->queued++; + stream->queued = 1; cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { @@ -671,409 +629,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } -static ngx_int_t -ngx_http_v2_push_resources(ngx_http_request_t *r) -{ - u_char *start, *end, *last; - ngx_int_t rc; - ngx_str_t path; - ngx_uint_t i, push; - ngx_table_elt_t *h; - ngx_http_v2_loc_conf_t *h2lcf; - ngx_http_complex_value_t *pushes; - ngx_str_t binary[NGX_HTTP_V2_PUSH_HEADERS]; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 push resources"); - - ngx_memzero(binary, NGX_HTTP_V2_PUSH_HEADERS * sizeof(ngx_str_t)); - - h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module); - - if (h2lcf->pushes) { - pushes = h2lcf->pushes->elts; - - for (i = 0; i < h2lcf->pushes->nelts; i++) { - - if (ngx_http_complex_value(r, &pushes[i], &path) != NGX_OK) { - return NGX_ERROR; - } - - if (path.len == 0) { - continue; - } - - if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) { - continue; - } - - rc = ngx_http_v2_push_resource(r, &path, binary); - - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc == NGX_ABORT) { - return NGX_OK; - } - - /* NGX_OK, NGX_DECLINED */ - } - } - - if (!h2lcf->push_preload) { - return NGX_OK; - } - - for (h = r->headers_out.link; h; h = h->next) { - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 parse link: \"%V\"", &h->value); - - start = h->value.data; - end = h->value.data + h->value.len; - - next_link: - - while (start < end && *start == ' ') { start++; } - - if (start == end || *start++ != '<') { - continue; - } - - while (start < end && *start == ' ') { start++; } - - for (last = start; last < end && *last != '>'; last++) { - /* void */ - } - - if (last == start || last == end) { - continue; - } - - path.len = last - start; - path.data = start; - - start = last + 1; - - while (start < end && *start == ' ') { start++; } - - if (start == end) { - continue; - } - - if (*start == ',') { - start++; - goto next_link; - } - - if (*start++ != ';') { - continue; - } - - last = ngx_strlchr(start, end, ','); - - if (last == NULL) { - last = end; - } - - push = 0; - - for ( ;; ) { - - while (start < last && *start == ' ') { start++; } - - if (last - start >= 6 - && ngx_strncasecmp(start, (u_char *) "nopush", 6) == 0) - { - start += 6; - - if (start == last || *start == ' ' || *start == ';') { - push = 0; - break; - } - - goto next_param; - } - - if (last - start >= 11 - && ngx_strncasecmp(start, (u_char *) "rel=preload", 11) == 0) - { - start += 11; - - if (start == last || *start == ' ' || *start == ';') { - push = 1; - } - - goto next_param; - } - - if (last - start >= 4 - && ngx_strncasecmp(start, (u_char *) "rel=", 4) == 0) - { - start += 4; - - while (start < last && *start == ' ') { start++; } - - if (start == last || *start++ != '"') { - goto next_param; - } - - for ( ;; ) { - - while (start < last && *start == ' ') { start++; } - - if (last - start >= 7 - && ngx_strncasecmp(start, (u_char *) "preload", 7) == 0) - { - start += 7; - - if (start < last && (*start == ' ' || *start == '"')) { - push = 1; - break; - } - } - - while (start < last && *start != ' ' && *start != '"') { - start++; - } - - if (start == last) { - break; - } - - if (*start == '"') { - break; - } - - start++; - } - } - - next_param: - - start = ngx_strlchr(start, last, ';'); - - if (start == NULL) { - break; - } - - start++; - } - - if (push) { - while (path.len && path.data[path.len - 1] == ' ') { - path.len--; - } - } - - if (push && path.len - && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/')) - { - rc = ngx_http_v2_push_resource(r, &path, binary); - - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc == NGX_ABORT) { - return NGX_OK; - } - - /* NGX_OK, NGX_DECLINED */ - } - - if (last < end) { - start = last + 1; - goto next_link; - } - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, - ngx_str_t *binary) -{ - u_char *start, *pos, *tmp; - size_t len; - ngx_str_t *value; - ngx_uint_t i; - ngx_table_elt_t **h; - ngx_connection_t *fc; - ngx_http_v2_stream_t *stream; - ngx_http_v2_out_frame_t *frame; - ngx_http_v2_connection_t *h2c; - ngx_http_v2_push_header_t *ph; - - fc = r->connection; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 push resource"); - - stream = r->stream; - h2c = stream->connection; - - if (!ngx_path_separator(path->data[0])) { - ngx_log_error(NGX_LOG_WARN, fc->log, 0, - "non-absolute path \"%V\" not pushed", path); - return NGX_DECLINED; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 pushing:%ui limit:%ui", - h2c->pushing, h2c->concurrent_pushes); - - if (h2c->pushing >= h2c->concurrent_pushes) { - return NGX_ABORT; - } - - if (h2c->last_push == 0x7ffffffe) { - return NGX_ABORT; - } - - if (path->len > NGX_HTTP_V2_MAX_FIELD) { - return NGX_DECLINED; - } - - if (r->headers_in.host == NULL) { - return NGX_ABORT; - } - - ph = ngx_http_v2_push_headers; - - len = ngx_max(r->schema.len, path->len); - - if (binary[0].len) { - tmp = ngx_palloc(r->pool, len); - if (tmp == NULL) { - return NGX_ERROR; - } - - } else { - for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { - h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); - - if (*h) { - len = ngx_max(len, (*h)->value.len); - } - } - - tmp = ngx_palloc(r->pool, len); - if (tmp == NULL) { - return NGX_ERROR; - } - - for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { - h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); - - if (*h == NULL) { - continue; - } - - value = &(*h)->value; - - len = 1 + NGX_HTTP_V2_INT_OCTETS + value->len; - - pos = ngx_pnalloc(r->pool, len); - if (pos == NULL) { - return NGX_ERROR; - } - - binary[i].data = pos; - - *pos++ = ngx_http_v2_inc_indexed(ph[i].index); - pos = ngx_http_v2_write_value(pos, value->data, value->len, tmp); - - binary[i].len = pos - binary[i].data; - } - } - - len = (h2c->table_update ? 1 : 0) - + 1 - + 1 + NGX_HTTP_V2_INT_OCTETS + path->len - + 1 + NGX_HTTP_V2_INT_OCTETS + r->schema.len; - - for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { - len += binary[i].len; - } - - pos = ngx_pnalloc(r->pool, len); - if (pos == NULL) { - return NGX_ERROR; - } - - start = pos; - - if (h2c->table_update) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 table size update: 0"); - *pos++ = (1 << 5) | 0; - h2c->table_update = 0; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 push header: \":method: GET\""); - - *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 push header: \":path: %V\"", path); - - *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); - pos = ngx_http_v2_write_value(pos, path->data, path->len, tmp); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 push header: \":scheme: %V\"", &r->schema); - - if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) { - *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); - - } else if (r->schema.len == 4 - && ngx_strncmp(r->schema.data, "http", 4) == 0) - { - *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); - - } else { - *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); - pos = ngx_http_v2_write_value(pos, r->schema.data, r->schema.len, tmp); - } - - for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { - h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); - - if (*h == NULL) { - continue; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 push header: \"%V: %V\"", - &ph[i].name, &(*h)->value); - - pos = ngx_cpymem(pos, binary[i].data, binary[i].len); - } - - frame = ngx_http_v2_create_push_frame(r, start, pos); - if (frame == NULL) { - return NGX_ERROR; - } - - ngx_http_v2_queue_blocked_frame(h2c, frame); - - stream->queued++; - - stream = ngx_http_v2_push_stream(stream, path); - - if (stream) { - stream->request->request_length = pos - start; - return NGX_OK; - } - - return NGX_ERROR; -} - - static ngx_http_v2_out_frame_t * ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin) @@ -1179,125 +734,6 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, } -static ngx_http_v2_out_frame_t * -ngx_http_v2_create_push_frame(ngx_http_request_t *r, u_char *pos, u_char *end) -{ - u_char type, flags; - size_t rest, frame_size, len; - ngx_buf_t *b; - ngx_chain_t *cl, **ll; - ngx_http_v2_stream_t *stream; - ngx_http_v2_out_frame_t *frame; - ngx_http_v2_connection_t *h2c; - - stream = r->stream; - h2c = stream->connection; - rest = NGX_HTTP_V2_STREAM_ID_SIZE + (end - pos); - - frame = ngx_palloc(r->pool, sizeof(ngx_http_v2_out_frame_t)); - if (frame == NULL) { - return NULL; - } - - frame->handler = ngx_http_v2_push_frame_handler; - frame->stream = stream; - frame->length = rest; - frame->blocked = 1; - frame->fin = 0; - - ll = &frame->first; - - type = NGX_HTTP_V2_PUSH_PROMISE_FRAME; - flags = NGX_HTTP_V2_NO_FLAG; - frame_size = h2c->frame_size; - - for ( ;; ) { - if (rest <= frame_size) { - frame_size = rest; - flags |= NGX_HTTP_V2_END_HEADERS_FLAG; - } - - b = ngx_create_temp_buf(r->pool, - NGX_HTTP_V2_FRAME_HEADER_SIZE - + ((type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) - ? NGX_HTTP_V2_STREAM_ID_SIZE : 0)); - if (b == NULL) { - return NULL; - } - - b->last = ngx_http_v2_write_len_and_type(b->last, frame_size, type); - *b->last++ = flags; - b->last = ngx_http_v2_write_sid(b->last, stream->node->id); - - b->tag = (ngx_buf_tag_t) &ngx_http_v2_module; - - if (type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) { - h2c->last_push += 2; - - b->last = ngx_http_v2_write_sid(b->last, h2c->last_push); - len = frame_size - NGX_HTTP_V2_STREAM_ID_SIZE; - - } else { - len = frame_size; - } - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NULL; - } - - cl->buf = b; - - *ll = cl; - ll = &cl->next; - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NULL; - } - - b->pos = pos; - - pos += len; - - b->last = pos; - b->start = b->pos; - b->end = b->last; - b->temporary = 1; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NULL; - } - - cl->buf = b; - - *ll = cl; - ll = &cl->next; - - rest -= frame_size; - - if (rest) { - frame->length += NGX_HTTP_V2_FRAME_HEADER_SIZE; - - type = NGX_HTTP_V2_CONTINUATION_FRAME; - continue; - } - - cl->next = NULL; - frame->last = cl; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2:%ui create PUSH_PROMISE frame %p: " - "sid:%ui len:%uz", - stream->node->id, frame, h2c->last_push, - frame->length); - - return frame; - } -} - - static ngx_http_v2_out_frame_t * ngx_http_v2_create_trailers_frame(ngx_http_request_t *r) { @@ -1901,62 +1337,6 @@ ngx_http_v2_headers_frame_handler(ngx_http_v2_connection_t *h2c, } -static ngx_int_t -ngx_http_v2_push_frame_handler(ngx_http_v2_connection_t *h2c, - ngx_http_v2_out_frame_t *frame) -{ - ngx_chain_t *cl, *ln; - ngx_http_v2_stream_t *stream; - - stream = frame->stream; - cl = frame->first; - - for ( ;; ) { - if (cl->buf->pos != cl->buf->last) { - frame->first = cl; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2:%ui PUSH_PROMISE frame %p was sent partially", - stream->node->id, frame); - - return NGX_AGAIN; - } - - ln = cl->next; - - if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) { - cl->next = stream->free_frame_headers; - stream->free_frame_headers = cl; - - } else { - cl->next = stream->free_bufs; - stream->free_bufs = cl; - } - - if (cl == frame->last) { - break; - } - - cl = ln; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2:%ui PUSH_PROMISE frame %p was sent", - stream->node->id, frame); - - stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE - + frame->length; - - h2c->payload_bytes += frame->length; - - ngx_http_v2_handle_frame(stream, frame); - - ngx_http_v2_handle_stream(h2c, stream); - - return NGX_OK; -} - - static ngx_int_t ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame) diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 0050886..d64488c 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -27,8 +27,6 @@ static void *ngx_http_v2_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_http_v2_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data); @@ -75,6 +73,13 @@ static ngx_conf_post_t ngx_http_v2_chunk_size_post = static ngx_command_t ngx_http_v2_commands[] = { + { ngx_string("http2"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, enable), + NULL }, + { ngx_string("http2_recv_buffer_size"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -98,9 +103,9 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_max_concurrent_pushes"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, concurrent_pushes), + ngx_http_v2_obsolete, + 0, + 0, NULL }, { ngx_string("http2_max_requests"), @@ -161,15 +166,15 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_push_preload"), 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_v2_loc_conf_t, push_preload), + ngx_http_v2_obsolete, + 0, + 0, NULL }, { ngx_string("http2_push"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_v2_push, - NGX_HTTP_LOC_CONF_OFFSET, + ngx_http_v2_obsolete, + 0, 0, NULL }, @@ -314,10 +319,11 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) return NULL; } + h2scf->enable = NGX_CONF_UNSET; + h2scf->pool_size = NGX_CONF_UNSET_SIZE; h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; - h2scf->concurrent_pushes = NGX_CONF_UNSET_UINT; h2scf->preread_size = NGX_CONF_UNSET_SIZE; @@ -333,12 +339,12 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_v2_srv_conf_t *prev = parent; ngx_http_v2_srv_conf_t *conf = child; + ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_size_value(conf->pool_size, prev->pool_size, 4096); ngx_conf_merge_uint_value(conf->concurrent_streams, prev->concurrent_streams, 128); - ngx_conf_merge_uint_value(conf->concurrent_pushes, - prev->concurrent_pushes, 10); ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536); @@ -359,17 +365,8 @@ ngx_http_v2_create_loc_conf(ngx_conf_t *cf) return NULL; } - /* - * set by ngx_pcalloc(): - * - * h2lcf->pushes = NULL; - */ - h2lcf->chunk_size = NGX_CONF_UNSET_SIZE; - h2lcf->push_preload = NGX_CONF_UNSET; - h2lcf->push = NGX_CONF_UNSET; - return h2lcf; } @@ -382,72 +379,6 @@ ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024); - ngx_conf_merge_value(conf->push, prev->push, 1); - - if (conf->push && conf->pushes == NULL) { - conf->pushes = prev->pushes; - } - - ngx_conf_merge_value(conf->push_preload, prev->push_preload, 0); - - return NGX_CONF_OK; -} - - -static char * -ngx_http_v2_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_v2_loc_conf_t *h2lcf = conf; - - ngx_str_t *value; - ngx_http_complex_value_t *cv; - ngx_http_compile_complex_value_t ccv; - - value = cf->args->elts; - - if (ngx_strcmp(value[1].data, "off") == 0) { - - if (h2lcf->pushes) { - return "\"off\" parameter cannot be used with URI"; - } - - if (h2lcf->push == 0) { - return "is duplicate"; - } - - h2lcf->push = 0; - return NGX_CONF_OK; - } - - if (h2lcf->push == 0) { - return "URI cannot be used with \"off\" parameter"; - } - - h2lcf->push = 1; - - if (h2lcf->pushes == NULL) { - h2lcf->pushes = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_complex_value_t)); - if (h2lcf->pushes == NULL) { - return NGX_CONF_ERROR; - } - } - - cv = ngx_array_push(h2lcf->pushes); - if (cv == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = cv; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - return NGX_CONF_OK; } @@ -457,7 +388,7 @@ ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data) { size_t *sp = data; - if (*sp <= 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE) { + if (*sp <= NGX_HTTP_V2_STATE_BUFFER_SIZE) { return "value is too small"; } @@ -551,10 +482,17 @@ ngx_http_v2_obsolete(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_conf_deprecated_t *d = cmd->post; - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"%s\" directive is obsolete, " - "use the \"%s\" directive instead", - d->old_name, d->new_name); + if (d) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"%s\" directive is obsolete, " + "use the \"%s\" directive instead", + d->old_name, d->new_name); + + } else { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"%V\" directive is obsolete, ignored", + &cmd->name); + } return NGX_CONF_OK; } diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index ca4a0bf..07a595c 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -20,26 +20,9 @@ typedef struct { } ngx_http_v2_main_conf_t; -typedef struct { - size_t pool_size; - ngx_uint_t concurrent_streams; - ngx_uint_t concurrent_pushes; - size_t preread_size; - ngx_uint_t streams_index_mask; -} ngx_http_v2_srv_conf_t; - - typedef struct { size_t chunk_size; - - ngx_flag_t push_preload; - - ngx_flag_t push; - ngx_array_t *pushes; } ngx_http_v2_loc_conf_t; -extern ngx_module_t ngx_http_v2_module; - - #endif /* _NGX_HTTP_V2_MODULE_H_INCLUDED_ */ diff --git a/src/http/v3/ngx_http_v3.c b/src/http/v3/ngx_http_v3.c new file mode 100644 index 0000000..8db229b --- /dev/null +++ b/src/http/v3/ngx_http_v3.c @@ -0,0 +1,111 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static void ngx_http_v3_keepalive_handler(ngx_event_t *ev); +static void ngx_http_v3_cleanup_session(void *data); + + +ngx_int_t +ngx_http_v3_init_session(ngx_connection_t *c) +{ + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_v3_session_t *h3c; + + hc = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init session"); + + h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_session_t)); + if (h3c == NULL) { + goto failed; + } + + h3c->http_connection = hc; + + ngx_queue_init(&h3c->blocked); + + h3c->keepalive.log = c->log; + h3c->keepalive.data = c; + h3c->keepalive.handler = ngx_http_v3_keepalive_handler; + + h3c->table.send_insert_count.log = c->log; + h3c->table.send_insert_count.data = c; + h3c->table.send_insert_count.handler = ngx_http_v3_inc_insert_count_handler; + + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_v3_cleanup_session; + cln->data = h3c; + + c->data = h3c; + + return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to create http3 session"); + return NGX_ERROR; +} + + +static void +ngx_http_v3_keepalive_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + c = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 keepalive handler"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, + "keepalive timeout"); +} + + +static void +ngx_http_v3_cleanup_session(void *data) +{ + ngx_http_v3_session_t *h3c = data; + + ngx_http_v3_cleanup_table(h3c); + + if (h3c->keepalive.timer_set) { + ngx_del_timer(&h3c->keepalive); + } + + if (h3c->table.send_insert_count.posted) { + ngx_delete_posted_event(&h3c->table.send_insert_count); + } +} + + +ngx_int_t +ngx_http_v3_check_flood(ngx_connection_t *c) +{ + ngx_http_v3_session_t *h3c; + + h3c = ngx_http_v3_get_session(c); + + if (h3c->total_bytes / 8 > h3c->payload_bytes + 1048576) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "http3 flood detected"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, + "HTTP/3 flood detected"); + return NGX_ERROR; + } + + return NGX_OK; +} diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h new file mode 100644 index 0000000..9dcb5e6 --- /dev/null +++ b/src/http/v3/ngx_http_v3.h @@ -0,0 +1,160 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_HTTP_V3_H_INCLUDED_ +#define _NGX_HTTP_V3_H_INCLUDED_ + + +#include +#include +#include + +#include +#include +#include +#include + + +#define NGX_HTTP_V3_ALPN_PROTO "\x02h3" +#define NGX_HTTP_V3_HQ_ALPN_PROTO "\x0Ahq-interop" +#define NGX_HTTP_V3_HQ_PROTO "hq-interop" + +#define NGX_HTTP_V3_VARLEN_INT_LEN 4 +#define NGX_HTTP_V3_PREFIX_INT_LEN 11 + +#define NGX_HTTP_V3_STREAM_CONTROL 0x00 +#define NGX_HTTP_V3_STREAM_PUSH 0x01 +#define NGX_HTTP_V3_STREAM_ENCODER 0x02 +#define NGX_HTTP_V3_STREAM_DECODER 0x03 + +#define NGX_HTTP_V3_FRAME_DATA 0x00 +#define NGX_HTTP_V3_FRAME_HEADERS 0x01 +#define NGX_HTTP_V3_FRAME_CANCEL_PUSH 0x03 +#define NGX_HTTP_V3_FRAME_SETTINGS 0x04 +#define NGX_HTTP_V3_FRAME_PUSH_PROMISE 0x05 +#define NGX_HTTP_V3_FRAME_GOAWAY 0x07 +#define NGX_HTTP_V3_FRAME_MAX_PUSH_ID 0x0d + +#define NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY 0x01 +#define NGX_HTTP_V3_PARAM_MAX_FIELD_SECTION_SIZE 0x06 +#define NGX_HTTP_V3_PARAM_BLOCKED_STREAMS 0x07 + +#define NGX_HTTP_V3_MAX_TABLE_CAPACITY 4096 + +#define NGX_HTTP_V3_STREAM_CLIENT_CONTROL 0 +#define NGX_HTTP_V3_STREAM_SERVER_CONTROL 1 +#define NGX_HTTP_V3_STREAM_CLIENT_ENCODER 2 +#define NGX_HTTP_V3_STREAM_SERVER_ENCODER 3 +#define NGX_HTTP_V3_STREAM_CLIENT_DECODER 4 +#define NGX_HTTP_V3_STREAM_SERVER_DECODER 5 +#define NGX_HTTP_V3_MAX_KNOWN_STREAM 6 +#define NGX_HTTP_V3_MAX_UNI_STREAMS 3 + +/* HTTP/3 errors */ +#define NGX_HTTP_V3_ERR_NO_ERROR 0x100 +#define NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR 0x101 +#define NGX_HTTP_V3_ERR_INTERNAL_ERROR 0x102 +#define NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR 0x103 +#define NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM 0x104 +#define NGX_HTTP_V3_ERR_FRAME_UNEXPECTED 0x105 +#define NGX_HTTP_V3_ERR_FRAME_ERROR 0x106 +#define NGX_HTTP_V3_ERR_EXCESSIVE_LOAD 0x107 +#define NGX_HTTP_V3_ERR_ID_ERROR 0x108 +#define NGX_HTTP_V3_ERR_SETTINGS_ERROR 0x109 +#define NGX_HTTP_V3_ERR_MISSING_SETTINGS 0x10a +#define NGX_HTTP_V3_ERR_REQUEST_REJECTED 0x10b +#define NGX_HTTP_V3_ERR_REQUEST_CANCELLED 0x10c +#define NGX_HTTP_V3_ERR_REQUEST_INCOMPLETE 0x10d +#define NGX_HTTP_V3_ERR_CONNECT_ERROR 0x10f +#define NGX_HTTP_V3_ERR_VERSION_FALLBACK 0x110 + +/* QPACK errors */ +#define NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED 0x200 +#define NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR 0x201 +#define NGX_HTTP_V3_ERR_DECODER_STREAM_ERROR 0x202 + + +#define ngx_http_v3_get_session(c) \ + ((ngx_http_v3_session_t *) ((c)->quic ? (c)->quic->parent->data \ + : (c)->data)) + +#define ngx_http_quic_get_connection(c) \ + (ngx_http_v3_get_session(c)->http_connection) + +#define ngx_http_v3_get_module_loc_conf(c, module) \ + ngx_http_get_module_loc_conf(ngx_http_quic_get_connection(c)->conf_ctx, \ + module) + +#define ngx_http_v3_get_module_srv_conf(c, module) \ + ngx_http_get_module_srv_conf(ngx_http_quic_get_connection(c)->conf_ctx, \ + module) + +#define ngx_http_v3_finalize_connection(c, code, reason) \ + ngx_quic_finalize_connection((c)->quic ? (c)->quic->parent : (c), \ + code, reason) + +#define ngx_http_v3_shutdown_connection(c, code, reason) \ + ngx_quic_shutdown_connection((c)->quic ? (c)->quic->parent : (c), \ + code, reason) + + +typedef struct { + ngx_flag_t enable; + ngx_flag_t enable_hq; + size_t max_table_capacity; + ngx_uint_t max_blocked_streams; + ngx_uint_t max_concurrent_streams; + ngx_quic_conf_t quic; +} ngx_http_v3_srv_conf_t; + + +struct ngx_http_v3_parse_s { + size_t header_limit; + ngx_http_v3_parse_headers_t headers; + ngx_http_v3_parse_data_t body; + ngx_array_t *cookies; +}; + + +struct ngx_http_v3_session_s { + ngx_http_connection_t *http_connection; + + ngx_http_v3_dynamic_table_t table; + + ngx_event_t keepalive; + ngx_uint_t nrequests; + + ngx_queue_t blocked; + ngx_uint_t nblocked; + + uint64_t next_request_id; + + off_t total_bytes; + off_t payload_bytes; + + unsigned goaway:1; + unsigned hq:1; + + ngx_connection_t *known_streams[NGX_HTTP_V3_MAX_KNOWN_STREAM]; +}; + + +void ngx_http_v3_init_stream(ngx_connection_t *c); +void ngx_http_v3_reset_stream(ngx_connection_t *c); +ngx_int_t ngx_http_v3_init_session(ngx_connection_t *c); +ngx_int_t ngx_http_v3_check_flood(ngx_connection_t *c); +ngx_int_t ngx_http_v3_init(ngx_connection_t *c); +void ngx_http_v3_shutdown(ngx_connection_t *c); + +ngx_int_t ngx_http_v3_read_request_body(ngx_http_request_t *r); +ngx_int_t ngx_http_v3_read_unbuffered_request_body(ngx_http_request_t *r); + + +extern ngx_module_t ngx_http_v3_module; + + +#endif /* _NGX_HTTP_V3_H_INCLUDED_ */ diff --git a/src/http/v3/ngx_http_v3_encode.c b/src/http/v3/ngx_http_v3_encode.c new file mode 100644 index 0000000..fb089c4 --- /dev/null +++ b/src/http/v3/ngx_http_v3_encode.c @@ -0,0 +1,304 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +uintptr_t +ngx_http_v3_encode_varlen_int(u_char *p, uint64_t value) +{ + if (value <= 63) { + if (p == NULL) { + return 1; + } + + *p++ = value; + return (uintptr_t) p; + } + + if (value <= 16383) { + if (p == NULL) { + return 2; + } + + *p++ = 0x40 | (value >> 8); + *p++ = value; + return (uintptr_t) p; + } + + if (value <= 1073741823) { + if (p == NULL) { + return 4; + } + + *p++ = 0x80 | (value >> 24); + *p++ = (value >> 16); + *p++ = (value >> 8); + *p++ = value; + return (uintptr_t) p; + } + + if (p == NULL) { + return 8; + } + + *p++ = 0xc0 | (value >> 56); + *p++ = (value >> 48); + *p++ = (value >> 40); + *p++ = (value >> 32); + *p++ = (value >> 24); + *p++ = (value >> 16); + *p++ = (value >> 8); + *p++ = value; + return (uintptr_t) p; +} + + +uintptr_t +ngx_http_v3_encode_prefix_int(u_char *p, uint64_t value, ngx_uint_t prefix) +{ + ngx_uint_t thresh, n; + + thresh = (1 << prefix) - 1; + + if (value < thresh) { + if (p == NULL) { + return 1; + } + + *p++ |= value; + return (uintptr_t) p; + } + + value -= thresh; + + if (p == NULL) { + for (n = 2; value >= 128; n++) { + value >>= 7; + } + + return n; + } + + *p++ |= thresh; + + while (value >= 128) { + *p++ = 0x80 | value; + value >>= 7; + } + + *p++ = value; + + return (uintptr_t) p; +} + + +uintptr_t +ngx_http_v3_encode_field_section_prefix(u_char *p, ngx_uint_t insert_count, + ngx_uint_t sign, ngx_uint_t delta_base) +{ + if (p == NULL) { + return ngx_http_v3_encode_prefix_int(NULL, insert_count, 8) + + ngx_http_v3_encode_prefix_int(NULL, delta_base, 7); + } + + *p = 0; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, insert_count, 8); + + *p = sign ? 0x80 : 0; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, delta_base, 7); + + return (uintptr_t) p; +} + + +uintptr_t +ngx_http_v3_encode_field_ri(u_char *p, ngx_uint_t dynamic, ngx_uint_t index) +{ + /* Indexed Field Line */ + + if (p == NULL) { + return ngx_http_v3_encode_prefix_int(NULL, index, 6); + } + + *p = dynamic ? 0x80 : 0xc0; + + return ngx_http_v3_encode_prefix_int(p, index, 6); +} + + +uintptr_t +ngx_http_v3_encode_field_lri(u_char *p, ngx_uint_t dynamic, ngx_uint_t index, + u_char *data, size_t len) +{ + size_t hlen; + u_char *p1, *p2; + + /* Literal Field Line With Name Reference */ + + if (p == NULL) { + return ngx_http_v3_encode_prefix_int(NULL, index, 4) + + ngx_http_v3_encode_prefix_int(NULL, len, 7) + + len; + } + + *p = dynamic ? 0x40 : 0x50; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 4); + + p1 = p; + *p = 0; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, len, 7); + + if (data) { + p2 = p; + hlen = ngx_http_huff_encode(data, len, p, 0); + + if (hlen) { + p = p1; + *p = 0x80; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 7); + + if (p != p2) { + ngx_memmove(p, p2, hlen); + } + + p += hlen; + + } else { + p = ngx_cpymem(p, data, len); + } + } + + return (uintptr_t) p; +} + + +uintptr_t +ngx_http_v3_encode_field_l(u_char *p, ngx_str_t *name, ngx_str_t *value) +{ + size_t hlen; + u_char *p1, *p2; + + /* Literal Field Line With Literal Name */ + + if (p == NULL) { + return ngx_http_v3_encode_prefix_int(NULL, name->len, 3) + + name->len + + ngx_http_v3_encode_prefix_int(NULL, value->len, 7) + + value->len; + } + + p1 = p; + *p = 0x20; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, name->len, 3); + + p2 = p; + hlen = ngx_http_huff_encode(name->data, name->len, p, 1); + + if (hlen) { + p = p1; + *p = 0x28; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 3); + + if (p != p2) { + ngx_memmove(p, p2, hlen); + } + + p += hlen; + + } else { + ngx_strlow(p, name->data, name->len); + p += name->len; + } + + p1 = p; + *p = 0; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, value->len, 7); + + p2 = p; + hlen = ngx_http_huff_encode(value->data, value->len, p, 0); + + if (hlen) { + p = p1; + *p = 0x80; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 7); + + if (p != p2) { + ngx_memmove(p, p2, hlen); + } + + p += hlen; + + } else { + p = ngx_cpymem(p, value->data, value->len); + } + + return (uintptr_t) p; +} + + +uintptr_t +ngx_http_v3_encode_field_pbi(u_char *p, ngx_uint_t index) +{ + /* Indexed Field Line With Post-Base Index */ + + if (p == NULL) { + return ngx_http_v3_encode_prefix_int(NULL, index, 4); + } + + *p = 0x10; + + return ngx_http_v3_encode_prefix_int(p, index, 4); +} + + +uintptr_t +ngx_http_v3_encode_field_lpbi(u_char *p, ngx_uint_t index, u_char *data, + size_t len) +{ + size_t hlen; + u_char *p1, *p2; + + /* Literal Field Line With Post-Base Name Reference */ + + if (p == NULL) { + return ngx_http_v3_encode_prefix_int(NULL, index, 3) + + ngx_http_v3_encode_prefix_int(NULL, len, 7) + + len; + } + + *p = 0; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 3); + + p1 = p; + *p = 0; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, len, 7); + + if (data) { + p2 = p; + hlen = ngx_http_huff_encode(data, len, p, 0); + + if (hlen) { + p = p1; + *p = 0x80; + p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 7); + + if (p != p2) { + ngx_memmove(p, p2, hlen); + } + + p += hlen; + + } else { + p = ngx_cpymem(p, data, len); + } + } + + return (uintptr_t) p; +} diff --git a/src/http/v3/ngx_http_v3_encode.h b/src/http/v3/ngx_http_v3_encode.h new file mode 100644 index 0000000..fca376d --- /dev/null +++ b/src/http/v3/ngx_http_v3_encode.h @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_HTTP_V3_ENCODE_H_INCLUDED_ +#define _NGX_HTTP_V3_ENCODE_H_INCLUDED_ + + +#include +#include +#include + + +uintptr_t ngx_http_v3_encode_varlen_int(u_char *p, uint64_t value); +uintptr_t ngx_http_v3_encode_prefix_int(u_char *p, uint64_t value, + ngx_uint_t prefix); + +uintptr_t ngx_http_v3_encode_field_section_prefix(u_char *p, + ngx_uint_t insert_count, ngx_uint_t sign, ngx_uint_t delta_base); +uintptr_t ngx_http_v3_encode_field_ri(u_char *p, ngx_uint_t dynamic, + ngx_uint_t index); +uintptr_t ngx_http_v3_encode_field_lri(u_char *p, ngx_uint_t dynamic, + ngx_uint_t index, u_char *data, size_t len); +uintptr_t ngx_http_v3_encode_field_l(u_char *p, ngx_str_t *name, + ngx_str_t *value); +uintptr_t ngx_http_v3_encode_field_pbi(u_char *p, ngx_uint_t index); +uintptr_t ngx_http_v3_encode_field_lpbi(u_char *p, ngx_uint_t index, + u_char *data, size_t len); + + +#endif /* _NGX_HTTP_V3_ENCODE_H_INCLUDED_ */ diff --git a/src/http/v3/ngx_http_v3_filter_module.c b/src/http/v3/ngx_http_v3_filter_module.c new file mode 100644 index 0000000..4d2276d --- /dev/null +++ b/src/http/v3/ngx_http_v3_filter_module.c @@ -0,0 +1,852 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +/* static table indices */ +#define NGX_HTTP_V3_HEADER_AUTHORITY 0 +#define NGX_HTTP_V3_HEADER_PATH_ROOT 1 +#define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO 4 +#define NGX_HTTP_V3_HEADER_DATE 6 +#define NGX_HTTP_V3_HEADER_LAST_MODIFIED 10 +#define NGX_HTTP_V3_HEADER_LOCATION 12 +#define NGX_HTTP_V3_HEADER_METHOD_GET 17 +#define NGX_HTTP_V3_HEADER_SCHEME_HTTP 22 +#define NGX_HTTP_V3_HEADER_SCHEME_HTTPS 23 +#define NGX_HTTP_V3_HEADER_STATUS_200 25 +#define NGX_HTTP_V3_HEADER_ACCEPT_ENCODING 31 +#define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN 53 +#define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING 59 +#define NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE 72 +#define NGX_HTTP_V3_HEADER_SERVER 92 +#define NGX_HTTP_V3_HEADER_USER_AGENT 95 + + +typedef struct { + ngx_chain_t *free; + ngx_chain_t *busy; +} ngx_http_v3_filter_ctx_t; + + +static ngx_int_t ngx_http_v3_header_filter(ngx_http_request_t *r); +static ngx_int_t ngx_http_v3_body_filter(ngx_http_request_t *r, + ngx_chain_t *in); +static ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r, + ngx_http_v3_filter_ctx_t *ctx); +static ngx_int_t ngx_http_v3_filter_init(ngx_conf_t *cf); + + +static ngx_http_module_t ngx_http_v3_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_v3_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_v3_filter_module = { + NGX_MODULE_V1, + &ngx_http_v3_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_v3_header_filter(ngx_http_request_t *r) +{ + u_char *p; + size_t len, n; + ngx_buf_t *b; + ngx_str_t host, location; + ngx_uint_t i, port; + ngx_chain_t *out, *hl, *cl, **ll; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_connection_t *c; + ngx_http_v3_session_t *h3c; + ngx_http_v3_filter_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + u_char addr[NGX_SOCKADDR_STRLEN]; + + if (r->http_version != NGX_HTTP_VERSION_30) { + return ngx_http_next_header_filter(r); + } + + if (r->header_sent) { + return NGX_OK; + } + + r->header_sent = 1; + + if (r != r->main) { + return NGX_OK; + } + + h3c = ngx_http_v3_get_session(r->connection); + + if (r->method == NGX_HTTP_HEAD) { + r->header_only = 1; + } + + if (r->headers_out.last_modified_time != -1) { + if (r->headers_out.status != NGX_HTTP_OK + && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT + && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) + { + r->headers_out.last_modified_time = -1; + r->headers_out.last_modified = NULL; + } + } + + if (r->headers_out.status == NGX_HTTP_NO_CONTENT) { + r->header_only = 1; + ngx_str_null(&r->headers_out.content_type); + r->headers_out.last_modified_time = -1; + r->headers_out.last_modified = NULL; + r->headers_out.content_length = NULL; + r->headers_out.content_length_n = -1; + } + + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + r->header_only = 1; + } + + c = r->connection; + + out = NULL; + ll = &out; + + len = ngx_http_v3_encode_field_section_prefix(NULL, 0, 0, 0); + + if (r->headers_out.status == NGX_HTTP_OK) { + len += ngx_http_v3_encode_field_ri(NULL, 0, + NGX_HTTP_V3_HEADER_STATUS_200); + + } else { + len += ngx_http_v3_encode_field_lri(NULL, 0, + NGX_HTTP_V3_HEADER_STATUS_200, + NULL, 3); + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->headers_out.server == NULL) { + if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { + n = sizeof(NGINX_VER) - 1; + + } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { + n = sizeof(NGINX_VER_BUILD) - 1; + + } else { + n = sizeof("nginx") - 1; + } + + len += ngx_http_v3_encode_field_lri(NULL, 0, + NGX_HTTP_V3_HEADER_SERVER, + NULL, n); + } + + if (r->headers_out.date == NULL) { + len += ngx_http_v3_encode_field_lri(NULL, 0, NGX_HTTP_V3_HEADER_DATE, + NULL, ngx_cached_http_time.len); + } + + if (r->headers_out.content_type.len) { + n = r->headers_out.content_type.len; + + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { + n += sizeof("; charset=") - 1 + r->headers_out.charset.len; + } + + len += ngx_http_v3_encode_field_lri(NULL, 0, + NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN, + NULL, n); + } + + if (r->headers_out.content_length == NULL) { + if (r->headers_out.content_length_n > 0) { + len += ngx_http_v3_encode_field_lri(NULL, 0, + NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO, + NULL, NGX_OFF_T_LEN); + + } else if (r->headers_out.content_length_n == 0) { + len += ngx_http_v3_encode_field_ri(NULL, 0, + NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO); + } + } + + if (r->headers_out.last_modified == NULL + && r->headers_out.last_modified_time != -1) + { + len += ngx_http_v3_encode_field_lri(NULL, 0, + NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL, + sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1); + } + + if (r->headers_out.location && r->headers_out.location->value.len) { + + if (r->headers_out.location->value.data[0] == '/' + && clcf->absolute_redirect) + { + if (clcf->server_name_in_redirect) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + host = cscf->server_name; + + } else if (r->headers_in.server.len) { + host = r->headers_in.server; + + } else { + host.len = NGX_SOCKADDR_STRLEN; + host.data = addr; + + if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { + return NGX_ERROR; + } + } + + port = ngx_inet_get_port(c->local_sockaddr); + + location.len = sizeof("https://") - 1 + host.len + + r->headers_out.location->value.len; + + if (clcf->port_in_redirect) { + port = (port == 443) ? 0 : port; + + } else { + port = 0; + } + + if (port) { + location.len += sizeof(":65535") - 1; + } + + location.data = ngx_pnalloc(r->pool, location.len); + if (location.data == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(location.data, "https://", sizeof("https://") - 1); + p = ngx_cpymem(p, host.data, host.len); + + if (port) { + p = ngx_sprintf(p, ":%ui", port); + } + + p = ngx_cpymem(p, r->headers_out.location->value.data, + r->headers_out.location->value.len); + + /* update r->headers_out.location->value for possible logging */ + + r->headers_out.location->value.len = p - location.data; + r->headers_out.location->value.data = location.data; + ngx_str_set(&r->headers_out.location->key, "Location"); + } + + r->headers_out.location->hash = 0; + + len += ngx_http_v3_encode_field_lri(NULL, 0, + NGX_HTTP_V3_HEADER_LOCATION, NULL, + r->headers_out.location->value.len); + } + +#if (NGX_HTTP_GZIP) + if (r->gzip_vary) { + if (clcf->gzip_vary) { + len += ngx_http_v3_encode_field_ri(NULL, 0, + NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING); + + } else { + r->gzip_vary = 0; + } + } +#endif + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + len += ngx_http_v3_encode_field_l(NULL, &header[i].key, + &header[i].value); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len); + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + b->last = (u_char *) ngx_http_v3_encode_field_section_prefix(b->last, + 0, 0, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \":status: %03ui\"", + r->headers_out.status); + + if (r->headers_out.status == NGX_HTTP_OK) { + b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0, + NGX_HTTP_V3_HEADER_STATUS_200); + + } else { + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_STATUS_200, + NULL, 3); + b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); + } + + if (r->headers_out.server == NULL) { + if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { + p = (u_char *) NGINX_VER; + n = sizeof(NGINX_VER) - 1; + + } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { + p = (u_char *) NGINX_VER_BUILD; + n = sizeof(NGINX_VER_BUILD) - 1; + + } else { + p = (u_char *) "nginx"; + n = sizeof("nginx") - 1; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"server: %*s\"", n, p); + + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_SERVER, + p, n); + } + + if (r->headers_out.date == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"date: %V\"", + &ngx_cached_http_time); + + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_DATE, + ngx_cached_http_time.data, + ngx_cached_http_time.len); + } + + if (r->headers_out.content_type.len) { + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { + n = r->headers_out.content_type.len + sizeof("; charset=") - 1 + + r->headers_out.charset.len; + + p = ngx_pnalloc(r->pool, n); + if (p == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(p, r->headers_out.content_type.data, + r->headers_out.content_type.len); + + p = ngx_cpymem(p, "; charset=", sizeof("; charset=") - 1); + + p = ngx_cpymem(p, r->headers_out.charset.data, + r->headers_out.charset.len); + + /* updated r->headers_out.content_type is also needed for logging */ + + r->headers_out.content_type.len = n; + r->headers_out.content_type.data = p - n; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"content-type: %V\"", + &r->headers_out.content_type); + + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN, + r->headers_out.content_type.data, + r->headers_out.content_type.len); + } + + if (r->headers_out.content_length == NULL + && r->headers_out.content_length_n >= 0) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"content-length: %O\"", + r->headers_out.content_length_n); + + if (r->headers_out.content_length_n > 0) { + p = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n); + n = p - b->last; + + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO, + NULL, n); + + b->last = ngx_sprintf(b->last, "%O", + r->headers_out.content_length_n); + + } else { + b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0, + NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO); + } + } + + if (r->headers_out.last_modified == NULL + && r->headers_out.last_modified_time != -1) + { + n = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; + + p = ngx_pnalloc(r->pool, n); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_http_time(p, r->headers_out.last_modified_time); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"last-modified: %*s\"", n, p); + + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_LAST_MODIFIED, + p, n); + } + + if (r->headers_out.location && r->headers_out.location->value.len) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"location: %V\"", + &r->headers_out.location->value); + + b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0, + NGX_HTTP_V3_HEADER_LOCATION, + r->headers_out.location->value.data, + r->headers_out.location->value.len); + } + +#if (NGX_HTTP_GZIP) + if (r->gzip_vary) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"vary: Accept-Encoding\""); + + b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0, + NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING); + } +#endif + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 output header: \"%V: %V\"", + &header[i].key, &header[i].value); + + b->last = (u_char *) ngx_http_v3_encode_field_l(b->last, + &header[i].key, + &header[i].value); + } + + if (r->header_only) { + b->last_buf = 1; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + n = b->last - b->pos; + + h3c->payload_bytes += n; + + len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_HEADERS) + + ngx_http_v3_encode_varlen_int(NULL, n); + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, + NGX_HTTP_V3_FRAME_HEADERS); + b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n); + + hl = ngx_alloc_chain_link(r->pool); + if (hl == NULL) { + return NGX_ERROR; + } + + hl->buf = b; + hl->next = cl; + + *ll = hl; + ll = &cl->next; + + if (r->headers_out.content_length_n >= 0 + && !r->header_only && !r->expect_trailers) + { + len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_DATA) + + ngx_http_v3_encode_varlen_int(NULL, + r->headers_out.content_length_n); + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, + NGX_HTTP_V3_FRAME_DATA); + b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, + r->headers_out.content_length_n); + + h3c->payload_bytes += r->headers_out.content_length_n; + h3c->total_bytes += r->headers_out.content_length_n; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + *ll = cl; + + } else { + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_v3_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_v3_filter_module); + } + + for (cl = out; cl; cl = cl->next) { + h3c->total_bytes += cl->buf->last - cl->buf->pos; + r->header_size += cl->buf->last - cl->buf->pos; + } + + return ngx_http_write_filter(r, out); +} + + +static ngx_int_t +ngx_http_v3_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + u_char *chunk; + off_t size; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *out, *cl, *tl, **ll; + ngx_http_v3_session_t *h3c; + ngx_http_v3_filter_ctx_t *ctx; + + if (in == NULL) { + return ngx_http_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_v3_filter_module); + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + h3c = ngx_http_v3_get_session(r->connection); + + out = NULL; + ll = &out; + + size = 0; + cl = in; + + for ( ;; ) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 chunk: %O", ngx_buf_size(cl->buf)); + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush + || cl->buf->sync + || ngx_buf_in_memory(cl->buf) + || cl->buf->in_file) + { + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; + } + + if (cl->next == NULL) { + break; + } + + cl = cl->next; + } + + if (size) { + tl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (tl == NULL) { + return NGX_ERROR; + } + + b = tl->buf; + chunk = b->start; + + if (chunk == NULL) { + chunk = ngx_palloc(r->pool, NGX_HTTP_V3_VARLEN_INT_LEN * 2); + if (chunk == NULL) { + return NGX_ERROR; + } + + b->start = chunk; + b->end = chunk + NGX_HTTP_V3_VARLEN_INT_LEN * 2; + } + + b->tag = (ngx_buf_tag_t) &ngx_http_v3_filter_module; + b->memory = 0; + b->temporary = 1; + b->pos = chunk; + + b->last = (u_char *) ngx_http_v3_encode_varlen_int(chunk, + NGX_HTTP_V3_FRAME_DATA); + b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, size); + + tl->next = out; + out = tl; + + h3c->payload_bytes += size; + } + + if (cl->buf->last_buf) { + tl = ngx_http_v3_create_trailers(r, ctx); + if (tl == NULL) { + return NGX_ERROR; + } + + cl->buf->last_buf = 0; + + *ll = tl; + + } else { + *ll = NULL; + } + + for (cl = out; cl; cl = cl->next) { + h3c->total_bytes += cl->buf->last - cl->buf->pos; + } + + rc = ngx_http_next_body_filter(r, out); + + ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, + (ngx_buf_tag_t) &ngx_http_v3_filter_module); + + return rc; +} + + +static ngx_chain_t * +ngx_http_v3_create_trailers(ngx_http_request_t *r, + ngx_http_v3_filter_ctx_t *ctx) +{ + size_t len, n; + u_char *p; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t *cl, *hl; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_v3_session_t *h3c; + + h3c = ngx_http_v3_get_session(r->connection); + + len = 0; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + len += ngx_http_v3_encode_field_l(NULL, &header[i].key, + &header[i].value); + } + + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NULL; + } + + b = cl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_v3_filter_module; + b->memory = 0; + b->last_buf = 1; + + if (len == 0) { + b->temporary = 0; + b->pos = b->last = NULL; + return cl; + } + + b->temporary = 1; + + len += ngx_http_v3_encode_field_section_prefix(NULL, 0, 0, 0); + + b->pos = ngx_palloc(r->pool, len); + if (b->pos == NULL) { + return NULL; + } + + b->last = (u_char *) ngx_http_v3_encode_field_section_prefix(b->pos, + 0, 0, 0); + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 output trailer: \"%V: %V\"", + &header[i].key, &header[i].value); + + b->last = (u_char *) ngx_http_v3_encode_field_l(b->last, + &header[i].key, + &header[i].value); + } + + n = b->last - b->pos; + + h3c->payload_bytes += n; + + hl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (hl == NULL) { + return NULL; + } + + b = hl->buf; + p = b->start; + + if (p == NULL) { + p = ngx_palloc(r->pool, NGX_HTTP_V3_VARLEN_INT_LEN * 2); + if (p == NULL) { + return NULL; + } + + b->start = p; + b->end = p + NGX_HTTP_V3_VARLEN_INT_LEN * 2; + } + + b->tag = (ngx_buf_tag_t) &ngx_http_v3_filter_module; + b->memory = 0; + b->temporary = 1; + b->pos = p; + + b->last = (u_char *) ngx_http_v3_encode_varlen_int(p, + NGX_HTTP_V3_FRAME_HEADERS); + b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n); + + hl->next = cl; + + return hl; +} + + +static ngx_int_t +ngx_http_v3_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_v3_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_v3_body_filter; + + return NGX_OK; +} diff --git a/src/http/v3/ngx_http_v3_module.c b/src/http/v3/ngx_http_v3_module.c new file mode 100644 index 0000000..139bd65 --- /dev/null +++ b/src/http/v3/ngx_http_v3_module.c @@ -0,0 +1,393 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include + + +static ngx_int_t ngx_http_v3_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_v3_add_variables(ngx_conf_t *cf); +static void *ngx_http_v3_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_v3_commands[] = { + + { ngx_string("http3"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, enable), + NULL }, + + { ngx_string("http3_hq"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, enable_hq), + NULL }, + + { ngx_string("http3_max_concurrent_streams"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, max_concurrent_streams), + NULL }, + + { ngx_string("http3_stream_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_v3_srv_conf_t, quic.stream_buffer_size), + NULL }, + + { ngx_string("quic_retry"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.retry), + NULL }, + + { ngx_string("quic_gso"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.gso_enabled), + NULL }, + + { ngx_string("quic_host_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_quic_host_key, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("quic_active_connection_id_limit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.active_connection_id_limit), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_v3_module_ctx = { + ngx_http_v3_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_v3_create_srv_conf, /* create server configuration */ + ngx_http_v3_merge_srv_conf, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_v3_module = { + NGX_MODULE_V1, + &ngx_http_v3_module_ctx, /* module context */ + ngx_http_v3_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_variable_t ngx_http_v3_vars[] = { + + { ngx_string("http3"), NULL, ngx_http_v3_variable, 0, 0, 0 }, + + ngx_http_null_variable +}; + +static ngx_str_t ngx_http_quic_salt = ngx_string("ngx_quic"); + + +static ngx_int_t +ngx_http_v3_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_v3_session_t *h3c; + + if (r->connection->quic) { + h3c = ngx_http_v3_get_session(r->connection); + + if (h3c->hq) { + v->len = sizeof("hq") - 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) "hq"; + + return NGX_OK; + } + + v->len = sizeof("h3") - 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) "h3"; + + return NGX_OK; + } + + *v = ngx_http_variable_null_value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v3_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_v3_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static void * +ngx_http_v3_create_srv_conf(ngx_conf_t *cf) +{ + ngx_http_v3_srv_conf_t *h3scf; + + h3scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v3_srv_conf_t)); + if (h3scf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * h3scf->quic.host_key = { 0, NULL } + * h3scf->quic.stream_reject_code_uni = 0; + * h3scf->quic.disable_active_migration = 0; + * h3scf->quic.idle_timeout = 0; + * h3scf->max_blocked_streams = 0; + */ + + h3scf->enable = NGX_CONF_UNSET; + h3scf->enable_hq = NGX_CONF_UNSET; + h3scf->max_table_capacity = NGX_HTTP_V3_MAX_TABLE_CAPACITY; + h3scf->max_concurrent_streams = NGX_CONF_UNSET_UINT; + + h3scf->quic.stream_buffer_size = NGX_CONF_UNSET_SIZE; + h3scf->quic.max_concurrent_streams_bidi = NGX_CONF_UNSET_UINT; + h3scf->quic.max_concurrent_streams_uni = NGX_HTTP_V3_MAX_UNI_STREAMS; + h3scf->quic.retry = NGX_CONF_UNSET; + h3scf->quic.gso_enabled = NGX_CONF_UNSET; + h3scf->quic.stream_close_code = NGX_HTTP_V3_ERR_NO_ERROR; + h3scf->quic.stream_reject_code_bidi = NGX_HTTP_V3_ERR_REQUEST_REJECTED; + h3scf->quic.active_connection_id_limit = NGX_CONF_UNSET_UINT; + + h3scf->quic.init = ngx_http_v3_init; + h3scf->quic.shutdown = ngx_http_v3_shutdown; + + return h3scf; +} + + +static char * +ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_v3_srv_conf_t *prev = parent; + ngx_http_v3_srv_conf_t *conf = child; + + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_core_srv_conf_t *cscf; + + ngx_conf_merge_value(conf->enable, prev->enable, 1); + + ngx_conf_merge_value(conf->enable_hq, prev->enable_hq, 0); + + ngx_conf_merge_uint_value(conf->max_concurrent_streams, + prev->max_concurrent_streams, 128); + + conf->max_blocked_streams = conf->max_concurrent_streams; + + ngx_conf_merge_size_value(conf->quic.stream_buffer_size, + prev->quic.stream_buffer_size, + 65536); + + conf->quic.max_concurrent_streams_bidi = conf->max_concurrent_streams; + + ngx_conf_merge_value(conf->quic.retry, prev->quic.retry, 0); + ngx_conf_merge_value(conf->quic.gso_enabled, prev->quic.gso_enabled, 0); + + ngx_conf_merge_str_value(conf->quic.host_key, prev->quic.host_key, ""); + + ngx_conf_merge_uint_value(conf->quic.active_connection_id_limit, + prev->quic.active_connection_id_limit, + 2); + + if (conf->quic.host_key.len == 0) { + + conf->quic.host_key.len = NGX_QUIC_DEFAULT_HOST_KEY_LEN; + conf->quic.host_key.data = ngx_palloc(cf->pool, + conf->quic.host_key.len); + if (conf->quic.host_key.data == NULL) { + return NGX_CONF_ERROR; + } + + if (RAND_bytes(conf->quic.host_key.data, NGX_QUIC_DEFAULT_HOST_KEY_LEN) + <= 0) + { + return NGX_CONF_ERROR; + } + } + + if (ngx_quic_derive_key(cf->log, "av_token_key", + &conf->quic.host_key, &ngx_http_quic_salt, + conf->quic.av_token_key, NGX_QUIC_AV_KEY_LEN) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_quic_derive_key(cf->log, "sr_token_key", + &conf->quic.host_key, &ngx_http_quic_salt, + conf->quic.sr_token_key, NGX_QUIC_SR_KEY_LEN) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); + conf->quic.handshake_timeout = cscf->client_header_timeout; + + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + conf->quic.ssl = &sscf->ssl; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_v3_srv_conf_t *h3scf = conf; + + u_char *buf; + size_t size; + ssize_t n; + ngx_str_t *value; + ngx_file_t file; + ngx_file_info_t fi; + ngx_quic_conf_t *qcf; + + qcf = &h3scf->quic; + + if (qcf->host_key.len) { + return "is duplicate"; + } + + buf = NULL; +#if (NGX_SUPPRESS_WARN) + size = 0; +#endif + + value = cf->args->elts; + + if (ngx_conf_full_name(cf->cycle, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.name = value[1]; + file.log = cf->log; + + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 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_CONF_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; + } + + size = ngx_file_size(&fi); + + if (size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" zero key size", &file.name); + goto failed; + } + + buf = ngx_pnalloc(cf->pool, size); + if (buf == NULL) { + goto failed; + } + + n = ngx_read_file(&file, buf, size, 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 ((size_t) n != size) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, + ngx_read_file_n " \"%V\" returned only " + "%z bytes instead of %uz", &file.name, n, size); + goto failed; + } + + qcf->host_key.data = buf; + qcf->host_key.len = n; + + 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_CONF_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); + } + + if (buf) { + ngx_explicit_memzero(buf, size); + } + + return NGX_CONF_ERROR; +} diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c new file mode 100644 index 0000000..5688163 --- /dev/null +++ b/src/http/v3/ngx_http_v3_parse.c @@ -0,0 +1,1933 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define ngx_http_v3_is_v2_frame(type) \ + ((type) == 0x02 || (type) == 0x06 || (type) == 0x08 || (type) == 0x09) + + +static void ngx_http_v3_parse_start_local(ngx_buf_t *b, ngx_buf_t *loc, + ngx_uint_t n); +static void ngx_http_v3_parse_end_local(ngx_buf_t *b, ngx_buf_t *loc, + ngx_uint_t *n); +static ngx_int_t ngx_http_v3_parse_skip(ngx_buf_t *b, ngx_uint_t *length); + +static ngx_int_t ngx_http_v3_parse_varlen_int(ngx_connection_t *c, + ngx_http_v3_parse_varlen_int_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_prefix_int(ngx_connection_t *c, + ngx_http_v3_parse_prefix_int_t *st, ngx_uint_t prefix, ngx_buf_t *b); + +static ngx_int_t ngx_http_v3_parse_field_section_prefix(ngx_connection_t *c, + ngx_http_v3_parse_field_section_prefix_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_rep(ngx_connection_t *c, + ngx_http_v3_parse_field_rep_t *st, ngx_uint_t base, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_literal(ngx_connection_t *c, + ngx_http_v3_parse_literal_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_ri(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_lri(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_l(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_pbi(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_lpbi(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); + +static ngx_int_t ngx_http_v3_parse_control(ngx_connection_t *c, + ngx_http_v3_parse_control_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_settings(ngx_connection_t *c, + ngx_http_v3_parse_settings_t *st, ngx_buf_t *b); + +static ngx_int_t ngx_http_v3_parse_encoder(ngx_connection_t *c, + ngx_http_v3_parse_encoder_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_inr(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); +static ngx_int_t ngx_http_v3_parse_field_iln(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b); + +static ngx_int_t ngx_http_v3_parse_decoder(ngx_connection_t *c, + ngx_http_v3_parse_decoder_t *st, ngx_buf_t *b); + +static ngx_int_t ngx_http_v3_parse_lookup(ngx_connection_t *c, + ngx_uint_t dynamic, ngx_uint_t index, ngx_str_t *name, ngx_str_t *value); + + +static void +ngx_http_v3_parse_start_local(ngx_buf_t *b, ngx_buf_t *loc, ngx_uint_t n) +{ + *loc = *b; + + if ((size_t) (loc->last - loc->pos) > n) { + loc->last = loc->pos + n; + } +} + + +static void +ngx_http_v3_parse_end_local(ngx_buf_t *b, ngx_buf_t *loc, ngx_uint_t *pn) +{ + *pn -= loc->pos - b->pos; + b->pos = loc->pos; +} + + +static ngx_int_t +ngx_http_v3_parse_skip(ngx_buf_t *b, ngx_uint_t *length) +{ + if ((size_t) (b->last - b->pos) < *length) { + *length -= b->last - b->pos; + b->pos = b->last; + return NGX_AGAIN; + } + + b->pos += *length; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_varlen_int(ngx_connection_t *c, + ngx_http_v3_parse_varlen_int_t *st, ngx_buf_t *b) +{ + u_char ch; + enum { + sw_start = 0, + sw_length_2, + sw_length_3, + sw_length_4, + sw_length_5, + sw_length_6, + sw_length_7, + sw_length_8 + }; + + for ( ;; ) { + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos++; + + switch (st->state) { + + case sw_start: + + st->value = ch; + if (st->value & 0xc0) { + st->state = sw_length_2; + break; + } + + goto done; + + case sw_length_2: + + st->value = (st->value << 8) + ch; + if ((st->value & 0xc000) == 0x4000) { + st->value &= 0x3fff; + goto done; + } + + st->state = sw_length_3; + break; + + case sw_length_4: + + st->value = (st->value << 8) + ch; + if ((st->value & 0xc0000000) == 0x80000000) { + st->value &= 0x3fffffff; + goto done; + } + + st->state = sw_length_5; + break; + + case sw_length_3: + case sw_length_5: + case sw_length_6: + case sw_length_7: + + st->value = (st->value << 8) + ch; + st->state++; + break; + + case sw_length_8: + + st->value = (st->value << 8) + ch; + st->value &= 0x3fffffffffffffff; + goto done; + } + } + +done: + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse varlen int %uL", st->value); + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_prefix_int(ngx_connection_t *c, + ngx_http_v3_parse_prefix_int_t *st, ngx_uint_t prefix, ngx_buf_t *b) +{ + u_char ch; + ngx_uint_t mask; + enum { + sw_start = 0, + sw_value + }; + + for ( ;; ) { + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos++; + + switch (st->state) { + + case sw_start: + + mask = (1 << prefix) - 1; + st->value = ch & mask; + + if (st->value != mask) { + goto done; + } + + st->shift = 0; + st->state = sw_value; + break; + + case sw_value: + + st->value += (uint64_t) (ch & 0x7f) << st->shift; + + if (st->shift == 56 + && ((ch & 0x80) || (st->value & 0xc000000000000000))) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client exceeded integer size limit"); + return NGX_HTTP_V3_ERR_EXCESSIVE_LOAD; + } + + if (ch & 0x80) { + st->shift += 7; + break; + } + + goto done; + } + } + +done: + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse prefix int %uL", st->value); + + st->state = sw_start; + return NGX_DONE; +} + + +ngx_int_t +ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st, + ngx_buf_t *b) +{ + ngx_buf_t loc; + ngx_int_t rc; + enum { + sw_start = 0, + sw_type, + sw_length, + sw_skip, + sw_prefix, + sw_verify, + sw_field_rep, + sw_done + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse headers"); + + st->state = sw_type; + + /* fall through */ + + case sw_type: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + st->type = st->vlint.value; + + if (ngx_http_v3_is_v2_frame(st->type) + || st->type == NGX_HTTP_V3_FRAME_DATA + || st->type == NGX_HTTP_V3_FRAME_GOAWAY + || st->type == NGX_HTTP_V3_FRAME_SETTINGS + || st->type == NGX_HTTP_V3_FRAME_MAX_PUSH_ID + || st->type == NGX_HTTP_V3_FRAME_CANCEL_PUSH + || st->type == NGX_HTTP_V3_FRAME_PUSH_PROMISE) + { + return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED; + } + + st->state = sw_length; + break; + + case sw_length: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + st->length = st->vlint.value; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse headers type:%ui, len:%ui", + st->type, st->length); + + if (st->type != NGX_HTTP_V3_FRAME_HEADERS) { + st->state = st->length > 0 ? sw_skip : sw_type; + break; + } + + if (st->length == 0) { + return NGX_HTTP_V3_ERR_FRAME_ERROR; + } + + st->state = sw_prefix; + break; + + case sw_skip: + + rc = ngx_http_v3_parse_skip(b, &st->length); + if (rc != NGX_DONE) { + return rc; + } + + st->state = sw_type; + break; + + case sw_prefix: + + ngx_http_v3_parse_start_local(b, &loc, st->length); + + rc = ngx_http_v3_parse_field_section_prefix(c, &st->prefix, &loc); + + ngx_http_v3_parse_end_local(b, &loc, &st->length); + + if (st->length == 0 && rc == NGX_AGAIN) { + return NGX_HTTP_V3_ERR_FRAME_ERROR; + } + + if (rc != NGX_DONE) { + return rc; + } + + st->state = sw_verify; + break; + + case sw_verify: + + rc = ngx_http_v3_check_insert_count(c, st->prefix.insert_count); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_field_rep; + + /* fall through */ + + case sw_field_rep: + + ngx_http_v3_parse_start_local(b, &loc, st->length); + + rc = ngx_http_v3_parse_field_rep(c, &st->field_rep, st->prefix.base, + &loc); + + ngx_http_v3_parse_end_local(b, &loc, &st->length); + + if (st->length == 0 && rc == NGX_AGAIN) { + return NGX_HTTP_V3_ERR_FRAME_ERROR; + } + + if (rc != NGX_DONE) { + return rc; + } + + if (st->length == 0) { + goto done; + } + + return NGX_OK; + } + } + +done: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers done"); + + if (st->prefix.insert_count > 0) { + if (ngx_http_v3_send_ack_section(c, c->quic->id) != NGX_OK) { + return NGX_ERROR; + } + + ngx_http_v3_ack_insert_count(c, st->prefix.insert_count); + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_section_prefix(ngx_connection_t *c, + ngx_http_v3_parse_field_section_prefix_t *st, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_req_insert_count, + sw_delta_base, + sw_read_delta_base + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field section prefix"); + + st->state = sw_req_insert_count; + + /* fall through */ + + case sw_req_insert_count: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 8, b); + if (rc != NGX_DONE) { + return rc; + } + + st->insert_count = st->pint.value; + st->state = sw_delta_base; + break; + + case sw_delta_base: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->sign = (ch & 0x80) ? 1 : 0; + st->state = sw_read_delta_base; + + /* fall through */ + + case sw_read_delta_base: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + st->delta_base = st->pint.value; + goto done; + } + } + +done: + + rc = ngx_http_v3_decode_insert_count(c, &st->insert_count); + if (rc != NGX_OK) { + return rc; + } + + if (st->sign) { + if (st->insert_count <= st->delta_base) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent negative base"); + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + st->base = st->insert_count - st->delta_base - 1; + + } else { + st->base = st->insert_count + st->delta_base; + } + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field section prefix done " + "insert_count:%ui, sign:%ui, delta_base:%ui, base:%ui", + st->insert_count, st->sign, st->delta_base, st->base); + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_rep(ngx_connection_t *c, + ngx_http_v3_parse_field_rep_t *st, ngx_uint_t base, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_field_ri, + sw_field_lri, + sw_field_l, + sw_field_pbi, + sw_field_lpbi + }; + + if (st->state == sw_start) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field representation"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + ngx_memzero(&st->field, sizeof(ngx_http_v3_parse_field_t)); + + st->field.base = base; + + if (ch & 0x80) { + /* Indexed Field Line */ + + st->state = sw_field_ri; + + } else if (ch & 0x40) { + /* Literal Field Line With Name Reference */ + + st->state = sw_field_lri; + + } else if (ch & 0x20) { + /* Literal Field Line With Literal Name */ + + st->state = sw_field_l; + + } else if (ch & 0x10) { + /* Indexed Field Line With Post-Base Index */ + + st->state = sw_field_pbi; + + } else { + /* Literal Field Line With Post-Base Name Reference */ + + st->state = sw_field_lpbi; + } + } + + switch (st->state) { + + case sw_field_ri: + rc = ngx_http_v3_parse_field_ri(c, &st->field, b); + break; + + case sw_field_lri: + rc = ngx_http_v3_parse_field_lri(c, &st->field, b); + break; + + case sw_field_l: + rc = ngx_http_v3_parse_field_l(c, &st->field, b); + break; + + case sw_field_pbi: + rc = ngx_http_v3_parse_field_pbi(c, &st->field, b); + break; + + case sw_field_lpbi: + rc = ngx_http_v3_parse_field_lpbi(c, &st->field, b); + break; + + default: + rc = NGX_OK; + } + + if (rc != NGX_DONE) { + return rc; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field representation done"); + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st, + ngx_buf_t *b) +{ + u_char ch; + ngx_uint_t n; + ngx_http_core_srv_conf_t *cscf; + enum { + sw_start = 0, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse literal huff:%ui, len:%ui", + st->huffman, st->length); + + n = st->length; + + cscf = ngx_http_v3_get_module_srv_conf(c, ngx_http_core_module); + + if (n > cscf->large_client_header_buffers.size) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too large field line"); + return NGX_HTTP_V3_ERR_EXCESSIVE_LOAD; + } + + if (st->huffman) { + n = n * 8 / 5; + st->huffstate = 0; + } + + st->last = ngx_pnalloc(c->pool, n + 1); + if (st->last == NULL) { + return NGX_ERROR; + } + + st->value.data = st->last; + st->state = sw_value; + + /* fall through */ + + case sw_value: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos++; + + if (st->huffman) { + if (ngx_http_huff_decode(&st->huffstate, &ch, 1, &st->last, + st->length == 1, c->log) + != NGX_OK) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid encoded field line"); + return NGX_ERROR; + } + + } else { + *st->last++ = ch; + } + + if (--st->length) { + break; + } + + st->value.len = st->last - st->value.data; + *st->last = '\0'; + goto done; + } + } + +done: + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse literal done \"%V\"", &st->value); + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_ri(ngx_connection_t *c, ngx_http_v3_parse_field_t *st, + ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_index + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field ri"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->dynamic = (ch & 0x40) ? 0 : 1; + st->state = sw_index; + + /* fall through */ + + case sw_index: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, b); + if (rc != NGX_DONE) { + return rc; + } + + st->index = st->pint.value; + goto done; + } + } + +done: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field ri done %s%ui]", + st->dynamic ? "dynamic[-" : "static[", st->index); + + if (st->dynamic) { + st->index = st->base - st->index - 1; + } + + rc = ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, + &st->value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_lri(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_index, + sw_value_len, + sw_read_value_len, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field lri"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->dynamic = (ch & 0x10) ? 0 : 1; + st->state = sw_index; + + /* fall through */ + + case sw_index: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 4, b); + if (rc != NGX_DONE) { + return rc; + } + + st->index = st->pint.value; + st->state = sw_value_len; + break; + + case sw_value_len: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x80) ? 1 : 0; + st->state = sw_read_value_len; + + /* fall through */ + + case sw_read_value_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + goto done; + } + + st->state = sw_value; + break; + + case sw_value: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->value = st->literal.value; + goto done; + } + } + +done: + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field lri done %s%ui] \"%V\"", + st->dynamic ? "dynamic[-" : "static[", + st->index, &st->value); + + if (st->dynamic) { + st->index = st->base - st->index - 1; + } + + rc = ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, NULL); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_l(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_name_len, + sw_name, + sw_value_len, + sw_read_value_len, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field l"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x08) ? 1 : 0; + st->state = sw_name_len; + + /* fall through */ + + case sw_name_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 3, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + return NGX_ERROR; + } + + st->state = sw_name; + break; + + case sw_name: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->name = st->literal.value; + st->state = sw_value_len; + break; + + case sw_value_len: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x80) ? 1 : 0; + st->state = sw_read_value_len; + + /* fall through */ + + case sw_read_value_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + goto done; + } + + st->state = sw_value; + break; + + case sw_value: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->value = st->literal.value; + goto done; + } + } + +done: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field l done \"%V\" \"%V\"", + &st->name, &st->value); + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_pbi(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b) +{ + ngx_int_t rc; + enum { + sw_start = 0, + sw_index + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field pbi"); + + st->state = sw_index; + + /* fall through */ + + case sw_index: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 4, b); + if (rc != NGX_DONE) { + return rc; + } + + st->index = st->pint.value; + goto done; + } + } + +done: + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field pbi done dynamic[+%ui]", st->index); + + rc = ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, + &st->value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_lpbi(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_index, + sw_value_len, + sw_read_value_len, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field lpbi"); + + st->state = sw_index; + + /* fall through */ + + case sw_index: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 3, b); + if (rc != NGX_DONE) { + return rc; + } + + st->index = st->pint.value; + st->state = sw_value_len; + break; + + case sw_value_len: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x80) ? 1 : 0; + st->state = sw_read_value_len; + + /* fall through */ + + case sw_read_value_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + goto done; + } + + st->state = sw_value; + break; + + case sw_value: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->value = st->literal.value; + goto done; + } + } + +done: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field lpbi done dynamic[+%ui] \"%V\"", + st->index, &st->value); + + rc = ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, NULL); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_lookup(ngx_connection_t *c, ngx_uint_t dynamic, + ngx_uint_t index, ngx_str_t *name, ngx_str_t *value) +{ + u_char *p; + + if (!dynamic) { + if (ngx_http_v3_lookup_static(c, index, name, value) != NGX_OK) { + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + return NGX_OK; + } + + if (ngx_http_v3_lookup(c, index, name, value) != NGX_OK) { + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + if (name) { + p = ngx_pnalloc(c->pool, name->len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, name->data, name->len); + p[name->len] = '\0'; + name->data = p; + } + + if (value) { + p = ngx_pnalloc(c->pool, value->len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, value->data, value->len); + p[value->len] = '\0'; + value->data = p; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v3_parse_control(ngx_connection_t *c, ngx_http_v3_parse_control_t *st, + ngx_buf_t *b) +{ + ngx_buf_t loc; + ngx_int_t rc; + enum { + sw_start = 0, + sw_first_type, + sw_type, + sw_length, + sw_settings, + sw_skip + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse control"); + + st->state = sw_first_type; + + /* fall through */ + + case sw_first_type: + case sw_type: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + st->type = st->vlint.value; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse frame type:%ui", st->type); + + if (st->state == sw_first_type + && st->type != NGX_HTTP_V3_FRAME_SETTINGS) + { + return NGX_HTTP_V3_ERR_MISSING_SETTINGS; + } + + if (st->state != sw_first_type + && st->type == NGX_HTTP_V3_FRAME_SETTINGS) + { + return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED; + } + + if (ngx_http_v3_is_v2_frame(st->type) + || st->type == NGX_HTTP_V3_FRAME_DATA + || st->type == NGX_HTTP_V3_FRAME_HEADERS + || st->type == NGX_HTTP_V3_FRAME_PUSH_PROMISE) + { + return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED; + } + + if (st->type == NGX_HTTP_V3_FRAME_CANCEL_PUSH) { + return NGX_HTTP_V3_ERR_ID_ERROR; + } + + st->state = sw_length; + break; + + case sw_length: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse frame len:%uL", st->vlint.value); + + st->length = st->vlint.value; + if (st->length == 0) { + st->state = sw_type; + break; + } + + switch (st->type) { + + case NGX_HTTP_V3_FRAME_SETTINGS: + st->state = sw_settings; + break; + + default: + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse skip unknown frame"); + st->state = sw_skip; + } + + break; + + case sw_settings: + + ngx_http_v3_parse_start_local(b, &loc, st->length); + + rc = ngx_http_v3_parse_settings(c, &st->settings, &loc); + + ngx_http_v3_parse_end_local(b, &loc, &st->length); + + if (st->length == 0 && rc == NGX_AGAIN) { + return NGX_HTTP_V3_ERR_SETTINGS_ERROR; + } + + if (rc != NGX_DONE) { + return rc; + } + + if (st->length == 0) { + st->state = sw_type; + } + + break; + + case sw_skip: + + rc = ngx_http_v3_parse_skip(b, &st->length); + if (rc != NGX_DONE) { + return rc; + } + + st->state = sw_type; + break; + } + } +} + + +static ngx_int_t +ngx_http_v3_parse_settings(ngx_connection_t *c, + ngx_http_v3_parse_settings_t *st, ngx_buf_t *b) +{ + ngx_int_t rc; + enum { + sw_start = 0, + sw_id, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse settings"); + + st->state = sw_id; + + /* fall through */ + + case sw_id: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + st->id = st->vlint.value; + st->state = sw_value; + break; + + case sw_value: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + if (ngx_http_v3_set_param(c, st->id, st->vlint.value) != NGX_OK) { + return NGX_HTTP_V3_ERR_SETTINGS_ERROR; + } + + goto done; + } + } + +done: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse settings done"); + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_encoder(ngx_connection_t *c, ngx_http_v3_parse_encoder_t *st, + ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_inr, + sw_iln, + sw_capacity, + sw_duplicate + }; + + for ( ;; ) { + + if (st->state == sw_start) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse encoder instruction"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + if (ch & 0x80) { + /* Insert With Name Reference */ + + st->state = sw_inr; + + } else if (ch & 0x40) { + /* Insert With Literal Name */ + + st->state = sw_iln; + + } else if (ch & 0x20) { + /* Set Dynamic Table Capacity */ + + st->state = sw_capacity; + + } else { + /* Duplicate */ + + st->state = sw_duplicate; + } + } + + switch (st->state) { + + case sw_inr: + + rc = ngx_http_v3_parse_field_inr(c, &st->field, b); + if (rc != NGX_DONE) { + return rc; + } + + st->state = sw_start; + break; + + case sw_iln: + + rc = ngx_http_v3_parse_field_iln(c, &st->field, b); + if (rc != NGX_DONE) { + return rc; + } + + st->state = sw_start; + break; + + case sw_capacity: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 5, b); + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_set_capacity(c, st->pint.value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + break; + + default: /* sw_duplicate */ + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 5, b); + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_duplicate(c, st->pint.value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + break; + } + } +} + + +static ngx_int_t +ngx_http_v3_parse_field_inr(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_name_index, + sw_value_len, + sw_read_value_len, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field inr"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->dynamic = (ch & 0x40) ? 0 : 1; + st->state = sw_name_index; + + /* fall through */ + + case sw_name_index: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, b); + if (rc != NGX_DONE) { + return rc; + } + + st->index = st->pint.value; + st->state = sw_value_len; + break; + + case sw_value_len: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x80) ? 1 : 0; + st->state = sw_read_value_len; + + /* fall through */ + + case sw_read_value_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + st->value.len = 0; + goto done; + } + + st->state = sw_value; + break; + + case sw_value: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->value = st->literal.value; + goto done; + } + } + +done: + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field inr done %s[%ui] \"%V\"", + st->dynamic ? "dynamic" : "static", + st->index, &st->value); + + rc = ngx_http_v3_ref_insert(c, st->dynamic, st->index, &st->value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_field_iln(ngx_connection_t *c, + ngx_http_v3_parse_field_t *st, ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_name_len, + sw_name, + sw_value_len, + sw_read_value_len, + sw_value + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field iln"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x20) ? 1 : 0; + st->state = sw_name_len; + + /* fall through */ + + case sw_name_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 5, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + return NGX_ERROR; + } + + st->state = sw_name; + break; + + case sw_name: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->name = st->literal.value; + st->state = sw_value_len; + break; + + case sw_value_len: + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + st->literal.huffman = (ch & 0x80) ? 1 : 0; + st->state = sw_read_value_len; + + /* fall through */ + + case sw_read_value_len: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { + st->value.len = 0; + goto done; + } + + st->state = sw_value; + break; + + case sw_value: + + rc = ngx_http_v3_parse_literal(c, &st->literal, b); + if (rc != NGX_DONE) { + return rc; + } + + st->value = st->literal.value; + goto done; + } + } + +done: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse field iln done \"%V\":\"%V\"", + &st->name, &st->value); + + rc = ngx_http_v3_insert(c, &st->name, &st->value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_v3_parse_decoder(ngx_connection_t *c, ngx_http_v3_parse_decoder_t *st, + ngx_buf_t *b) +{ + u_char ch; + ngx_int_t rc; + enum { + sw_start = 0, + sw_ack_section, + sw_cancel_stream, + sw_inc_insert_count + }; + + for ( ;; ) { + + if (st->state == sw_start) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse decoder instruction"); + + if (b->pos == b->last) { + return NGX_AGAIN; + } + + ch = *b->pos; + + if (ch & 0x80) { + /* Section Acknowledgment */ + + st->state = sw_ack_section; + + } else if (ch & 0x40) { + /* Stream Cancellation */ + + st->state = sw_cancel_stream; + + } else { + /* Insert Count Increment */ + + st->state = sw_inc_insert_count; + } + } + + switch (st->state) { + + case sw_ack_section: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, b); + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_ack_section(c, st->pint.value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + break; + + case sw_cancel_stream: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, b); + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_cancel_stream(c, st->pint.value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + break; + + case sw_inc_insert_count: + + rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, b); + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_inc_insert_count(c, st->pint.value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_start; + break; + } + } +} + + +ngx_int_t +ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, + ngx_buf_t *b) +{ + ngx_int_t rc; + enum { + sw_start = 0, + sw_type, + sw_length, + sw_skip + }; + + for ( ;; ) { + + switch (st->state) { + + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data"); + + st->state = sw_type; + + /* fall through */ + + case sw_type: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + st->type = st->vlint.value; + + if (st->type == NGX_HTTP_V3_FRAME_HEADERS) { + /* trailers */ + goto done; + } + + if (ngx_http_v3_is_v2_frame(st->type) + || st->type == NGX_HTTP_V3_FRAME_GOAWAY + || st->type == NGX_HTTP_V3_FRAME_SETTINGS + || st->type == NGX_HTTP_V3_FRAME_MAX_PUSH_ID + || st->type == NGX_HTTP_V3_FRAME_CANCEL_PUSH + || st->type == NGX_HTTP_V3_FRAME_PUSH_PROMISE) + { + return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED; + } + + st->state = sw_length; + break; + + case sw_length: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + st->length = st->vlint.value; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse data type:%ui, len:%ui", + st->type, st->length); + + if (st->type != NGX_HTTP_V3_FRAME_DATA && st->length > 0) { + st->state = sw_skip; + break; + } + + st->state = sw_type; + return NGX_OK; + + case sw_skip: + + rc = ngx_http_v3_parse_skip(b, &st->length); + if (rc != NGX_DONE) { + return rc; + } + + st->state = sw_type; + break; + } + } + +done: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data done"); + + st->state = sw_start; + return NGX_DONE; +} + + +ngx_int_t +ngx_http_v3_parse_uni(ngx_connection_t *c, ngx_http_v3_parse_uni_t *st, + ngx_buf_t *b) +{ + ngx_int_t rc; + enum { + sw_start = 0, + sw_type, + sw_control, + sw_encoder, + sw_decoder, + sw_unknown + }; + + for ( ;; ) { + + switch (st->state) { + case sw_start: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse uni"); + + st->state = sw_type; + + /* fall through */ + + case sw_type: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, b); + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_register_uni_stream(c, st->vlint.value); + if (rc != NGX_OK) { + return rc; + } + + switch (st->vlint.value) { + case NGX_HTTP_V3_STREAM_CONTROL: + st->state = sw_control; + break; + + case NGX_HTTP_V3_STREAM_ENCODER: + st->state = sw_encoder; + break; + + case NGX_HTTP_V3_STREAM_DECODER: + st->state = sw_decoder; + break; + + default: + st->state = sw_unknown; + } + + break; + + case sw_control: + + return ngx_http_v3_parse_control(c, &st->u.control, b); + + case sw_encoder: + + return ngx_http_v3_parse_encoder(c, &st->u.encoder, b); + + case sw_decoder: + + return ngx_http_v3_parse_decoder(c, &st->u.decoder, b); + + case sw_unknown: + + b->pos = b->last; + return NGX_AGAIN; + } + } +} diff --git a/src/http/v3/ngx_http_v3_parse.h b/src/http/v3/ngx_http_v3_parse.h new file mode 100644 index 0000000..ba004db --- /dev/null +++ b/src/http/v3/ngx_http_v3_parse.h @@ -0,0 +1,146 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_HTTP_V3_PARSE_H_INCLUDED_ +#define _NGX_HTTP_V3_PARSE_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + ngx_uint_t state; + uint64_t value; +} ngx_http_v3_parse_varlen_int_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t shift; + uint64_t value; +} ngx_http_v3_parse_prefix_int_t; + + +typedef struct { + ngx_uint_t state; + uint64_t id; + ngx_http_v3_parse_varlen_int_t vlint; +} ngx_http_v3_parse_settings_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t insert_count; + ngx_uint_t delta_base; + ngx_uint_t sign; + ngx_uint_t base; + ngx_http_v3_parse_prefix_int_t pint; +} ngx_http_v3_parse_field_section_prefix_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t length; + ngx_uint_t huffman; + ngx_str_t value; + u_char *last; + u_char huffstate; +} ngx_http_v3_parse_literal_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t index; + ngx_uint_t base; + ngx_uint_t dynamic; + + ngx_str_t name; + ngx_str_t value; + + ngx_http_v3_parse_prefix_int_t pint; + ngx_http_v3_parse_literal_t literal; +} ngx_http_v3_parse_field_t; + + +typedef struct { + ngx_uint_t state; + ngx_http_v3_parse_field_t field; +} ngx_http_v3_parse_field_rep_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t type; + ngx_uint_t length; + ngx_http_v3_parse_varlen_int_t vlint; + ngx_http_v3_parse_field_section_prefix_t prefix; + ngx_http_v3_parse_field_rep_t field_rep; +} ngx_http_v3_parse_headers_t; + + +typedef struct { + ngx_uint_t state; + ngx_http_v3_parse_field_t field; + ngx_http_v3_parse_prefix_int_t pint; +} ngx_http_v3_parse_encoder_t; + + +typedef struct { + ngx_uint_t state; + ngx_http_v3_parse_prefix_int_t pint; +} ngx_http_v3_parse_decoder_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t type; + ngx_uint_t length; + ngx_http_v3_parse_varlen_int_t vlint; + ngx_http_v3_parse_settings_t settings; +} ngx_http_v3_parse_control_t; + + +typedef struct { + ngx_uint_t state; + ngx_http_v3_parse_varlen_int_t vlint; + union { + ngx_http_v3_parse_encoder_t encoder; + ngx_http_v3_parse_decoder_t decoder; + ngx_http_v3_parse_control_t control; + } u; +} ngx_http_v3_parse_uni_t; + + +typedef struct { + ngx_uint_t state; + ngx_uint_t type; + ngx_uint_t length; + ngx_http_v3_parse_varlen_int_t vlint; +} ngx_http_v3_parse_data_t; + + +/* + * Parse functions return codes: + * NGX_DONE - parsing done + * NGX_OK - sub-element done + * NGX_AGAIN - more data expected + * NGX_BUSY - waiting for external event + * NGX_ERROR - internal error + * NGX_HTTP_V3_ERROR_XXX - HTTP/3 or QPACK error + */ + +ngx_int_t ngx_http_v3_parse_headers(ngx_connection_t *c, + ngx_http_v3_parse_headers_t *st, ngx_buf_t *b); +ngx_int_t ngx_http_v3_parse_data(ngx_connection_t *c, + ngx_http_v3_parse_data_t *st, ngx_buf_t *b); +ngx_int_t ngx_http_v3_parse_uni(ngx_connection_t *c, + ngx_http_v3_parse_uni_t *st, ngx_buf_t *b); + + +#endif /* _NGX_HTTP_V3_PARSE_H_INCLUDED_ */ diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c new file mode 100644 index 0000000..87f5f32 --- /dev/null +++ b/src/http/v3/ngx_http_v3_request.c @@ -0,0 +1,1710 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static void ngx_http_v3_init_request_stream(ngx_connection_t *c); +static void ngx_http_v3_wait_request_handler(ngx_event_t *rev); +static void ngx_http_v3_cleanup_connection(void *data); +static void ngx_http_v3_cleanup_request(void *data); +static void ngx_http_v3_process_request(ngx_event_t *rev); +static ngx_int_t ngx_http_v3_process_header(ngx_http_request_t *r, + ngx_str_t *name, ngx_str_t *value); +static ngx_int_t ngx_http_v3_validate_header(ngx_http_request_t *r, + ngx_str_t *name, ngx_str_t *value); +static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, + ngx_str_t *name, ngx_str_t *value); +static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r); +static ngx_int_t ngx_http_v3_process_request_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_v3_cookie(ngx_http_request_t *r, ngx_str_t *value); +static ngx_int_t ngx_http_v3_construct_cookie_header(ngx_http_request_t *r); +static void ngx_http_v3_read_client_request_body_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_v3_do_read_client_request_body(ngx_http_request_t *r); +static ngx_int_t ngx_http_v3_request_body_filter(ngx_http_request_t *r, + ngx_chain_t *in); + + +static const struct { + ngx_str_t name; + ngx_uint_t method; +} ngx_http_v3_methods[] = { + + { ngx_string("GET"), NGX_HTTP_GET }, + { ngx_string("POST"), NGX_HTTP_POST }, + { ngx_string("HEAD"), NGX_HTTP_HEAD }, + { ngx_string("OPTIONS"), NGX_HTTP_OPTIONS }, + { ngx_string("PROPFIND"), NGX_HTTP_PROPFIND }, + { ngx_string("PUT"), NGX_HTTP_PUT }, + { ngx_string("MKCOL"), NGX_HTTP_MKCOL }, + { ngx_string("DELETE"), NGX_HTTP_DELETE }, + { ngx_string("COPY"), NGX_HTTP_COPY }, + { ngx_string("MOVE"), NGX_HTTP_MOVE }, + { ngx_string("PROPPATCH"), NGX_HTTP_PROPPATCH }, + { ngx_string("LOCK"), NGX_HTTP_LOCK }, + { ngx_string("UNLOCK"), NGX_HTTP_UNLOCK }, + { ngx_string("PATCH"), NGX_HTTP_PATCH }, + { ngx_string("TRACE"), NGX_HTTP_TRACE }, + { ngx_string("CONNECT"), NGX_HTTP_CONNECT } +}; + + +void +ngx_http_v3_init_stream(ngx_connection_t *c) +{ + ngx_http_connection_t *hc, *phc; + ngx_http_v3_srv_conf_t *h3scf; + ngx_http_core_loc_conf_t *clcf; + + hc = c->data; + + hc->ssl = 1; + + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); + + if (c->quic == NULL) { + h3scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); + h3scf->quic.idle_timeout = clcf->keepalive_timeout; + + ngx_quic_run(c, &h3scf->quic); + return; + } + + phc = ngx_http_quic_get_connection(c); + + if (phc->ssl_servername) { + hc->ssl_servername = phc->ssl_servername; +#if (NGX_PCRE) + hc->ssl_servername_regex = phc->ssl_servername_regex; +#endif + hc->conf_ctx = phc->conf_ctx; + + ngx_set_connection_log(c, clcf->error_log); + } + + if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { + ngx_http_v3_init_uni_stream(c); + + } else { + ngx_http_v3_init_request_stream(c); + } +} + + +ngx_int_t +ngx_http_v3_init(ngx_connection_t *c) +{ + unsigned int len; + const unsigned char *data; + ngx_http_v3_session_t *h3c; + ngx_http_v3_srv_conf_t *h3scf; + ngx_http_core_loc_conf_t *clcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init"); + + if (ngx_http_v3_init_session(c) != NGX_OK) { + return NGX_ERROR; + } + + h3c = ngx_http_v3_get_session(c); + clcf = ngx_http_v3_get_module_loc_conf(c, ngx_http_core_module); + ngx_add_timer(&h3c->keepalive, clcf->keepalive_timeout); + + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + + if (h3scf->enable_hq) { + if (!h3scf->enable) { + h3c->hq = 1; + return NGX_OK; + } + + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + + if (len == sizeof(NGX_HTTP_V3_HQ_PROTO) - 1 + && ngx_strncmp(data, NGX_HTTP_V3_HQ_PROTO, len) == 0) + { + h3c->hq = 1; + return NGX_OK; + } + } + + return ngx_http_v3_send_settings(c); +} + + +void +ngx_http_v3_shutdown(ngx_connection_t *c) +{ + ngx_http_v3_session_t *h3c; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 shutdown"); + + h3c = ngx_http_v3_get_session(c); + + if (h3c == NULL) { + ngx_quic_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, + "connection shutdown"); + return; + } + + if (!h3c->goaway) { + h3c->goaway = 1; + + if (!h3c->hq) { + (void) ngx_http_v3_send_goaway(c, h3c->next_request_id); + } + + ngx_http_v3_shutdown_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, + "connection shutdown"); + } +} + + +static void +ngx_http_v3_init_request_stream(ngx_connection_t *c) +{ + uint64_t n; + ngx_event_t *rev; + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_v3_session_t *h3c; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init request stream"); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + hc = c->data; + + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); + + n = c->quic->id >> 2; + + if (n >= clcf->keepalive_requests * 2) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD, + "too many requests per connection"); + ngx_http_close_connection(c); + return; + } + + h3c = ngx_http_v3_get_session(c); + + if (h3c->goaway) { + c->close = 1; + ngx_http_close_connection(c); + return; + } + + h3c->next_request_id = c->quic->id + 0x04; + + if (n + 1 == clcf->keepalive_requests + || ngx_current_msec - c->start_time > clcf->keepalive_time) + { + h3c->goaway = 1; + + if (!h3c->hq) { + if (ngx_http_v3_send_goaway(c, h3c->next_request_id) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + } + + ngx_http_v3_shutdown_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, + "reached maximum number of requests"); + } + + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + ngx_http_close_connection(c); + return; + } + + cln->handler = ngx_http_v3_cleanup_connection; + cln->data = c; + + h3c->nrequests++; + + if (h3c->keepalive.timer_set) { + ngx_del_timer(&h3c->keepalive); + } + + rev = c->read; + + if (!h3c->hq) { + rev->handler = ngx_http_v3_wait_request_handler; + c->write->handler = ngx_http_empty_handler; + } + + if (rev->ready) { + rev->handler(rev); + return; + } + + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); + + ngx_add_timer(rev, cscf->client_header_timeout); + ngx_reusable_connection(c, 1); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; + } +} + + +static void +ngx_http_v3_wait_request_handler(ngx_event_t *rev) +{ + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_connection_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_request_t *r; + ngx_http_connection_t *hc; + ngx_http_core_srv_conf_t *cscf; + + c = rev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 wait request handler"); + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + c->timedout = 1; + ngx_http_close_connection(c); + return; + } + + if (c->close) { + ngx_http_close_connection(c); + return; + } + + hc = c->data; + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); + + size = cscf->client_header_buffer_size; + + b = c->buffer; + + if (b == NULL) { + b = ngx_create_temp_buf(c->pool, size); + if (b == NULL) { + ngx_http_close_connection(c); + return; + } + + c->buffer = b; + + } else if (b->start == NULL) { + + b->start = ngx_palloc(c->pool, size); + if (b->start == NULL) { + ngx_http_close_connection(c); + return; + } + + b->pos = b->start; + b->last = b->start; + b->end = b->last + size; + } + + n = c->recv(c, b->last, size); + + if (n == NGX_AGAIN) { + + if (!rev->timer_set) { + ngx_add_timer(rev, cscf->client_header_timeout); + ngx_reusable_connection(c, 1); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + + /* + * We are trying to not hold c->buffer's memory for an idle connection. + */ + + if (ngx_pfree(c->pool, b->start) == NGX_OK) { + b->start = NULL; + } + + return; + } + + if (n == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (n == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client closed connection"); + ngx_http_close_connection(c); + return; + } + + b->last += n; + + c->log->action = "reading client request"; + + ngx_reusable_connection(c, 0); + + r = ngx_http_create_request(c); + if (r == NULL) { + ngx_http_close_connection(c); + return; + } + + r->http_version = NGX_HTTP_VERSION_30; + + r->v3_parse = ngx_pcalloc(r->pool, sizeof(ngx_http_v3_parse_t)); + if (r->v3_parse == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + r->v3_parse->header_limit = cscf->large_client_header_buffers.size + * cscf->large_client_header_buffers.num; + + c->data = r; + c->requests = (c->quic->id >> 2) + 1; + + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + cln->handler = ngx_http_v3_cleanup_request; + cln->data = r; + + rev->handler = ngx_http_v3_process_request; + ngx_http_v3_process_request(rev); +} + + +void +ngx_http_v3_reset_stream(ngx_connection_t *c) +{ + ngx_http_v3_session_t *h3c; + ngx_http_v3_srv_conf_t *h3scf; + + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + + h3c = ngx_http_v3_get_session(c); + + if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq + && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) + { + (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); + } + + if (c->timedout) { + ngx_quic_reset_stream(c, NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR); + + } else if (c->close) { + ngx_quic_reset_stream(c, NGX_HTTP_V3_ERR_REQUEST_REJECTED); + + } else if (c->requests == 0 || c->error) { + ngx_quic_reset_stream(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR); + } +} + + +static void +ngx_http_v3_cleanup_connection(void *data) +{ + ngx_connection_t *c = data; + + ngx_http_v3_session_t *h3c; + ngx_http_core_loc_conf_t *clcf; + + h3c = ngx_http_v3_get_session(c); + + if (--h3c->nrequests == 0) { + clcf = ngx_http_v3_get_module_loc_conf(c, ngx_http_core_module); + ngx_add_timer(&h3c->keepalive, clcf->keepalive_timeout); + } +} + + +static void +ngx_http_v3_cleanup_request(void *data) +{ + ngx_http_request_t *r = data; + + if (!r->response_sent) { + r->connection->error = 1; + } +} + + +static void +ngx_http_v3_process_request(ngx_event_t *rev) +{ + u_char *p; + ssize_t n; + ngx_buf_t *b; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_v3_session_t *h3c; + ngx_http_core_srv_conf_t *cscf; + ngx_http_v3_parse_headers_t *st; + + c = rev->data; + r = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http3 process request"); + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + c->timedout = 1; + ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); + return; + } + + h3c = ngx_http_v3_get_session(c); + + st = &r->v3_parse->headers; + + b = r->header_in; + + for ( ;; ) { + + if (b->pos == b->last) { + + if (rev->ready) { + n = c->recv(c, b->start, b->end - b->start); + + } else { + n = NGX_AGAIN; + } + + if (n == NGX_AGAIN) { + if (!rev->timer_set) { + cscf = ngx_http_get_module_srv_conf(r, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + + break; + } + + if (n == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client prematurely closed connection"); + } + + if (n == 0 || n == NGX_ERROR) { + c->error = 1; + c->log->action = "reading client request"; + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + break; + } + + b->pos = b->start; + b->last = b->start + n; + } + + p = b->pos; + + rc = ngx_http_v3_parse_headers(c, st, b); + + if (rc > 0) { + ngx_quic_reset_stream(c, rc); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent invalid header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + break; + } + + if (rc == NGX_ERROR) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + break; + } + + r->request_length += b->pos - p; + h3c->total_bytes += b->pos - p; + + if (ngx_http_v3_check_flood(c) != NGX_OK) { + ngx_http_close_request(r, NGX_HTTP_CLOSE); + break; + } + + if (rc == NGX_BUSY) { + if (rev->error) { + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + break; + } + + if (!rev->timer_set) { + cscf = ngx_http_get_module_srv_conf(r, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + + break; + } + + if (rc == NGX_AGAIN) { + continue; + } + + /* rc == NGX_OK || rc == NGX_DONE */ + + h3c->payload_bytes += ngx_http_v3_encode_field_l(NULL, + &st->field_rep.field.name, + &st->field_rep.field.value); + + if (ngx_http_v3_process_header(r, &st->field_rep.field.name, + &st->field_rep.field.value) + != NGX_OK) + { + break; + } + + if (rc == NGX_DONE) { + if (ngx_http_v3_process_request_header(r) != NGX_OK) { + break; + } + + ngx_http_process_request(r); + break; + } + } + + ngx_http_run_posted_requests(c); + + return; +} + + +static ngx_int_t +ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name, + ngx_str_t *value) +{ + size_t len; + ngx_table_elt_t *h; + ngx_http_header_t *hh; + ngx_http_core_srv_conf_t *cscf; + ngx_http_core_main_conf_t *cmcf; + + static ngx_str_t cookie = ngx_string("cookie"); + + len = name->len + value->len; + + if (len > r->v3_parse->header_limit) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent too large header"); + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); + return NGX_ERROR; + } + + r->v3_parse->header_limit -= len; + + if (ngx_http_v3_validate_header(r, name, value) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + if (r->invalid_header) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + if (cscf->ignore_invalid_headers) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header: \"%V\"", name); + + return NGX_OK; + } + } + + if (name->len && name->data[0] == ':') { + return ngx_http_v3_process_pseudo_header(r, name, value); + } + + if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) { + return NGX_ERROR; + } + + if (name->len == cookie.len + && ngx_memcmp(name->data, cookie.data, cookie.len) == 0) + { + if (ngx_http_v3_cookie(r, value) != NGX_OK) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + } else { + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + h->key = *name; + h->value = *value; + h->lowcase_key = h->key.data; + h->hash = ngx_hash_key(h->key.data, h->key.len); + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); + + if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { + return NGX_ERROR; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 header: \"%V: %V\"", name, value); + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v3_validate_header(ngx_http_request_t *r, ngx_str_t *name, + ngx_str_t *value) +{ + u_char ch; + ngx_uint_t i; + ngx_http_core_srv_conf_t *cscf; + + r->invalid_header = 0; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + for (i = (name->data[0] == ':'); i != name->len; i++) { + ch = name->data[i]; + + if ((ch >= 'a' && ch <= 'z') + || (ch == '-') + || (ch >= '0' && ch <= '9') + || (ch == '_' && cscf->underscores_in_headers)) + { + continue; + } + + if (ch <= 0x20 || ch == 0x7f || ch == ':' + || (ch >= 'A' && ch <= 'Z')) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header name: \"%V\"", name); + + return NGX_ERROR; + } + + r->invalid_header = 1; + } + + for (i = 0; i != value->len; i++) { + ch = value->data[i]; + + if (ch == '\0' || ch == LF || ch == CR) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent header \"%V\" with " + "invalid value: \"%V\"", name, value); + + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, + ngx_str_t *value) +{ + u_char ch, c; + ngx_uint_t i; + + if (r->request_line.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent out of order pseudo-headers"); + goto failed; + } + + if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { + + if (r->method_name.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate \":method\" header"); + goto failed; + } + + if (value->len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent empty \":method\" header"); + goto failed; + } + + r->method_name = *value; + + for (i = 0; i < sizeof(ngx_http_v3_methods) + / sizeof(ngx_http_v3_methods[0]); i++) + { + if (value->len == ngx_http_v3_methods[i].name.len + && ngx_strncmp(value->data, + ngx_http_v3_methods[i].name.data, value->len) + == 0) + { + r->method = ngx_http_v3_methods[i].method; + break; + } + } + + for (i = 0; i < value->len; i++) { + ch = value->data[i]; + + if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid method: \"%V\"", value); + goto failed; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 method \"%V\" %ui", value, r->method); + return NGX_OK; + } + + if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { + + if (r->uri_start) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate \":path\" header"); + goto failed; + } + + if (value->len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent empty \":path\" header"); + goto failed; + } + + r->uri_start = value->data; + r->uri_end = value->data + value->len; + + if (ngx_http_parse_uri(r) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid \":path\" header: \"%V\"", + value); + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 path \"%V\"", value); + return NGX_OK; + } + + if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { + + if (r->schema.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate \":scheme\" header"); + goto failed; + } + + if (value->len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent empty \":scheme\" header"); + goto failed; + } + + for (i = 0; i < value->len; i++) { + ch = value->data[i]; + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'z') { + continue; + } + + if (((ch >= '0' && ch <= '9') + || ch == '+' || ch == '-' || ch == '.') + && i > 0) + { + continue; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid \":scheme\" header: \"%V\"", + value); + goto failed; + } + + r->schema = *value; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 schema \"%V\"", value); + return NGX_OK; + } + + if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { + + if (r->host_start) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate \":authority\" header"); + goto failed; + } + + r->host_start = value->data; + r->host_end = value->data + value->len; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 authority \"%V\"", value); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent unknown pseudo-header \"%V\"", name); + +failed: + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r) +{ + size_t len; + u_char *p; + ngx_int_t rc; + ngx_str_t host; + + if (r->request_line.len) { + return NGX_OK; + } + + if (r->method_name.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no \":method\" header"); + goto failed; + } + + if (r->schema.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no \":scheme\" header"); + goto failed; + } + + if (r->uri_start == NULL) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no \":path\" header"); + goto failed; + } + + len = r->method_name.len + 1 + + (r->uri_end - r->uri_start) + 1 + + sizeof("HTTP/3.0") - 1; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + r->request_line.data = p; + + p = ngx_cpymem(p, r->method_name.data, r->method_name.len); + *p++ = ' '; + p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); + *p++ = ' '; + p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1); + + r->request_line.len = p - r->request_line.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 request line: \"%V\"", &r->request_line); + + ngx_str_set(&r->http_protocol, "HTTP/3.0"); + + if (ngx_http_process_request_uri(r) != NGX_OK) { + return NGX_ERROR; + } + + if (r->host_end) { + + host.len = r->host_end - r->host_start; + host.data = r->host_start; + + rc = ngx_http_validate_host(&host, r->pool, 0); + + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid host in request line"); + goto failed; + } + + if (rc == NGX_ERROR) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { + return NGX_ERROR; + } + + r->headers_in.server = host; + } + + if (ngx_list_init(&r->headers_in.headers, r->pool, 20, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + return NGX_OK; + +failed: + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_v3_process_request_header(ngx_http_request_t *r) +{ + ssize_t n; + ngx_buf_t *b; + ngx_connection_t *c; + ngx_http_v3_session_t *h3c; + ngx_http_v3_srv_conf_t *h3scf; + + c = r->connection; + + if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) { + return NGX_ERROR; + } + + h3c = ngx_http_v3_get_session(c); + h3scf = ngx_http_get_module_srv_conf(r, ngx_http_v3_module); + + if ((h3c->hq && !h3scf->enable_hq) || (!h3c->hq && !h3scf->enable)) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client attempted to request the server name " + "for which the negotiated protocol is disabled"); + ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST); + return NGX_ERROR; + } + + if (ngx_http_v3_construct_cookie_header(r) != NGX_OK) { + return NGX_ERROR; + } + + if (r->headers_in.server.len == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent neither \":authority\" nor \"Host\" header"); + goto failed; + } + + if (r->headers_in.host) { + if (r->headers_in.host->value.len != r->headers_in.server.len + || ngx_memcmp(r->headers_in.host->value.data, + r->headers_in.server.data, + r->headers_in.server.len) + != 0) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent \":authority\" and \"Host\" headers " + "with different values"); + goto failed; + } + } + + if (r->headers_in.content_length) { + r->headers_in.content_length_n = + ngx_atoof(r->headers_in.content_length->value.data, + r->headers_in.content_length->value.len); + + if (r->headers_in.content_length_n == NGX_ERROR) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid \"Content-Length\" header"); + goto failed; + } + + } else { + b = r->header_in; + n = b->last - b->pos; + + if (n == 0) { + n = c->recv(c, b->start, b->end - b->start); + + if (n == NGX_ERROR) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + if (n > 0) { + b->pos = b->start; + b->last = b->start + n; + } + } + + if (n != 0) { + r->headers_in.chunked = 1; + } + } + + if (r->method == NGX_HTTP_CONNECT) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent CONNECT method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + + if (r->method == NGX_HTTP_TRACE) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent TRACE method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + + return NGX_OK; + +failed: + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_v3_cookie(ngx_http_request_t *r, ngx_str_t *value) +{ + ngx_str_t *val; + ngx_array_t *cookies; + + cookies = r->v3_parse->cookies; + + if (cookies == NULL) { + cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t)); + if (cookies == NULL) { + return NGX_ERROR; + } + + r->v3_parse->cookies = cookies; + } + + val = ngx_array_push(cookies); + if (val == NULL) { + return NGX_ERROR; + } + + *val = *value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v3_construct_cookie_header(ngx_http_request_t *r) +{ + u_char *buf, *p, *end; + size_t len; + ngx_str_t *vals; + ngx_uint_t i; + ngx_array_t *cookies; + ngx_table_elt_t *h; + ngx_http_header_t *hh; + ngx_http_core_main_conf_t *cmcf; + + static ngx_str_t cookie = ngx_string("cookie"); + + cookies = r->v3_parse->cookies; + + if (cookies == NULL) { + return NGX_OK; + } + + vals = cookies->elts; + + i = 0; + len = 0; + + do { + len += vals[i].len + 2; + } while (++i != cookies->nelts); + + len -= 2; + + buf = ngx_pnalloc(r->pool, len + 1); + if (buf == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + p = buf; + end = buf + len; + + for (i = 0; /* void */ ; i++) { + + p = ngx_cpymem(p, vals[i].data, vals[i].len); + + if (p == end) { + *p = '\0'; + break; + } + + *p++ = ';'; *p++ = ' '; + } + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( + ngx_hash('c', 'o'), 'o'), 'k'), 'i'), 'e'); + + h->key.len = cookie.len; + h->key.data = cookie.data; + + h->value.len = len; + h->value.data = buf; + + h->lowcase_key = cookie.data; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); + + if (hh == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + if (hh->handler(r, h, hh->offset) != NGX_OK) { + /* + * request has been finalized already + * in ngx_http_process_multi_header_lines() + */ + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v3_read_request_body(ngx_http_request_t *r) +{ + size_t preread; + ngx_int_t rc; + ngx_chain_t *cl, out; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + + rb = r->request_body; + + preread = r->header_in->last - r->header_in->pos; + + if (preread) { + + /* there is the pre-read part of the request body */ + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 client request body preread %uz", preread); + + out.buf = r->header_in; + out.next = NULL; + cl = &out; + + } else { + cl = NULL; + } + + rc = ngx_http_v3_request_body_filter(r, cl); + if (rc != NGX_OK) { + return rc; + } + + if (rb->rest == 0 && rb->last_saved) { + /* the whole request body was pre-read */ + r->request_body_no_buffering = 0; + rb->post_handler(r); + return NGX_OK; + } + + if (rb->rest < 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "negative request body rest"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + rb->buf = ngx_create_temp_buf(r->pool, clcf->client_body_buffer_size); + if (rb->buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->read_event_handler = ngx_http_v3_read_client_request_body_handler; + r->write_event_handler = ngx_http_request_empty_handler; + + return ngx_http_v3_do_read_client_request_body(r); +} + + +static void +ngx_http_v3_read_client_request_body_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + + if (r->connection->read->timedout) { + r->connection->timedout = 1; + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); + return; + } + + rc = ngx_http_v3_do_read_client_request_body(r); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ngx_http_finalize_request(r, rc); + } +} + + +ngx_int_t +ngx_http_v3_read_unbuffered_request_body(ngx_http_request_t *r) +{ + ngx_int_t rc; + + if (r->connection->read->timedout) { + r->connection->timedout = 1; + return NGX_HTTP_REQUEST_TIME_OUT; + } + + rc = ngx_http_v3_do_read_client_request_body(r); + + if (rc == NGX_OK) { + r->reading_body = 0; + } + + return rc; +} + + +static ngx_int_t +ngx_http_v3_do_read_client_request_body(ngx_http_request_t *r) +{ + off_t rest; + size_t size; + ssize_t n; + ngx_int_t rc; + ngx_uint_t flush; + ngx_chain_t out; + ngx_connection_t *c; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + + c = r->connection; + rb = r->request_body; + flush = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 read client request body"); + + for ( ;; ) { + for ( ;; ) { + if (rb->rest == 0) { + break; + } + + if (rb->buf->last == rb->buf->end) { + + /* update chains */ + + rc = ngx_http_v3_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + return rc; + } + + if (rb->busy != NULL) { + if (r->request_body_no_buffering) { + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + + if (rb->filter_need_buffering) { + clcf = ngx_http_get_module_loc_conf(r, + ngx_http_core_module); + ngx_add_timer(c->read, clcf->client_body_timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "busy buffers after request body flush"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + flush = 0; + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; + } + + size = rb->buf->end - rb->buf->last; + rest = rb->rest - (rb->buf->last - rb->buf->pos); + + if ((off_t) size > rest) { + size = (size_t) rest; + } + + if (size == 0) { + break; + } + + n = c->recv(c, rb->buf->last, size); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 client request body recv %z", n); + + if (n == NGX_AGAIN) { + break; + } + + if (n == 0) { + rb->buf->last_buf = 1; + } + + if (n == NGX_ERROR) { + c->error = 1; + return NGX_HTTP_BAD_REQUEST; + } + + rb->buf->last += n; + + /* pass buffer to request body filter chain */ + + flush = 0; + out.buf = rb->buf; + out.next = NULL; + + rc = ngx_http_v3_request_body_filter(r, &out); + + if (rc != NGX_OK) { + return rc; + } + + if (rb->rest == 0) { + break; + } + + if (rb->buf->last < rb->buf->end) { + break; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 client request body rest %O", rb->rest); + + if (flush) { + rc = ngx_http_v3_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { + break; + } + + if (!c->read->ready || rb->rest == 0) { + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(c->read, clcf->client_body_timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (!r->request_body_no_buffering) { + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v3_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + off_t max; + size_t size; + u_char *p; + ngx_int_t rc; + ngx_buf_t *b; + ngx_uint_t last; + ngx_chain_t *cl, *out, *tl, **ll; + ngx_http_v3_session_t *h3c; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + ngx_http_v3_parse_data_t *st; + + rb = r->request_body; + st = &r->v3_parse->body; + + h3c = ngx_http_v3_get_session(r->connection); + + if (rb->rest == -1) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http3 request body filter"); + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + rb->rest = cscf->large_client_header_buffers.size; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + max = r->headers_in.content_length_n; + + if (max == -1 && clcf->client_max_body_size) { + max = clcf->client_max_body_size; + } + + out = NULL; + ll = &out; + last = 0; + + for (cl = in; cl; cl = cl->next) { + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "http3 body buf " + "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + + if (cl->buf->last_buf) { + last = 1; + } + + b = NULL; + + while (cl->buf->pos < cl->buf->last) { + + if (st->length == 0) { + p = cl->buf->pos; + + rc = ngx_http_v3_parse_data(r->connection, st, cl->buf); + + r->request_length += cl->buf->pos - p; + h3c->total_bytes += cl->buf->pos - p; + + if (ngx_http_v3_check_flood(r->connection) != NGX_OK) { + return NGX_HTTP_CLOSE; + } + + if (rc == NGX_AGAIN) { + continue; + } + + if (rc == NGX_DONE) { + last = 1; + goto done; + } + + if (rc > 0) { + ngx_quic_reset_stream(r->connection, rc); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent invalid body"); + return NGX_HTTP_BAD_REQUEST; + } + + if (rc == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* rc == NGX_OK */ + + if (max != -1 && (uint64_t) (max - rb->received) < st->length) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client intended to send too large " + "body: %O+%ui bytes", + rb->received, st->length); + + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } + + continue; + } + + if (b + && st->length <= 128 + && (uint64_t) (cl->buf->last - cl->buf->pos) >= st->length) + { + rb->received += st->length; + r->request_length += st->length; + h3c->total_bytes += st->length; + h3c->payload_bytes += st->length; + + if (st->length < 8) { + + while (st->length) { + *b->last++ = *cl->buf->pos++; + st->length--; + } + + } else { + ngx_memmove(b->last, cl->buf->pos, st->length); + b->last += st->length; + cl->buf->pos += st->length; + st->length = 0; + } + + continue; + } + + tl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (tl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = tl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->temporary = 1; + b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; + b->start = cl->buf->pos; + b->pos = cl->buf->pos; + b->last = cl->buf->last; + b->end = cl->buf->end; + b->flush = r->request_body_no_buffering; + + *ll = tl; + ll = &tl->next; + + size = cl->buf->last - cl->buf->pos; + + if (size > st->length) { + cl->buf->pos += (size_t) st->length; + rb->received += st->length; + r->request_length += st->length; + h3c->total_bytes += st->length; + h3c->payload_bytes += st->length; + st->length = 0; + + } else { + st->length -= size; + rb->received += size; + r->request_length += size; + h3c->total_bytes += size; + h3c->payload_bytes += size; + cl->buf->pos = cl->buf->last; + } + + b->last = cl->buf->pos; + } + } + +done: + + if (last) { + + if (st->length > 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client prematurely closed stream"); + r->connection->error = 1; + return NGX_HTTP_BAD_REQUEST; + } + + if (r->headers_in.content_length_n == -1) { + r->headers_in.content_length_n = rb->received; + + } else if (r->headers_in.content_length_n != rb->received) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent less body data than expected: " + "%O out of %O bytes of request body received", + rb->received, r->headers_in.content_length_n); + return NGX_HTTP_BAD_REQUEST; + } + + rb->rest = 0; + + tl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (tl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = tl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->last_buf = 1; + + *ll = tl; + + } else { + + /* set rb->rest, amount of data we want to see next time */ + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + rb->rest = (off_t) cscf->large_client_header_buffers.size; + } + + rc = ngx_http_top_request_body_filter(r, out); + + ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, + (ngx_buf_tag_t) &ngx_http_read_client_request_body); + + return rc; +} diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c new file mode 100644 index 0000000..f49a8fc --- /dev/null +++ b/src/http/v3/ngx_http_v3_table.c @@ -0,0 +1,715 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define ngx_http_v3_table_entry_size(n, v) ((n)->len + (v)->len + 32) + + +static ngx_int_t ngx_http_v3_evict(ngx_connection_t *c, size_t target); +static void ngx_http_v3_unblock(void *data); +static ngx_int_t ngx_http_v3_new_entry(ngx_connection_t *c); + + +typedef struct { + ngx_queue_t queue; + ngx_connection_t *connection; + ngx_uint_t *nblocked; +} ngx_http_v3_block_t; + + +static ngx_http_v3_field_t ngx_http_v3_static_table[] = { + + { ngx_string(":authority"), ngx_string("") }, + { ngx_string(":path"), ngx_string("/") }, + { ngx_string("age"), ngx_string("0") }, + { ngx_string("content-disposition"), ngx_string("") }, + { ngx_string("content-length"), ngx_string("0") }, + { ngx_string("cookie"), ngx_string("") }, + { ngx_string("date"), ngx_string("") }, + { ngx_string("etag"), ngx_string("") }, + { ngx_string("if-modified-since"), ngx_string("") }, + { ngx_string("if-none-match"), ngx_string("") }, + { ngx_string("last-modified"), ngx_string("") }, + { ngx_string("link"), ngx_string("") }, + { ngx_string("location"), ngx_string("") }, + { ngx_string("referer"), ngx_string("") }, + { ngx_string("set-cookie"), ngx_string("") }, + { ngx_string(":method"), ngx_string("CONNECT") }, + { ngx_string(":method"), ngx_string("DELETE") }, + { ngx_string(":method"), ngx_string("GET") }, + { ngx_string(":method"), ngx_string("HEAD") }, + { ngx_string(":method"), ngx_string("OPTIONS") }, + { ngx_string(":method"), ngx_string("POST") }, + { ngx_string(":method"), ngx_string("PUT") }, + { ngx_string(":scheme"), ngx_string("http") }, + { ngx_string(":scheme"), ngx_string("https") }, + { ngx_string(":status"), ngx_string("103") }, + { ngx_string(":status"), ngx_string("200") }, + { ngx_string(":status"), ngx_string("304") }, + { ngx_string(":status"), ngx_string("404") }, + { ngx_string(":status"), ngx_string("503") }, + { ngx_string("accept"), ngx_string("*/*") }, + { ngx_string("accept"), + ngx_string("application/dns-message") }, + { ngx_string("accept-encoding"), ngx_string("gzip, deflate, br") }, + { ngx_string("accept-ranges"), ngx_string("bytes") }, + { ngx_string("access-control-allow-headers"), + ngx_string("cache-control") }, + { ngx_string("access-control-allow-headers"), + ngx_string("content-type") }, + { ngx_string("access-control-allow-origin"), + ngx_string("*") }, + { ngx_string("cache-control"), ngx_string("max-age=0") }, + { ngx_string("cache-control"), ngx_string("max-age=2592000") }, + { ngx_string("cache-control"), ngx_string("max-age=604800") }, + { ngx_string("cache-control"), ngx_string("no-cache") }, + { ngx_string("cache-control"), ngx_string("no-store") }, + { ngx_string("cache-control"), + ngx_string("public, max-age=31536000") }, + { ngx_string("content-encoding"), ngx_string("br") }, + { ngx_string("content-encoding"), ngx_string("gzip") }, + { ngx_string("content-type"), + ngx_string("application/dns-message") }, + { ngx_string("content-type"), + ngx_string("application/javascript") }, + { ngx_string("content-type"), ngx_string("application/json") }, + { ngx_string("content-type"), + ngx_string("application/x-www-form-urlencoded") }, + { ngx_string("content-type"), ngx_string("image/gif") }, + { ngx_string("content-type"), ngx_string("image/jpeg") }, + { ngx_string("content-type"), ngx_string("image/png") }, + { ngx_string("content-type"), ngx_string("text/css") }, + { ngx_string("content-type"), + ngx_string("text/html;charset=utf-8") }, + { ngx_string("content-type"), ngx_string("text/plain") }, + { ngx_string("content-type"), + ngx_string("text/plain;charset=utf-8") }, + { ngx_string("range"), ngx_string("bytes=0-") }, + { ngx_string("strict-transport-security"), + ngx_string("max-age=31536000") }, + { ngx_string("strict-transport-security"), + ngx_string("max-age=31536000;includesubdomains") }, + { ngx_string("strict-transport-security"), + ngx_string("max-age=31536000;includesubdomains;preload") }, + { ngx_string("vary"), ngx_string("accept-encoding") }, + { ngx_string("vary"), ngx_string("origin") }, + { ngx_string("x-content-type-options"), + ngx_string("nosniff") }, + { ngx_string("x-xss-protection"), ngx_string("1;mode=block") }, + { ngx_string(":status"), ngx_string("100") }, + { ngx_string(":status"), ngx_string("204") }, + { ngx_string(":status"), ngx_string("206") }, + { ngx_string(":status"), ngx_string("302") }, + { ngx_string(":status"), ngx_string("400") }, + { ngx_string(":status"), ngx_string("403") }, + { ngx_string(":status"), ngx_string("421") }, + { ngx_string(":status"), ngx_string("425") }, + { ngx_string(":status"), ngx_string("500") }, + { ngx_string("accept-language"), ngx_string("") }, + { ngx_string("access-control-allow-credentials"), + ngx_string("FALSE") }, + { ngx_string("access-control-allow-credentials"), + ngx_string("TRUE") }, + { ngx_string("access-control-allow-headers"), + ngx_string("*") }, + { ngx_string("access-control-allow-methods"), + ngx_string("get") }, + { ngx_string("access-control-allow-methods"), + ngx_string("get, post, options") }, + { ngx_string("access-control-allow-methods"), + ngx_string("options") }, + { ngx_string("access-control-expose-headers"), + ngx_string("content-length") }, + { ngx_string("access-control-request-headers"), + ngx_string("content-type") }, + { ngx_string("access-control-request-method"), + ngx_string("get") }, + { ngx_string("access-control-request-method"), + ngx_string("post") }, + { ngx_string("alt-svc"), ngx_string("clear") }, + { ngx_string("authorization"), ngx_string("") }, + { ngx_string("content-security-policy"), + ngx_string("script-src 'none';object-src 'none';base-uri 'none'") }, + { ngx_string("early-data"), ngx_string("1") }, + { ngx_string("expect-ct"), ngx_string("") }, + { ngx_string("forwarded"), ngx_string("") }, + { ngx_string("if-range"), ngx_string("") }, + { ngx_string("origin"), ngx_string("") }, + { ngx_string("purpose"), ngx_string("prefetch") }, + { ngx_string("server"), ngx_string("") }, + { ngx_string("timing-allow-origin"), ngx_string("*") }, + { ngx_string("upgrade-insecure-requests"), + ngx_string("1") }, + { ngx_string("user-agent"), ngx_string("") }, + { ngx_string("x-forwarded-for"), ngx_string("") }, + { ngx_string("x-frame-options"), ngx_string("deny") }, + { ngx_string("x-frame-options"), ngx_string("sameorigin") } +}; + + +ngx_int_t +ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic, + ngx_uint_t index, ngx_str_t *value) +{ + ngx_str_t name; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + if (dynamic) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 ref insert dynamic[%ui] \"%V\"", index, value); + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + if (dt->base + dt->nelts <= index) { + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + index = dt->base + dt->nelts - 1 - index; + + if (ngx_http_v3_lookup(c, index, &name, NULL) != NGX_OK) { + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + } else { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 ref insert static[%ui] \"%V\"", index, value); + + if (ngx_http_v3_lookup_static(c, index, &name, NULL) != NGX_OK) { + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + } + + return ngx_http_v3_insert(c, &name, value); +} + + +ngx_int_t +ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name, ngx_str_t *value) +{ + u_char *p; + size_t size; + ngx_http_v3_field_t *field; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + size = ngx_http_v3_table_entry_size(name, value); + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + if (size > dt->capacity) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "not enough dynamic table capacity"); + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 insert [%ui] \"%V\":\"%V\", size:%uz", + dt->base + dt->nelts, name, value, size); + + p = ngx_alloc(sizeof(ngx_http_v3_field_t) + name->len + value->len, + c->log); + if (p == NULL) { + return NGX_ERROR; + } + + field = (ngx_http_v3_field_t *) p; + + field->name.data = p + sizeof(ngx_http_v3_field_t); + field->name.len = name->len; + field->value.data = ngx_cpymem(field->name.data, name->data, name->len); + field->value.len = value->len; + ngx_memcpy(field->value.data, value->data, value->len); + + dt->elts[dt->nelts++] = field; + dt->size += size; + + dt->insert_count++; + + if (ngx_http_v3_evict(c, dt->capacity) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(&dt->send_insert_count, &ngx_posted_events); + + if (ngx_http_v3_new_entry(c) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +void +ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + c = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 inc insert count handler"); + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + if (dt->insert_count > dt->ack_insert_count) { + if (ngx_http_v3_send_inc_insert_count(c, + dt->insert_count - dt->ack_insert_count) + != NGX_OK) + { + return; + } + + dt->ack_insert_count = dt->insert_count; + } +} + + +ngx_int_t +ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity) +{ + ngx_uint_t max, prev_max; + ngx_http_v3_field_t **elts; + ngx_http_v3_session_t *h3c; + ngx_http_v3_srv_conf_t *h3scf; + ngx_http_v3_dynamic_table_t *dt; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 set capacity %ui", capacity); + + h3c = ngx_http_v3_get_session(c); + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + + if (capacity > h3scf->max_table_capacity) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client exceeded http3_max_table_capacity limit"); + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + if (ngx_http_v3_evict(c, capacity) != NGX_OK) { + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + dt = &h3c->table; + max = capacity / 32; + prev_max = dt->capacity / 32; + + if (max > prev_max) { + elts = ngx_alloc(max * sizeof(void *), c->log); + if (elts == NULL) { + return NGX_ERROR; + } + + if (dt->elts) { + ngx_memcpy(elts, dt->elts, dt->nelts * sizeof(void *)); + ngx_free(dt->elts); + } + + dt->elts = elts; + } + + dt->capacity = capacity; + + return NGX_OK; +} + + +void +ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c) +{ + ngx_uint_t n; + ngx_http_v3_dynamic_table_t *dt; + + dt = &h3c->table; + + if (dt->elts == NULL) { + return; + } + + for (n = 0; n < dt->nelts; n++) { + ngx_free(dt->elts[n]); + } + + ngx_free(dt->elts); +} + + +static ngx_int_t +ngx_http_v3_evict(ngx_connection_t *c, size_t target) +{ + size_t size; + ngx_uint_t n; + ngx_http_v3_field_t *field; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + n = 0; + + while (dt->size > target) { + field = dt->elts[n++]; + size = ngx_http_v3_table_entry_size(&field->name, &field->value); + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 evict [%ui] \"%V\":\"%V\" size:%uz", + dt->base, &field->name, &field->value, size); + + ngx_free(field); + dt->size -= size; + } + + if (n) { + dt->nelts -= n; + dt->base += n; + ngx_memmove(dt->elts, &dt->elts[n], dt->nelts * sizeof(void *)); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v3_duplicate(ngx_connection_t *c, ngx_uint_t index) +{ + ngx_str_t name, value; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 duplicate %ui", index); + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + if (dt->base + dt->nelts <= index) { + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + index = dt->base + dt->nelts - 1 - index; + + if (ngx_http_v3_lookup(c, index, &name, &value) != NGX_OK) { + return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR; + } + + return ngx_http_v3_insert(c, &name, &value); +} + + +ngx_int_t +ngx_http_v3_ack_section(ngx_connection_t *c, ngx_uint_t stream_id) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 ack section %ui", stream_id); + + /* we do not use dynamic tables */ + + return NGX_HTTP_V3_ERR_DECODER_STREAM_ERROR; +} + + +ngx_int_t +ngx_http_v3_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 increment insert count %ui", inc); + + /* we do not use dynamic tables */ + + return NGX_HTTP_V3_ERR_DECODER_STREAM_ERROR; +} + + +ngx_int_t +ngx_http_v3_lookup_static(ngx_connection_t *c, ngx_uint_t index, + ngx_str_t *name, ngx_str_t *value) +{ + ngx_uint_t nelts; + ngx_http_v3_field_t *field; + + nelts = sizeof(ngx_http_v3_static_table) + / sizeof(ngx_http_v3_static_table[0]); + + if (index >= nelts) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 static[%ui] lookup out of bounds: %ui", + index, nelts); + return NGX_ERROR; + } + + field = &ngx_http_v3_static_table[index]; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 static[%ui] lookup \"%V\":\"%V\"", + index, &field->name, &field->value); + + if (name) { + *name = field->name; + } + + if (value) { + *value = field->value; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v3_lookup(ngx_connection_t *c, ngx_uint_t index, ngx_str_t *name, + ngx_str_t *value) +{ + ngx_http_v3_field_t *field; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + if (index < dt->base || index - dt->base >= dt->nelts) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 dynamic[%ui] lookup out of bounds: [%ui,%ui]", + index, dt->base, dt->base + dt->nelts); + return NGX_ERROR; + } + + field = dt->elts[index - dt->base]; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 dynamic[%ui] lookup \"%V\":\"%V\"", + index, &field->name, &field->value); + + if (name) { + *name = field->name; + } + + if (value) { + *value = field->value; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v3_decode_insert_count(ngx_connection_t *c, ngx_uint_t *insert_count) +{ + ngx_uint_t max_entries, full_range, max_value, + max_wrapped, req_insert_count; + ngx_http_v3_srv_conf_t *h3scf; + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + /* QPACK 4.5.1.1. Required Insert Count */ + + if (*insert_count == 0) { + return NGX_OK; + } + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + + max_entries = h3scf->max_table_capacity / 32; + full_range = 2 * max_entries; + + if (*insert_count > full_range) { + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + max_value = dt->base + dt->nelts + max_entries; + max_wrapped = (max_value / full_range) * full_range; + req_insert_count = max_wrapped + *insert_count - 1; + + if (req_insert_count > max_value) { + if (req_insert_count <= full_range) { + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + req_insert_count -= full_range; + } + + if (req_insert_count == 0) { + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 decode insert_count %ui -> %ui", + *insert_count, req_insert_count); + + *insert_count = req_insert_count; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v3_check_insert_count(ngx_connection_t *c, ngx_uint_t insert_count) +{ + size_t n; + ngx_pool_cleanup_t *cln; + ngx_http_v3_block_t *block; + ngx_http_v3_session_t *h3c; + ngx_http_v3_srv_conf_t *h3scf; + ngx_http_v3_dynamic_table_t *dt; + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + n = dt->base + dt->nelts; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 check insert count req:%ui, have:%ui", + insert_count, n); + + if (n >= insert_count) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 block stream"); + + block = NULL; + + for (cln = c->pool->cleanup; cln; cln = cln->next) { + if (cln->handler == ngx_http_v3_unblock) { + block = cln->data; + break; + } + } + + if (block == NULL) { + cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_v3_block_t)); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_http_v3_unblock; + + block = cln->data; + block->queue.prev = NULL; + block->connection = c; + block->nblocked = &h3c->nblocked; + } + + if (block->queue.prev == NULL) { + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + + if (h3c->nblocked == h3scf->max_blocked_streams) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client exceeded http3_max_blocked_streams limit"); + + ngx_http_v3_finalize_connection(c, + NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED, + "too many blocked streams"); + return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; + } + + h3c->nblocked++; + ngx_queue_insert_tail(&h3c->blocked, &block->queue); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 blocked:%ui", h3c->nblocked); + + return NGX_BUSY; +} + + +void +ngx_http_v3_ack_insert_count(ngx_connection_t *c, uint64_t insert_count) +{ + ngx_http_v3_session_t *h3c; + ngx_http_v3_dynamic_table_t *dt; + + h3c = ngx_http_v3_get_session(c); + dt = &h3c->table; + + if (dt->ack_insert_count < insert_count) { + dt->ack_insert_count = insert_count; + } +} + + +static void +ngx_http_v3_unblock(void *data) +{ + ngx_http_v3_block_t *block = data; + + if (block->queue.prev) { + ngx_queue_remove(&block->queue); + block->queue.prev = NULL; + (*block->nblocked)--; + } +} + + +static ngx_int_t +ngx_http_v3_new_entry(ngx_connection_t *c) +{ + ngx_queue_t *q; + ngx_connection_t *bc; + ngx_http_v3_block_t *block; + ngx_http_v3_session_t *h3c; + + h3c = ngx_http_v3_get_session(c); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 new dynamic entry, blocked:%ui", h3c->nblocked); + + while (!ngx_queue_empty(&h3c->blocked)) { + q = ngx_queue_head(&h3c->blocked); + block = (ngx_http_v3_block_t *) q; + bc = block->connection; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, bc->log, 0, "http3 unblock stream"); + + ngx_http_v3_unblock(block); + ngx_post_event(bc->read, &ngx_posted_events); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v3_set_param(ngx_connection_t *c, uint64_t id, uint64_t value) +{ + switch (id) { + + case NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 param QPACK_MAX_TABLE_CAPACITY:%uL", value); + break; + + case NGX_HTTP_V3_PARAM_MAX_FIELD_SECTION_SIZE: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 param SETTINGS_MAX_FIELD_SECTION_SIZE:%uL", + value); + break; + + case NGX_HTTP_V3_PARAM_BLOCKED_STREAMS: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 param QPACK_BLOCKED_STREAMS:%uL", value); + break; + + default: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 param #%uL:%uL", id, value); + } + + return NGX_OK; +} diff --git a/src/http/v3/ngx_http_v3_table.h b/src/http/v3/ngx_http_v3_table.h new file mode 100644 index 0000000..1c2fb17 --- /dev/null +++ b/src/http/v3/ngx_http_v3_table.h @@ -0,0 +1,58 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_HTTP_V3_TABLE_H_INCLUDED_ +#define _NGX_HTTP_V3_TABLE_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + ngx_str_t name; + ngx_str_t value; +} ngx_http_v3_field_t; + + +typedef struct { + ngx_http_v3_field_t **elts; + ngx_uint_t nelts; + ngx_uint_t base; + size_t size; + size_t capacity; + uint64_t insert_count; + uint64_t ack_insert_count; + ngx_event_t send_insert_count; +} ngx_http_v3_dynamic_table_t; + + +void ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev); +void ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c); +ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic, + ngx_uint_t index, ngx_str_t *value); +ngx_int_t ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name, + ngx_str_t *value); +ngx_int_t ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity); +ngx_int_t ngx_http_v3_duplicate(ngx_connection_t *c, ngx_uint_t index); +ngx_int_t ngx_http_v3_ack_section(ngx_connection_t *c, ngx_uint_t stream_id); +ngx_int_t ngx_http_v3_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc); +ngx_int_t ngx_http_v3_lookup_static(ngx_connection_t *c, ngx_uint_t index, + ngx_str_t *name, ngx_str_t *value); +ngx_int_t ngx_http_v3_lookup(ngx_connection_t *c, ngx_uint_t index, + ngx_str_t *name, ngx_str_t *value); +ngx_int_t ngx_http_v3_decode_insert_count(ngx_connection_t *c, + ngx_uint_t *insert_count); +ngx_int_t ngx_http_v3_check_insert_count(ngx_connection_t *c, + ngx_uint_t insert_count); +void ngx_http_v3_ack_insert_count(ngx_connection_t *c, uint64_t insert_count); +ngx_int_t ngx_http_v3_set_param(ngx_connection_t *c, uint64_t id, + uint64_t value); + + +#endif /* _NGX_HTTP_V3_TABLE_H_INCLUDED_ */ diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c new file mode 100644 index 0000000..2fc5b07 --- /dev/null +++ b/src/http/v3/ngx_http_v3_uni.c @@ -0,0 +1,624 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_http_v3_parse_uni_t parse; + ngx_int_t index; +} ngx_http_v3_uni_stream_t; + + +static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); +static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); +static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); +static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); +static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, + ngx_uint_t type); + + +void +ngx_http_v3_init_uni_stream(ngx_connection_t *c) +{ + uint64_t n; + ngx_http_v3_session_t *h3c; + ngx_http_v3_uni_stream_t *us; + + h3c = ngx_http_v3_get_session(c); + if (h3c->hq) { + ngx_http_v3_finalize_connection(c, + NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR, + "uni stream in hq mode"); + c->data = NULL; + ngx_http_v3_close_uni_stream(c); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init uni stream"); + + n = c->quic->id >> 2; + + if (n >= NGX_HTTP_V3_MAX_UNI_STREAMS) { + ngx_http_v3_finalize_connection(c, + NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR, + "reached maximum number of uni streams"); + c->data = NULL; + ngx_http_v3_close_uni_stream(c); + return; + } + + ngx_quic_cancelable_stream(c); + + us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t)); + if (us == NULL) { + ngx_http_v3_finalize_connection(c, + NGX_HTTP_V3_ERR_INTERNAL_ERROR, + "memory allocation error"); + c->data = NULL; + ngx_http_v3_close_uni_stream(c); + return; + } + + us->index = -1; + + c->data = us; + + c->read->handler = ngx_http_v3_uni_read_handler; + c->write->handler = ngx_http_v3_uni_dummy_write_handler; + + ngx_http_v3_uni_read_handler(c->read); +} + + +static void +ngx_http_v3_close_uni_stream(ngx_connection_t *c) +{ + ngx_pool_t *pool; + ngx_http_v3_session_t *h3c; + ngx_http_v3_uni_stream_t *us; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 close stream"); + + us = c->data; + + if (us && us->index >= 0) { + h3c = ngx_http_v3_get_session(c); + h3c->known_streams[us->index] = NULL; + } + + c->destroyed = 1; + + pool = c->pool; + + ngx_close_connection(c); + + ngx_destroy_pool(pool); +} + + +ngx_int_t +ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type) +{ + ngx_int_t index; + ngx_http_v3_session_t *h3c; + ngx_http_v3_uni_stream_t *us; + + h3c = ngx_http_v3_get_session(c); + + switch (type) { + + case NGX_HTTP_V3_STREAM_ENCODER: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 encoder stream"); + index = NGX_HTTP_V3_STREAM_CLIENT_ENCODER; + break; + + case NGX_HTTP_V3_STREAM_DECODER: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 decoder stream"); + index = NGX_HTTP_V3_STREAM_CLIENT_DECODER; + break; + + case NGX_HTTP_V3_STREAM_CONTROL: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 control stream"); + index = NGX_HTTP_V3_STREAM_CLIENT_CONTROL; + + break; + + default: + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 stream 0x%02xL", type); + + if (h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_ENCODER] == NULL + || h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_DECODER] == NULL + || h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_CONTROL] == NULL) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "missing mandatory stream"); + return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR; + } + + index = -1; + } + + if (index >= 0) { + if (h3c->known_streams[index]) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream exists"); + return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR; + } + + h3c->known_streams[index] = c; + + us = c->data; + us->index = index; + } + + return NGX_OK; +} + + +static void +ngx_http_v3_uni_read_handler(ngx_event_t *rev) +{ + u_char buf[128]; + ssize_t n; + ngx_buf_t b; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_v3_session_t *h3c; + ngx_http_v3_uni_stream_t *us; + + c = rev->data; + us = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read handler"); + + if (c->close) { + ngx_http_v3_close_uni_stream(c); + return; + } + + ngx_memzero(&b, sizeof(ngx_buf_t)); + + while (rev->ready) { + + n = c->recv(c, buf, sizeof(buf)); + + if (n == NGX_ERROR) { + rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR; + goto failed; + } + + if (n == 0) { + if (us->index >= 0) { + rc = NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM; + goto failed; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read eof"); + ngx_http_v3_close_uni_stream(c); + return; + } + + if (n == NGX_AGAIN) { + break; + } + + b.pos = buf; + b.last = buf + n; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (ngx_http_v3_check_flood(c) != NGX_OK) { + ngx_http_v3_close_uni_stream(c); + return; + } + + rc = ngx_http_v3_parse_uni(c, &us->parse, &b); + + if (rc == NGX_DONE) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 read done"); + ngx_http_v3_close_uni_stream(c); + return; + } + + if (rc > 0) { + goto failed; + } + + if (rc != NGX_AGAIN) { + rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR; + goto failed; + } + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR; + goto failed; + } + + return; + +failed: + + ngx_http_v3_finalize_connection(c, rc, "stream error"); + ngx_http_v3_close_uni_stream(c); +} + + +static void +ngx_http_v3_uni_dummy_read_handler(ngx_event_t *rev) +{ + u_char ch; + ngx_connection_t *c; + + c = rev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy read handler"); + + if (c->close) { + ngx_http_v3_close_uni_stream(c); + return; + } + + if (rev->ready) { + if (c->recv(c, &ch, 1) != 0) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, NULL); + ngx_http_v3_close_uni_stream(c); + return; + } + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, + NULL); + ngx_http_v3_close_uni_stream(c); + } +} + + +static void +ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev) +{ + ngx_connection_t *c; + + c = wev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy write handler"); + + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, + NULL); + ngx_http_v3_close_uni_stream(c); + } +} + + +static ngx_connection_t * +ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type) +{ + u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; + size_t n; + ngx_int_t index; + ngx_connection_t *sc; + ngx_http_v3_session_t *h3c; + ngx_http_v3_uni_stream_t *us; + + switch (type) { + case NGX_HTTP_V3_STREAM_ENCODER: + index = NGX_HTTP_V3_STREAM_SERVER_ENCODER; + break; + case NGX_HTTP_V3_STREAM_DECODER: + index = NGX_HTTP_V3_STREAM_SERVER_DECODER; + break; + case NGX_HTTP_V3_STREAM_CONTROL: + index = NGX_HTTP_V3_STREAM_SERVER_CONTROL; + break; + default: + index = -1; + } + + h3c = ngx_http_v3_get_session(c); + + if (index >= 0) { + if (h3c->known_streams[index]) { + return h3c->known_streams[index]; + } + } + + sc = ngx_quic_open_stream(c, 0); + if (sc == NULL) { + goto failed; + } + + ngx_quic_cancelable_stream(sc); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 create uni stream, type:%ui", type); + + us = ngx_pcalloc(sc->pool, sizeof(ngx_http_v3_uni_stream_t)); + if (us == NULL) { + goto failed; + } + + us->index = index; + + sc->data = us; + + sc->read->handler = ngx_http_v3_uni_dummy_read_handler; + sc->write->handler = ngx_http_v3_uni_dummy_write_handler; + + if (index >= 0) { + h3c->known_streams[index] = sc; + } + + n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (sc->send(sc, buf, n) != (ssize_t) n) { + goto failed; + } + + ngx_post_event(sc->read, &ngx_posted_events); + + return sc; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to create server stream"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR, + "failed to create server stream"); + if (sc) { + ngx_http_v3_close_uni_stream(sc); + } + + return NULL; +} + + +ngx_int_t +ngx_http_v3_send_settings(ngx_connection_t *c) +{ + u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6]; + size_t n; + ngx_connection_t *cc; + ngx_http_v3_session_t *h3c; + ngx_http_v3_srv_conf_t *h3scf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings"); + + cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); + if (cc == NULL) { + return NGX_ERROR; + } + + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + + n = ngx_http_v3_encode_varlen_int(NULL, + NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY); + n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_table_capacity); + n += ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_PARAM_BLOCKED_STREAMS); + n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_blocked_streams); + + p = (u_char *) ngx_http_v3_encode_varlen_int(buf, + NGX_HTTP_V3_FRAME_SETTINGS); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, n); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, + NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_table_capacity); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, + NGX_HTTP_V3_PARAM_BLOCKED_STREAMS); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams); + n = p - buf; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (cc->send(cc, buf, n) != (ssize_t) n) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send settings"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD, + "failed to send settings"); + ngx_http_v3_close_uni_stream(cc); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id) +{ + u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3]; + size_t n; + ngx_connection_t *cc; + ngx_http_v3_session_t *h3c; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send goaway %uL", id); + + cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); + if (cc == NULL) { + return NGX_ERROR; + } + + n = ngx_http_v3_encode_varlen_int(NULL, id); + p = (u_char *) ngx_http_v3_encode_varlen_int(buf, NGX_HTTP_V3_FRAME_GOAWAY); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, n); + p = (u_char *) ngx_http_v3_encode_varlen_int(p, id); + n = p - buf; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (cc->send(cc, buf, n) != (ssize_t) n) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send goaway"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD, + "failed to send goaway"); + ngx_http_v3_close_uni_stream(cc); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_v3_send_ack_section(ngx_connection_t *c, ngx_uint_t stream_id) +{ + u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; + size_t n; + ngx_connection_t *dc; + ngx_http_v3_session_t *h3c; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 send section acknowledgement %ui", stream_id); + + dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); + if (dc == NULL) { + return NGX_ERROR; + } + + buf[0] = 0x80; + n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (dc->send(dc, buf, n) != (ssize_t) n) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "failed to send section acknowledgement"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD, + "failed to send section acknowledgement"); + ngx_http_v3_close_uni_stream(dc); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_v3_send_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id) +{ + u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; + size_t n; + ngx_connection_t *dc; + ngx_http_v3_session_t *h3c; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 send stream cancellation %ui", stream_id); + + dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); + if (dc == NULL) { + return NGX_ERROR; + } + + buf[0] = 0x40; + n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (dc->send(dc, buf, n) != (ssize_t) n) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send stream cancellation"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD, + "failed to send stream cancellation"); + ngx_http_v3_close_uni_stream(dc); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc) +{ + u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; + size_t n; + ngx_connection_t *dc; + ngx_http_v3_session_t *h3c; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 send insert count increment %ui", inc); + + dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); + if (dc == NULL) { + return NGX_ERROR; + } + + buf[0] = 0; + n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf; + + h3c = ngx_http_v3_get_session(c); + h3c->total_bytes += n; + + if (dc->send(dc, buf, n) != (ssize_t) n) { + goto failed; + } + + return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "failed to send insert count increment"); + + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD, + "failed to send insert count increment"); + ngx_http_v3_close_uni_stream(dc); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 cancel stream %ui", stream_id); + + /* we do not use dynamic tables */ + + return NGX_OK; +} diff --git a/src/http/v3/ngx_http_v3_uni.h b/src/http/v3/ngx_http_v3_uni.h new file mode 100644 index 0000000..911e153 --- /dev/null +++ b/src/http/v3/ngx_http_v3_uni.h @@ -0,0 +1,32 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_HTTP_V3_UNI_H_INCLUDED_ +#define _NGX_HTTP_V3_UNI_H_INCLUDED_ + + +#include +#include +#include + + +void ngx_http_v3_init_uni_stream(ngx_connection_t *c); +ngx_int_t ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type); + +ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id); + +ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); +ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id); +ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c, + ngx_uint_t stream_id); +ngx_int_t ngx_http_v3_send_cancel_stream(ngx_connection_t *c, + ngx_uint_t stream_id); +ngx_int_t ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, + ngx_uint_t inc); + + +#endif /* _NGX_HTTP_V3_UNI_H_INCLUDED_ */ diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 487c5de..228a8d0 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -441,7 +441,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "bind ipv6only is not supported " + "ipv6only is not supported " "on this platform"); return NGX_CONF_ERROR; #endif @@ -564,7 +564,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the invalid \"%V\" parameter", &value[i]); + "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 246ba97..1167df3 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -283,11 +283,11 @@ ngx_mail_init_session_handler(ngx_event_t *rev) s = c->data; - sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); - - if (sslcf->enable || s->ssl) { + if (s->ssl) { c->log->action = "SSL handshaking"; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); + ngx_mail_ssl_init_connection(&sslcf->ssl, c); return; } diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 28737ac..aebb4cc 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -23,8 +23,6 @@ static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, @@ -65,24 +63,12 @@ static ngx_conf_enum_t ngx_mail_ssl_verify[] = { }; -static ngx_conf_deprecated_t ngx_mail_ssl_deprecated = { - ngx_conf_deprecated, "ssl", "listen ... ssl" -}; - - static ngx_conf_post_t ngx_mail_ssl_conf_command_post = { ngx_mail_ssl_conf_command_check }; static ngx_command_t ngx_mail_ssl_commands[] = { - { ngx_string("ssl"), - NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, - ngx_mail_ssl_enable, - NGX_MAIL_SRV_CONF_OFFSET, - offsetof(ngx_mail_ssl_conf_t, enable), - &ngx_mail_ssl_deprecated }, - { ngx_string("starttls"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_mail_ssl_starttls, @@ -322,7 +308,6 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) * scf->shm_zone = NULL; */ - scf->enable = NGX_CONF_UNSET; scf->starttls = NGX_CONF_UNSET_UINT; scf->certificates = NGX_CONF_UNSET_PTR; scf->certificate_keys = NGX_CONF_UNSET_PTR; @@ -349,7 +334,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) char *mode; ngx_pool_cleanup_t *cln; - ngx_conf_merge_value(conf->enable, prev->enable, 0); ngx_conf_merge_uint_value(conf->starttls, prev->starttls, NGX_MAIL_STARTTLS_OFF); @@ -394,9 +378,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) if (conf->listen) { mode = "listen ... ssl"; - } else if (conf->enable) { - mode = "ssl"; - } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { mode = "starttls"; @@ -545,34 +526,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } -static char * -ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_mail_ssl_conf_t *scf = conf; - - char *rv; - - rv = ngx_conf_set_flag_slot(cf, cmd, conf); - - if (rv != NGX_CONF_OK) { - return rv; - } - - if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"starttls\" directive conflicts with \"ssl on\""); - return NGX_CONF_ERROR; - } - - if (!scf->listen) { - scf->file = cf->conf_file->file.name.data; - scf->line = cf->conf_file->line; - } - - return NGX_CONF_OK; -} - - static char * ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -586,12 +539,6 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return rv; } - if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"ssl\" directive conflicts with \"starttls\""); - return NGX_CONF_ERROR; - } - if (!scf->listen) { scf->file = cf->conf_file->file.name.data; scf->line = cf->conf_file->line; diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index a0a6113..c0eb6a3 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -20,7 +20,6 @@ typedef struct { - ngx_flag_t enable; ngx_flag_t prefer_server_ciphers; ngx_ssl_t ssl; diff --git a/src/os/unix/ngx_darwin_init.c b/src/os/unix/ngx_darwin_init.c index aabe02f..70748ee 100644 --- a/src/os/unix/ngx_darwin_init.c +++ b/src/os/unix/ngx_darwin_init.c @@ -9,11 +9,12 @@ #include -char ngx_darwin_kern_ostype[16]; -char ngx_darwin_kern_osrelease[128]; -int ngx_darwin_hw_ncpu; -int ngx_darwin_kern_ipc_somaxconn; -u_long ngx_darwin_net_inet_tcp_sendspace; +char ngx_darwin_kern_ostype[16]; +char ngx_darwin_kern_osrelease[128]; +int ngx_darwin_hw_ncpu; +int ngx_darwin_kern_ipc_somaxconn; +u_long ngx_darwin_net_inet_tcp_sendspace; +int64_t ngx_darwin_hw_cachelinesize; ngx_uint_t ngx_debug_malloc; @@ -56,6 +57,10 @@ sysctl_t sysctls[] = { &ngx_darwin_kern_ipc_somaxconn, sizeof(ngx_darwin_kern_ipc_somaxconn), 0 }, + { "hw.cachelinesize", + &ngx_darwin_hw_cachelinesize, + sizeof(ngx_darwin_hw_cachelinesize), 0 }, + { NULL, NULL, 0, 0 } }; @@ -155,6 +160,7 @@ ngx_os_specific_init(ngx_log_t *log) return NGX_ERROR; } + ngx_cacheline_size = ngx_darwin_hw_cachelinesize; ngx_ncpu = ngx_darwin_hw_ncpu; if (ngx_darwin_kern_ipc_somaxconn > 32767) { diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h index 7d6ca76..07fa8ce 100644 --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -54,6 +54,7 @@ typedef int ngx_err_t; #define NGX_ENOMOREFILES 0 #define NGX_ELOOP ELOOP #define NGX_EBADF EBADF +#define NGX_EMSGSIZE EMSGSIZE #if (NGX_HAVE_OPENAT) #define NGX_EMLINK EMLINK diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 1c82a8e..2fec1ec 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -110,6 +110,8 @@ ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, return NGX_ERROR; } + task->event.log = file->log; + file->thread_task = task; } @@ -493,6 +495,8 @@ ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, return NGX_ERROR; } + task->event.log = file->log; + file->thread_task = task; } diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 101d91a..603f917 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -332,6 +332,7 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) return NGX_ERROR; } + task->event.log = c->log; task->handler = ngx_linux_sendfile_thread_handler; c->sendfile_task = task; diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c index 7824735..6ac931c 100644 --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -51,7 +51,10 @@ ngx_os_init(ngx_log_t *log) } ngx_pagesize = getpagesize(); - ngx_cacheline_size = NGX_CPU_CACHE_LINE; + + if (ngx_cacheline_size == 0) { + ngx_cacheline_size = NGX_CPU_CACHE_LINE; + } for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ } diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 98d2dd2..5bc5ce9 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -948,7 +948,7 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) } } - if (ngx_exiting) { + if (ngx_exiting && !ngx_terminate) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 @@ -963,11 +963,11 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) ngx_debug_quit = 1; } } + } - if (ngx_debug_quit) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting"); - ngx_debug_point(); - } + if (ngx_debug_quit) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting"); + ngx_debug_point(); } /* diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h index ec66a6f..4480adc 100644 --- a/src/os/unix/ngx_socket.h +++ b/src/os/unix/ngx_socket.h @@ -13,6 +13,8 @@ #define NGX_WRITE_SHUTDOWN SHUT_WR +#define NGX_READ_SHUTDOWN SHUT_RD +#define NGX_RDWR_SHUTDOWN SHUT_RDWR typedef int ngx_socket_t; diff --git a/src/os/win32/ngx_errno.h b/src/os/win32/ngx_errno.h index 255a39d..1e73a83 100644 --- a/src/os/win32/ngx_errno.h +++ b/src/os/win32/ngx_errno.h @@ -57,6 +57,7 @@ typedef DWORD ngx_err_t; #define NGX_EILSEQ ERROR_NO_UNICODE_TRANSLATION #define NGX_ELOOP 0 #define NGX_EBADF WSAEBADF +#define NGX_EMSGSIZE WSAEMSGSIZE #define NGX_EALREADY WSAEALREADY #define NGX_EINVAL WSAEINVAL diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index 6e59a6f..78ba13a 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -154,7 +154,8 @@ ngx_int_t ngx_file_info(u_char *filename, ngx_file_info_t *fi); (((off_t) (fi)->nFileSizeHigh << 32) | (fi)->nFileSizeLow) #define ngx_file_fs_size(fi) ngx_file_size(fi) -#define ngx_file_uniq(fi) (*(ngx_file_uniq_t *) &(fi)->nFileIndexHigh) +#define ngx_file_uniq(fi) \ + (((ngx_file_uniq_t) (fi)->nFileIndexHigh << 32) | (fi)->nFileIndexLow) /* 116444736000000000 is commented in src/os/win32/ngx_time.c */ diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c index 0c848ef..a39335f 100644 --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -834,7 +834,7 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) } } - if (ngx_exiting) { + if (ngx_exiting && !ngx_terminate) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != (ngx_socket_t) -1 diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h index ab56bc8..5b61389 100644 --- a/src/os/win32/ngx_socket.h +++ b/src/os/win32/ngx_socket.h @@ -14,6 +14,8 @@ #define NGX_WRITE_SHUTDOWN SD_SEND +#define NGX_READ_SHUTDOWN SD_RECEIVE +#define NGX_RDWR_SHUTDOWN SD_BOTH typedef SOCKET ngx_socket_t; diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h index 406003a..7045613 100644 --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -280,7 +280,11 @@ typedef int sig_atomic_t; #define NGX_HAVE_GETADDRINFO 1 -#define ngx_random rand +#define ngx_random() \ + ((long) (0x7fffffff & ( ((uint32_t) rand() << 16) \ + ^ ((uint32_t) rand() << 8) \ + ^ ((uint32_t) rand()) ))) + #define ngx_debug_init() diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 3304c84..b6eeb23 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -16,16 +16,34 @@ static ngx_int_t ngx_stream_init_phases(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf); static ngx_int_t ngx_stream_init_phase_handlers(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf); -static ngx_int_t ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, - ngx_stream_listen_t *listen); -static char *ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports); + +static ngx_int_t ngx_stream_add_addresses(ngx_conf_t *cf, + ngx_stream_core_srv_conf_t *cscf, ngx_stream_conf_port_t *port, + ngx_stream_listen_opt_t *lsopt); +static ngx_int_t ngx_stream_add_address(ngx_conf_t *cf, + ngx_stream_core_srv_conf_t *cscf, ngx_stream_conf_port_t *port, + ngx_stream_listen_opt_t *lsopt); +static ngx_int_t ngx_stream_add_server(ngx_conf_t *cf, + ngx_stream_core_srv_conf_t *cscf, ngx_stream_conf_addr_t *addr); + +static ngx_int_t ngx_stream_optimize_servers(ngx_conf_t *cf, + ngx_stream_core_main_conf_t *cmcf, ngx_array_t *ports); +static ngx_int_t ngx_stream_server_names(ngx_conf_t *cf, + ngx_stream_core_main_conf_t *cmcf, ngx_stream_conf_addr_t *addr); +static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two); +static int ngx_libc_cdecl ngx_stream_cmp_dns_wildcards(const void *one, + const void *two); + +static ngx_int_t ngx_stream_init_listening(ngx_conf_t *cf, + ngx_stream_conf_port_t *port); +static ngx_listening_t *ngx_stream_add_listening(ngx_conf_t *cf, + ngx_stream_conf_addr_t *addr); static ngx_int_t ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, ngx_stream_conf_addr_t *addr); #if (NGX_HAVE_INET6) static ngx_int_t ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, ngx_stream_conf_addr_t *addr); #endif -static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two); ngx_uint_t ngx_stream_max_module; @@ -74,10 +92,8 @@ static char * ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_uint_t i, m, mi, s; + ngx_uint_t mi, m, s; ngx_conf_t pcf; - ngx_array_t ports; - ngx_stream_listen_t *listen; ngx_stream_module_t *module; ngx_stream_conf_ctx_t *ctx; ngx_stream_core_srv_conf_t **cscfp; @@ -251,21 +267,13 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_stream_conf_port_t)) - != NGX_OK) - { + /* optimize the lists of ports, addresses and server names */ + + if (ngx_stream_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) { return NGX_CONF_ERROR; } - listen = cmcf->listen.elts; - - for (i = 0; i < cmcf->listen.nelts; i++) { - if (ngx_stream_add_ports(cf, &ports, &listen[i]) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - - return ngx_stream_optimize_servers(cf, &ports); + return NGX_CONF_OK; } @@ -377,73 +385,295 @@ ngx_stream_init_phase_handlers(ngx_conf_t *cf, } -static ngx_int_t -ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, - ngx_stream_listen_t *listen) +ngx_int_t +ngx_stream_add_listen(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf, + ngx_stream_listen_opt_t *lsopt) { - in_port_t p; - ngx_uint_t i; - struct sockaddr *sa; - ngx_stream_conf_port_t *port; - ngx_stream_conf_addr_t *addr; + in_port_t p; + ngx_uint_t i; + struct sockaddr *sa; + ngx_stream_conf_port_t *port; + ngx_stream_core_main_conf_t *cmcf; - sa = listen->sockaddr; + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + if (cmcf->ports == NULL) { + cmcf->ports = ngx_array_create(cf->temp_pool, 2, + sizeof(ngx_stream_conf_port_t)); + if (cmcf->ports == NULL) { + return NGX_ERROR; + } + } + + sa = lsopt->sockaddr; p = ngx_inet_get_port(sa); - port = ports->elts; - for (i = 0; i < ports->nelts; i++) { + port = cmcf->ports->elts; + for (i = 0; i < cmcf->ports->nelts; i++) { - if (p == port[i].port - && listen->type == port[i].type - && sa->sa_family == port[i].family) + if (p != port[i].port + || lsopt->type != port[i].type + || sa->sa_family != port[i].family) { - /* a port is already in the port list */ - - port = &port[i]; - goto found; + continue; } + + /* a port is already in the port list */ + + return ngx_stream_add_addresses(cf, cscf, &port[i], lsopt); } /* add a port to the port list */ - port = ngx_array_push(ports); + port = ngx_array_push(cmcf->ports); if (port == NULL) { return NGX_ERROR; } port->family = sa->sa_family; - port->type = listen->type; + port->type = lsopt->type; port->port = p; + port->addrs.elts = NULL; - if (ngx_array_init(&port->addrs, cf->temp_pool, 2, - sizeof(ngx_stream_conf_addr_t)) - != NGX_OK) - { - return NGX_ERROR; + return ngx_stream_add_address(cf, cscf, port, lsopt); +} + + +static ngx_int_t +ngx_stream_add_addresses(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf, + ngx_stream_conf_port_t *port, ngx_stream_listen_opt_t *lsopt) +{ + ngx_uint_t i, default_server, proxy_protocol, + protocols, protocols_prev; + ngx_stream_conf_addr_t *addr; +#if (NGX_STREAM_SSL) + ngx_uint_t ssl; +#endif + + /* + * we cannot compare whole sockaddr struct's as kernel + * may fill some fields in inherited sockaddr struct's + */ + + addr = port->addrs.elts; + + for (i = 0; i < port->addrs.nelts; i++) { + + if (ngx_cmp_sockaddr(lsopt->sockaddr, lsopt->socklen, + addr[i].opt.sockaddr, + addr[i].opt.socklen, 0) + != NGX_OK) + { + continue; + } + + /* the address is already in the address list */ + + if (ngx_stream_add_server(cf, cscf, &addr[i]) != NGX_OK) { + return NGX_ERROR; + } + + /* preserve default_server bit during listen options overwriting */ + default_server = addr[i].opt.default_server; + + proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol; + protocols = lsopt->proxy_protocol; + protocols_prev = addr[i].opt.proxy_protocol; + +#if (NGX_STREAM_SSL) + ssl = lsopt->ssl || addr[i].opt.ssl; + protocols |= lsopt->ssl << 1; + protocols_prev |= addr[i].opt.ssl << 1; +#endif + + if (lsopt->set) { + + if (addr[i].opt.set) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate listen options for %V", + &addr[i].opt.addr_text); + return NGX_ERROR; + } + + addr[i].opt = *lsopt; + } + + /* check the duplicate "default" server for this address:port */ + + if (lsopt->default_server) { + + if (default_server) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "a duplicate default server for %V", + &addr[i].opt.addr_text); + return NGX_ERROR; + } + + default_server = 1; + addr[i].default_server = cscf; + } + + /* check for conflicting protocol options */ + + if ((protocols | protocols_prev) != protocols_prev) { + + /* options added */ + + if ((addr[i].opt.set && !lsopt->set) + || addr[i].protocols_changed + || (protocols | protocols_prev) != protocols) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols_prev; + addr[i].protocols_set = 1; + addr[i].protocols_changed = 1; + + } else if ((protocols_prev | protocols) != protocols) { + + /* options removed */ + + if (lsopt->set + || (addr[i].protocols_set && protocols != addr[i].protocols)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols; + addr[i].protocols_set = 1; + addr[i].protocols_changed = 1; + + } else { + + /* the same options */ + + if ((lsopt->set && addr[i].protocols_changed) + || (addr[i].protocols_set && protocols != addr[i].protocols)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols; + addr[i].protocols_set = 1; + } + + addr[i].opt.default_server = default_server; + addr[i].opt.proxy_protocol = proxy_protocol; +#if (NGX_STREAM_SSL) + addr[i].opt.ssl = ssl; +#endif + + return NGX_OK; } -found: + /* add the address to the addresses list that bound to this port */ + + return ngx_stream_add_address(cf, cscf, port, lsopt); +} + + +/* + * add the server address, the server names and the server core module + * configurations to the port list + */ + +static ngx_int_t +ngx_stream_add_address(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf, + ngx_stream_conf_port_t *port, ngx_stream_listen_opt_t *lsopt) +{ + ngx_stream_conf_addr_t *addr; + + if (port->addrs.elts == NULL) { + if (ngx_array_init(&port->addrs, cf->temp_pool, 4, + sizeof(ngx_stream_conf_addr_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } addr = ngx_array_push(&port->addrs); if (addr == NULL) { return NGX_ERROR; } - addr->opt = *listen; + addr->opt = *lsopt; + addr->protocols = 0; + addr->protocols_set = 0; + addr->protocols_changed = 0; + addr->hash.buckets = NULL; + addr->hash.size = 0; + addr->wc_head = NULL; + addr->wc_tail = NULL; +#if (NGX_PCRE) + addr->nregex = 0; + addr->regex = NULL; +#endif + addr->default_server = cscf; + addr->servers.elts = NULL; + + return ngx_stream_add_server(cf, cscf, addr); +} + + +/* add the server core module configuration to the address:port */ + +static ngx_int_t +ngx_stream_add_server(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf, + ngx_stream_conf_addr_t *addr) +{ + ngx_uint_t i; + ngx_stream_core_srv_conf_t **server; + + if (addr->servers.elts == NULL) { + if (ngx_array_init(&addr->servers, cf->temp_pool, 4, + sizeof(ngx_stream_core_srv_conf_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + server = addr->servers.elts; + for (i = 0; i < addr->servers.nelts; i++) { + if (server[i] == cscf) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "a duplicate listen %V", + &addr->opt.addr_text); + return NGX_ERROR; + } + } + } + + server = ngx_array_push(&addr->servers); + if (server == NULL) { + return NGX_ERROR; + } + + *server = cscf; return NGX_OK; } -static char * -ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) +static ngx_int_t +ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf, + ngx_array_t *ports) { - ngx_uint_t i, p, last, bind_wildcard; - ngx_listening_t *ls; - ngx_stream_port_t *stport; - ngx_stream_conf_port_t *port; - ngx_stream_conf_addr_t *addr; - ngx_stream_core_srv_conf_t *cscf; + ngx_uint_t p, a; + ngx_stream_conf_port_t *port; + ngx_stream_conf_addr_t *addr; + + if (ports == NULL) { + return NGX_OK; + } port = ports->elts; for (p = 0; p < ports->nelts; p++) { @@ -451,176 +681,192 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, sizeof(ngx_stream_conf_addr_t), ngx_stream_cmp_conf_addrs); - addr = port[p].addrs.elts; - last = port[p].addrs.nelts; - /* - * if there is the binding to the "*:port" then we need to bind() - * to the "*:port" only and ignore the other bindings + * check whether all name-based servers have the same + * configuration as a default server for given address:port */ - if (addr[last - 1].opt.wildcard) { - addr[last - 1].opt.bind = 1; - bind_wildcard = 1; + addr = port[p].addrs.elts; + for (a = 0; a < port[p].addrs.nelts; a++) { - } else { - bind_wildcard = 0; + if (addr[a].servers.nelts > 1 +#if (NGX_PCRE) + || addr[a].default_server->captures +#endif + ) + { + if (ngx_stream_server_names(cf, cmcf, &addr[a]) != NGX_OK) { + return NGX_ERROR; + } + } } - i = 0; + if (ngx_stream_init_listening(cf, &port[p]) != NGX_OK) { + return NGX_ERROR; + } + } - while (i < last) { + return NGX_OK; +} - if (bind_wildcard && !addr[i].opt.bind) { - i++; + +static ngx_int_t +ngx_stream_server_names(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf, + ngx_stream_conf_addr_t *addr) +{ + ngx_int_t rc; + ngx_uint_t n, s; + ngx_hash_init_t hash; + ngx_hash_keys_arrays_t ha; + ngx_stream_server_name_t *name; + ngx_stream_core_srv_conf_t **cscfp; +#if (NGX_PCRE) + ngx_uint_t regex, i; + + regex = 0; +#endif + + ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); + + ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (ha.temp_pool == NULL) { + return NGX_ERROR; + } + + ha.pool = cf->pool; + + if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { + goto failed; + } + + cscfp = addr->servers.elts; + + for (s = 0; s < addr->servers.nelts; s++) { + + name = cscfp[s]->server_names.elts; + + for (n = 0; n < cscfp[s]->server_names.nelts; n++) { + +#if (NGX_PCRE) + if (name[n].regex) { + regex++; continue; } +#endif - ls = ngx_create_listening(cf, addr[i].opt.sockaddr, - addr[i].opt.socklen); - if (ls == NULL) { - return NGX_CONF_ERROR; + rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server, + NGX_HASH_WILDCARD_KEY); + + if (rc == NGX_ERROR) { + goto failed; } - ls->addr_ntop = 1; - ls->handler = ngx_stream_init_connection; - ls->pool_size = 256; - ls->type = addr[i].opt.type; - - cscf = addr->opt.ctx->srv_conf[ngx_stream_core_module.ctx_index]; - - ls->logp = cscf->error_log; - ls->log.data = &ls->addr_text; - ls->log.handler = ngx_accept_log_error; - - ls->backlog = addr[i].opt.backlog; - ls->rcvbuf = addr[i].opt.rcvbuf; - ls->sndbuf = addr[i].opt.sndbuf; - - ls->wildcard = addr[i].opt.wildcard; - - ls->keepalive = addr[i].opt.so_keepalive; -#if (NGX_HAVE_KEEPALIVE_TUNABLE) - ls->keepidle = addr[i].opt.tcp_keepidle; - ls->keepintvl = addr[i].opt.tcp_keepintvl; - ls->keepcnt = addr[i].opt.tcp_keepcnt; -#endif - -#if (NGX_HAVE_INET6) - ls->ipv6only = addr[i].opt.ipv6only; -#endif - -#if (NGX_HAVE_TCP_FASTOPEN) - ls->fastopen = addr[i].opt.fastopen; -#endif - -#if (NGX_HAVE_REUSEPORT) - ls->reuseport = addr[i].opt.reuseport; -#endif - - stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t)); - if (stport == NULL) { - return NGX_CONF_ERROR; + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid server name or wildcard \"%V\" on %V", + &name[n].name, &addr->opt.addr_text); + goto failed; } - ls->servers = stport; - - stport->naddrs = i + 1; - - switch (ls->sockaddr->sa_family) { -#if (NGX_HAVE_INET6) - case AF_INET6: - if (ngx_stream_add_addrs6(cf, stport, addr) != NGX_OK) { - return NGX_CONF_ERROR; - } - break; -#endif - default: /* AF_INET */ - if (ngx_stream_add_addrs(cf, stport, addr) != NGX_OK) { - return NGX_CONF_ERROR; - } - break; + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "conflicting server name \"%V\" on %V, ignored", + &name[n].name, &addr->opt.addr_text); } - - addr++; - last--; } } - return NGX_CONF_OK; -} + hash.key = ngx_hash_key_lc; + hash.max_size = cmcf->server_names_hash_max_size; + hash.bucket_size = cmcf->server_names_hash_bucket_size; + hash.name = "server_names_hash"; + hash.pool = cf->pool; + if (ha.keys.nelts) { + hash.hash = &addr->hash; + hash.temp_pool = NULL; -static ngx_int_t -ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, - ngx_stream_conf_addr_t *addr) -{ - ngx_uint_t i; - struct sockaddr_in *sin; - ngx_stream_in_addr_t *addrs; + if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) { + goto failed; + } + } - stport->addrs = ngx_pcalloc(cf->pool, - stport->naddrs * sizeof(ngx_stream_in_addr_t)); - if (stport->addrs == NULL) { + if (ha.dns_wc_head.nelts) { + + ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts, + sizeof(ngx_hash_key_t), ngx_stream_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = ha.temp_pool; + + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, + ha.dns_wc_head.nelts) + != NGX_OK) + { + goto failed; + } + + addr->wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ha.dns_wc_tail.nelts) { + + ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), ngx_stream_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = ha.temp_pool; + + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, + ha.dns_wc_tail.nelts) + != NGX_OK) + { + goto failed; + } + + addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash; + } + + ngx_destroy_pool(ha.temp_pool); + +#if (NGX_PCRE) + + if (regex == 0) { + return NGX_OK; + } + + addr->nregex = regex; + addr->regex = ngx_palloc(cf->pool, + regex * sizeof(ngx_stream_server_name_t)); + if (addr->regex == NULL) { return NGX_ERROR; } - addrs = stport->addrs; + i = 0; - for (i = 0; i < stport->naddrs; i++) { + for (s = 0; s < addr->servers.nelts; s++) { - sin = (struct sockaddr_in *) addr[i].opt.sockaddr; - addrs[i].addr = sin->sin_addr.s_addr; + name = cscfp[s]->server_names.elts; - addrs[i].conf.ctx = addr[i].opt.ctx; -#if (NGX_STREAM_SSL) - addrs[i].conf.ssl = addr[i].opt.ssl; -#endif - addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; - addrs[i].conf.addr_text = addr[i].opt.addr_text; + for (n = 0; n < cscfp[s]->server_names.nelts; n++) { + if (name[n].regex) { + addr->regex[i++] = name[n]; + } + } } +#endif + return NGX_OK; + +failed: + + ngx_destroy_pool(ha.temp_pool); + + return NGX_ERROR; } -#if (NGX_HAVE_INET6) - -static ngx_int_t -ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, - ngx_stream_conf_addr_t *addr) -{ - ngx_uint_t i; - struct sockaddr_in6 *sin6; - ngx_stream_in6_addr_t *addrs6; - - stport->addrs = ngx_pcalloc(cf->pool, - stport->naddrs * sizeof(ngx_stream_in6_addr_t)); - if (stport->addrs == NULL) { - return NGX_ERROR; - } - - addrs6 = stport->addrs; - - for (i = 0; i < stport->naddrs; i++) { - - sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; - addrs6[i].addr6 = sin6->sin6_addr; - - addrs6[i].conf.ctx = addr[i].opt.ctx; -#if (NGX_STREAM_SSL) - addrs6[i].conf.ssl = addr[i].opt.ssl; -#endif - addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; - addrs6[i].conf.addr_text = addr[i].opt.addr_text; - } - - return NGX_OK; -} - -#endif - - static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two) { @@ -630,12 +876,12 @@ ngx_stream_cmp_conf_addrs(const void *one, const void *two) second = (ngx_stream_conf_addr_t *) two; if (first->opt.wildcard) { - /* a wildcard must be the last resort, shift it to the end */ + /* a wildcard address must be the last resort, shift it to the end */ return 1; } if (second->opt.wildcard) { - /* a wildcard must be the last resort, shift it to the end */ + /* a wildcard address must be the last resort, shift it to the end */ return -1; } @@ -653,3 +899,277 @@ ngx_stream_cmp_conf_addrs(const void *one, const void *two) return 0; } + + +static int ngx_libc_cdecl +ngx_stream_cmp_dns_wildcards(const void *one, const void *two) +{ + ngx_hash_key_t *first, *second; + + first = (ngx_hash_key_t *) one; + second = (ngx_hash_key_t *) two; + + return ngx_dns_strcmp(first->key.data, second->key.data); +} + + +static ngx_int_t +ngx_stream_init_listening(ngx_conf_t *cf, ngx_stream_conf_port_t *port) +{ + ngx_uint_t i, last, bind_wildcard; + ngx_listening_t *ls; + ngx_stream_port_t *stport; + ngx_stream_conf_addr_t *addr; + + addr = port->addrs.elts; + last = port->addrs.nelts; + + /* + * If there is a binding to an "*:port" then we need to bind() to + * the "*:port" only and ignore other implicit bindings. The bindings + * have been already sorted: explicit bindings are on the start, then + * implicit bindings go, and wildcard binding is in the end. + */ + + if (addr[last - 1].opt.wildcard) { + addr[last - 1].opt.bind = 1; + bind_wildcard = 1; + + } else { + bind_wildcard = 0; + } + + i = 0; + + while (i < last) { + + if (bind_wildcard && !addr[i].opt.bind) { + i++; + continue; + } + + ls = ngx_stream_add_listening(cf, &addr[i]); + if (ls == NULL) { + return NGX_ERROR; + } + + stport = ngx_pcalloc(cf->pool, sizeof(ngx_stream_port_t)); + if (stport == NULL) { + return NGX_ERROR; + } + + ls->servers = stport; + + stport->naddrs = i + 1; + + switch (ls->sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + if (ngx_stream_add_addrs6(cf, stport, addr) != NGX_OK) { + return NGX_ERROR; + } + break; +#endif + default: /* AF_INET */ + if (ngx_stream_add_addrs(cf, stport, addr) != NGX_OK) { + return NGX_ERROR; + } + break; + } + + addr++; + last--; + } + + return NGX_OK; +} + + +static ngx_listening_t * +ngx_stream_add_listening(ngx_conf_t *cf, ngx_stream_conf_addr_t *addr) +{ + ngx_listening_t *ls; + ngx_stream_core_srv_conf_t *cscf; + + ls = ngx_create_listening(cf, addr->opt.sockaddr, addr->opt.socklen); + if (ls == NULL) { + return NULL; + } + + ls->addr_ntop = 1; + + ls->handler = ngx_stream_init_connection; + + ls->pool_size = 256; + + cscf = addr->default_server; + + ls->logp = cscf->error_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; + + ls->type = addr->opt.type; + ls->backlog = addr->opt.backlog; + ls->rcvbuf = addr->opt.rcvbuf; + ls->sndbuf = addr->opt.sndbuf; + + ls->keepalive = addr->opt.so_keepalive; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + ls->keepidle = addr->opt.tcp_keepidle; + ls->keepintvl = addr->opt.tcp_keepintvl; + ls->keepcnt = addr->opt.tcp_keepcnt; +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + ls->accept_filter = addr->opt.accept_filter; +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ls->deferred_accept = addr->opt.deferred_accept; +#endif + +#if (NGX_HAVE_INET6) + ls->ipv6only = addr->opt.ipv6only; +#endif + +#if (NGX_HAVE_SETFIB) + ls->setfib = addr->opt.setfib; +#endif + +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = addr->opt.fastopen; +#endif + +#if (NGX_HAVE_REUSEPORT) + ls->reuseport = addr->opt.reuseport; +#endif + + ls->wildcard = addr->opt.wildcard; + + return ls; +} + + +static ngx_int_t +ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, + ngx_stream_conf_addr_t *addr) +{ + ngx_uint_t i; + struct sockaddr_in *sin; + ngx_stream_in_addr_t *addrs; + ngx_stream_virtual_names_t *vn; + + stport->addrs = ngx_pcalloc(cf->pool, + stport->naddrs * sizeof(ngx_stream_in_addr_t)); + if (stport->addrs == NULL) { + return NGX_ERROR; + } + + addrs = stport->addrs; + + for (i = 0; i < stport->naddrs; i++) { + + sin = (struct sockaddr_in *) addr[i].opt.sockaddr; + addrs[i].addr = sin->sin_addr.s_addr; + addrs[i].conf.default_server = addr[i].default_server; +#if (NGX_STREAM_SSL) + addrs[i].conf.ssl = addr[i].opt.ssl; +#endif + addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; + + if (addr[i].hash.buckets == NULL + && (addr[i].wc_head == NULL + || addr[i].wc_head->hash.buckets == NULL) + && (addr[i].wc_tail == NULL + || addr[i].wc_tail->hash.buckets == NULL) +#if (NGX_PCRE) + && addr[i].nregex == 0 +#endif + ) + { + continue; + } + + vn = ngx_palloc(cf->pool, sizeof(ngx_stream_virtual_names_t)); + if (vn == NULL) { + return NGX_ERROR; + } + + addrs[i].conf.virtual_names = vn; + + vn->names.hash = addr[i].hash; + vn->names.wc_head = addr[i].wc_head; + vn->names.wc_tail = addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = addr[i].nregex; + vn->regex = addr[i].regex; +#endif + } + + return NGX_OK; +} + + +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, + ngx_stream_conf_addr_t *addr) +{ + ngx_uint_t i; + struct sockaddr_in6 *sin6; + ngx_stream_in6_addr_t *addrs6; + ngx_stream_virtual_names_t *vn; + + stport->addrs = ngx_pcalloc(cf->pool, + stport->naddrs * sizeof(ngx_stream_in6_addr_t)); + if (stport->addrs == NULL) { + return NGX_ERROR; + } + + addrs6 = stport->addrs; + + for (i = 0; i < stport->naddrs; i++) { + + sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; + addrs6[i].addr6 = sin6->sin6_addr; + addrs6[i].conf.default_server = addr[i].default_server; +#if (NGX_STREAM_SSL) + addrs6[i].conf.ssl = addr[i].opt.ssl; +#endif + addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; + + if (addr[i].hash.buckets == NULL + && (addr[i].wc_head == NULL + || addr[i].wc_head->hash.buckets == NULL) + && (addr[i].wc_tail == NULL + || addr[i].wc_tail->hash.buckets == NULL) +#if (NGX_PCRE) + && addr[i].nregex == 0 +#endif + ) + { + continue; + } + + vn = ngx_palloc(cf->pool, sizeof(ngx_stream_virtual_names_t)); + if (vn == NULL) { + return NGX_ERROR; + } + + addrs6[i].conf.virtual_names = vn; + + vn->names.hash = addr[i].hash; + vn->names.wc_head = addr[i].wc_head; + vn->names.wc_tail = addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = addr[i].nregex; + vn->regex = addr[i].regex; +#endif + } + + return NGX_OK; +} + +#endif diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 46c3622..dc05dc5 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -45,74 +45,39 @@ typedef struct { socklen_t socklen; ngx_str_t addr_text; - /* server ctx */ - ngx_stream_conf_ctx_t *ctx; - + unsigned set:1; + unsigned default_server:1; unsigned bind:1; unsigned wildcard:1; unsigned ssl:1; #if (NGX_HAVE_INET6) unsigned ipv6only:1; #endif + unsigned deferred_accept:1; unsigned reuseport:1; unsigned so_keepalive:2; unsigned proxy_protocol:1; + + int backlog; + int rcvbuf; + int sndbuf; + int type; +#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; int tcp_keepcnt; #endif - int backlog; - int rcvbuf; - int sndbuf; -#if (NGX_HAVE_TCP_FASTOPEN) - int fastopen; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + char *accept_filter; #endif - int type; -} ngx_stream_listen_t; - - -typedef struct { - ngx_stream_conf_ctx_t *ctx; - ngx_str_t addr_text; - unsigned ssl:1; - unsigned proxy_protocol:1; -} ngx_stream_addr_conf_t; - -typedef struct { - in_addr_t addr; - ngx_stream_addr_conf_t conf; -} ngx_stream_in_addr_t; - - -#if (NGX_HAVE_INET6) - -typedef struct { - struct in6_addr addr6; - ngx_stream_addr_conf_t conf; -} ngx_stream_in6_addr_t; - -#endif - - -typedef struct { - /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */ - void *addrs; - ngx_uint_t naddrs; -} ngx_stream_port_t; - - -typedef struct { - int family; - int type; - in_port_t port; - ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ -} ngx_stream_conf_port_t; - - -typedef struct { - ngx_stream_listen_t opt; -} ngx_stream_conf_addr_t; +} ngx_stream_listen_opt_t; typedef enum { @@ -153,7 +118,6 @@ typedef struct { typedef struct { ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ - ngx_array_t listen; /* ngx_stream_listen_t */ ngx_stream_phase_engine_t phase_engine; @@ -163,16 +127,24 @@ typedef struct { ngx_array_t prefix_variables; /* ngx_stream_variable_t */ ngx_uint_t ncaptures; + ngx_uint_t server_names_hash_max_size; + ngx_uint_t server_names_hash_bucket_size; + ngx_uint_t variables_hash_max_size; ngx_uint_t variables_hash_bucket_size; ngx_hash_keys_arrays_t *variables_keys; + ngx_array_t *ports; + ngx_stream_phase_t phases[NGX_STREAM_LOG_PHASE + 1]; } ngx_stream_core_main_conf_t; typedef struct { + /* array of the ngx_stream_server_name_t, "server_name" directive */ + ngx_array_t server_names; + ngx_stream_content_handler_pt handler; ngx_stream_conf_ctx_t *ctx; @@ -180,6 +152,8 @@ typedef struct { u_char *file_name; ngx_uint_t line; + ngx_str_t server_name; + ngx_flag_t tcp_nodelay; size_t preread_buffer_size; ngx_msec_t preread_timeout; @@ -191,10 +165,98 @@ typedef struct { ngx_msec_t proxy_protocol_timeout; - ngx_uint_t listen; /* unsigned listen:1; */ + unsigned listen:1; +#if (NGX_PCRE) + unsigned captures:1; +#endif } ngx_stream_core_srv_conf_t; +/* list of structures to find core_srv_conf quickly at run time */ + + +typedef struct { +#if (NGX_PCRE) + ngx_stream_regex_t *regex; +#endif + ngx_stream_core_srv_conf_t *server; /* virtual name server conf */ + ngx_str_t name; +} ngx_stream_server_name_t; + + +typedef struct { + ngx_hash_combined_t names; + + ngx_uint_t nregex; + ngx_stream_server_name_t *regex; +} ngx_stream_virtual_names_t; + + +typedef struct { + /* the default server configuration for this address:port */ + ngx_stream_core_srv_conf_t *default_server; + + ngx_stream_virtual_names_t *virtual_names; + + unsigned ssl:1; + unsigned proxy_protocol:1; +} ngx_stream_addr_conf_t; + + +typedef struct { + in_addr_t addr; + ngx_stream_addr_conf_t conf; +} ngx_stream_in_addr_t; + + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr6; + ngx_stream_addr_conf_t conf; +} ngx_stream_in6_addr_t; + +#endif + + +typedef struct { + /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */ + void *addrs; + ngx_uint_t naddrs; +} ngx_stream_port_t; + + +typedef struct { + int family; + int type; + in_port_t port; + ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ +} ngx_stream_conf_port_t; + + +typedef struct { + ngx_stream_listen_opt_t opt; + + unsigned protocols:3; + unsigned protocols_set:1; + unsigned protocols_changed:1; + + ngx_hash_t hash; + ngx_hash_wildcard_t *wc_head; + ngx_hash_wildcard_t *wc_tail; + +#if (NGX_PCRE) + ngx_uint_t nregex; + ngx_stream_server_name_t *regex; +#endif + + /* the default server configuration for this address:port */ + ngx_stream_core_srv_conf_t *default_server; + ngx_array_t servers; + /* array of ngx_stream_core_srv_conf_t */ +} ngx_stream_conf_addr_t; + + struct ngx_stream_session_s { uint32_t signature; /* "STRM" */ @@ -210,6 +272,8 @@ struct ngx_stream_session_s { void **main_conf; void **srv_conf; + ngx_stream_virtual_names_t *virtual_names; + ngx_stream_upstream_t *upstream; ngx_array_t *upstream_states; /* of ngx_stream_upstream_state_t */ @@ -283,6 +347,9 @@ typedef struct { #define NGX_STREAM_WRITE_BUFFERED 0x10 +ngx_int_t ngx_stream_add_listen(ngx_conf_t *cf, + ngx_stream_core_srv_conf_t *cscf, ngx_stream_listen_opt_t *lsopt); + void ngx_stream_core_run_phases(ngx_stream_session_t *s); ngx_int_t ngx_stream_core_generic_phase(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph); @@ -291,6 +358,10 @@ ngx_int_t ngx_stream_core_preread_phase(ngx_stream_session_t *s, ngx_int_t ngx_stream_core_content_phase(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph); +ngx_int_t ngx_stream_validate_host(ngx_str_t *host, ngx_pool_t *pool, + ngx_uint_t alloc); +ngx_int_t ngx_stream_find_virtual_server(ngx_stream_session_t *s, + ngx_str_t *host, ngx_stream_core_srv_conf_t **cscfp); void ngx_stream_init_connection(ngx_connection_t *c); void ngx_stream_session_handler(ngx_event_t *rev); diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c index a3020d4..070c226 100644 --- a/src/stream/ngx_stream_access_module.c +++ b/src/stream/ngx_stream_access_module.c @@ -144,7 +144,7 @@ ngx_stream_access_handler(ngx_stream_session_t *s) p = sin6->sin6_addr.s6_addr; if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - addr = p[12] << 24; + addr = (in_addr_t) p[12] << 24; addr += p[13] << 16; addr += p[14] << 8; addr += p[15]; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index f0b7934..3093963 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -10,6 +10,11 @@ #include +static ngx_uint_t ngx_stream_preread_can_peek(ngx_connection_t *c); +static ngx_int_t ngx_stream_preread_peek(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph); +static ngx_int_t ngx_stream_preread(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph); static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf); static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf); static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf); @@ -22,6 +27,8 @@ static char *ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -42,6 +49,20 @@ static ngx_command_t ngx_stream_core_commands[] = { offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size), NULL }, + { ngx_string("server_names_hash_max_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_core_main_conf_t, server_names_hash_max_size), + NULL }, + + { ngx_string("server_names_hash_bucket_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_core_main_conf_t, server_names_hash_bucket_size), + NULL }, + { ngx_string("server"), NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_stream_core_server, @@ -56,6 +77,13 @@ static ngx_command_t ngx_stream_core_commands[] = { 0, NULL }, + { ngx_string("server_name"), + NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_core_server_name, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("error_log"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, ngx_stream_core_error_log, @@ -203,8 +231,6 @@ ngx_int_t ngx_stream_core_preread_phase(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph) { - size_t size; - ssize_t n; ngx_int_t rc; ngx_connection_t *c; ngx_stream_core_srv_conf_t *cscf; @@ -217,56 +243,33 @@ ngx_stream_core_preread_phase(ngx_stream_session_t *s, if (c->read->timedout) { rc = NGX_STREAM_OK; + goto done; + } - } else if (c->read->timer_set) { - rc = NGX_AGAIN; + if (!c->read->timer_set) { + rc = ph->handler(s); + + if (rc != NGX_AGAIN) { + goto done; + } + } + + if (c->buffer == NULL) { + c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size); + if (c->buffer == NULL) { + rc = NGX_ERROR; + goto done; + } + } + + if (ngx_stream_preread_can_peek(c)) { + rc = ngx_stream_preread_peek(s, ph); } else { - rc = ph->handler(s); + rc = ngx_stream_preread(s, ph); } - while (rc == NGX_AGAIN) { - - if (c->buffer == NULL) { - c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size); - if (c->buffer == NULL) { - rc = NGX_ERROR; - break; - } - } - - size = c->buffer->end - c->buffer->last; - - if (size == 0) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full"); - rc = NGX_STREAM_BAD_REQUEST; - break; - } - - if (c->read->eof) { - rc = NGX_STREAM_OK; - break; - } - - if (!c->read->ready) { - break; - } - - n = c->recv(c, c->buffer->last, size); - - if (n == NGX_ERROR || n == 0) { - rc = NGX_STREAM_OK; - break; - } - - if (n == NGX_AGAIN) { - break; - } - - c->buffer->last += n; - - rc = ph->handler(s); - } +done: if (rc == NGX_AGAIN) { if (ngx_handle_read_event(c->read, 0) != NGX_OK) { @@ -311,6 +314,129 @@ ngx_stream_core_preread_phase(ngx_stream_session_t *s, } +static ngx_uint_t +ngx_stream_preread_can_peek(ngx_connection_t *c) +{ +#if (NGX_STREAM_SSL) + if (c->ssl) { + return 0; + } +#endif + + if ((ngx_event_flags & NGX_USE_CLEAR_EVENT) == 0) { + return 0; + } + +#if (NGX_HAVE_KQUEUE) + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + return 1; + } +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) { + return 1; + } +#endif + + return 0; +} + + +static ngx_int_t +ngx_stream_preread_peek(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph) +{ + ssize_t n; + ngx_int_t rc; + ngx_err_t err; + ngx_connection_t *c; + + c = s->connection; + + n = recv(c->fd, (char *) c->buffer->last, + c->buffer->end - c->buffer->last, MSG_PEEK); + + err = ngx_socket_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream recv(): %z", n); + + if (n == -1) { + if (err == NGX_EAGAIN) { + c->read->ready = 0; + return NGX_AGAIN; + } + + ngx_connection_error(c, err, "recv() failed"); + return NGX_STREAM_OK; + } + + if (n == 0) { + return NGX_STREAM_OK; + } + + c->buffer->last += n; + + rc = ph->handler(s); + + if (rc != NGX_AGAIN) { + c->buffer->last = c->buffer->pos; + return rc; + } + + if (c->buffer->last == c->buffer->end) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full"); + return NGX_STREAM_BAD_REQUEST; + } + + if (c->read->pending_eof) { + return NGX_STREAM_OK; + } + + c->buffer->last = c->buffer->pos; + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_stream_preread(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph) +{ + ssize_t n; + ngx_int_t rc; + ngx_connection_t *c; + + c = s->connection; + + while (c->read->ready) { + + n = c->recv(c, c->buffer->last, c->buffer->end - c->buffer->last); + + if (n == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (n == NGX_ERROR || n == 0) { + return NGX_STREAM_OK; + } + + c->buffer->last += n; + + rc = ph->handler(s); + + if (rc != NGX_AGAIN) { + return rc; + } + + if (c->buffer->last == c->buffer->end) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full"); + return NGX_STREAM_BAD_REQUEST; + } + } + + return NGX_AGAIN; +} + + ngx_int_t ngx_stream_core_content_phase(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph) @@ -338,6 +464,149 @@ ngx_stream_core_content_phase(ngx_stream_session_t *s, } +ngx_int_t +ngx_stream_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) +{ + u_char *h, ch; + size_t i, dot_pos, host_len; + + enum { + sw_usual = 0, + sw_literal, + sw_rest + } state; + + dot_pos = host->len; + host_len = host->len; + + h = host->data; + + state = sw_usual; + + for (i = 0; i < host->len; i++) { + ch = h[i]; + + switch (ch) { + + case '.': + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + dot_pos = i; + break; + + case ':': + if (state == sw_usual) { + host_len = i; + state = sw_rest; + } + break; + + case '[': + if (i == 0) { + state = sw_literal; + } + break; + + case ']': + if (state == sw_literal) { + host_len = i + 1; + state = sw_rest; + } + break; + + default: + + if (ngx_path_separator(ch)) { + return NGX_DECLINED; + } + + if (ch <= 0x20 || ch == 0x7f) { + return NGX_DECLINED; + } + + if (ch >= 'A' && ch <= 'Z') { + alloc = 1; + } + + break; + } + } + + if (dot_pos == host_len - 1) { + host_len--; + } + + if (host_len == 0) { + return NGX_DECLINED; + } + + if (alloc) { + host->data = ngx_pnalloc(pool, host_len); + if (host->data == NULL) { + return NGX_ERROR; + } + + ngx_strlow(host->data, h, host_len); + } + + host->len = host_len; + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_find_virtual_server(ngx_stream_session_t *s, + ngx_str_t *host, ngx_stream_core_srv_conf_t **cscfp) +{ + ngx_stream_core_srv_conf_t *cscf; + + if (s->virtual_names == NULL) { + return NGX_DECLINED; + } + + cscf = ngx_hash_find_combined(&s->virtual_names->names, + ngx_hash_key(host->data, host->len), + host->data, host->len); + + if (cscf) { + *cscfp = cscf; + return NGX_OK; + } + +#if (NGX_PCRE) + + if (host->len && s->virtual_names->nregex) { + ngx_int_t n; + ngx_uint_t i; + ngx_stream_server_name_t *sn; + + sn = s->virtual_names->regex; + + for (i = 0; i < s->virtual_names->nregex; i++) { + + n = ngx_stream_regex_exec(s, sn[i].regex, host); + + if (n == NGX_DECLINED) { + continue; + } + + if (n == NGX_OK) { + *cscfp = sn[i].server; + return NGX_OK; + } + + return NGX_ERROR; + } + } + +#endif /* NGX_PCRE */ + + return NGX_DECLINED; +} + + static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf) { @@ -362,11 +631,8 @@ ngx_stream_core_create_main_conf(ngx_conf_t *cf) return NULL; } - if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_stream_listen_t)) - != NGX_OK) - { - return NULL; - } + cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT; + cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT; cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT; cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT; @@ -380,6 +646,14 @@ ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_stream_core_main_conf_t *cmcf = conf; + 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); + + ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024); ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64); @@ -411,6 +685,13 @@ ngx_stream_core_create_srv_conf(ngx_conf_t *cf) * cscf->error_log = NULL; */ + if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4, + sizeof(ngx_stream_server_name_t)) + != NGX_OK) + { + return NULL; + } + cscf->file_name = cf->conf_file->file.name.data; cscf->line = cf->conf_file->line; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; @@ -429,6 +710,9 @@ ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_stream_core_srv_conf_t *prev = parent; ngx_stream_core_srv_conf_t *conf = child; + ngx_str_t name; + ngx_stream_server_name_t *sn; + ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); @@ -476,6 +760,37 @@ ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->preread_timeout, prev->preread_timeout, 30000); + if (conf->server_names.nelts == 0) { + /* the array has 4 empty preallocated elements, so push cannot fail */ + sn = ngx_array_push(&conf->server_names); +#if (NGX_PCRE) + sn->regex = NULL; +#endif + sn->server = conf; + ngx_str_set(&sn->name, ""); + } + + sn = conf->server_names.elts; + name = sn[0].name; + +#if (NGX_PCRE) + if (sn->regex) { + name.len++; + name.data--; + } else +#endif + + if (name.data[0] == '.') { + name.len--; + name.data++; + } + + conf->server_name.len = name.len; + conf->server_name.data = ngx_pstrdup(cf->pool, &name); + if (conf->server_name.data == NULL) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } @@ -575,11 +890,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_stream_core_srv_conf_t *cscf = conf; - ngx_str_t *value, size; - ngx_url_t u; - ngx_uint_t i, n, backlog; - ngx_stream_listen_t *ls, *als, *nls; - ngx_stream_core_main_conf_t *cmcf; + ngx_str_t *value, size; + ngx_url_t u; + ngx_uint_t n, i, backlog; + ngx_stream_listen_opt_t lsopt; cscf->listen = 1; @@ -600,51 +914,67 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + ngx_memzero(&lsopt, sizeof(ngx_stream_listen_opt_t)); - ls = ngx_array_push(&cmcf->listen); - if (ls == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memzero(ls, sizeof(ngx_stream_listen_t)); - - ls->backlog = NGX_LISTEN_BACKLOG; - ls->rcvbuf = -1; - ls->sndbuf = -1; - ls->type = SOCK_STREAM; - ls->ctx = cf->ctx; - -#if (NGX_HAVE_TCP_FASTOPEN) - ls->fastopen = -1; + lsopt.backlog = NGX_LISTEN_BACKLOG; + lsopt.type = SOCK_STREAM; + lsopt.rcvbuf = -1; + lsopt.sndbuf = -1; +#if (NGX_HAVE_SETFIB) + lsopt.setfib = -1; +#endif +#if (NGX_HAVE_TCP_FASTOPEN) + lsopt.fastopen = -1; #endif - #if (NGX_HAVE_INET6) - ls->ipv6only = 1; + lsopt.ipv6only = 1; #endif backlog = 0; for (i = 2; i < cf->args->nelts; i++) { + if (ngx_strcmp(value[i].data, "default_server") == 0) { + lsopt.default_server = 1; + continue; + } + #if !(NGX_WIN32) if (ngx_strcmp(value[i].data, "udp") == 0) { - ls->type = SOCK_DGRAM; + lsopt.type = SOCK_DGRAM; continue; } #endif if (ngx_strcmp(value[i].data, "bind") == 0) { - ls->bind = 1; + lsopt.set = 1; + lsopt.bind = 1; continue; } +#if (NGX_HAVE_SETFIB) + if (ngx_strncmp(value[i].data, "setfib=", 7) == 0) { + lsopt.setfib = ngx_atoi(value[i].data + 7, value[i].len - 7); + lsopt.set = 1; + lsopt.bind = 1; + + if (lsopt.setfib == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setfib \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } +#endif + #if (NGX_HAVE_TCP_FASTOPEN) if (ngx_strncmp(value[i].data, "fastopen=", 9) == 0) { - ls->fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9); - ls->bind = 1; + lsopt.fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9); + lsopt.set = 1; + lsopt.bind = 1; - if (ls->fastopen == NGX_ERROR) { + if (lsopt.fastopen == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid fastopen \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -655,10 +985,11 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) { - ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); - ls->bind = 1; + lsopt.backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); + lsopt.set = 1; + lsopt.bind = 1; - if (ls->backlog == NGX_ERROR || ls->backlog == 0) { + if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid backlog \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -673,10 +1004,11 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) size.len = value[i].len - 7; size.data = value[i].data + 7; - ls->rcvbuf = ngx_parse_size(&size); - ls->bind = 1; + lsopt.rcvbuf = ngx_parse_size(&size); + lsopt.set = 1; + lsopt.bind = 1; - if (ls->rcvbuf == NGX_ERROR) { + if (lsopt.rcvbuf == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid rcvbuf \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -689,10 +1021,11 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) size.len = value[i].len - 7; size.data = value[i].data + 7; - ls->sndbuf = ngx_parse_size(&size); - ls->bind = 1; + lsopt.sndbuf = ngx_parse_size(&size); + lsopt.set = 1; + lsopt.bind = 1; - if (ls->sndbuf == NGX_ERROR) { + if (lsopt.sndbuf == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid sndbuf \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -701,13 +1034,40 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "accept_filter=", 14) == 0) { +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + lsopt.accept_filter = (char *) &value[i].data[14]; + lsopt.set = 1; + lsopt.bind = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "accept filters \"%V\" are not supported " + "on this platform, ignored", + &value[i]); +#endif + continue; + } + + if (ngx_strcmp(value[i].data, "deferred") == 0) { +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + lsopt.deferred_accept = 1; + lsopt.set = 1; + lsopt.bind = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the deferred accept is not supported " + "on this platform, ignored"); +#endif + continue; + } + if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ngx_strcmp(&value[i].data[10], "n") == 0) { - ls->ipv6only = 1; + lsopt.ipv6only = 1; } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { - ls->ipv6only = 0; + lsopt.ipv6only = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -716,11 +1076,13 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ls->bind = 1; + lsopt.set = 1; + lsopt.bind = 1; + continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "bind ipv6only is not supported " + "ipv6only is not supported " "on this platform"); return NGX_CONF_ERROR; #endif @@ -728,8 +1090,9 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, "reuseport") == 0) { #if (NGX_HAVE_REUSEPORT) - ls->reuseport = 1; - ls->bind = 1; + lsopt.reuseport = 1; + lsopt.set = 1; + lsopt.bind = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "reuseport is not supported " @@ -740,17 +1103,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, "ssl") == 0) { #if (NGX_STREAM_SSL) - ngx_stream_ssl_conf_t *sslcf; - - sslcf = ngx_stream_conf_get_module_srv_conf(cf, - ngx_stream_ssl_module); - - sslcf->listen = 1; - sslcf->file = cf->conf_file->file.name.data; - sslcf->line = cf->conf_file->line; - - ls->ssl = 1; - + lsopt.ssl = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -763,10 +1116,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[i].data[13], "on") == 0) { - ls->so_keepalive = 1; + lsopt.so_keepalive = 1; } else if (ngx_strcmp(&value[i].data[13], "off") == 0) { - ls->so_keepalive = 2; + lsopt.so_keepalive = 2; } else { @@ -785,8 +1138,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (p > s.data) { s.len = p - s.data; - ls->tcp_keepidle = ngx_parse_time(&s, 1); - if (ls->tcp_keepidle == (time_t) NGX_ERROR) { + lsopt.tcp_keepidle = ngx_parse_time(&s, 1); + if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } @@ -801,8 +1154,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (p > s.data) { s.len = p - s.data; - ls->tcp_keepintvl = ngx_parse_time(&s, 1); - if (ls->tcp_keepintvl == (time_t) NGX_ERROR) { + lsopt.tcp_keepintvl = ngx_parse_time(&s, 1); + if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } @@ -812,19 +1165,19 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (s.data < end) { s.len = end - s.data; - ls->tcp_keepcnt = ngx_atoi(s.data, s.len); - if (ls->tcp_keepcnt == NGX_ERROR) { + lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len); + if (lsopt.tcp_keepcnt == NGX_ERROR) { goto invalid_so_keepalive; } } - if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0 - && ls->tcp_keepcnt == 0) + if (lsopt.tcp_keepidle == 0 && lsopt.tcp_keepintvl == 0 + && lsopt.tcp_keepcnt == 0) { goto invalid_so_keepalive; } - ls->so_keepalive = 1; + lsopt.so_keepalive = 1; #else @@ -836,7 +1189,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } - ls->bind = 1; + lsopt.set = 1; + lsopt.bind = 1; continue; @@ -851,39 +1205,51 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { - ls->proxy_protocol = 1; + lsopt.proxy_protocol = 1; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the invalid \"%V\" parameter", &value[i]); + "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } - if (ls->type == SOCK_DGRAM) { + if (lsopt.type == SOCK_DGRAM) { +#if (NGX_HAVE_TCP_FASTOPEN) + if (lsopt.fastopen != -1) { + return "\"fastopen\" parameter is incompatible with \"udp\""; + } +#endif + if (backlog) { return "\"backlog\" parameter is incompatible with \"udp\""; } +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + if (lsopt.accept_filter) { + return "\"accept_filter\" parameter is incompatible with \"udp\""; + } +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + if (lsopt.deferred_accept) { + return "\"deferred\" parameter is incompatible with \"udp\""; + } +#endif + #if (NGX_STREAM_SSL) - if (ls->ssl) { + if (lsopt.ssl) { return "\"ssl\" parameter is incompatible with \"udp\""; } #endif - if (ls->so_keepalive) { + if (lsopt.so_keepalive) { return "\"so_keepalive\" parameter is incompatible with \"udp\""; } - if (ls->proxy_protocol) { + if (lsopt.proxy_protocol) { return "\"proxy_protocol\" parameter is incompatible with \"udp\""; } - -#if (NGX_HAVE_TCP_FASTOPEN) - if (ls->fastopen != -1) { - return "\"fastopen\" parameter is incompatible with \"udp\""; - } -#endif } for (n = 0; n < u.naddrs; n++) { @@ -897,40 +1263,12 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - if (n != 0) { - nls = ngx_array_push(&cmcf->listen); - if (nls == NULL) { - return NGX_CONF_ERROR; - } + lsopt.sockaddr = u.addrs[n].sockaddr; + lsopt.socklen = u.addrs[n].socklen; + lsopt.addr_text = u.addrs[n].name; + lsopt.wildcard = ngx_inet_wildcard(lsopt.sockaddr); - *nls = *ls; - - } else { - nls = ls; - } - - nls->sockaddr = u.addrs[n].sockaddr; - nls->socklen = u.addrs[n].socklen; - nls->addr_text = u.addrs[n].name; - nls->wildcard = ngx_inet_wildcard(nls->sockaddr); - - als = cmcf->listen.elts; - - for (i = 0; i < cmcf->listen.nelts - 1; i++) { - if (nls->type != als[i].type) { - continue; - } - - if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen, - nls->sockaddr, nls->socklen, 1) - != NGX_OK) - { - continue; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate \"%V\" address and port pair", - &nls->addr_text); + if (ngx_stream_add_listen(cf, cscf, &lsopt) != NGX_OK) { return NGX_CONF_ERROR; } @@ -942,6 +1280,107 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_stream_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_core_srv_conf_t *cscf = conf; + + u_char ch; + ngx_str_t *value; + ngx_uint_t i; + ngx_stream_server_name_t *sn; + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + ch = value[i].data[0]; + + if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.')) + || (ch == '.' && value[i].len < 2)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "server name \"%V\" is invalid", &value[i]); + return NGX_CONF_ERROR; + } + + if (ngx_strchr(value[i].data, '/')) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "server name \"%V\" has suspicious symbols", + &value[i]); + } + + sn = ngx_array_push(&cscf->server_names); + if (sn == NULL) { + return NGX_CONF_ERROR; + } + +#if (NGX_PCRE) + sn->regex = NULL; +#endif + sn->server = cscf; + + if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) { + sn->name = cf->cycle->hostname; + + } else { + sn->name = value[i]; + } + + if (value[i].data[0] != '~') { + ngx_strlow(sn->name.data, sn->name.data, sn->name.len); + continue; + } + +#if (NGX_PCRE) + { + u_char *p; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + if (value[i].len == 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "empty regex in server name \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + value[i].len--; + value[i].data++; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = value[i]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + for (p = value[i].data; p < value[i].data + value[i].len; p++) { + if (*p >= 'A' && *p <= 'Z') { + rc.options = NGX_REGEX_CASELESS; + break; + } + } + + sn->regex = ngx_stream_regex_compile(cf, &rc); + if (sn->regex == NULL) { + return NGX_CONF_ERROR; + } + + sn->name = value[i]; + cscf->captures = (rc.captures > 0); + } +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "using regex \"%V\" " + "requires PCRE library", &value[i]); + + return NGX_CONF_ERROR; +#endif + } + + return NGX_CONF_OK; +} + + static char * ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c index 4b4cad8..2324bef 100644 --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -190,7 +190,7 @@ ngx_stream_geo_cidr_variable(ngx_stream_session_t *s, p = inaddr6->s6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; @@ -263,7 +263,7 @@ ngx_stream_geo_range_variable(ngx_stream_session_t *s, if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; @@ -1209,7 +1209,7 @@ ngx_stream_geo_value(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, return gvvn->value; } - val = ngx_palloc(ctx->pool, sizeof(ngx_stream_variable_value_t)); + val = ngx_pcalloc(ctx->pool, sizeof(ngx_stream_variable_value_t)); if (val == NULL) { return NULL; } @@ -1221,8 +1221,6 @@ ngx_stream_geo_value(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, } val->valid = 1; - val->no_cacheable = 0; - val->not_found = 0; gvvn = ngx_palloc(ctx->temp_pool, sizeof(ngx_stream_geo_variable_value_node_t)); diff --git a/src/stream/ngx_stream_geoip_module.c b/src/stream/ngx_stream_geoip_module.c index 6507b71..3ee8f0e 100644 --- a/src/stream/ngx_stream_geoip_module.c +++ b/src/stream/ngx_stream_geoip_module.c @@ -236,7 +236,7 @@ ngx_stream_geoip_addr(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf) if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index 669b6a1..a7ffc6e 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -30,6 +30,7 @@ ngx_stream_init_connection(ngx_connection_t *c) struct sockaddr_in *sin; ngx_stream_in_addr_t *addr; ngx_stream_session_t *s; + ngx_stream_conf_ctx_t *ctx; ngx_stream_addr_conf_t *addr_conf; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; @@ -121,9 +122,12 @@ ngx_stream_init_connection(ngx_connection_t *c) return; } + ctx = addr_conf->default_server->ctx; + s->signature = NGX_STREAM_MODULE; - s->main_conf = addr_conf->ctx->main_conf; - s->srv_conf = addr_conf->ctx->srv_conf; + s->main_conf = ctx->main_conf; + s->srv_conf = ctx->srv_conf; + s->virtual_names = addr_conf->virtual_names; #if (NGX_STREAM_SSL) s->ssl = addr_conf->ssl; @@ -144,7 +148,7 @@ ngx_stream_init_connection(ngx_connection_t *c) ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA %sclient %*s connected to %V", c->number, c->type == SOCK_DGRAM ? "udp " : "", - len, text, &addr_conf->addr_text); + len, text, &c->listening->addr_text); c->log->connection = c->number; c->log->handler = ngx_stream_log_error; diff --git a/src/stream/ngx_stream_pass_module.c b/src/stream/ngx_stream_pass_module.c new file mode 100644 index 0000000..2c1c60c --- /dev/null +++ b/src/stream/ngx_stream_pass_module.c @@ -0,0 +1,327 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_STREAM_PASS_MAX_PASSES 10 + + +typedef struct { + ngx_addr_t *addr; + ngx_stream_complex_value_t *addr_value; +} ngx_stream_pass_srv_conf_t; + + +static void ngx_stream_pass_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_pass_check_cycle(ngx_connection_t *c); +static void ngx_stream_pass_cleanup(void *data); +static ngx_int_t ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr); +static void *ngx_stream_pass_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_command_t ngx_stream_pass_commands[] = { + + { ngx_string("pass"), + NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_pass, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_pass_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_pass_create_srv_conf, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_pass_module = { + NGX_MODULE_V1, + &ngx_stream_pass_module_ctx, /* module context */ + ngx_stream_pass_commands, /* module directives */ + NGX_STREAM_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 void +ngx_stream_pass_handler(ngx_stream_session_t *s) +{ + ngx_url_t u; + ngx_str_t url; + ngx_addr_t *addr; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_connection_t *c; + ngx_stream_pass_srv_conf_t *pscf; + + c = s->connection; + + c->log->action = "passing connection to port"; + + if (c->buffer && c->buffer->pos != c->buffer->last) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "cannot pass connection with preread data"); + goto failed; + } + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_pass_module); + + addr = pscf->addr; + + if (addr == NULL) { + if (ngx_stream_complex_value(s, pscf->addr_value, &url) != NGX_OK) { + goto failed; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = url; + u.no_resolve = 1; + + if (ngx_parse_url(c->pool, &u) != NGX_OK) { + if (u.err) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%s in pass \"%V\"", u.err, &u.url); + } + + goto failed; + } + + if (u.naddrs == 0) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no addresses in pass \"%V\"", &u.url); + goto failed; + } + + if (u.no_port) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no port in pass \"%V\"", &u.url); + goto failed; + } + + addr = &u.addrs[0]; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream pass addr: \"%V\"", &addr->name); + + if (ngx_stream_pass_check_cycle(c) != NGX_OK) { + goto failed; + } + + ls = ngx_cycle->listening.elts; + + for (i = 0; i < ngx_cycle->listening.nelts; i++) { + + if (ngx_stream_pass_match(&ls[i], addr) != NGX_OK) { + continue; + } + + c->listening = &ls[i]; + + c->data = NULL; + c->buffer = NULL; + + *c->log = c->listening->log; + c->log->handler = NULL; + c->log->data = NULL; + + c->local_sockaddr = addr->sockaddr; + c->local_socklen = addr->socklen; + + c->listening->handler(c); + + return; + } + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "port not found for \"%V\"", &addr->name); + + ngx_stream_finalize_session(s, NGX_STREAM_OK); + + return; + +failed: + + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); +} + + +static ngx_int_t +ngx_stream_pass_check_cycle(ngx_connection_t *c) +{ + ngx_uint_t *num; + ngx_pool_cleanup_t *cln; + + for (cln = c->pool->cleanup; cln; cln = cln->next) { + if (cln->handler != ngx_stream_pass_cleanup) { + continue; + } + + num = cln->data; + + if (++(*num) > NGX_STREAM_PASS_MAX_PASSES) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "stream pass cycle"); + return NGX_ERROR; + } + + return NGX_OK; + } + + cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_uint_t)); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_stream_pass_cleanup; + + num = cln->data; + *num = 1; + + return NGX_OK; +} + + +static void +ngx_stream_pass_cleanup(void *data) +{ + return; +} + + +static ngx_int_t +ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr) +{ + if (!ls->wildcard) { + return ngx_cmp_sockaddr(ls->sockaddr, ls->socklen, + addr->sockaddr, addr->socklen, 1); + } + + if (ls->sockaddr->sa_family == addr->sockaddr->sa_family + && ngx_inet_get_port(ls->sockaddr) == ngx_inet_get_port(addr->sockaddr)) + { + return NGX_OK; + } + + return NGX_DECLINED; +} + + +static void * +ngx_stream_pass_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_pass_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_pass_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->addr = NULL; + * conf->addr_value = NULL; + */ + + return conf; +} + + +static char * +ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_pass_srv_conf_t *pscf = conf; + + ngx_url_t u; + ngx_str_t *value, *url; + ngx_stream_complex_value_t cv; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_compile_complex_value_t ccv; + + if (pscf->addr || pscf->addr_value) { + return "is duplicate"; + } + + cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module); + + cscf->handler = ngx_stream_pass_handler; + + value = cf->args->elts; + + url = &value[1]; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = url; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths) { + pscf->addr_value = ngx_palloc(cf->pool, + sizeof(ngx_stream_complex_value_t)); + if (pscf->addr_value == NULL) { + return NGX_CONF_ERROR; + } + + *pscf->addr_value = cv; + + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = *url; + u.no_resolve = 1; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"pass\" directive", + u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + if (u.naddrs == 0) { + return "has no addresses"; + } + + if (u.no_port) { + return "has no port"; + } + + pscf->addr = &u.addrs[0]; + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 1ba1825..ba44477 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -40,12 +40,12 @@ static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_add_variables(ngx_conf_t *cf); -static void *ngx_stream_ssl_create_conf(ngx_conf_t *cf); -static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, +static void *ngx_stream_ssl_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, - ngx_stream_ssl_conf_t *conf); + ngx_stream_ssl_srv_conf_t *conf); static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -90,21 +90,21 @@ static ngx_command_t ngx_stream_ssl_commands[] = { NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, handshake_timeout), + offsetof(ngx_stream_ssl_srv_conf_t, handshake_timeout), NULL }, { ngx_string("ssl_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, certificates), + offsetof(ngx_stream_ssl_srv_conf_t, certificates), NULL }, { ngx_string("ssl_certificate_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, certificate_keys), + offsetof(ngx_stream_ssl_srv_conf_t, certificate_keys), NULL }, { ngx_string("ssl_password_file"), @@ -118,63 +118,63 @@ static ngx_command_t ngx_stream_ssl_commands[] = { NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, dhparam), + offsetof(ngx_stream_ssl_srv_conf_t, dhparam), NULL }, { ngx_string("ssl_ecdh_curve"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, ecdh_curve), + offsetof(ngx_stream_ssl_srv_conf_t, ecdh_curve), NULL }, { ngx_string("ssl_protocols"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, protocols), + offsetof(ngx_stream_ssl_srv_conf_t, protocols), &ngx_stream_ssl_protocols }, { ngx_string("ssl_ciphers"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, ciphers), + offsetof(ngx_stream_ssl_srv_conf_t, ciphers), NULL }, { ngx_string("ssl_verify_client"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, verify), + offsetof(ngx_stream_ssl_srv_conf_t, verify), &ngx_stream_ssl_verify }, { ngx_string("ssl_verify_depth"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, verify_depth), + offsetof(ngx_stream_ssl_srv_conf_t, verify_depth), NULL }, { ngx_string("ssl_client_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, client_certificate), + offsetof(ngx_stream_ssl_srv_conf_t, client_certificate), NULL }, { ngx_string("ssl_trusted_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, trusted_certificate), + offsetof(ngx_stream_ssl_srv_conf_t, trusted_certificate), NULL }, { ngx_string("ssl_prefer_server_ciphers"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, prefer_server_ciphers), + offsetof(ngx_stream_ssl_srv_conf_t, prefer_server_ciphers), NULL }, { ngx_string("ssl_session_cache"), @@ -188,37 +188,44 @@ static ngx_command_t ngx_stream_ssl_commands[] = { NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, session_tickets), + offsetof(ngx_stream_ssl_srv_conf_t, session_tickets), NULL }, { ngx_string("ssl_session_ticket_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, session_ticket_keys), + offsetof(ngx_stream_ssl_srv_conf_t, session_ticket_keys), NULL }, { ngx_string("ssl_session_timeout"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_sec_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, session_timeout), + offsetof(ngx_stream_ssl_srv_conf_t, session_timeout), NULL }, { ngx_string("ssl_crl"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, crl), + offsetof(ngx_stream_ssl_srv_conf_t, crl), NULL }, { ngx_string("ssl_conf_command"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, ngx_conf_set_keyval_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, conf_commands), + offsetof(ngx_stream_ssl_srv_conf_t, conf_commands), &ngx_stream_ssl_conf_command_post }, + { ngx_string("ssl_reject_handshake"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_srv_conf_t, reject_handshake), + NULL }, + { ngx_string("ssl_alpn"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, ngx_stream_ssl_alpn, @@ -237,8 +244,8 @@ static ngx_stream_module_t ngx_stream_ssl_module_ctx = { NULL, /* create main configuration */ NULL, /* init main configuration */ - ngx_stream_ssl_create_conf, /* create server configuration */ - ngx_stream_ssl_merge_conf /* merge server configuration */ + ngx_stream_ssl_create_srv_conf, /* create server configuration */ + ngx_stream_ssl_merge_srv_conf /* merge server configuration */ }; @@ -332,11 +339,11 @@ static ngx_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); static ngx_int_t ngx_stream_ssl_handler(ngx_stream_session_t *s) { - long rc; - X509 *cert; - ngx_int_t rv; - ngx_connection_t *c; - ngx_stream_ssl_conf_t *sslcf; + long rc; + X509 *cert; + ngx_int_t rv; + ngx_connection_t *c; + ngx_stream_ssl_srv_conf_t *sscf; if (!s->ssl) { return NGX_OK; @@ -344,23 +351,23 @@ ngx_stream_ssl_handler(ngx_stream_session_t *s) c = s->connection; - sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); if (c->ssl == NULL) { c->log->action = "SSL handshaking"; - rv = ngx_stream_ssl_init_connection(&sslcf->ssl, c); + rv = ngx_stream_ssl_init_connection(&sscf->ssl, c); if (rv != NGX_OK) { return rv; } } - if (sslcf->verify) { + if (sscf->verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK - && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) + && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client SSL certificate verify error: (%l:%s)", @@ -371,7 +378,7 @@ ngx_stream_ssl_handler(ngx_stream_session_t *s) return NGX_ERROR; } - if (sslcf->verify == 1) { + if (sscf->verify == 1) { cert = SSL_get_peer_certificate(c->ssl->connection); if (cert == NULL) { @@ -396,7 +403,7 @@ ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) { ngx_int_t rc; ngx_stream_session_t *s; - ngx_stream_ssl_conf_t *sslcf; + ngx_stream_ssl_srv_conf_t *sscf; ngx_stream_core_srv_conf_t *cscf; s = c->data; @@ -418,9 +425,9 @@ ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) } if (rc == NGX_AGAIN) { - sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); - ngx_add_timer(c->read, sslcf->handshake_timeout); + ngx_add_timer(c->read, sscf->handshake_timeout); c->ssl->handler = ngx_stream_ssl_handshake_handler; @@ -458,7 +465,112 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c) static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { + ngx_int_t rc; + ngx_str_t host; + const char *servername; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_ssl_srv_conf_t *sscf; + ngx_stream_core_srv_conf_t *cscf; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->handshaked) { + *ad = SSL_AD_NO_RENEGOTIATION; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + s = c->data; + + servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); + + if (servername == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL server name: null"); + goto done; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL server name: \"%s\"", servername); + + host.len = ngx_strlen(servername); + + if (host.len == 0) { + goto done; + } + + host.data = (u_char *) servername; + + rc = ngx_stream_validate_host(&host, c->pool, 1); + + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_DECLINED) { + goto done; + } + + rc = ngx_stream_find_virtual_server(s, &host, &cscf); + + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_DECLINED) { + goto done; + } + + s->srv_conf = cscf->ctx->srv_conf; + + ngx_set_connection_log(c, cscf->error_log); + + sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + + if (sscf->ssl.ctx) { + if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) { + goto error; + } + + /* + * SSL_set_SSL_CTX() only changes certs as of 1.0.0d + * adjust other things we care about + */ + + SSL_set_verify(ssl_conn, SSL_CTX_get_verify_mode(sscf->ssl.ctx), + SSL_CTX_get_verify_callback(sscf->ssl.ctx)); + + SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx)); + +#if OPENSSL_VERSION_NUMBER >= 0x009080dfL + /* only in 0.9.8m+ */ + SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) & + ~SSL_CTX_get_options(sscf->ssl.ctx)); +#endif + + SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx)); + +#ifdef SSL_OP_NO_RENEGOTIATION + SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION); +#endif + } + +done: + + sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + + if (sscf->reject_handshake) { + c->ssl->handshake_rejected = 1; + *ad = SSL_AD_UNRECOGNIZED_NAME; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + return SSL_TLSEXT_ERR_OK; + +error: + + *ad = SSL_AD_INTERNAL_ERROR; + return SSL_TLSEXT_ERR_ALERT_FATAL; } #endif @@ -513,7 +625,7 @@ ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) ngx_uint_t i, nelts; ngx_connection_t *c; ngx_stream_session_t *s; - ngx_stream_ssl_conf_t *sslcf; + ngx_stream_ssl_srv_conf_t *sscf; ngx_stream_complex_value_t *certs, *keys; c = ngx_ssl_get_connection(ssl_conn); @@ -524,11 +636,11 @@ ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) s = c->data; - sslcf = arg; + sscf = arg; - nelts = sslcf->certificate_values->nelts; - certs = sslcf->certificate_values->elts; - keys = sslcf->certificate_key_values->elts; + nelts = sscf->certificate_values->nelts; + certs = sscf->certificate_values->elts; + keys = sscf->certificate_key_values->elts; for (i = 0; i < nelts; i++) { @@ -547,7 +659,7 @@ ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) "ssl key: \"%s\"", key.data); if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, - sslcf->passwords) + sscf->passwords) != NGX_OK) { return 0; @@ -643,53 +755,53 @@ ngx_stream_ssl_add_variables(ngx_conf_t *cf) static void * -ngx_stream_ssl_create_conf(ngx_conf_t *cf) +ngx_stream_ssl_create_srv_conf(ngx_conf_t *cf) { - ngx_stream_ssl_conf_t *scf; + ngx_stream_ssl_srv_conf_t *sscf; - scf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_conf_t)); - if (scf == NULL) { + sscf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_srv_conf_t)); + if (sscf == NULL) { return NULL; } /* * set by ngx_pcalloc(): * - * scf->listen = 0; - * scf->protocols = 0; - * scf->certificate_values = NULL; - * scf->dhparam = { 0, NULL }; - * scf->ecdh_curve = { 0, NULL }; - * scf->client_certificate = { 0, NULL }; - * scf->trusted_certificate = { 0, NULL }; - * scf->crl = { 0, NULL }; - * scf->alpn = { 0, NULL }; - * scf->ciphers = { 0, NULL }; - * scf->shm_zone = NULL; + * sscf->protocols = 0; + * sscf->certificate_values = NULL; + * sscf->dhparam = { 0, NULL }; + * sscf->ecdh_curve = { 0, NULL }; + * sscf->client_certificate = { 0, NULL }; + * sscf->trusted_certificate = { 0, NULL }; + * sscf->crl = { 0, NULL }; + * sscf->alpn = { 0, NULL }; + * sscf->ciphers = { 0, NULL }; + * sscf->shm_zone = NULL; */ - scf->handshake_timeout = NGX_CONF_UNSET_MSEC; - scf->certificates = NGX_CONF_UNSET_PTR; - scf->certificate_keys = NGX_CONF_UNSET_PTR; - scf->passwords = NGX_CONF_UNSET_PTR; - scf->conf_commands = NGX_CONF_UNSET_PTR; - scf->prefer_server_ciphers = NGX_CONF_UNSET; - scf->verify = NGX_CONF_UNSET_UINT; - scf->verify_depth = NGX_CONF_UNSET_UINT; - 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; + sscf->handshake_timeout = NGX_CONF_UNSET_MSEC; + sscf->certificates = NGX_CONF_UNSET_PTR; + sscf->certificate_keys = NGX_CONF_UNSET_PTR; + sscf->passwords = NGX_CONF_UNSET_PTR; + sscf->conf_commands = NGX_CONF_UNSET_PTR; + sscf->prefer_server_ciphers = NGX_CONF_UNSET; + sscf->reject_handshake = NGX_CONF_UNSET; + sscf->verify = NGX_CONF_UNSET_UINT; + sscf->verify_depth = NGX_CONF_UNSET_UINT; + sscf->builtin_session_cache = NGX_CONF_UNSET; + sscf->session_timeout = NGX_CONF_UNSET; + sscf->session_tickets = NGX_CONF_UNSET; + sscf->session_ticket_keys = NGX_CONF_UNSET_PTR; - return scf; + return sscf; } static char * -ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) +ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { - ngx_stream_ssl_conf_t *prev = parent; - ngx_stream_ssl_conf_t *conf = child; + ngx_stream_ssl_srv_conf_t *prev = parent; + ngx_stream_ssl_srv_conf_t *conf = child; ngx_pool_cleanup_t *cln; @@ -702,6 +814,8 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->prefer_server_ciphers, prev->prefer_server_ciphers, 0); + ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0); + ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, (NGX_CONF_BITMASK_SET |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 @@ -735,37 +849,23 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; - if (!conf->listen) { + if (conf->certificates) { + + if (conf->certificate_keys == NULL + || conf->certificate_keys->nelts < conf->certificates->nelts) + { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\"", + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1); + return NGX_CONF_ERROR; + } + + } else if (!conf->reject_handshake) { return NGX_CONF_OK; } - if (conf->certificates == NULL) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate\" is defined for " - "the \"listen ... ssl\" directive in %s:%ui", - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - if (conf->certificate_keys == NULL) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined for " - "the \"listen ... ssl\" directive in %s:%ui", - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - if (conf->certificate_keys->nelts < conf->certificates->nelts) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\" and " - "the \"listen ... ssl\" directive in %s:%ui", - ((ngx_str_t *) conf->certificates->elts) - + conf->certificates->nelts - 1, - conf->file, conf->line); - return NGX_CONF_ERROR; - } - if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { return NGX_CONF_ERROR; } @@ -818,7 +918,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; #endif - } else { + } else if (conf->certificates) { /* configure certificates */ @@ -910,13 +1010,17 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, - ngx_stream_ssl_conf_t *conf) + ngx_stream_ssl_srv_conf_t *conf) { ngx_str_t *cert, *key; ngx_uint_t i, nelts; ngx_stream_complex_value_t *cv; ngx_stream_compile_complex_value_t ccv; + if (conf->certificates == NULL) { + return NGX_OK; + } + cert = conf->certificates->elts; key = conf->certificate_keys->elts; nelts = conf->certificates->nelts; @@ -995,19 +1099,19 @@ found: static char * ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_stream_ssl_conf_t *scf = conf; + ngx_stream_ssl_srv_conf_t *sscf = conf; ngx_str_t *value; - if (scf->passwords != NGX_CONF_UNSET_PTR) { + if (sscf->passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - scf->passwords = ngx_ssl_read_password_file(cf, &value[1]); + sscf->passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (scf->passwords == NULL) { + if (sscf->passwords == NULL) { return NGX_CONF_ERROR; } @@ -1018,7 +1122,7 @@ ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static char * ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_stream_ssl_conf_t *scf = conf; + ngx_stream_ssl_srv_conf_t *sscf = conf; size_t len; ngx_str_t *value, name, size; @@ -1030,17 +1134,17 @@ ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 1; i < cf->args->nelts; i++) { if (ngx_strcmp(value[i].data, "off") == 0) { - scf->builtin_session_cache = NGX_SSL_NO_SCACHE; + sscf->builtin_session_cache = NGX_SSL_NO_SCACHE; continue; } if (ngx_strcmp(value[i].data, "none") == 0) { - scf->builtin_session_cache = NGX_SSL_NONE_SCACHE; + sscf->builtin_session_cache = NGX_SSL_NONE_SCACHE; continue; } if (ngx_strcmp(value[i].data, "builtin") == 0) { - scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; + sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; } @@ -1055,7 +1159,7 @@ ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) goto invalid; } - scf->builtin_session_cache = n; + sscf->builtin_session_cache = n; continue; } @@ -1098,13 +1202,13 @@ ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - scf->shm_zone = ngx_shared_memory_add(cf, &name, n, + sscf->shm_zone = ngx_shared_memory_add(cf, &name, n, &ngx_stream_ssl_module); - if (scf->shm_zone == NULL) { + if (sscf->shm_zone == NULL) { return NGX_CONF_ERROR; } - scf->shm_zone->init = ngx_ssl_session_cache_init; + sscf->shm_zone->init = ngx_ssl_session_cache_init; continue; } @@ -1112,8 +1216,8 @@ ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) goto invalid; } - if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) { - scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; + if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) { + sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; } return NGX_CONF_OK; @@ -1132,14 +1236,14 @@ ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation - ngx_stream_ssl_conf_t *scf = conf; + ngx_stream_ssl_srv_conf_t *sscf = conf; u_char *p; size_t len; ngx_str_t *value; ngx_uint_t i; - if (scf->alpn.len) { + if (sscf->alpn.len) { return "is duplicate"; } @@ -1156,19 +1260,19 @@ ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) len += value[i].len + 1; } - scf->alpn.data = ngx_pnalloc(cf->pool, len); - if (scf->alpn.data == NULL) { + sscf->alpn.data = ngx_pnalloc(cf->pool, len); + if (sscf->alpn.data == NULL) { return NGX_CONF_ERROR; } - p = scf->alpn.data; + p = sscf->alpn.data; for (i = 1; i < cf->args->nelts; i++) { *p++ = value[i].len; p = ngx_cpymem(p, value[i].data, value[i].len); } - scf->alpn.len = len; + sscf->alpn.len = len; return NGX_CONF_OK; @@ -1195,8 +1299,13 @@ ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) static ngx_int_t ngx_stream_ssl_init(ngx_conf_t *cf) { - ngx_stream_handler_pt *h; - ngx_stream_core_main_conf_t *cmcf; + ngx_uint_t a, p, s; + ngx_stream_handler_pt *h; + ngx_stream_conf_addr_t *addr; + ngx_stream_conf_port_t *port; + ngx_stream_ssl_srv_conf_t *sscf; + ngx_stream_core_srv_conf_t **cscfp, *cscf; + ngx_stream_core_main_conf_t *cmcf; cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); @@ -1207,5 +1316,58 @@ ngx_stream_ssl_init(ngx_conf_t *cf) *h = ngx_stream_ssl_handler; + if (cmcf->ports == NULL) { + return NGX_OK; + } + + port = cmcf->ports->elts; + for (p = 0; p < cmcf->ports->nelts; p++) { + + addr = port[p].addrs.elts; + for (a = 0; a < port[p].addrs.nelts; a++) { + + if (!addr[a].opt.ssl) { + continue; + } + + cscf = addr[a].default_server; + sscf = cscf->ctx->srv_conf[ngx_stream_ssl_module.ctx_index]; + + if (sscf->certificates) { + continue; + } + + if (!sscf->reject_handshake) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"listen ... ssl\" directive in %s:%ui", + cscf->file_name, cscf->line); + return NGX_ERROR; + } + + /* + * if no certificates are defined in the default server, + * check all non-default server blocks + */ + + cscfp = addr[a].servers.elts; + for (s = 0; s < addr[a].servers.nelts; s++) { + + cscf = cscfp[s]; + sscf = cscf->ctx->srv_conf[ngx_stream_ssl_module.ctx_index]; + + if (sscf->certificates || sscf->reject_handshake) { + continue; + } + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"listen ... ssl\" directive in %s:%ui", + cscf->file_name, cscf->line); + return NGX_ERROR; + } + } + } + return NGX_OK; } diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index e7c825e..6f6d9ae 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -18,10 +18,10 @@ typedef struct { ngx_msec_t handshake_timeout; ngx_flag_t prefer_server_ciphers; + ngx_flag_t reject_handshake; ngx_ssl_t ssl; - ngx_uint_t listen; ngx_uint_t protocols; ngx_uint_t verify; @@ -53,10 +53,7 @@ typedef struct { ngx_flag_t session_tickets; ngx_array_t *session_ticket_keys; - - u_char *file; - ngx_uint_t line; -} ngx_stream_ssl_conf_t; +} ngx_stream_ssl_srv_conf_t; extern ngx_module_t ngx_stream_ssl_module; diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c index a236fc5..bc96ade 100644 --- a/src/stream/ngx_stream_ssl_preread_module.c +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -33,6 +33,8 @@ typedef struct { static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_ssl_preread_parse_record( ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); +static ngx_int_t ngx_stream_ssl_preread_servername(ngx_stream_session_t *s, + ngx_str_t *servername); static ngx_int_t ngx_stream_ssl_preread_protocol_variable( ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_preread_server_name_variable( @@ -187,6 +189,10 @@ ngx_stream_ssl_preread_handler(ngx_stream_session_t *s) return NGX_DECLINED; } + if (rc == NGX_OK) { + return ngx_stream_ssl_preread_servername(s, &ctx->host); + } + if (rc != NGX_AGAIN) { return rc; } @@ -404,9 +410,6 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, case sw_sni_host: ctx->host.len = (p[1] << 8) + p[2]; - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, - "ssl preread: SNI hostname \"%V\"", &ctx->host); - state = sw_ext; dst = NULL; size = ext; @@ -496,6 +499,54 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, } +static ngx_int_t +ngx_stream_ssl_preread_servername(ngx_stream_session_t *s, + ngx_str_t *servername) +{ + ngx_int_t rc; + ngx_str_t host; + ngx_connection_t *c; + ngx_stream_core_srv_conf_t *cscf; + + c = s->connection; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL preread server name: \"%V\"", servername); + + if (servername->len == 0) { + return NGX_OK; + } + + host = *servername; + + rc = ngx_stream_validate_host(&host, c->pool, 1); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + return NGX_OK; + } + + rc = ngx_stream_find_virtual_server(s, &host, &cscf); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + return NGX_OK; + } + + s->srv_conf = cscf->ctx->srv_conf; + + ngx_set_connection_log(c, cscf->error_log); + + return NGX_OK; +} + + static ngx_int_t ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s, ngx_variable_value_t *v, uintptr_t data) diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 8126890..4658104 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -29,6 +29,8 @@ static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_server_name(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s, @@ -91,6 +93,9 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { { ngx_string("server_port"), NULL, ngx_stream_variable_server_port, 0, 0, 0 }, + { ngx_string("server_name"), NULL, ngx_stream_variable_server_name, + 0, 0, 0 }, + { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes, 0, 0, 0 }, @@ -721,6 +726,24 @@ ngx_stream_variable_server_port(ngx_stream_session_t *s, } +static ngx_int_t +ngx_stream_variable_server_name(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_core_srv_conf_t *cscf; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + v->len = cscf->server_name.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = cscf->server_name.data; + + return NGX_OK; +} + + static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) From dd2f4866aa905e5e4ad8f9e1fb758c4e8fa76701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 17:42:53 +0200 Subject: [PATCH 31/89] d/changelog new version 1.26.0-1 --- debian/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 15fb8e3..cb98ace 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ -nginx (1.24.0-3) UNRELEASED; urgency=medium +nginx (1.26.0-1) UNRELEASED; urgency=medium + * New upstream version 1.26.0 * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, the key is used to sign the 1.26.0 release From 443e5c11eb9e9812386eb130d5cbdfb8400b3700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 17:44:10 +0200 Subject: [PATCH 32/89] nginx ABI release: nginx-abi-1.26.0-1 --- debian/changelog | 1 + debian/libnginx-mod.abisubstvars | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index cb98ace..8a4f9be 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * New upstream version 1.26.0 + * nginx ABI release: nginx-abi-1.26.0-1 * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, the key is used to sign the 1.26.0 release diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index 556875b..6455c05 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -5,7 +5,7 @@ # note that debian revision can increase without breaking ABI # # TODO: use $(DEB_VERSION_UPSTREAM) -nginx:abi=nginx-abi-1.24.0-1 +nginx:abi=nginx-abi-1.26.0-1 # ABI-compatible versions of third-party modules libnginx-mod-http-auth-pam:Version=1:1.5.3-4 From 0f09f394ed0ec41086e68a016b18d75e69ff21ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 17:52:34 +0200 Subject: [PATCH 33/89] d/p/CVE-2023-44487.patch remove, fixed in upstream --- debian/changelog | 1 + debian/patches/CVE-2023-44487.patch | 75 ----------------------------- debian/patches/series | 1 - 3 files changed, 1 insertion(+), 76 deletions(-) delete mode 100644 debian/patches/CVE-2023-44487.patch diff --git a/debian/changelog b/debian/changelog index 8a4f9be..fa0c808 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * nginx ABI release: nginx-abi-1.26.0-1 * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, the key is used to sign the 1.26.0 release + * d/p/CVE-2023-44487.patch remove, fixed in upstream -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 diff --git a/debian/patches/CVE-2023-44487.patch b/debian/patches/CVE-2023-44487.patch deleted file mode 100644 index 401f30b..0000000 --- a/debian/patches/CVE-2023-44487.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 6ceef192e7af1c507826ac38a2d43f08bf265fb9 Mon Sep 17 00:00:00 2001 -From: Maxim Dounin -Date: Tue, 10 Oct 2023 15:13:39 +0300 -Subject: [PATCH] HTTP/2: per-iteration stream handling limit. -Origin: https://github.com/nginx/nginx/commit/6ceef192e7af1c507826ac38a2d43f08bf265fb9 -Forwarded: not-needed - -To ensure that attempts to flood servers with many streams are detected -early, a limit of no more than 2 * max_concurrent_streams new streams per one -event loop iteration was introduced. This limit is applied even if -max_concurrent_streams is not yet reached - for example, if corresponding -streams are handled synchronously or reset. - -Further, refused streams are now limited to maximum of max_concurrent_streams -and 100, similarly to priority_limit initial value, providing some tolerance -to clients trying to open several streams at the connection start, yet -low tolerance to flooding attempts. ---- - src/http/v2/ngx_http_v2.c | 15 +++++++++++++++ - src/http/v2/ngx_http_v2.h | 2 ++ - 2 files changed, 17 insertions(+) - -Index: nginx/src/http/v2/ngx_http_v2.c -=================================================================== ---- nginx.orig/src/http/v2/ngx_http_v2.c -+++ nginx/src/http/v2/ngx_http_v2.c -@@ -361,6 +361,7 @@ ngx_http_v2_read_handler(ngx_event_t *re - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); - - h2c->blocked = 1; -+ h2c->new_streams = 0; - - if (c->close) { - c->close = 0; -@@ -1321,6 +1322,14 @@ ngx_http_v2_state_headers(ngx_http_v2_co - goto rst_stream; - } - -+ if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) { -+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, -+ "client sent too many streams at once"); -+ -+ status = NGX_HTTP_V2_REFUSED_STREAM; -+ goto rst_stream; -+ } -+ - if (!h2c->settings_ack - && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) - && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW) -@@ -1386,6 +1395,12 @@ ngx_http_v2_state_headers(ngx_http_v2_co - - rst_stream: - -+ if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) { -+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, -+ "client sent too many refused streams"); -+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR); -+ } -+ - if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) { - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); - } -Index: nginx/src/http/v2/ngx_http_v2.h -=================================================================== ---- nginx.orig/src/http/v2/ngx_http_v2.h -+++ nginx/src/http/v2/ngx_http_v2.h -@@ -124,6 +124,8 @@ struct ngx_http_v2_connection_s { - ngx_uint_t processing; - ngx_uint_t frames; - ngx_uint_t idle; -+ ngx_uint_t new_streams; -+ ngx_uint_t refused_streams; - ngx_uint_t priority_limit; - - ngx_uint_t pushing; diff --git a/debian/patches/series b/debian/patches/series index 48dd724..52e1dc4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,4 +1,3 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch -CVE-2023-44487.patch From 4c1fc35cb6024effa4f8e52710beb7aa22d7cc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 18:35:43 +0200 Subject: [PATCH 34/89] d/changelog update --- debian/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/changelog b/debian/changelog index fa0c808..49ccacb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, the key is used to sign the 1.26.0 release * d/p/CVE-2023-44487.patch remove, fixed in upstream + * d/ufw/nginx update, add QUICK, thanks Marcus Bointon -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 From a6a3352563ec92929361a3746a62cd497be25dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 18:42:05 +0200 Subject: [PATCH 35/89] d/changelog update --- debian/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/changelog b/debian/changelog index 49ccacb..bc20cac 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium the key is used to sign the 1.26.0 release * d/p/CVE-2023-44487.patch remove, fixed in upstream * d/ufw/nginx update, add QUICK, thanks Marcus Bointon + * d/conf/mime.types add application/xslt+xml, thanks K. Widholm -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 From 3fb6af3d349a44c2584724404441e67346cec198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 19:03:47 +0200 Subject: [PATCH 36/89] d/copyright: updated copyright related to new upstream version --- debian/changelog | 1 + debian/copyright | 47 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/debian/changelog b/debian/changelog index bc20cac..0421fb2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/p/CVE-2023-44487.patch remove, fixed in upstream * d/ufw/nginx update, add QUICK, thanks Marcus Bointon * d/conf/mime.types add application/xslt+xml, thanks K. Widholm + * d/copyright: updated copyright related to new upstream version -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 diff --git a/debian/copyright b/debian/copyright index 7fc2b36..f1c00c1 100644 --- a/debian/copyright +++ b/debian/copyright @@ -7,9 +7,9 @@ Copyright: Valentin V. Bartenev Ruslan Ermilov Roman Arutyunyan Maxim Dounin - 2011-2022, Nginx, Inc. + 2011-2024, Nginx, Inc. 2002-2021, Igor Sysoev - 2011-2022, Nginx, Inc. + 2011-2024, Nginx, Inc. 2002-2021, Igor Sysoev License: BSD-2-clause @@ -19,7 +19,7 @@ Copyright: Valentin V. Bartenev Ruslan Ermilov Roman Arutyunyan Maxim Dounin - 2011-2022, Nginx, Inc. + 2011-2024, Nginx, Inc. 2002-2021, Igor Sysoev License: BSD-2-clause @@ -46,7 +46,7 @@ Copyright: Valentin V. Bartenev Ruslan Ermilov Roman Arutyunyan Maxim Dounin - 2011-2022, Nginx, Inc. + 2011-2024, Nginx, Inc. 2002-2021, Igor Sysoev License: BSD-2-clause @@ -60,7 +60,7 @@ Copyright: Valentin V. Bartenev Ruslan Ermilov Roman Arutyunyan Maxim Dounin - 2011-2022, Nginx, Inc. + 2011-2024, Nginx, Inc. 2002-2021, Igor Sysoev License: BSD-2-clause @@ -111,6 +111,13 @@ Copyright: Nginx, Inc. Igor Sysoev License: BSD-2-clause +Files: src/core/ngx_bpf.c + src/core/ngx_bpf.h + src/core/ngx_syslog.c + src/core/ngx_syslog.h +Copyright: Nginx, Inc. +License: BSD-2-clause + Files: src/core/ngx_crypt.c Copyright: Maxim Dounin License: BSD-2-clause @@ -154,11 +161,6 @@ Copyright: Nginx, Inc. Maxim Dounin License: BSD-2-clause -Files: src/core/ngx_syslog.c - src/core/ngx_syslog.h -Copyright: Nginx, Inc. -License: BSD-2-clause - Files: src/core/ngx_thread_pool.c Copyright: Valentin V. Bartenev Ruslan Ermilov @@ -190,6 +192,25 @@ Files: src/event/ngx_event_udp.h Copyright: Nginx, Inc. License: BSD-2-clause +Files: src/event/quic/* +Copyright: Nginx, Inc. +License: BSD-2-clause + +Files: src/event/quic/bpf/* +Copyright: Nginx, Inc. + Igor Sysoev +License: BSD-2-clause + +Files: src/event/quic/ngx_event_quic_bpf_code.c +Copyright: Nginx, Inc. + Igor Sysoev +License: BSD-2-clause + +Files: src/event/quic/ngx_event_quic_udp.c +Copyright: Roman Arutyunyan + Nginx, Inc. +License: BSD-2-clause + Files: src/http/modules/ngx_http_auth_request_module.c src/http/modules/ngx_http_grpc_module.c src/http/modules/ngx_http_upstream_keepalive_module.c @@ -264,6 +285,11 @@ Copyright: Valentin V. Bartenev Nginx, Inc. License: BSD-2-clause +Files: src/http/v3/* +Copyright: Roman Arutyunyan + Nginx, Inc. +License: BSD-2-clause + Files: src/misc/* Copyright: Valentin V. Bartenev Ruslan Ermilov @@ -299,6 +325,7 @@ Files: src/stream/ngx_stream.c src/stream/ngx_stream.h src/stream/ngx_stream_core_module.c src/stream/ngx_stream_handler.c + src/stream/ngx_stream_pass_module.c src/stream/ngx_stream_proxy_module.c src/stream/ngx_stream_return_module.c src/stream/ngx_stream_upstream_hash_module.c From 7dc4f2ecb77a85279937bff4798ecc7268ca05e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 19:04:28 +0200 Subject: [PATCH 37/89] d/copyright: bump my copyright year --- debian/changelog | 1 + debian/copyright | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0421fb2..5b4943e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/ufw/nginx update, add QUICK, thanks Marcus Bointon * d/conf/mime.types add application/xslt+xml, thanks K. Widholm * d/copyright: updated copyright related to new upstream version + * d/copyright: bump my copyright year -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 diff --git a/debian/copyright b/debian/copyright index f1c00c1..816d187 100644 --- a/debian/copyright +++ b/debian/copyright @@ -69,7 +69,7 @@ Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause Files: debian/* -Copyright: 2022, 2023, Jan Mojžíš +Copyright: 2022-2024, Jan Mojžíš 2020-2022, Ondřej Nový 2019-2022, Thomas Ward 2013-2016, Christos Trochalakis From b023f3fbf654fcb582841f9f664bf05db0b79df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 30 Apr 2024 22:04:10 +0200 Subject: [PATCH 38/89] d/copyright update --- debian/copyright | 280 +---------------------------------------------- 1 file changed, 3 insertions(+), 277 deletions(-) diff --git a/debian/copyright b/debian/copyright index 816d187..7106e51 100644 --- a/debian/copyright +++ b/debian/copyright @@ -3,59 +3,6 @@ Upstream-Name: nginx Source: https://nginx.org/en/download.html Files: * -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Roman Arutyunyan - Maxim Dounin - 2011-2024, Nginx, Inc. - 2002-2021, Igor Sysoev - 2011-2024, Nginx, Inc. - 2002-2021, Igor Sysoev -License: BSD-2-clause - -Files: CHANGES - README -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Roman Arutyunyan - Maxim Dounin - 2011-2024, Nginx, Inc. - 2002-2021, Igor Sysoev -License: BSD-2-clause - -Files: auto/* -Copyright: Nginx, Inc. - Igor Sysoev -License: BSD-2-clause - -Files: auto/cc/clang -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: auto/module -Copyright: Ruslan Ermilov - Nginx, Inc. -License: BSD-2-clause - -Files: auto/threads -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: conf/* -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Roman Arutyunyan - Maxim Dounin - 2011-2024, Nginx, Inc. - 2002-2021, Igor Sysoev -License: BSD-2-clause - -Files: configure -Copyright: Nginx, Inc. - Igor Sysoev -License: BSD-2-clause - -Files: contrib/* Copyright: Valentin V. Bartenev Ruslan Ermilov Roman Arutyunyan @@ -93,160 +40,27 @@ Files: debian/debhelper/dh_nginx Copyright: 2016, Christos Trochalakis License: GPL-2+ -Files: debian/debhelper/nginx_mod.pm -Copyright: © 2022, Miao Wang -License: BSD-2-clause - -Files: debian/help/examples/nginx_modsite -Copyright: 2010, Michael Lustfield -License: BSD-2-clause +Files: debian/ngx-conf/ngx-conf +Copyright: 2015, Michael Lustfield +License: Expat Files: man/* Copyright: Nginx, Inc. 2010, 2019, Sergey A. Osokin License: BSD-2-clause -Files: src/* -Copyright: Nginx, Inc. - Igor Sysoev -License: BSD-2-clause - -Files: src/core/ngx_bpf.c - src/core/ngx_bpf.h - src/core/ngx_syslog.c - src/core/ngx_syslog.h -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: src/core/ngx_crypt.c -Copyright: Maxim Dounin -License: BSD-2-clause - -Files: src/core/ngx_md5.c -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Roman Arutyunyan - Maxim Dounin - 2011-2022, Nginx, Inc. - 2002-2021, Igor Sysoev -License: BSD-2-clause - -Files: src/core/ngx_module.c - src/core/ngx_module.h -Copyright: Nginx, Inc. - Maxim Dounin - Igor Sysoev -License: BSD-2-clause - Files: src/core/ngx_murmurhash.c Copyright: Austin Appleby License: public-domain All MurmurHash versions are public domain software, and the author disclaims all copyright to their code. -Files: src/core/ngx_proxy_protocol.c - src/core/ngx_proxy_protocol.h -Copyright: Roman Arutyunyan - Nginx, Inc. -License: BSD-2-clause - -Files: src/core/ngx_rwlock.c - src/core/ngx_rwlock.h -Copyright: Ruslan Ermilov - Nginx, Inc. -License: BSD-2-clause - -Files: src/core/ngx_sha1.c -Copyright: Nginx, Inc. - Maxim Dounin -License: BSD-2-clause - -Files: src/core/ngx_thread_pool.c -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Nginx, Inc. -License: BSD-2-clause - -Files: src/core/ngx_thread_pool.h -Copyright: Valentin V. Bartenev - Nginx, Inc. -License: BSD-2-clause - -Files: src/event/modules/ngx_win32_poll_module.c -Copyright: Nginx, Inc. - Maxim Dounin - Igor Sysoev -License: BSD-2-clause - -Files: src/event/ngx_event_openssl_stapling.c -Copyright: Nginx, Inc. - Maxim Dounin -License: BSD-2-clause - -Files: src/event/ngx_event_udp.c -Copyright: Roman Arutyunyan - Nginx, Inc. -License: BSD-2-clause - -Files: src/event/ngx_event_udp.h -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: src/event/quic/* -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: src/event/quic/bpf/* -Copyright: Nginx, Inc. - Igor Sysoev -License: BSD-2-clause - -Files: src/event/quic/ngx_event_quic_bpf_code.c -Copyright: Nginx, Inc. - Igor Sysoev -License: BSD-2-clause - -Files: src/event/quic/ngx_event_quic_udp.c -Copyright: Roman Arutyunyan - Nginx, Inc. -License: BSD-2-clause - -Files: src/http/modules/ngx_http_auth_request_module.c - src/http/modules/ngx_http_grpc_module.c - src/http/modules/ngx_http_upstream_keepalive_module.c - src/http/modules/ngx_http_upstream_least_conn_module.c -Copyright: Nginx, Inc. - Maxim Dounin -License: BSD-2-clause - -Files: src/http/modules/ngx_http_gunzip_filter_module.c -Copyright: Nginx, Inc. - Maxim Dounin - Igor Sysoev -License: BSD-2-clause - -Files: src/http/modules/ngx_http_mirror_module.c - src/http/modules/ngx_http_slice_filter_module.c - src/http/modules/ngx_http_upstream_hash_module.c -Copyright: Roman Arutyunyan - Nginx, Inc. -License: BSD-2-clause - Files: src/http/modules/ngx_http_scgi_module.c Copyright: Nginx, Inc. Manlio Perillo (manlio.perillo@gmail.com) Igor Sysoev License: BSD-2-clause -Files: src/http/modules/ngx_http_upstream_random_module.c -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: src/http/modules/ngx_http_upstream_zone_module.c -Copyright: Ruslan Ermilov - Nginx, Inc. -License: BSD-2-clause - Files: src/http/modules/ngx_http_uwsgi_module.c Copyright: Nginx, Inc. Igor Sysoev @@ -254,105 +68,17 @@ Copyright: Nginx, Inc. 2008, Manlio Perillo (manlio.perillo@gmail.com) License: BSD-2-clause -Files: src/http/modules/perl/typemap -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Roman Arutyunyan - Maxim Dounin - 2011-2022, Nginx, Inc. - 2002-2021, Igor Sysoev -License: BSD-2-clause - -Files: src/http/ngx_http_huff_decode.c -Copyright: Valentin V. Bartenev - Nginx, Inc. -License: BSD-2-clause - Files: src/http/ngx_http_huff_encode.c Copyright: Valentin V. Bartenev Nginx, Inc. 2015, Vlad Krasnov License: BSD-2-clause -Files: src/http/v2/* -Copyright: Valentin V. Bartenev - Nginx, Inc. -License: BSD-2-clause - -Files: src/http/v2/ngx_http_v2_filter_module.c -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Nginx, Inc. -License: BSD-2-clause - -Files: src/http/v3/* -Copyright: Roman Arutyunyan - Nginx, Inc. -License: BSD-2-clause - -Files: src/misc/* -Copyright: Valentin V. Bartenev - Ruslan Ermilov - Roman Arutyunyan - Maxim Dounin - 2011-2022, Nginx, Inc. - 2002-2021, Igor Sysoev -License: BSD-2-clause - -Files: src/misc/ngx_google_perftools_module.c -Copyright: Nginx, Inc. - Igor Sysoev -License: BSD-2-clause - -Files: src/os/unix/ngx_dlopen.c - src/os/unix/ngx_dlopen.h -Copyright: Nginx, Inc. - Maxim Dounin -License: BSD-2-clause - -Files: src/os/unix/ngx_setaffinity.c - src/os/unix/ngx_setaffinity.h -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: src/os/win32/ngx_dlopen.c - src/os/win32/ngx_dlopen.h -Copyright: Nginx, Inc. - Maxim Dounin -License: BSD-2-clause - -Files: src/stream/ngx_stream.c - src/stream/ngx_stream.h - src/stream/ngx_stream_core_module.c - src/stream/ngx_stream_handler.c - src/stream/ngx_stream_pass_module.c - src/stream/ngx_stream_proxy_module.c - src/stream/ngx_stream_return_module.c - src/stream/ngx_stream_upstream_hash_module.c -Copyright: Roman Arutyunyan - Nginx, Inc. -License: BSD-2-clause - Files: src/stream/ngx_stream_set_module.c Copyright: Pavel Pautov Nginx, Inc. License: BSD-2-clause -Files: src/stream/ngx_stream_ssl_preread_module.c - src/stream/ngx_stream_upstream_random_module.c -Copyright: Nginx, Inc. -License: BSD-2-clause - -Files: src/stream/ngx_stream_upstream_least_conn_module.c -Copyright: Nginx, Inc. - Maxim Dounin -License: BSD-2-clause - -Files: src/stream/ngx_stream_upstream_zone_module.c -Copyright: Ruslan Ermilov - Nginx, Inc. -License: BSD-2-clause - License: BSD-2-clause All rights reserved. . From 9b80dfac5a0aabcc90336aef3878166578e8fdc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 1 May 2024 05:33:34 +0200 Subject: [PATCH 39/89] d/conf/nginx.conf: add worker_cpu_affinity auto --- debian/changelog | 1 + debian/conf/nginx.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/debian/changelog b/debian/changelog index 5b4943e..9d745d9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/conf/mime.types add application/xslt+xml, thanks K. Widholm * d/copyright: updated copyright related to new upstream version * d/copyright: bump my copyright year + * d/conf/nginx.conf: add worker_cpu_affinity auto (Closes: 1063659) -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index f52668a..d72573c 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -1,5 +1,6 @@ user www-data; worker_processes auto; +worker_cpu_affinity auto; pid /run/nginx.pid; error_log /var/log/nginx/error.log; include /etc/nginx/modules-enabled/*.conf; From 5c050148b66589785a7ef6b3d0047492cce8daf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 1 May 2024 05:35:33 +0200 Subject: [PATCH 40/89] d/changelog update --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 9d745d9..a5318bd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * New upstream version 1.26.0 - * nginx ABI release: nginx-abi-1.26.0-1 + * nginx ABI release: nginx-abi-1.26.0-1 (Closes: 1069997) * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, the key is used to sign the 1.26.0 release * d/p/CVE-2023-44487.patch remove, fixed in upstream From 2148a071bfa0dab4643f4b15dcd1f710ee961a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 1 May 2024 06:28:55 +0200 Subject: [PATCH 41/89] d/libnginx-mod.abisubstvars: remove third-party modules version constraints --- debian/changelog | 1 + debian/control | 42 ++++++++++++++++---------------- debian/libnginx-mod.abisubstvars | 15 ------------ 3 files changed, 22 insertions(+), 36 deletions(-) diff --git a/debian/changelog b/debian/changelog index a5318bd..46baa56 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * New upstream version 1.26.0 * nginx ABI release: nginx-abi-1.26.0-1 (Closes: 1069997) + * d/libnginx-mod.abisubstvars: remove third-party modules version constraints * d/u/signing-key.asc add Roman Arutyunyan’s PGP public key, the key is used to sign the 1.26.0 release * d/p/CVE-2023-44487.patch remove, fixed in upstream diff --git a/debian/control b/debian/control index a1fcbe9..2f6df9f 100644 --- a/debian/control +++ b/debian/control @@ -123,13 +123,13 @@ Description: nginx web/proxy server (standard version) Package: nginx-full Architecture: all -Depends: libnginx-mod-http-auth-pam (>= ${libnginx-mod-http-auth-pam:Version}~), - libnginx-mod-http-dav-ext (>= ${libnginx-mod-http-dav-ext:Version}~), - libnginx-mod-http-echo (>= ${libnginx-mod-http-echo:Version}~), - libnginx-mod-http-geoip2 (>= ${libnginx-mod-geoip2:Version}~), - libnginx-mod-http-subs-filter (>= ${libnginx-mod-http-subs-filter:Version}~), - libnginx-mod-http-upstream-fair (>= ${libnginx-mod-http-upstream-fair:Version}~), - libnginx-mod-stream-geoip2 (>= ${libnginx-mod-geoip2:Version}~), +Depends: libnginx-mod-http-auth-pam, + libnginx-mod-http-dav-ext, + libnginx-mod-http-echo, + libnginx-mod-http-geoip2, + libnginx-mod-http-subs-filter, + libnginx-mod-http-upstream-fair, + libnginx-mod-stream-geoip2, nginx (>= ${source:Version}), nginx (<< ${source:Version}.1~), ${misc:Depends}, @@ -161,7 +161,7 @@ Description: nginx web/proxy server (standard version with 3rd parties) Package: nginx-light Architecture: all -Depends: libnginx-mod-http-echo (>= ${libnginx-mod-http-echo:Version}~), +Depends: libnginx-mod-http-echo, nginx (>= ${source:Version}), nginx (<< ${source:Version}.1~), ${misc:Depends}, @@ -193,19 +193,19 @@ Depends: nginx (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), libnginx-mod-stream-geoip (= ${binary:Version}), - libnginx-mod-http-auth-pam (>= ${libnginx-mod-http-auth-pam:Version}~), - libnginx-mod-http-cache-purge (>= ${libnginx-mod-http-cache-purge:Version}~), - libnginx-mod-http-dav-ext (>= ${libnginx-mod-http-dav-ext:Version}~), - libnginx-mod-http-echo (>= ${libnginx-mod-http-echo:Version}~), - libnginx-mod-http-fancyindex (>= ${libnginx-mod-http-fancyindex:Version}~), - libnginx-mod-http-geoip2 (>= ${libnginx-mod-geoip2:Version}~), - libnginx-mod-http-headers-more-filter (>= ${libnginx-mod-http-headers-more-filter:Version}~), - libnginx-mod-http-lua (>=${libnginx-mod-http-lua:Version}~) [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], - libnginx-mod-http-subs-filter (>= ${libnginx-mod-http-subs-filter:Version}~), - libnginx-mod-http-uploadprogress (>= ${libnginx-mod-http-uploadprogress:Version}~), - libnginx-mod-http-upstream-fair (>= ${libnginx-mod-http-upstream-fair:Version}~), - libnginx-mod-nchan (>= ${libnginx-mod-nchan:Version}~), - libnginx-mod-stream-geoip2 (>= ${libnginx-mod-geoip2:Version}~), + libnginx-mod-http-auth-pam, + libnginx-mod-http-cache-purge, + libnginx-mod-http-dav-ext, + libnginx-mod-http-echo, + libnginx-mod-http-fancyindex, + libnginx-mod-http-geoip2, + libnginx-mod-http-headers-more-filter, + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], + libnginx-mod-http-subs-filter, + libnginx-mod-http-uploadprogress, + libnginx-mod-http-upstream-fair, + libnginx-mod-nchan, + libnginx-mod-stream-geoip2, ${misc:Depends}, ${shlibs:Depends} Description: nginx web/proxy server (extended version) diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index 6455c05..2b3d99d 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -6,18 +6,3 @@ # # TODO: use $(DEB_VERSION_UPSTREAM) nginx:abi=nginx-abi-1.26.0-1 - -# ABI-compatible versions of third-party modules -libnginx-mod-http-auth-pam:Version=1:1.5.3-4 -libnginx-mod-http-cache-purge:Version=1:2.3-5 -libnginx-mod-http-dav-ext:Version=1:3.0.0-4 -libnginx-mod-http-echo:Version=1:0.63-5 -libnginx-mod-http-fancyindex:Version=1:0.5.2-4 -libnginx-mod-http-geoip2:Version=1:3.4-4 -libnginx-mod-http-headers-more-filter:Version=1:0.34-4 -libnginx-mod-http-lua:Version=1:0.10.23-2 -libnginx-mod-http-subs-filter:Version=1:0.6.4-5 -libnginx-mod-http-uploadprogress:Version=1:0.9.2-4 -libnginx-mod-http-upstream-fair:Version=1:0.0~git20120408.a18b409-4 -libnginx-mod-nchan:Version=1:1.3.6+dfsg-3 -libnginx-mod-geoip2:Version=1:3.4-4 From f5ed2727e51e4a26335493db5a31555f145769e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 1 May 2024 06:46:13 +0200 Subject: [PATCH 42/89] debian/upstream/signing-key.asc remove extra signatures --- debian/upstream/signing-key.asc | 125 ++++++++++---------------------- 1 file changed, 38 insertions(+), 87 deletions(-) diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc index 4b7818c..0264a10 100644 --- a/debian/upstream/signing-key.asc +++ b/debian/upstream/signing-key.asc @@ -122,91 +122,42 @@ qftDsCTQhssP1MHJWlejeqPlND3iT2vBDeOxqd6WhKuAc+L04iyBB6p867pwrgDF ecg82DPehsAnO2XBAFuIE/SLewkYm0B9HK7/J4LZqPwTAksPf/dnbMAmHWoBDqsu 4U4U4SsJKsZ87R9ao8qO7IWCzHrXavHFmnbqweFfHToeKF/L4PB+tYoW3YmUOged CglpJv13bNWmRwL7+x8b7BwpVwClxHBHteDX4RIN5iPH9h20J4jIpzRa1kNJsTu1 -v4ZkqLWJlkiiiQEzBBABCAAdFiEEcziXMGntP0Q/TTffpk/VsXrbOagFAmYdpjsA -CgkQpk/VsXrbOahISgf/U7ZO0yK0PsOcAFTB0TQBCNsAhxtJAEJoVoweuYiLk8jR -0OeDRCy0BC//qWDLFT7NKuP50SM2u0Csbg+n6b0bdy+vXbbGVzIAYzG09rPYe2Q5 -qwqyAx+MMzyICXul9lGNU2qN2qjUXMb0mCWUhxwMvzRUeS7shT1CBhGrnpoYkY56 -NhWj7iG1BbLwYVQzDZC/Rp6rvwJQgZo7+DjaMjryGAEI0ujpUp8ywrPaJpwIuXDI -D5BhcyUaEd3XOondHQNedlgERXHT4pN+oNMPWwN3+DeQYLS3FHiqyz05ZvoeWnao -A2/fWNA+BqIdjilp/TDDI4Ef7c9hp13weaZggYB3M4kBMwQQAQgAHRYhBFc7/Ws9 -j7xkEHmmq6v1vYJ72b9iBQJmHabkAAoJEKv1vYJ72b9iDgoIAP1QJjl4ynLAV9Bo -Ol4AAzxZ3x/2NEgLSnjLfhb/OduDxQlL9oPulWoLDG41xiZJkepEnQWmSsIYF6Xe -RsAB+eREU2uCxqCvBXpyIs5npXvVDV2/PQuVEop7HByx6Hjr9XK8hugihnEi1p+9 -Ecbu+89fi93m3C/5uIIil46cHByjRZ+5Yy1UFUB/wsYud1qMcYmvDaqEo5AqWNcM -gWUFhUfgGTtBbyvIWTeX0NHnrbzHP7lhmPfWsfOjAtO8PpM8Gz5RdNRq44DdRKdG -uWVby/kni868H+8/tHalDR0I9/Mmg2Uax0eggTVpECv/4+xBduqSB2iPwgRnSzhZ -6SVKJvKJAjMEEAEIAB0WIQT5TVS8DF1qZBfIzz/oLBEYr5TfbgUCZh5KVgAKCRDo -LBEYr5TfbitgD/wMamMFfFZnPS7JS1NWEMb5fbhHob1EkmedIpbpRDXUtj0ksehW -ZAEpmVF9btqS4B+B9tSK1VS2sy4XwEGodNVSGxdtF9W8+iAHAb6Hq1Z7ifWyb991 -Kt/pVk/8adxlU4G8h1fq0idhpnI8KvkAlPJR7+PoJOEN1+VdHS6tkE5LMTf6dF9F -iVxKQczOS1b/GmfL3kYfu6UvI07ZuaP+90mOt/TZTwkzsWjRY2vofCIPSDY94rLj -m6PmVFoU3PHLKW7yDz1YXkVE6SgQYGZ2bqB6OHJZnDXUTSHncHTbDVzZQekIs1lP -V6e5N8Xo/VOpv28feKAsBqQ8ML53djmGUL0azjEz1g2kgPmTuZdKzZ5kcUsULdQV -aRKcfyYD1oRpwwlw9GJAxliJHck1IdGGaCslrHtzkh3RMULlloAYitzD9jtKsrOj -R19s+JK/tIfFZZ5gR5qhzgOL8WgkSrIaq2o9R4sigBz1IxnXXC573RDA2F5FAeE/ -K6EmAO+BqVkImZcmP1JsLtr+OM+jihXIILACEJwhOKPtZth9zrLYkXWB1nCaDxHp -XEUpp6UPCQNgNX8NCghnJr5gis/SmYppgFlO9R9yZ7/LtP0tUX0CmhOeqGMnHt4R -F8n8D7EBwMWvWjlUbsDkMKX4JORgojguHJZciWQC1gVRwJ0iTH/ImtzDnbQhUm9t -YW4gQXJ1dHl1bnlhbiA8YXJ1dEBuZ2lueC5jb20+iQJOBBMBCAA4FiEEQzh4Jd2x -u5fsNrpdAHyNfBXYc2kFAmYXyiQCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AA -CgkQAHyNfBXYc2kRFw//VFuCnW3EwoLCWWgWCikgI9kbVDr0/Qiyf2Gb9sfOyzBN -q/+ZGjTs7EqTHbYUiCTgjy8t0SNKizoCXjSWLToTAXhOeTY3wDuHkdc3C2OPMPgm -HPGmdnfplmsZjj689sy0MTnlLmU/87texR/f3REAKtchVjo5AojuZxXJi+ryBvoz -KXi82M1JaYlIr15T+OiRtfZ3cgfTkb5CRa0YRV7QQ1zhOiF0AFKVVikFwRuquphT -y2cSLILLzOpwG/CjMJzO4VOASmGJmdicIfYSsZSzz37RrcfeYwR6quJ55Y9QF9IU -fg5AHWufpXaf6FbMsW1U1mOq0tMvwvdcO+u5I5SBj6IkqO4zavmW/i5zkxaq96wF -Qn6+oRkqHnNNn0hl/B4MWdEjDJsaDXfkQ3Snn4Bfl1JPT6cH2NDVYQn1siIOim/W -G5lhGLNB1TOAVLHblQ2xILadK0T33y6lfRUV3BOW01BDoF0ndyd7LjG5Di/cjfSo -1hvhTkW7QJGfzVV4IAAxEyHKlmgONfggZoplqukuPsq7eNNRPhvlZq632QXIqt6Y -xE43Nk0O41rX/tWtB7eNcPvfNOc+sGljnCSwpRWyx9xO7plELVD9KdtcyHrIgora -Flh7KsSbppSQ/iUKRNP+lfCQsMa1yrnQyxazss8OGlB7YpUJL4trQW35f/jXFD+J -ATMEEAEIAB0WIQRzOJcwae0/RD9NN9+mT9Wxets5qAUCZh2mQQAKCRCmT9Wxets5 -qPBjB/0SDkET7h/Vw2PJKxuYujsL+tn3SKXshgyCM2u00njJM9TqpZbZV681unKM -l8uHtj9b0Z4U0nHoNEC37wI5FJlxy1hLBw5f2fd/yi8LsD1KP2htjMUW+I2xjcdo -FusQsIF0s8SyW1DZ3vvN2WcZpKHwub1sY9ZFBfxRc6w+33N4dJwXVXP57kj3Ci8j -LDLfkaKyiuYgMtFYZiKKX0tfvaM5pXxLvLOzma9vwfjIMIllooZHDSI65jrbmMv0 -rfDKOX9Ws5Xi8n85jq6Oyq28QPLZUsmymCbhvBwq4FcdiyTl9sxCY4HLq0MzmJJ5 -DMhlFd2Ds3BopFTWCB2fvYyVoXRaiQEzBBABCAAdFiEEVzv9az2PvGQQeaarq/W9 -gnvZv2IFAmYdpugACgkQq/W9gnvZv2Jk4Qf+N0P/7FIHowlO01XmBB5KaztBmVb2 -Tj+jtYgPDHRf86O0kW40Rjx++zMlIRNWK4Ue5PKAi82Yue5uvZcVlpWpx/sMvL+N -C4Xds3Q3qnkxkoemoIMqUKGvePjBpyUWArBkBQ3FrvZtywnzyFWNrvOpeM+5HIuz -WBri/SHBHzQm1/Jl2r5pHcbUdSxB2o1v3f+SaS2vGxwigIf8v44pRfyeWgkoxYgN -+2zR0Ing6URZCYkAbwILsmmWGxJIuq+N9Xs1CQ1WZd5S78p/JBMDQ1prUDLCLFMc -AvlZpQ0HvzEbKGiIVNa1LEQRF4ZWjQOHaPJhg/D3r/Q7VaFlgsOqrwtQaYkCMwQQ -AQgAHRYhBPlNVLwMXWpkF8jPP+gsERivlN9uBQJmHkpZAAoJEOgsERivlN9u8fYQ -AK0s0CvQNTXrg/Oe92Ajj+CpFIGhEUgXsufpg3OF+4doXOoRrVcv6y/0dGC+u899 -Qiz5rzP8JkgT3Bvs/oFbQnESX7zob/GuBiRAnaanQQGjQsc8tXUcIgIB8vZI6Hxr -BZYyjXMrc1fAp1zy6F3YfVtjntp6Zt740zlcFSHPL6pKeNC8lCas7f7EPGm9ERlf -XvPOsMyKVDRTrtYVrQ17pgmWzMFl9eYzAV81X/cK7O9BmTvLb9HB9THl9QM6iKWd -UPNNhMseMA55i1y1trvv2rQSP2tm7xAijlffNu/LHyVjOJA+63rk9JqpQi2O/sI6 -naCZ5kLky3+OisbzJLtsIv3KWGF4jnpZJwPI97UbRAxrBCPd8BDXW06qQ0xfF9GA -sW46IDnf5uNV5Fj9T1IhZUUCU6XwwhcTENwcaJ2hubPzW19gvxieRpxdvnXhjUxR -UgqgFjtlpyBSABYr2REiaBTHkR1qVMa8tThpSyzfmfBNe9chBGQBdDMzTTUDf4dU -cw4UGGPXqrBEapleoZBszXLrZxQxCNmLGFBW3vcJDfRRTvg/OMCIwD72kfd8KY1t -SRRi5vQ3CvV8E0EEXshjxVk0fwS+5muM1thWZM4xCSgyH6Ka/5biMeUv1VNcKJne -J51xs9jfS/JltrT/ahWG4J9msJFtmYyrLh/nMxccXK75uQINBGYXyiQBEAC5tT5O -uysy75BcwAg8jIK+Cw6hNy+riOoCIzsMen8ps4tyDFLmRdpJmVOpmtvESaix2MHf -Hc/t9hOsQ8LmF3kDG/JisDXcB/v28EOiDpp5Ug/5UOFBnbu4DkxbakJF8KF/rQ9t -i29lt03saGCf2XbqzTLI6FvZ2TT8hDwAZF5aOtDEHV3ChBPn6gplnJADiZ9DioMZ -ji1HnL8Zu4IYHMNOgpxULi6TMhBH/MkHbyycOdt/EsQFamnLGeV8KR2fubYjrpbH -pLZzSRepQyvKIhHAFj6DUeDyEt2XAitxI8YI40IVO75Zu8ZZq0qYGML8Am+t6ZjJ -3ZR8/DWjxRUYeo+YVEe5f+oRl5GRNkLtGvTAD38Nb2/7SUYdSXA3y3Ocfo/bySwa -qggeFpDqK5eHXmrO4hvRqYoEyNyW4VQlGyvYq4s2cLeCF/S2w6dV8OFsksIoq8uq -R1/IQ8Bonsf7iAYpsMAZZOGKiJzr01W3GA4Ka3B/MmZP5CysUhFlFxMsDr3/TWfg -p3CHd5yGAnuWWWkjqVQzx0tcub3gyDsHCPuws8P2OKJ2lzNPqpp08MjYMMRZb4Y6 -9REXkKw7kXU8zM5+1IpW2U+z83NU86QR08PTpjATz05ltdGqF82Z+Ygl2nav8oqV -RqNd/k+WE60e1eJmgykjmz6nPbm0S2jt1C7QLQARAQABiQI2BBgBCAAgFiEEQzh4 -Jd2xu5fsNrpdAHyNfBXYc2kFAmYXyiQCGwwACgkQAHyNfBXYc2mTihAAqB+sv9lw -kRorE6iXwvvj2Dt2iIy7jc1AhZQOH/j7B4GHpV3Ej/ptdUwuzj/aX5EnEeDPZ2JU -sSKy2q0RpKGKdKOvgy5yVfd8xqujkawXv26QU53mgyfgQCZLhFFhq0MIAqnxPb8h -SCQeol18Wqs++LjeDMwkgMrHJeNhW2U2llqTS37YfRMOo0Vr022ZHlMlkyMz1sQH -+C2/nzmmtkI4+vlPeccoN+3239YzndW1+XM8S3dXNcsGTyLAbkCowfpuqQdIP0MY -lBwx/Xj9fxBNAuqGVCjrjGMg7mozMkeCDzrAoZiaD3Kud8zSs9VpAyAymrPQJSSS -96b+vr2mDKbV11QJeJZv/d02n4JMjK7Ai//3j/TqkJF4UoYH45g5hvGSrym1UKrf -n8TqHdtTFjcxAMXLbWICHdDk7/0ole8Bl8csiSHyKy/sGJ0b/7zcB88CS8OfsR3C -OanK13emeD6rHOp8wEWA1/PA1JoAC5suS/uIgPWa5ujLaViJ9pW6ohfzMqOtLABF -BB/FgD/qgPF+uTPPLQZw3XO8Q61kFq6x0RJGNgBEOpseounx+T6FCxZqrvjWm/WK -VQUiRBtJIvD7Z8UCP+NUzdj3hwLAXpXrPz0gkcbI+hdlTJHCC6i61Qf5OIWnhtw6 -kZv2zEcTtzlAYNEumy8KrJzICmPLS7BEC8w= -=ilJ3 +v4ZkqLWJlkiitCFSb21hbiBBcnV0eXVueWFuIDxhcnV0QG5naW54LmNvbT6JAk4E +EwEIADgWIQRDOHgl3bG7l+w2ul0AfI18FdhzaQUCZhfKJAIbAwULCQgHAgYVCgkI +CwIEFgIDAQIeAQIXgAAKCRAAfI18FdhzaREXD/9UW4KdbcTCgsJZaBYKKSAj2RtU +OvT9CLJ/YZv2x87LME2r/5kaNOzsSpMdthSIJOCPLy3RI0qLOgJeNJYtOhMBeE55 +NjfAO4eR1zcLY48w+CYc8aZ2d+mWaxmOPrz2zLQxOeUuZT/zu17FH9/dEQAq1yFW +OjkCiO5nFcmL6vIG+jMpeLzYzUlpiUivXlP46JG19ndyB9ORvkJFrRhFXtBDXOE6 +IXQAUpVWKQXBG6q6mFPLZxIsgsvM6nAb8KMwnM7hU4BKYYmZ2Jwh9hKxlLPPftGt +x95jBHqq4nnlj1AX0hR+DkAda5+ldp/oVsyxbVTWY6rS0y/C91w767kjlIGPoiSo +7jNq+Zb+LnOTFqr3rAVCfr6hGSoec02fSGX8HgxZ0SMMmxoNd+RDdKefgF+XUk9P +pwfY0NVhCfWyIg6Kb9YbmWEYs0HVM4BUsduVDbEgtp0rRPffLqV9FRXcE5bTUEOg +XSd3J3suMbkOL9yN9KjWG+FORbtAkZ/NVXggADETIcqWaA41+CBmimWq6S4+yrt4 +01E+G+VmrrfZBciq3pjETjc2TQ7jWtf+1a0Ht41w+9805z6waWOcJLClFbLH3E7u +mUQtUP0p21zIesiCitoWWHsqxJumlJD+JQpE0/6V8JCwxrXKudDLFrOyzw4aUHti +lQkvi2tBbfl/+NcUP7kCDQRmF8okARAAubU+TrsrMu+QXMAIPIyCvgsOoTcvq4jq +AiM7DHp/KbOLcgxS5kXaSZlTqZrbxEmosdjB3x3P7fYTrEPC5hd5AxvyYrA13Af7 +9vBDog6aeVIP+VDhQZ27uA5MW2pCRfChf60PbYtvZbdN7Ghgn9l26s0yyOhb2dk0 +/IQ8AGReWjrQxB1dwoQT5+oKZZyQA4mfQ4qDGY4tR5y/GbuCGBzDToKcVC4ukzIQ +R/zJB28snDnbfxLEBWppyxnlfCkdn7m2I66Wx6S2c0kXqUMryiIRwBY+g1Hg8hLd +lwIrcSPGCONCFTu+WbvGWatKmBjC/AJvremYyd2UfPw1o8UVGHqPmFRHuX/qEZeR +kTZC7Rr0wA9/DW9v+0lGHUlwN8tznH6P28ksGqoIHhaQ6iuXh15qzuIb0amKBMjc +luFUJRsr2KuLNnC3ghf0tsOnVfDhbJLCKKvLqkdfyEPAaJ7H+4gGKbDAGWThioic +69NVtxgOCmtwfzJmT+QsrFIRZRcTLA69/01n4Kdwh3echgJ7lllpI6lUM8dLXLm9 +4Mg7Bwj7sLPD9jiidpczT6qadPDI2DDEWW+GOvURF5CsO5F1PMzOftSKVtlPs/Nz +VPOkEdPD06YwE89OZbXRqhfNmfmIJdp2r/KKlUajXf5PlhOtHtXiZoMpI5s+pz25 +tEto7dQu0C0AEQEAAYkCNgQYAQgAIBYhBEM4eCXdsbuX7Da6XQB8jXwV2HNpBQJm +F8okAhsMAAoJEAB8jXwV2HNpk4oQAKgfrL/ZcJEaKxOol8L749g7doiMu43NQIWU +Dh/4+weBh6VdxI/6bXVMLs4/2l+RJxHgz2diVLEistqtEaShinSjr4MuclX3fMar +o5GsF79ukFOd5oMn4EAmS4RRYatDCAKp8T2/IUgkHqJdfFqrPvi43gzMJIDKxyXj +YVtlNpZak0t+2H0TDqNFa9NtmR5TJZMjM9bEB/gtv585prZCOPr5T3nHKDft9t/W +M53VtflzPEt3VzXLBk8iwG5AqMH6bqkHSD9DGJQcMf14/X8QTQLqhlQo64xjIO5q +MzJHgg86wKGYmg9yrnfM0rPVaQMgMpqz0CUkkvem/r69pgym1ddUCXiWb/3dNp+C +TIyuwIv/94/06pCReFKGB+OYOYbxkq8ptVCq35/E6h3bUxY3MQDFy21iAh3Q5O/9 +KJXvAZfHLIkh8isv7BidG/+83AfPAkvDn7Edwjmpytd3png+qxzqfMBFgNfzwNSa +AAubLkv7iID1muboy2lYifaVuqIX8zKjrSwARQQfxYA/6oDxfrkzzy0GcN1zvEOt +ZBausdESRjYARDqbHqLp8fk+hQsWaq741pv1ilUFIkQbSSLw+2fFAj/jVM3Y94cC +wF6V6z89IJHGyPoXZUyRwguoutUH+TiFp4bcOpGb9sxHE7c5QGDRLpsvCqycyApj +y0uwRAvM +=atsZ -----END PGP PUBLIC KEY BLOCK----- From 880afec3d70c49ba5c17b1dccdc85c1028dbadff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 1 May 2024 06:48:05 +0200 Subject: [PATCH 43/89] d/changelog fix whitespace --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 46baa56..2589f9b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,7 +9,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/ufw/nginx update, add QUICK, thanks Marcus Bointon * d/conf/mime.types add application/xslt+xml, thanks K. Widholm * d/copyright: updated copyright related to new upstream version - * d/copyright: bump my copyright year + * d/copyright: bump my copyright year * d/conf/nginx.conf: add worker_cpu_affinity auto (Closes: 1063659) -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 From 2d4405e08a97826722785acd595b6011fb61a419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 1 May 2024 12:18:01 +0200 Subject: [PATCH 44/89] d/gbp.conf: add sign-tags = True, [pull] track-missing = True, [import-orig] merge-mode = replace --- debian/changelog | 2 ++ debian/gbp.conf | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 2589f9b..3f5f042 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/copyright: updated copyright related to new upstream version * d/copyright: bump my copyright year * d/conf/nginx.conf: add worker_cpu_affinity auto (Closes: 1063659) + * d/gbp.conf: add sign-tags = True, [pull] track-missing = True, + [import-orig] merge-mode = replace -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 diff --git a/debian/gbp.conf b/debian/gbp.conf index 49473cf..97cd209 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -1,5 +1,12 @@ [DEFAULT] debian-branch = main -pristine-tar = True upstream-branch = upstream upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace + +[pull] +track-missing = True From 6ccf66d20e676adb7df510d82be575cf4d1ee875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 5 May 2024 18:49:07 +0200 Subject: [PATCH 45/89] release nginx 1.26.0-1, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3f5f042..a3ccd3e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.26.0-1) UNRELEASED; urgency=medium +nginx (1.26.0-1) unstable; urgency=medium * New upstream version 1.26.0 * nginx ABI release: nginx-abi-1.26.0-1 (Closes: 1069997) @@ -14,7 +14,7 @@ nginx (1.26.0-1) UNRELEASED; urgency=medium * d/gbp.conf: add sign-tags = True, [pull] track-missing = True, [import-orig] merge-mode = replace - -- Jan Mojžíš Tue, 30 Apr 2024 17:40:59 +0200 + -- Jan Mojžíš Sun, 05 May 2024 18:48:05 +0200 nginx (1.24.0-2) unstable; urgency=medium From 5651e6f455f4eeb45e856e8337a9f4e789382e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 7 May 2024 19:12:06 +0200 Subject: [PATCH 46/89] d/rules: enable QUIC and HTTP/3 module --- debian/changelog | 6 ++++++ debian/rules | 1 + 2 files changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index a3ccd3e..8ed3f90 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.26.0-2) UNRELEASED; urgency=medium + + * d/rules: enable QUIC and HTTP/3 module (Closes: 1070488) + + -- Jan Mojžíš Tue, 07 May 2024 19:09:56 +0200 + nginx (1.26.0-1) unstable; urgency=medium * New upstream version 1.26.0 diff --git a/debian/rules b/debian/rules index 1d037dd..7b56607 100755 --- a/debian/rules +++ b/debian/rules @@ -42,6 +42,7 @@ basic_configure_flags := \ --with-http_realip_module \ --with-http_auth_request_module \ --with-http_v2_module \ + --with-http_v3_module \ --with-http_dav_module \ --with-http_slice_module \ --with-threads From 9ede767588de8085c5a219e6081d99e37632893a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 7 May 2024 19:12:52 +0200 Subject: [PATCH 47/89] d/control: bump Standards-Version: 4.7.0, no changes --- debian/changelog | 1 + debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 8ed3f90..1842f18 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium * d/rules: enable QUIC and HTTP/3 module (Closes: 1070488) + * d/control: bump Standards-Version: 4.7.0, no changes -- Jan Mojžíš Tue, 07 May 2024 19:09:56 +0200 diff --git a/debian/control b/debian/control index 2f6df9f..1b1a145 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Build-Depends: debhelper-compat (= 13), libxslt1-dev, po-debconf, zlib1g-dev -Standards-Version: 4.6.2 +Standards-Version: 4.7.0 Homepage: https://nginx.org Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx From 3e7838a6b214e430dadaecf931c1f1531c636581 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 17 Jun 2024 15:43:12 +0000 Subject: [PATCH 48/89] Update nginx.conf defaults - Match current security practices for SSL protocols and SSL Prefer Server Ciphers - Hide NGINX version in responses, modern security practice --- debian/conf/nginx.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index d72573c..594c93e 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -19,7 +19,7 @@ http { sendfile on; tcp_nopush on; types_hash_max_size 2048; - # server_tokens off; + server_tokens off; # Recommended security practice is to turn this off # server_names_hash_bucket_size 64; # server_name_in_redirect off; @@ -31,8 +31,8 @@ http { # SSL Settings ## - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE - ssl_prefer_server_ciphers on; + ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE; TLS 1.0, 1.1 deprecated. + ssl_prefer_server_ciphers off; # Modern security: don't force server cipher order. ## # Logging Settings From 6ef563d4f40f44f1c5422c80a59572559a1561ed Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 17 Jun 2024 11:52:46 -0400 Subject: [PATCH 49/89] Update comments --- debian/conf/nginx.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 594c93e..f1466a7 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -19,7 +19,7 @@ http { sendfile on; tcp_nopush on; types_hash_max_size 2048; - server_tokens off; # Recommended security practice is to turn this off + server_tokens off; # Recommended practice is to turn this off # server_names_hash_bucket_size 64; # server_name_in_redirect off; @@ -31,8 +31,8 @@ http { # SSL Settings ## - ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE; TLS 1.0, 1.1 deprecated. - ssl_prefer_server_ciphers off; # Modern security: don't force server cipher order. + ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1 + ssl_prefer_server_ciphers off; # Don't force server cipher order. ## # Logging Settings From 2a1513acc87a1090cbeb8156d440f87a34e5e456 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 17 Jun 2024 11:53:50 -0400 Subject: [PATCH 50/89] Debian changelog entry --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index a3ccd3e..39c80c0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.26.0-2) UNRELEASED; urgency=medium + + * d/conf/nginx.conf: Update default options for current security + practices and standards. SSL protos, disable prefer server + ciphers, hide server tokens/versions in responses. + + -- Thomas Ward Mon, 17 Jun 2024 11:52:48 -0400 + nginx (1.26.0-1) unstable; urgency=medium * New upstream version 1.26.0 From 363e53be5d010d9e401007637b8994fac9c629da Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 17 Jun 2024 16:25:34 +0000 Subject: [PATCH 51/89] Update nginx.conf: whitespace matching --- debian/conf/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index f1466a7..68a8fd4 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -19,7 +19,7 @@ http { sendfile on; tcp_nopush on; types_hash_max_size 2048; - server_tokens off; # Recommended practice is to turn this off + server_tokens off; # Recommended practice is to turn this off # server_names_hash_bucket_size 64; # server_name_in_redirect off; From 45c7770c5ef1f485dd1d4755dcb554868f0ddd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 17 Jun 2024 18:46:59 +0200 Subject: [PATCH 52/89] d/p/nginx-1.26.1.patch add, backport changes from the nginx 1.26.1 --- debian/changelog | 2 + debian/patches/nginx-1.26.1.patch | 367 ++++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 370 insertions(+) create mode 100644 debian/patches/nginx-1.26.1.patch diff --git a/debian/changelog b/debian/changelog index a179f58..791b894 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,8 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/rules: enable QUIC and HTTP/3 module (Closes: 1070488) * d/control: bump Standards-Version: 4.7.0, no changes + * d/p/nginx-1.26.1.patch add, backport changes from the nginx 1.26.1 and fix + CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161 [ Thomas Ward ] * d/conf/nginx.conf: Update default options for current security diff --git a/debian/patches/nginx-1.26.1.patch b/debian/patches/nginx-1.26.1.patch new file mode 100644 index 0000000..8086ae8 --- /dev/null +++ b/debian/patches/nginx-1.26.1.patch @@ -0,0 +1,367 @@ +From: =?utf-8?b?SmFuIE1vasW+w63FoQ==?= +Date: Mon, 17 Jun 2024 18:40:09 +0200 +Subject: nginx-1.26.1 +Forwarded: not-needed + +Backport changes from the nginx 1.26.1 and fix +CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161 + +--- + auto/lib/libatomic/conf | 2 +- + src/core/ngx_output_chain.c | 10 ++++++++-- + src/event/quic/ngx_event_quic_frames.c | 1 + + src/event/quic/ngx_event_quic_ssl.c | 5 +++++ + src/event/quic/ngx_event_quic_transport.c | 8 ++++++++ + src/http/modules/ngx_http_grpc_module.c | 5 ++++- + src/http/modules/ngx_http_gunzip_filter_module.c | 18 ++++++++++++++---- + src/http/modules/ngx_http_gzip_filter_module.c | 10 +++++++--- + src/http/modules/ngx_http_ssi_filter_module.c | 8 ++++++-- + src/http/modules/ngx_http_sub_filter_module.c | 8 ++++++-- + src/http/v3/ngx_http_v3_parse.c | 3 +++ + src/http/v3/ngx_http_v3_request.c | 20 ++++++++++++++------ + src/http/v3/ngx_http_v3_table.c | 2 +- + src/http/v3/ngx_http_v3_uni.c | 4 +--- + src/http/v3/ngx_http_v3_uni.h | 2 ++ + 15 files changed, 81 insertions(+), 25 deletions(-) + +diff --git a/auto/lib/libatomic/conf b/auto/lib/libatomic/conf +index d1e484a..8c8cb43 100644 +--- a/auto/lib/libatomic/conf ++++ b/auto/lib/libatomic/conf +@@ -19,7 +19,7 @@ else + #include " + ngx_feature_path= + ngx_feature_libs="-latomic_ops" +- ngx_feature_test="long n = 0; ++ ngx_feature_test="AO_t n = 0; + if (!AO_compare_and_swap(&n, 0, 1)) + return 1; + if (AO_fetch_and_add(&n, 1) != 1) +diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c +index 8570742..a46209c 100644 +--- a/src/core/ngx_output_chain.c ++++ b/src/core/ngx_output_chain.c +@@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) + + ngx_debug_point(); + +- ctx->in = ctx->in->next; ++ cl = ctx->in; ++ ctx->in = cl->next; ++ ++ ngx_free_chain(ctx->pool, cl); + + continue; + } +@@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) + /* delete the completed buf from the ctx->in chain */ + + if (ngx_buf_size(ctx->in->buf) == 0) { +- ctx->in = ctx->in->next; ++ cl = ctx->in; ++ ctx->in = cl->next; ++ ++ ngx_free_chain(ctx->pool, cl); + } + + cl = ngx_alloc_chain_link(ctx->pool); +diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c +index 42b7d9f..6ea908c 100644 +--- a/src/event/quic/ngx_event_quic_frames.c ++++ b/src/event/quic/ngx_event_quic_frames.c +@@ -648,6 +648,7 @@ ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb) + ngx_quic_free_chain(c, qb->chain); + + qb->chain = NULL; ++ qb->last_chain = NULL; + } + + +diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c +index 7872783..ba0b592 100644 +--- a/src/event/quic/ngx_event_quic_ssl.c ++++ b/src/event/quic/ngx_event_quic_ssl.c +@@ -326,6 +326,11 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, + ngx_quic_crypto_frame_t *f; + + qc = ngx_quic_get_connection(c); ++ ++ if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) { ++ return NGX_OK; ++ } ++ + ctx = ngx_quic_get_send_ctx(qc, pkt->level); + f = &frame->u.crypto; + +diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c +index 19670a6..fba098c 100644 +--- a/src/event/quic/ngx_event_quic_transport.c ++++ b/src/event/quic/ngx_event_quic_transport.c +@@ -1750,6 +1750,14 @@ ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp, + return NGX_ERROR; + } + ++ if ((size_t) (end - p) < len) { ++ ngx_log_error(NGX_LOG_INFO, log, 0, ++ "quic failed to parse" ++ " transport param id:0x%xL, data length %uL too long", ++ id, len); ++ return NGX_ERROR; ++ } ++ + rc = ngx_quic_parse_transport_param(p, p + len, id, tp); + + if (rc == NGX_ERROR) { +diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c +index dfe49c5..e7726f3 100644 +--- a/src/http/modules/ngx_http_grpc_module.c ++++ b/src/http/modules/ngx_http_grpc_module.c +@@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) + ngx_buf_t *b; + ngx_int_t rc; + ngx_uint_t next, last; +- ngx_chain_t *cl, *out, **ll; ++ ngx_chain_t *cl, *out, *ln, **ll; + ngx_http_upstream_t *u; + ngx_http_grpc_ctx_t *ctx; + ngx_http_grpc_frame_t *f; +@@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) + last = 1; + } + ++ ln = in; + in = in->next; ++ ++ ngx_free_chain(r->pool, ln); + } + + ctx->in = in; +diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c +index c1341f5..5d170a1 100644 +--- a/src/http/modules/ngx_http_gunzip_filter_module.c ++++ b/src/http/modules/ngx_http_gunzip_filter_module.c +@@ -333,6 +333,8 @@ static ngx_int_t + ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) + { ++ ngx_chain_t *cl; ++ + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { + return NGX_OK; + } +@@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, + return NGX_DECLINED; + } + +- ctx->in_buf = ctx->in->buf; +- ctx->in = ctx->in->next; ++ cl = ctx->in; ++ ctx->in_buf = cl->buf; ++ ctx->in = cl->next; ++ ++ ngx_free_chain(r->pool, cl); + + ctx->zstream.next_in = ctx->in_buf->pos; + ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; +@@ -374,6 +379,7 @@ static ngx_int_t + ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) + { ++ ngx_chain_t *cl; + ngx_http_gunzip_conf_t *conf; + + if (ctx->zstream.avail_out) { +@@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, + conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); + + if (ctx->free) { +- ctx->out_buf = ctx->free->buf; +- ctx->free = ctx->free->next; ++ ++ cl = ctx->free; ++ ctx->out_buf = cl->buf; ++ ctx->free = cl->next; ++ ++ ngx_free_chain(r->pool, cl); + + ctx->out_buf->flush = 0; + +diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c +index ed0de60..b555278 100644 +--- a/src/http/modules/ngx_http_gzip_filter_module.c ++++ b/src/http/modules/ngx_http_gzip_filter_module.c +@@ -985,10 +985,14 @@ static void + ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, + ngx_http_gzip_ctx_t *ctx) + { +- ngx_chain_t *cl; ++ ngx_chain_t *cl, *ln; ++ ++ for (cl = ctx->copied; cl; /* void */) { ++ ln = cl; ++ cl = cl->next; + +- for (cl = ctx->copied; cl; cl = cl->next) { +- ngx_pfree(r->pool, cl->buf->start); ++ ngx_pfree(r->pool, ln->buf->start); ++ ngx_free_chain(r->pool, ln); + } + + ctx->copied = NULL; +diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c +index 0b84bd3..47068f7 100644 +--- a/src/http/modules/ngx_http_ssi_filter_module.c ++++ b/src/http/modules/ngx_http_ssi_filter_module.c +@@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) + while (ctx->in || ctx->buf) { + + if (ctx->buf == NULL) { +- ctx->buf = ctx->in->buf; +- ctx->in = ctx->in->next; ++ ++ cl = ctx->in; ++ ctx->buf = cl->buf; ++ ctx->in = cl->next; + ctx->pos = ctx->buf->pos; ++ ++ ngx_free_chain(r->pool, cl); + } + + if (ctx->state == ssi_start_state) { +diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c +index 6d3de59..456bb27 100644 +--- a/src/http/modules/ngx_http_sub_filter_module.c ++++ b/src/http/modules/ngx_http_sub_filter_module.c +@@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) + while (ctx->in || ctx->buf) { + + if (ctx->buf == NULL) { +- ctx->buf = ctx->in->buf; +- ctx->in = ctx->in->next; ++ ++ cl = ctx->in; ++ ctx->buf = cl->buf; ++ ctx->in = cl->next; + ctx->pos = ctx->buf->pos; ++ ++ ngx_free_chain(r->pool, cl); + } + + if (ctx->buf->flush || ctx->buf->recycled) { +diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c +index 5688163..436765c 100644 +--- a/src/http/v3/ngx_http_v3_parse.c ++++ b/src/http/v3/ngx_http_v3_parse.c +@@ -810,6 +810,7 @@ ngx_http_v3_parse_field_lri(ngx_connection_t *c, + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { ++ st->value.data = (u_char *) ""; + goto done; + } + +@@ -932,6 +933,7 @@ ngx_http_v3_parse_field_l(ngx_connection_t *c, + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { ++ st->value.data = (u_char *) ""; + goto done; + } + +@@ -1072,6 +1074,7 @@ ngx_http_v3_parse_field_lpbi(ngx_connection_t *c, + + st->literal.length = st->pint.value; + if (st->literal.length == 0) { ++ st->value.data = (u_char *) ""; + goto done; + } + +diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c +index 87f5f32..0faddd2 100644 +--- a/src/http/v3/ngx_http_v3_request.c ++++ b/src/http/v3/ngx_http_v3_request.c +@@ -134,7 +134,17 @@ ngx_http_v3_init(ngx_connection_t *c) + } + } + +- return ngx_http_v3_send_settings(c); ++ if (ngx_http_v3_send_settings(c) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (h3scf->max_table_capacity > 0) { ++ if (ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER) == NULL) { ++ return NGX_ERROR; ++ } ++ } ++ ++ return NGX_OK; + } + + +@@ -398,14 +408,12 @@ ngx_http_v3_wait_request_handler(ngx_event_t *rev) + void + ngx_http_v3_reset_stream(ngx_connection_t *c) + { +- ngx_http_v3_session_t *h3c; +- ngx_http_v3_srv_conf_t *h3scf; +- +- h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); ++ ngx_http_v3_session_t *h3c; + + h3c = ngx_http_v3_get_session(c); + +- if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq ++ if (!c->read->eof && !h3c->hq ++ && h3c->known_streams[NGX_HTTP_V3_STREAM_SERVER_DECODER] + && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) + { + (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); +diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c +index f49a8fc..428e732 100644 +--- a/src/http/v3/ngx_http_v3_table.c ++++ b/src/http/v3/ngx_http_v3_table.c +@@ -308,7 +308,7 @@ ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity) + prev_max = dt->capacity / 32; + + if (max > prev_max) { +- elts = ngx_alloc(max * sizeof(void *), c->log); ++ elts = ngx_alloc((max + 1) * sizeof(void *), c->log); + if (elts == NULL) { + return NGX_ERROR; + } +diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c +index 2fc5b07..302064b 100644 +--- a/src/http/v3/ngx_http_v3_uni.c ++++ b/src/http/v3/ngx_http_v3_uni.c +@@ -20,8 +20,6 @@ static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); + static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); + static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); + static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); +-static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, +- ngx_uint_t type); + + + void +@@ -307,7 +305,7 @@ ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev) + } + + +-static ngx_connection_t * ++ngx_connection_t * + ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type) + { + u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; +diff --git a/src/http/v3/ngx_http_v3_uni.h b/src/http/v3/ngx_http_v3_uni.h +index 911e153..2805894 100644 +--- a/src/http/v3/ngx_http_v3_uni.h ++++ b/src/http/v3/ngx_http_v3_uni.h +@@ -19,6 +19,8 @@ ngx_int_t ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type); + + ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id); + ++ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, ++ ngx_uint_t type); + ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); + ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id); + ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c, diff --git a/debian/patches/series b/debian/patches/series index 52e1dc4..548660c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,4 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch +nginx-1.26.1.patch From b3d7b0f3ed5c23cb50515a900d74340a3958a22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 18 Aug 2024 08:15:33 +0200 Subject: [PATCH 53/89] d/p/CVE-2024-7347.patch add, backport CVE-2024-7347 fix --- debian/changelog | 1 + debian/patches/CVE-2024-7347.patch | 45 ++++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 47 insertions(+) create mode 100644 debian/patches/CVE-2024-7347.patch diff --git a/debian/changelog b/debian/changelog index 791b894..5fdfbca 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium * d/control: bump Standards-Version: 4.7.0, no changes * d/p/nginx-1.26.1.patch add, backport changes from the nginx 1.26.1 and fix CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161 + * d/p/CVE-2024-7347.patch add, backport CVE-2024-7347 fix [ Thomas Ward ] * d/conf/nginx.conf: Update default options for current security diff --git a/debian/patches/CVE-2024-7347.patch b/debian/patches/CVE-2024-7347.patch new file mode 100644 index 0000000..1ca3e79 --- /dev/null +++ b/debian/patches/CVE-2024-7347.patch @@ -0,0 +1,45 @@ +Origin: https://nginx.org/download/patch.2024.mp4.txt + +diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c +--- a/src/http/modules/ngx_http_mp4_module.c ++++ b/src/http/modules/ngx_http_mp4_module.c +@@ -3099,7 +3099,8 @@ 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, ++ uint64_t n; ++ uint32_t start_sample, chunk, samples, id, next_chunk, + prev_samples; + ngx_buf_t *data, *buf; + ngx_uint_t entries, target_chunk, chunk_samples; +@@ -3155,12 +3156,19 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4 + + next_chunk = ngx_mp4_get_32value(entry->chunk); + ++ if (next_chunk < chunk) { ++ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, ++ "unordered mp4 stsc chunks in \"%s\"", ++ mp4->file.name.data); ++ return NGX_ERROR; ++ } ++ + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "sample:%uD, chunk:%uD, chunks:%uD, " + "samples:%uD, id:%uD", + start_sample, chunk, next_chunk - chunk, samples, id); + +- n = (next_chunk - chunk) * samples; ++ n = (uint64_t) (next_chunk - chunk) * samples; + + if (start_sample < n) { + goto found; +@@ -3182,7 +3190,7 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4 + "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", + start_sample, chunk, next_chunk - chunk, samples); + +- n = (next_chunk - chunk) * samples; ++ n = (uint64_t) (next_chunk - chunk) * samples; + + if (start_sample > n) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, diff --git a/debian/patches/series b/debian/patches/series index 548660c..56e7725 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -2,3 +2,4 @@ nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch nginx-1.26.1.patch +CVE-2024-7347.patch From 7137628c08aed485e5c8e88737ee5a8bc74f9c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 18 Aug 2024 08:59:49 +0200 Subject: [PATCH 54/89] d/libnginx-mod.abisubstvars updated comment when ABI needs to be changed --- debian/changelog | 1 + debian/libnginx-mod.abisubstvars | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 5fdfbca..1b37dee 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,7 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium * d/p/nginx-1.26.1.patch add, backport changes from the nginx 1.26.1 and fix CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161 * d/p/CVE-2024-7347.patch add, backport CVE-2024-7347 fix + * d/libnginx-mod.abisubstvars updated comment when ABI needs to be changed [ Thomas Ward ] * d/conf/nginx.conf: Update default options for current security diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index 2b3d99d..d793435 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -1,8 +1,11 @@ -# update the ABI version when: -# - nginx upstream has changed -# - a patch might change the ABI -# - a build-dependency has changed -# note that debian revision can increase without breaking ABI +# ABI must be changed: +# - when upstream nginx version is changed +# - when module signature is changed (e.g. time_t change from 32bit integer to 64bit integer https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1069997) +# - when symbols/structures/... (exported from header files) are changed # -# TODO: use $(DEB_VERSION_UPSTREAM) +# ABI format: nginx-abi-{UPSTREAM_VERSION}-{SUFFIX} +# the {SUFFIX} provides a mechanism on rare cases when there have to be ABI +# changes without upgrading the upstream nginx version, e.g. security updates +# in oldstable + nginx:abi=nginx-abi-1.26.0-1 From a079a02186531e8d5634d5c4c2cb9f48a3aed880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 18 Aug 2024 21:07:25 +0200 Subject: [PATCH 55/89] d/changelog close bug for CVE-2024-7347 --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 1b37dee..9b48673 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,7 +5,7 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium * d/control: bump Standards-Version: 4.7.0, no changes * d/p/nginx-1.26.1.patch add, backport changes from the nginx 1.26.1 and fix CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161 - * d/p/CVE-2024-7347.patch add, backport CVE-2024-7347 fix + * d/p/CVE-2024-7347.patch add, backport CVE-2024-7347 fix (Closes: 1078971) * d/libnginx-mod.abisubstvars updated comment when ABI needs to be changed [ Thomas Ward ] From 6e88f6d8584cea9c504d6fe78f1dea73b864aeb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 19 Aug 2024 10:59:44 +0200 Subject: [PATCH 56/89] d/changelog fix whitespace --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9b48673..4d148a7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,8 +9,8 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium * d/libnginx-mod.abisubstvars updated comment when ABI needs to be changed [ Thomas Ward ] - * d/conf/nginx.conf: Update default options for current security - practices and standards. SSL protos, disable prefer server + * d/conf/nginx.conf: Update default options for current security + practices and standards. SSL protos, disable prefer server ciphers, hide server tokens/versions in responses. -- Jan Mojžíš Tue, 07 May 2024 19:09:56 +0200 From 9cd731914a2df9cc531106d486d9eb23ec144ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 19 Aug 2024 18:46:47 +0200 Subject: [PATCH 57/89] release nginx 1.26.0-2, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4d148a7..c4b1813 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.26.0-2) UNRELEASED; urgency=medium +nginx (1.26.0-2) unstable; urgency=medium [ Jan Mojžíš ] * d/rules: enable QUIC and HTTP/3 module (Closes: 1070488) @@ -13,7 +13,7 @@ nginx (1.26.0-2) UNRELEASED; urgency=medium practices and standards. SSL protos, disable prefer server ciphers, hide server tokens/versions in responses. - -- Jan Mojžíš Tue, 07 May 2024 19:09:56 +0200 + -- Jan Mojžíš Mon, 19 Aug 2024 18:46:30 +0200 nginx (1.26.0-1) unstable; urgency=medium From 0722a5648de88e45079f9c7c4efa9271df0d12bf Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Fri, 20 Sep 2024 21:37:33 -0400 Subject: [PATCH 58/89] Resolve dependency loop (debbugs #1082373) --- debian/changelog | 7 +++++++ debian/control | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index c4b1813..40d44d8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.26.0-3) UNRELEASED; urgency=medium + + * d/control: Resolve dependency loop between nginx and nginx-common. + (Fixes: #1082373) + + -- Thomas Ward Fri, 20 Sep 2024 21:35:42 -0400 + nginx (1.26.0-2) unstable; urgency=medium [ Jan Mojžíš ] diff --git a/debian/control b/debian/control index 1b1a145..756f31f 100644 --- a/debian/control +++ b/debian/control @@ -50,9 +50,7 @@ Breaks: nginx (<< 1.22.1-8) Replaces: nginx (<< 1.22.1-8) Architecture: all Multi-Arch: foreign -Depends: ${misc:Depends}, - nginx (>= ${source:Version}), - nginx (<< ${source:Version}.1~), +Depends: ${misc:Depends} Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server From df67526348924acb51ae870baed33a114efbdc07 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 30 Sep 2024 11:39:49 -0400 Subject: [PATCH 59/89] Actual release --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 40d44d8..f7bbbcb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.26.0-3) UNRELEASED; urgency=medium +nginx (1.26.0-3) unstable; urgency=medium * d/control: Resolve dependency loop between nginx and nginx-common. (Fixes: #1082373) From f180e25eb4b066aca70b47eb74e1b2851fe521b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 28 Jan 2025 08:27:48 +0100 Subject: [PATCH 60/89] d/u/signing-key.asc add Sergey Kandaurov public key --- debian/changelog | 7 + debian/upstream/signing-key.asc | 392 ++++++++++++++++++++++++++++++++ 2 files changed, 399 insertions(+) diff --git a/debian/changelog b/debian/changelog index f7bbbcb..ab2519c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.26.0-4) UNRELEASED; urgency=medium + + * d/u/signing-key.asc: add Sergey Kandaurov public key, + the key is used to sign the 1.26.2 release + + -- Jan Mojžíš Tue, 28 Jan 2025 08:26:25 +0100 + nginx (1.26.0-3) unstable; urgency=medium * d/control: Resolve dependency loop between nginx and nginx-common. diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc index 0264a10..1014f9e 100644 --- a/debian/upstream/signing-key.asc +++ b/debian/upstream/signing-key.asc @@ -161,3 +161,395 @@ wF6V6z89IJHGyPoXZUyRwguoutUH+TiFp4bcOpGb9sxHE7c5QGDRLpsvCqycyApj y0uwRAvM =atsZ -----END PGP PUBLIC KEY BLOCK----- + +# Sergey Kandaurov public key, +# the key is used to sign the 1.26.2 release + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFcok2QBEACt2nzM7Oqh6Tl/yNDzT9EXf4C5TTfxnKih6ehm0T0VWLFkWOxz +bmVqo7PgS0q3bcMoUl8CIbs4foC+GCAVj8DNoiMkxvfxBb+V+qdzve0sh9WHUpDP +dRBEHQb5T5KzTtGDarkhv1/15VqK1AOCSBroeFZXefr9bZqrGJCgixta/JZXSr6t +xbouELXWzdviUEtcrN9V9rNJy7QvS2n/UqhjgCKhX5bdLVUy8Abja20rHiVUdBww +aAee0+yZuS8Y/TksItquNwWce4qDtRrKxs2dmlLYsRULtoRKmTHPcpyrhVN7jIZX +glYumuG0e5plY/4TUHeEu3ReFC+AdQIESa+6+IxgdIT6szwMF4u+50HFAFDiYfdt +rjjAoD0fwEW7wSc8Ow9lA3m10yLqRuL+HbVQfb2F5iLsHa+TrSWOKfPboLo+Cg9o +g7fVRYmPhSogcnGbFdFr52GGp/YRk8M7kbbYzuHmQLuDyiG7kyifq6fOBil2Jgyg +MxRJcFl5G/sYw1naEKjAUKAMvCYaPdfFmOSJKDyFsR8ZaDO58rE/HUVsumCuN/kG +wAFmRp3AzT9CrWFSXuZW1tLdd9d+6uHx9BZZUdKaMICpgP62OW1r4h0W8FrEkywf +Tp/5FxEXjXE/xWRdeZ5sp9QbzJ6xm79c/N79vQQN+Jbq+T9o/p6pbUJ3rQARAQAB +tCRKYW4gTW9qxb7DrcWhIDxqYW5tb2p6aXNAZGViaWFuLm9yZz6JAk4EEwEKADgW +IQSq3y7fVSnxcCdyyKLexNJGkx70mwUCZyFKcQIbLwULCQgHAgYVCgkICwIEFgID +AQIeAQIXgAAKCRDexNJGkx70m/ymEACpUcHefaXAiGEEvJa8eBJ+9qZUdtVSWDwE +eP+GzlM/+6gbNRxFJAdcDDP3x3ALvAwA39vh8iIsrTONYcbCKi4uFMCH9/h08TzK +jT/2Z9PmXb0wGaVt/Jz+qe4SjDimnEB0cE8HMRB5Uo6NPhaSTDjMGXYpx49RVzsL +sJ9xsIDDd1it/KNVjpBMeLtyLRKQARjiAjVkLlWsy+PFxd7To0BnhmZ/9r42JrR9 +eBg3c8n+9hJ+ITA+nSV6RTuox4vADj5yPM0fNcITKpgbgvMv82C5S4DIs3KG/t/Q +Cth25DHrrm+S0oiHSr9cF85IbwuX07E1HAYTUPuW2X2jLzRwlVihp/txg81W9fkz +aJCv/tfvzo9oVecUx50WdkEFpJjjGTY+hMKE05dsU+SjY6Wi1kozcreSX4iAdlzV +Y4u2Z8BNz+29dFnJSs8DMMgYslqiSzLraBuJ1gXo/gKeYuobgxZS2Yk4lft4xbJG +STUjpLFbq29zGheUxjr9tGJKMrAyhK1X680KTjusR4sd4npAgBQgwYP9c8ozQ9+Q +IniSZX3mLMcaTBay5JoqK9jR6sc545ltd/NFA9jA0eP7lUJPVjEOcO05DvrLihw5 +KEVopWd50S6/OtJAvd4T7kOxabolG/3K6Mfcz1XL3BMPKUK8dc4k4gEyiUfbYZkj +05JdIMlO5rQkSmFuIE1vasW+w63FoSA8amFuLm1vanppc0BnbWFpbC5jb20+iQI3 +BBMBAgAiBQJXQ/pWAhsvBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDexNJG +kx70m8pSD/QPwKHIg4ke+Gj49tnogx5I78x/5wIrY7ekk+OsOI/EisUkle/wpz+W +nwEY0tVMGwg9G8XaWI3FWuUYnmHRaqIoeMlNaiYHJES00K5gWrrs4PrKNsHCMIct +XTla88fKjnEgZFJ5KSnLTQoeIgxogbtEtAZyceAWrDc5LuW025xtleU3NLUM0jxi +hlD4WAMz0Ov0qFH+FB0mTYvfFBKl/TpXnyMN0KSOmRQ8hqyAfeTi3hcz51PSH5uI +g8nVLSPs6No253FE0MqQoED/tZGHNrkAEz1FIlYJE8Ze27vXMHhfx9Ik7rEbyS4T +NQSJfVPxmiU/aI2gqN8Kom+vLP1qgrEoYXFPxFnYr73+iyq8UxIZcqGvQOx6XVHU +GhIxj7fahGD2Q5s0GPJPnlCNvt6X3AGlARBdLAb/qIRAYD456kWlWon2P3raheEa +EJBeFf1Z3s4/eOOCRP+ojQJPIr+g9MpKdfhlqvG43mrwRuO+ZPRPggixaK1LbWJk +yImd/DXnTriSHeCKvHwvD2O74xvrKYPbYBSCTdG/0FG/3fT8XGXL84mWObRd3/IF +fjjAnUugU75B+vE8dJh2B/fIzT8+TuXYCf5oyB1Q+INhwOSulJ2OUyizX8PhCJpR +ykfmgACSJtM/dMJn1Q5eofii8tAIOjCaPK2olHJTWkS4hkPxd9y6tCpKYW4gTW9q +xb7DrcWhIDxqYW4ubW9qemlzQGZpcm1hLnNlem5hbS5jej6JAjgEEwECACIFAlco +m9ACGy8GCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEN7E0kaTHvSbCwkQAIuw +/1e1jQkoGKEOJFtI1DMM85ByXwAwS8A4Xh7tOTYYYU59L6DeBFEGXXYsyb87U31p +9nFEPmst/EG75wmaPGqqIT2IL2QKuVZiD30OXdQ5aJ3JVAJ++nwb7FYLUFt4JDDk +jcB5f3dzHIy182EpbazDQwvlIn058n0b2Wm23nYsZOmXXd3b7KHJGU06jsnV6igC +4VP3r8jwlWMh48SebTrx/kTDPO7VSayk6PBrr6ZEDkVs11s9rVNyXmXNVzmBTOGQ +fllmsRdAFCUio4pTECrl1iAXLGsp+OJ80PsgDHSAVwiWmfhm6spHvDCGi0yMakmX +5f/BWtimwqdAv+75wDB7TnHre40Lafqyr6kCkCzwr1B5RyOk3QhYZbGaed2dmDID +lsF4MppiY46FxTu0kQroZOZtq/AwmPtxL+2R8cXgTBL2Jh7oQDmIxOKrvLK4hCbq +mv7kCmgBUtNqzZ3sZdN3Va/deIHaFAJen20jOSLlokAtfFzyXpiRJqVwY7B96yXh +dten5hRnAU+g2GcIPXd9BtDgDdyfbSDoREfh4fhUQzzwewegHjjiSJlGHKycDeFn +NkdjjKQ/QiL3yiqEEXDDBZlMrdyz62DGWRZQLv/ZWRmbBAi/ftIjuMzXsZfuU/E4 +sB7GPnEouoKEhCqIV83RPjPI/IqduHu7sUK9LhR1tB5KYW4gTW9qxb7DrcWhIDxq +YW5AbW9qemlzLmNvbT6JAjgEEwECACIFAlcok2QCGy8GCwkIBwMCBhUIAgkKCwQW +AgMBAh4BAheAAAoJEN7E0kaTHvSb6QEP/j0PUJRm7NN8svpHy5AFz74MhGQtkQlz +89WTZHX5kf+Bx6iGkOpCP5Z4iJBWWGn0XpMPwbDOw5R4LiBOhGwJvCpjxFLByOts +EEsgqPy1ZsX10zg6MG2JVjFOYHUh+BaWZzCtchh7cUUwUM6SDE3H9Iis2+7Fkfz/ +UP6ha0/zLZONIq6bIzIZHJ1VDvfgY7v68R+XEFsQZpr4EKrriBQQZ6dsZs5xDYLo +BoljD6KypOw6Cv9i7CCZnQnyctkVDLx4EOll/tRX+8tkl+5GpgRDGPzL83hBfm7q +QNqK2J3Ex+iPcTfMCN64DRyyq4HpmvEJsMG+jfHJay87jKcU2F8+P8kwL28eBDGV +ngl1hWOiOvZnSP13s6Ckjm95bLG+RyhcH30+sy9i75JxoWfh/sekYOVo4NmPFRls +SdcMOJ5Znk702wx24qa4EgjcgtID6yr2IsotM/I+Y2maKBAluYDkRFROqLz0jsed +1gMBNPse0oMEz2NRbzk6rfRJcYqX+s8jsS/VhzGd1JIgoGRkvFZlQTAfRe8NsDF2 +Yif504zarJABHRoGzLXvlYuhEPXZhpE5l/7i2PLVCG0rva+jBqwDValTaLyemVqb +mM1FJuHf6Bb6UND4ccgXCiOIH/cGBXiVeYQQxHuuw1JZ+UlDViduVrnpWw7mFD8x +BiMOjwL4PFp9uQINBFcok2QBEADPuwkLt5jAhIAjVVWNgDBNyqX5mW5bMvCFy7qy +QLPaCPrxpEGjKA+hvK8FG9i/KPUlsdReZH3JPAngUteU16iJo8HbDum93+4a555B +Ea4+Bzw5q0qREZPvybvhcrk/S93RpC7NAvwMUieAmJMZJnckjrcznQTYljTcX/NS +WODutapYbCwgPf76kCsYFLcbcFuOSDiRxL7iHBjx3eB/3D1+dZBTfoTRqHQ23f4g +M9q0DuBpifKI2KBaDU8z6LarT7wY+S2TsPESZ65vk9L5cMoZZkefTUlUEzYzL8DY +CmjFqyeji7WoM28ophaLJrsgqtAbmzZLrvlq5F1OwlQJW7fvOwyppnBgTTkdYM2x +gSLCtUfccgvjBpAcRPhP0MjAAyj7kFTwY6uaVMqyH4PL+e91OWMag2ZDtQ2y28RY +PFkNBwOlFKemYyhylwLdPT9hYUXcnwmKh8R3vpvR2lnxRomKkx5IpTFIBaapf9eh +9VBJ+Z2lEEhAprag2YaAgREGI4Ohp9WM1DtX6+bUf50TOllP78uKMUASGETtIeTN +UoxCktefm4kGAk11OR1cfiyAAnFXXbMGYPPH1/TtPZUSgasrwjW89ER1xrYqklam +BWEXbSEn4XCmeNJX2rVMhXZb0rJQuXEY0rIkVcyBXHHwnbUPgWeBtlsd4nxLxJeH +zBQTrwARAQABiQQ+BBgBAgAJBQJXKJNkAhsuAikJEN7E0kaTHvSbwV0gBBkBAgAG +BQJXKJNkAAoJEEXaUXSWk5/5mfUP/3cgCzFWd6QXk/oTqiXNJv5IxOM83XCyjoDu +Zuphw/rzj+kYiBkez9YMJ4G7eGqZZsxHLgBbLOrom/a+cS862os9iRTEE/N+uqWG +I6gSDPWihT/cnbBZaNcj+FKFtpe77WNcFKTw1K6vKGH/PkmlQgC9S4YJHFvLierr +XUWp+J8sQn+vSbT4ntvcdqxuxYtIvHf89liZI3gmPemkapfPJ1ZdS7nNDSw74ijO +rRzz45aZetm7hRY/BkujmJQ/27UVZaFHQ2AddUSLAA8keFLe4N47wL7UEVhPUTq0 +JCIZOSXnY/twMrlWv3OnVRRLtnph+WwAZ6O0qMV611kru77HHGCudAwiglkrkgvQ +je4uRIqRLmFA9LyE1726n7Z20H3r8aptQ7wj6N6Ir0ARMC2/mHhFv8bgOEKnx4Zb +8rLwfv/fqYF0brvyzaIUU3UqMYN4uSB37Y5HfBmtIp7yGqLWBslKLvbrizD4gFm2 +TqInaxClbfaX69dHYM5zZQK3GNsA6WXuIKTZFIWdnqYfzu6ihJmtLf5J6uX0PVt0 +728lL3fsXyi5K42kKnu3FBTY1iOTAGXDpGsYBcUney9mcrtbhr1V+/6y+B7UhNQp +fAO/lCTyNwsorPSAaAEGIpUKJ6YZ9+kzcDnhz6ZQG0C1/EFRUGn0Qf2xNv8+RtB5 +tpXmVyqUtPgQAKjTE4DS+Fe/7MYf5KjQC7pc3/sgJVmXfjO3z9vclp4zcm8wGQAJ +XZVCzY9xkyPJTWGtLBxdmyKUx39ZbXH3BBj6g8pVUiNER2JoHDleb2/YDnmC1hfe +PA6trfKEfQFRPY8OkQj1z/vTosbwLTZMD6zjGGkZZe/bUMEK3pvl52Du54vANz1c ++wEEK3+73lh3L8zcBN5mzlNZHSeAQMlkX+JG46y3RqQuli+NzF40/KLSh/LH7Wwm +7pn7ju0sR0NxWyRpwx1tKJeZf8AzqSTlUEqPSmGuy1sGwBwf0f2HxGpegctpfLM8 +4CF4fYMvmLj4rSReRnTblbKmTmmiPDN1Qnm5qYHVPnNtgrwap9/6Xr2akJGlxcvx +OyUV9xLDToPlde9PFgruWpzh7EiQbO38LNF0ckoV+1z9muPh0s9D3NP+IgYcKuc8 +pOa4U2Y+ExAfAmEmiSUpJ/7G6bCxrdaF0/DFtA5TIwnTOI0CTh9AOBtqPcTe0TGT +UARO0X5NqLsQy+sXn5gXdnrupzijgDrLU9v3ke4oXGAWZwuzsEtQpAuq/jPJF2Gu +HgYDQ2qkNDM5Jxxjo/QC9ZKSbkJy3oU1Qf0lJCum2XHDjbD8RAaqGkiR3etBCO93 +Pmp1UMXdYLNqHC32BUIqrBBEWyBvHBhvF5gdqeddGszTm8kD36VL44FBmQINBFX2 +5mMBEAC9NHGWvdZGzFJ85VLglbBRgqoaFMznC6Dz329M8Y+pVvPE/YY4rhX6FGxT +3lOLY7mSpRf3PpRBrGf1Iz6IpM/ZBs2fFfL1uXqtJ++VkOG5ZRpTzVoyFloDndqx +v6VpYjE2ljb0kxdyOkMPIRQHxRelQwHJyKZI01oG5vXr0Th8/1giPSTwJ7m0h04y +iweREuUr5Q1kBr1+Q1MgmErngVm1bKO/aJoWMW/aPA3Dp7kh5rGst7gp/wX7veH3 +K5KTaqM4NinGgCNhHJfaf4ANBjN4+Ot/cYehbPUDmdrI3gcz95DSS0N0R5YgpzFl +yHxJ3FGyCrtbNro88Qxn5/JErevx3GDsvhsGBWrywF4VnFvoG8R5O7wZGpd44Mpu +YngouH2n4O7oDq2n/0hIi2BZsVBO8MRxEBJPZEOwkRIBD86NXjZrA6LB2dQeg/uT +eNdPAkxhhxrA/nDgYILNVDIIMq91DpjQBPWp9OO+mHhcM0eeSJWfONdK1cT18kfV +v0r7fOGtFJvJ46EQvlHMORYVHsFZhtOsHbbybSVQeqqf86YtO1wDw2pEjRdz369V +3bMd76WsCx1g8p0PursJO5l2c7Mha8NzSRbM3yeKuP61L8JKHx1prp6o25UOMszR +JaQoYheyduhc49KfnKLj8i9593KzpIfvMJpoSCBV+OV6AwowfQARAQABtB9PbmTF +mWVqIE5vdsO9IDxub3Z5QG9uZHJlai5vcmc+iQJXBBMBCgBBAhsDBQsJCAcDBRUK +CQgLBRYCAwEAAh4BAheAAhkBFiEEPZg8UuuFmAxGpWCQNXMSVZ0eBksFAmch9N0F +CRTtdXoACgkQNXMSVZ0eBktE/g//VfuzVv6KmNZClp3nT9Z5tZ/keOUpV0aElRjh +TCO//OqigTVnsdApEIMGhkFmHPFRd8rJ6uhuYYtM6aS89/YhsGlPcDJOOqSipeSC +No9eBBTtPAuo9sXvQUlO5frEAWXT2MNRz56af6IoMVYpr6lLJPlXG4UJ6jpNwZPM ++d8L2PC+riDAIjXDQ+ZZv3sqBLsSMb1OCKCTu6uaSeSaA8hPfgMz/6oyjcFLsATR +wY9ixcRzjxHqpuiMWXK6yt8VK/+cyEYLT2p5Kc3sChjtqLSjcYM+rousYfBy+qUZ +eOhZPgtzbTdIu6RhZQitRDlf1HQb2dLGDl+AtCZQFXxY/lnSB4D3JHYGjadZ9q+4 +pU9v2shGear7lTXAwNq356I/6EooT3iwNGySiehBl2sIWB8PWBDa5bibLdhmlYCM +XLAFA8v4tgoU+/eY5elo0cweXVu0VVaou5XNTK4bVAUnoLCdd7kOtqUiapGxFFFg +8pa2VzB0G/Syscf4VS6uw312lUQUCggj01ZggRFkiqaCMq+ldp3zt/wVShuU4zlO +Ft6nf/wGEaFX6Nz/uWy14NZoFNO6i0SA2zL29Lh8VyHAeEqvwNvTQWyqXH/q0JJa ++/ANKpdOCYZoOGZK3kLzuexwGFz7v/Dhp61QeQXlPxKwk5BWR3zFuD1L4iECAUK/ +rSZBcFK0IE9uZMWZZWogTm92w70gPG9ub3Z5QGRlYmlhbi5vcmc+iQJUBBMBCgA+ +AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEEPZg8UuuFmAxGpWCQNXMSVZ0e +BksFAmch9N8FCRTtdXoACgkQNXMSVZ0eBkvNKw//aY3KISL+gJCDqxJw4jM1KG2R ++yCj3Pk/kd+Jn2V6w0zcdGZNUGlDKju4WC+pGfhNt0sPEFIBqVlvqo2g8LWzYMEY +ObHGmGGExdcNasSROEecEZCEO5tUkO0mIGVjj34Uz+2vEqA70cIrV9OTXjbCTu5/ +5wdMu3WhuOs5nos23wuuYtsSELW0rA34AH2E64YlNQj/kaa/NQbd0kmqENuRrrua +Btm37mht9rpazN4leGJ058/33F5MvgGvJlXiZeHPLWAGqcqvdV/S0DEoLnnA28kp +MjoTc5mdsqrlFzbKzGAmPT2GsAOId9NFR++A1ZwRHnEykQZPhpYynoJLBCRdHn6a +adrJmP3UlDEpNjr82Dwg1KljshhDrVQ+BpVDSuBjw7g1BzX2iFoym9Z+ZH8Sgsbq +4rbyyXXipO5vvrENCIm2K+h/Se6Gp370lIc7N1YIfdFxdNgf8Xm2gsjb/N+TLPYm +WA6+/0vAMA/SfQMo+8KzO2R/kpko5SPy7aVmc+/wI/X8FcYFe4dhHpp+pdGgxgUe +KJJF0TMBnSYbtUrsVgZL3eHMd6KhA7GioE/JknpuqDjVFQ9Pqxsrw+S98HhsJJll +KgUBMel5SF5nnealImOk+At7oqJOC3cMDdl1ljq3KA1OzMTQPQ2o9MqVZQCOqN+v +c1R0nTsLBeUqS9sDcWq0K09uZMWZZWogTm92w70gPG9uZHJlai5ub3Z5QGZpcm1h +LnNlem5hbS5jej6JAlQEEwEKAD4CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AW +IQQ9mDxS64WYDEalYJA1cxJVnR4GSwUCZyH03wUJFO11egAKCRA1cxJVnR4GS8I1 +D/9DHGPgpK1w5WF64fZ6OmksJlsXh95u4YHmP5skQoazHpurH/KxUqMPTZsJmZJ6 +hbbiEmuv8DJWdNH2+m1YbJZMsBFO6Yccf6KjiFhWHhqBX0VTBn+OoYpNZ30yxP4z +p7QdJtF5+JyhOa1FzKYPBL2xpNLSqOn0FJe3sjXpv3LuYKhWxVD9MZcLdxbILVIB +H9h/fzlSqA8eCa9Me09MVjVBcpHi7odtnyiJCEOmom1fjAGJxIBjWswc45pNXk9L +feaOtIAkP5wZykR5ja3KwnSKcwyef137UFmLXYWUslvUyN7iCWhcEbuS+naYZm84 +9a6+CXNt2CiLeNCN9aUqE5YB4A1hsVrXRPmdGUMqqwqDV32mtkWHm9fFKvlIBOmd +7DrziXp/TtOCwn7ssS09mVAywuk7emJbQ/TZW2ErTE9+GBvEVbDsiDS+O9/O9FL7 +EvLbZ9ZiQaT7Gaw/1sFpph5fzuKH/2QjbtNk4SrSWnSTaF9E0b1sw7PZ0V9so656 +Q3+xE8Bxk06r02QtHDMhe1bBVrm+mYHl0xGgOVPGP4JxyiGaSrv4m9tsGuKui+6R +UoGrD/+RofeJ3yprm15MwsZ/l677LVQOaJW8+g2ZHuxzgNBeFXzxgpmKOkIni8Er +5aBLXZZGunxMeix922d8veVIoBh26bI8KSJdAbfngkJzR7kCDQRV9uZjARAAqSfp +goyJefQfvRg/deF1BNZKc/c6Vc2E0Tdwe44xQiUlAKv7V45v/uCWuNDeW+LzslqV +bAtQZJJQhgOzPjwonUH9vb7DDCXZAUaYSFVu/9WAVCXa+LyNn3DlYZjnCQylGDDj +NephM+VlS5jj/8CcG7Jq849trN7Pu8miAzjp6xwC/kFiaUhkGHRX/9jBlD+BJIEe +0v0U79ztHU5jYRgpto7Wi2EKLjquUcM8fAhgqXyjBPgJUENcDBpv9xHDMG6iK0LJ +pje9a0rQQMjFPFpEJRrP2hZEdhANtaiHmPw4v7EZFMmKqlYA0rmA6xlgf1tQPvWB +zY5Sm4JWpPA6oloTHaHQp4cQAOyhkUIzs4lBfAI67izZ0f4OSV2YN316TyVVL52b +Z9hDxD8OEpMNJB+UMmyWj3E0/UT6LJpwia2++gShtEjmcAvLoSOp63Jpoc9kivdq +FJru+480XCZgCMfRw2AjXSh3oCH9EJKVK/7ZfCWunjlvTgz6JeLuPiBEhnGDtung +D7qjvJzj1TFwj3atRdO0Nvv+OnqZ313pCgLQ8xekmqG9ctSSekD31/U/iF09aIHd +saTzJoQqGnVmFXjKgmCTP2fa5pvsL5gwLaH9+oqTDasFaq6UdbOuLQWYld+8kLKM +2pxg8P92spjaOQMlyViiRztlmKa4jehpL3XPRX0AEQEAAYkCPAQYAQoAJgIbDBYh +BD2YPFLrhZgMRqVgkDVzElWdHgZLBQJnIfUPBQkU7XWsAAoJEDVzElWdHgZLB+QQ +AKCzJ+0EqJ8HvtpmuxmQYMuh80TMMDagGzA3Vg9XrVMCW55WpjfZrrp+31IeSIob +DMGiplsZaEkGZj7a+FIXH6Goh8aH05cdETZRWYPa3AMVj0suTZ8YEm/cXKh2BfRu +6zXuMBVXNpVhhBe9TJK0SFKNkbvTunDhvD7qIJJ6r6+btTYMRt6VCE/MGuR77kfo +N8orZq5tpAGyi6jLK0gDMEsNuPzXpzZJRUX5MCtnizDFMpM+7p83kiZqEEwU2emi +9HjyKfU1I3QekW7AmQAj/YR9zV+9cs5OtqR+cUGbcltbtwqexfLC9ySnCoxPxyqu +FqFVXmBXongIAWnnxqiYol5V7CLaVmBI57s6cjgvQt/Gj8jcfiPkBmFbzGx6ivIh +pG+KvdpMj4XUQ5cBQL7z6X1KYggk3UxEBigNC4MAyLeHsaEYpKowXLpRrgFYFUHD +vUSym0C9s7iMZFX677tt6nJs3dJScyJdkJOhFfnb0gDQE0A1WMkQx8XWqQehD5Pr +qv9ashfY8zaHlclnZ6QqYKHULkIaoVDNGZCkLiwBid0+PvdGvGhu7OL1TDPCng/6 +E727g6wZcxMYZTAmewva/KIuOpb+QWy4r0Rsg1eeF6ulTIEGfjOKPJd6/RsVd2eJ +zymVrCUVcPvLU8nVKsgJZLYsBeiq4mtaNJ3rvmUeaaZImQINBFilU2YBEADQf/CT +tDpsKjzVeGJa+PIJq+qjdEWU2KWAcarjyafNQEDjEaW/FSj5k1PLWuz/GLdPCH6s +bHRu92vYUZ1gU/GehUKirz+r/fPI3T0l4MVL+PqldE7j5TOf7WJ7y0OXzNzbUWWd ++7L9NkN++c7Dd0F1CbGsVsITn0lF6P0G1g5oee1i5RWs+l5JkYG4b5Yjzxs0Fn9E +Ie+Ka5bdxF3r4Gha/zc2BVScUCi8raYroLRd1wD84UunrTjxHmVkLujHzeIX130A +cKKZ/z025DeVkyGAO6d0gF5KaET+O/emlHQ7/dvY34ol6CHVCnnP7C9VDQL+3Qr8 +EBclXh9KHbASMgaU/iMYmF+7llDvtivc5l2A7NypLPOUW0RukmyGnLj8M8LtDzhV +yP7apG2tXEDVZ1VaHmvDcbwparCiDzAbmX4J9QD9m7s9r+V0yEFxGAKtsvVrb8Pc +ZHhtbuGJaFMrcco222pbPCGYOclqvSXQr59/8+qkP6lSKnYa6UAGIMVHW4LmOznA +vBm6akw3t8QYlKByb8C+j0w0lVpfkDwol5+VDnTLnE/aVGw0nDgvWwyq1PrJz1Mf +PrHi0nFKVizuZOD6mlncKFPuU3cNaSfkv0iNg5tnIalGIsKbxq2fjDhcHAfxXEFH +Qb1e0DkgLB+cApLBX+XsEDTCLiMPqUN0sggHHwARAQABtCRPbmTFmWVqIEtvYmxp +xb5layA8a29ibGFAZGViaWFuLm9yZz6JAlcEEwEKAEECGwMFCwkIBwIGFQoJCAsC +BBYCAwECHgECF4ACGQEWIQR0bN0YYYY0KGDrnrVj/hDq1V0P2wUCZl3cnwUJEXrw +OQAKCRBj/hDq1V0P2xxyEACu4krhemDHg6kxxr9mNPEf1sPcZGA286cpvNfr6+yB +sbpqLuu4QCSJbg4hkPhB/hJHhtNpg0gZJpITEdT2+J+GKEIYBQ5IkGLxZl8uSFJ8 +3MsGEzLKfFMHoBpiPwAE0ajWI6ZGhvOFkuWDBYVSrnIG7PKA6OiNCD8VlrOMwOU8 +X6jmjw+zmUni8iDlM2zGjgZcg99zdZnAPuj5VbrNMya4kTNZVAaA69QmxWyAGJI8 +DApwj4ATAAQCCB8MCzYwKEvyF+jdu9AFLeK1RoMQVZzxXvDBsSg0a4xHYMcHrrxP +YxkAlU1V1FcZ71Aw45rs/qJXKlFiPzOnEGezJUawbNm6Zujx4vyTihtBZxaHMuNU +4wcrF4zUck9puaIXzEFuTwkCLWkb6xWz+X9XNVsF8dYJ+2klM9q3rKtDBqsnS+WM +E1g9+TwpSyJrf174OTVztlgAfjeQfLeYmTMEl7FLDEnRgyHK0aHeFHwxKllZD0sI +9Qhda1MKR2yPnmbsY39cV4+cVzrDwW25SGC6X5fSZtK5PmfneiuHW5EDRtkSODXU +i81fYGCjtlEgCJ9y0Iv+Pb7aLulIWUfqTYWRbNZv7kSOgZ6uU5hcjLpO2xfcV/sD +Qs7iffX8Yp0/+Q4/wxU+Xb8XElpei8X3XO63/Mvjym2zpIWLptd06h8a27E5PjEy +KrQzT25kxZllaiBLb2JsacW+ZWsgPG9uZHJlai5rb2JsaXpla0BmaXJtYS5zZXpu +YW0uY3o+iQJUBBMBCgA+AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEEdGzd +GGGGNChg6561Y/4Q6tVdD9sFAmZd3LUFCRF68DkACgkQY/4Q6tVdD9sc/A/+Il+7 +/pixpTIXkQwqExrTAdJ+jfzwyJ0CDZc8Cei3crfZNOwLMZ2ZGPJkTOURHkDHp/+j +JUyJOBPwXeBWGR28ynGASZ/ydhLBGcTnVUpDE1h92D/D1zJx5i/yVwmsWxiP5ZyI +Ua+RX3cVUJfYjLvljNrYiD9/cm21+Us1Kgqm9q3omMZUnarIFRmj9uIJ2HNO1n+H +6HpifrRGl1oI8Ru/NA48wPaYfrB/Z9QqRmv8UhXRXp1q3REQ70d7odvd/KS7ssV8 +O90vdm1FSx38B21ZBgr0d+wDDVazzdrdi9Hby/4ONiAz2LoLDB+TuoUV8nfvyRhB +KQTS+pFfEPP8U9cM5gJeQzXB/5LFycopAjPzjFolVtXRgXTGzjFmoGiQ4QVXtGA2 +Rp3ohZnoViUJvkcRXZ+RWJ06tOg8IGpk1LhI9M6B7YXTVMQq3/L/89oES3Sro09R +wUw7gpglbuHdV4SrLeXotx15cnlKUOfU4oekgMEU3xY2ojbJOOJrchlBhw8s8tlH +MhOWoI8ea8Pf2RpuGK0sBFzenf9naE8Q9mdcsK7OQ8smEhlueGu2devbv1wpDt3e +UN+oxXN+b0hXg9T8v+NdmuX4fQ9NE6E1MU01K8XdHBtq+IrQAwT2IffdCS4Ghgqu +Tj/KRJmL/E7TZYhbvCXCMFCVlhZHroDx+3X6vlK0J09uZMWZZWogS29ibGnFvmVr +IDxrb2JsaXpla29AZ21haWwuY29tPokCVAQTAQoAPgIbAwULCQgHAwUVCgkICwUW +AgMBAAIeAQIXgBYhBHRs3RhhhjQoYOuetWP+EOrVXQ/bBQJmXdy0BQkRevA5AAoJ +EGP+EOrVXQ/blm4QAKlj9eJPZQA4nxda5qf8qMc9061mzs6vBsnYiE8PZF/zZR7e +AmVT6Nh+MQH3D6j4FrbRTC+KjJ5Hl0aFG//V1U2mEckK4VdkYHxWMTyJlZ91TFK/ +vPhdszmhOxdhT0gcA9CmbGhnYb62t4uWw3T5s6bH7GKPuiVBSLu18QryiiHHXzyu +jDB9znlJGwH5DUsO1jXirCVduiJ8+KSAU898s14D280ytMl26nxQE5n86jIe4s4z +xOW13nKOLSnF7YDWhkpDSegE6+Kd0X26PiqRuMHdknbV86nktn27wP+/woNyzaDF +4Ga3HXInW8s/5BHtQfhcuA++pHWrYZhPiBzNAcsFIim1Zv3GfxM4+lUbkwddIaHx +kfMmuRKBYVA9/3TIujuAK8ovBHl7/zB9WBeEnAML3wzSmnAFnQdyshc7WAMNh5nB +hWFTa4O9UmPRKdIfWdNVEp5TDor62r3R4Khjij6LPCnTzpX4OmwV6keRAikDYH6n +Kik4lrXwhTJCF/HsXFyNhJWYsLXai9b3oiWrayJ4hX1WE8eYc/Gq7cNlHHin4wDD +ftPpsyDBq6WYs43U4x4jaKsiRWgPnZdYPIbL0OkDtfH5Te3VQqHSRTeyuNtlVWJb +XHn568yDeIxA5bAlpQWIKlui1exTZtyZIVMxOSaEBa7AutGnSW0WjaCG9YV+uQIN +BFilU2YBEADWFWz8yy8cS3z+fnj++pL974UMe0X37GmZzw6EUHePOwI22Xl6DseC +E3LpbnRUHlbnKOwLm/R5tUy5fXgXgAi5REntWJ3iJNgQK2NxG58ow3la+8jRMGdk +GXhdtH6R8JG/jFCUUdIbT9FfhvKUKRT5Yja/Ai/Vy71abyzNuNBA0i8UejHntFHX +//LCwVyuSN4XgorXLWLg/Vg81j2C2kbznfDLfdEzM3OUyozm1i1InIwT/oRAyIRk +JbgmDLRY/qwED04YmDcteDemDGbDdTrmMSklMSSGR6M9V429EFjLdVEWA9YKX/BT +Y6ZNPL1R7E/IQtHS20JJzKvFAVeDz8fPD1N8sfulOaZvx6b+UE+G+fcv+mUP0wEG +2rlYgdIWD4rOQh2+eLIPoPDaVTfaPy34B0EYtk3T2sDGXlIEG3wqqRFkSxfEX4Qw +gT8/rvIbmzi0QFGrBKS5WtMA2sz8lKedXYlRqN4FaIAKRj6isErqgxvRyZRmhWyZ +khfKhwcoMZJDdjbvoIEp6cos18QQYKYczKz7nbnGTpjT1IFX2wik/vBxRYvgW1gP +u/ZkmnsbuG2RRxtXKiqs7GInoY16ptMWTjilAanv/XSXpCHGfmBmeBGnJHo7hCxo +TIpA5rDmFrIgGEKZhvaI3P7+BKuQ+SFq076NSOReGpnaaISmjo9kWQARAQABiQI8 +BBgBCgAmAhsMFiEEdGzdGGGGNChg6561Y/4Q6tVdD9sFAmZd3a4FCRF68UgACgkQ +Y/4Q6tVdD9vfPA/+IrezMN9C3FJEwDYuyJ5uvltgh97NdtCelvJ9lvwa370X8G5f +wRMdMMYa02InhuskSuArLuIsvKYETcLiEZyiQaeEWvuPqSQs1Y0gIjmAz6FIQBxY +JFZsc7GmOeuq5JKBLFNhN3g7bSWGvm9/+02swi6IuLwcyoUBbH+aPoGQF9yZlwgu +ylTGozu292ZtLlr9iS1foJVug+Hl0xacaiAAbRxNqR/EfHTVj7m63DS4kTJpfLb5 +ldGWZD5AGdvUTytJv8eDMdOGoUnADThIILgneXu33SUUoUwO3JiDPw9dicmez+yP +M6l3H8E1OqfeeCUQpaTLlAGLYSCrDVH9iMXANjW9/W+y9pioo14gsmBft/sIY88u +TxbKb3H2NSmk8IM4fc+XduKGsxYVEf9IWlLOpaxtD1r056NBJsjjbpMjaWywW+zn +aXWBRqRy8BTf1/XOtXXpqligXAXAzEbDIJVTuQ/KZql5/dRHMR2zF9kdjKJ+d7Sk +TEw772uVyhuKIMqtjp29jwqcw63BkmJ9k8jJC+yXUSLTj0WMKoI0DPl9cQSbE6z5 +LDGtZ1blbieh6whwYvkcOBJd6vSs/na6qqEIK9oMsUtG9mI/8q2zWV7xfGl5o1k+ +raM9hP1zGCymc3FdhrjqB8zB7wN7oBW7Or//Ct1ijdR69HN8aTRknIj6GPaZAQ0E +UiC0aQEIAMHzTknImxjohJjz+EIl1DB09sJ2vBmt0vL5wkM8KccaYA0MpmOMqooz +gyqKoxywdOO3Phqk6n5fLtjsqTgWoG7YivipiddPz77pnMvnm+1x5bbNCBKdGQZp +a2gkf5RbEYwjEjPgbzt5FHzpQT7++oVfVnWKg0oeyjsTXGxRHLoRxqAhDSWrFHij +K+iW1E7n9eE2DZuPO4ATZRr9zUoQT9pkCIoGKXO7+daCU4aViHwUfF295ukKWg+h +Ldigp/eq2xGICTo2zqOMmJU/PpVFv19ij8O/jOLKuQjlTBOgDZ9vv3OFLAp1YBeR +rUqWwcn7FZfRjaSl0lYV/3bXsp5+NYcAEQEAAbQrU3RlZmFuIFNhZmFyIDxTdGVm +YW4uU2FmYXJAZmlybWEuc2V6bmFtLmN6PokBOQQTAQIAIwUCUiC0aQIbLwcLCQgH +AwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEC8q9jUqRTyt9GwH/3BW2Su1m6H1z3ad +S3wrNZxgvF9mcsySFh6DTNzRzx1g7qlZb0Z3NATHgmYZ50Q5Ib4e4ga70kqUiiOW +zS8pZjrKU4cQ+dGj8XOdfJj1j+xD9lrbXFHw5w0B0adb8GM2R8Evh+1lv2LXLwaC +Iu75z2+uMdsTgJZV257tGKqb3avSvmo0BPNGAXcRrAo9ejJR2g1g0XwWjFSCOIah +fUEWA4vivy7+wrgAqYER1WyrYoQ54yGJuJgcQ1T6HjJ6dHkFfWmDMPz9VrrjMLWP +Wz+6ZPCsRUNM4K/u0do0gmxel0ewguEH269ImDyovYMi75TPmkeLLgM6EickFa+9 +gB4WEKG5AQ0EUiC0aQEIAMQGNvwuaaa+RXHMHMaRdocdgLP637RQqqEncy6b46A2 +BqZhLWf1i1kSrdaTgsgjIYlTWB6jxtWDEbwXeVsJK7gZebjZyb2sO2/26/aT2FQ/ +jrEnYXn6f5QGXjV2OEIaz7+jGKGRCE6HCjGbh2O7yCRFp6AM3tci/XV1LaszERb0 +f3KB7V8HDW/h2zAgQDOXabv/c2sTt4tQNSwPExg8gU1xWNpsnUNfJ/O0o6xLUUkj +7Z+VGHmag8EzUermS9TtF4/oNlrNZPD6GZTT/qw4Pff0t4alAsV9jc5J0tq7odS5 +X/38WGZNF9GAGCtSSAHZFhNoxetz11Z0ncQT9S+71K8AEQEAAYkCPgQYAQIACQUC +UiC0aQIbLgEpCRAvKvY1KkU8rcBdIAQZAQIABgUCUiC0aQAKCRCi0IsGAXXWCnEg +B/9fcao+ET8dLGl/ASL35sPv2W4Xn/sduwB+FdWtrgfmrK2a2RW1cY4KStgY3suT +8AYob0E2TVm4KSu6TQrtke0F6ViR+Aione98tDMaOn4gp2x8ZVe5ZiBkdNLbDvG/ +l5fjgl60WRibkiRJp4LiyXKvjXDxs+2y/cODZNutGL9cus/IYshMUXEgztCnr8AN +pjLobgWklRF77Vb2Gj0Xyok56E1U8hX5WMI5SgguV4mOg0wXpiQytgHah48ZquWx +9I56EuODmCsKdXJNl6xdcYZR21UkS0mWeU+p85nY0mRwE1MWPN7IH7S40vpRi3nV +aC++3YneSr1EGtQZxJmVZpInj74IAI1yP3KldOts74awN5YOXiDbbh/6Mtkelxpe ++FzSeiHX/olqZn+Om38Vme2ntU9V2Y9fbtxAo6VboITf5tXP3FclQxOhM10rN2gC +UOPDIRrNDXxRWoDjbbihpUJIKbVTYWtqbQgSCs+S0rUROK5/+sAkMX2WZ4NmyADU +XXCTLRpSJ7bNei4OFMSJtwhgFzXU5+YCaX9NRsnEdCQVga+IDFtSFSSo4cIfECND +FuyfEnjto0mI0sosCtOv2yeNBLkl3sS3X7/F9UdinPcsChfR+1Vrk/zwtP6EdjIv +B+5MMuXbP4f9mdDCCUSJ2Mte66kuds2AL42AME/4M2tE2aB2HTWZAg0EXEM+0gEQ +ALzF49pa+rlwMwFi2ul2ZHbRhfnGsNdR4eC55JUT0zDzIJqfYKrUBzWMdidfGngm +Peri0hL0mragBurHK8Ex0lioTPjPvT14OdgFpxlBwaqiMuHccjY/uWaYrGQvytLd +DdSDTmZhP4zCCZG8g7X6TBBNyrUB4H3P3/OKSBjUm/VHzqAfwbzg49slSjB0T+ZP +elD7ZRCdqsJU8ndYm1k0Nc9HOySTS3mH4yDlG1f4I6gd+y9YeIRROYcx/KfDj0Yb +9gXqMtJXMyUozPeN0548gCumbYE1S7wO8Sf1q3p1opHgCH66MN3TyX2PzAWEmd6e +f/34Q2Ob2Q4ZBY6Yf98Qg6UwABNV1kR8dV8BZuAgI9Ks/KL6/cAITi4ShrDzkuBs +ABuHN2zCUt7MvFLsstOl8NlQVl+SGjUxIZdoJDjvn+JUB67GLrUHZVyYfiU5Ifsd +g2QxjyCAaTb9Ybfl6rw9mZ7w+9dSYu75/aPPL1cV6Qiv78qzZNyEJNgLDpuFIs9r +X0dqkLG9ZeA1xjNnyNQuoFewB+Pg2fMFOfq7mewnWt4Dwag728tpB/csOCv5Rj/P +7o3jviUBV+vR4h1bORY+9fx9wEJ+IH3jis+v5DnRFR9z2eAgo/gmx+WFdOfrTVov +ivqqQJwFWo795GFvi8IBSjtyx6ZMrMj/TmigZ9C1nc7lABEBAAG0Hk1hcmsgV2ll +bGFhcmQgPG1hcmtAa2xvbXAub3JnPokCUQQTAQoAOwIbAQULCQgHAgYVCgkICwIE +FgIDAQIeAQIXgBYhBOw8/oj2ygeId09cHRqkS+ZJ3nYKBQJcTfuZAhkBAAoJEBqk +S+ZJ3nYK470P/0WLos6tT6JgeN8iT7BPyPKEXVg0BOeihrlbvL/hCVc4jIqaRcz/ +R9ofWFk0Z/ipUrh0FR7C6EAswTO52RcSHO52D0qkH1Jodk1HkNn5gejbTjMnzg/5 +olrsXwU5Jxs0CIbikUYLuxDG+0DPSyQzTIux2E2Da0zyUzef17+s7gQrtpHnmiPM +T2kJaFFLH8AphPvnjkrNe4JFOTLx9Fwjxh400s8ix6hXdA+R/uo2LpheXTJQdXmB +AwJaqBt90cCWN3b43VFm93N8Q4tU8tfj92DFvfqL04qS4IAcugvZRd/NwASWW0dC +6d02L/FjNKLPMRgF4htWtu6qIk/XOaI9QrEeJuRTdOFllRuicpE1U9B7WE7jsLHK +PVHFeXo23251rdb2jDoqv3oGOzdZUFKqy6iGpoCUDELpFxyyWsTD/s3uXxLjbcsk +jplX4W/InOZICqQs3P+24VIyPvq4fizV0ttG/wrh9zDW9mCrL/iMiEEXJyfb2Ew2 +8iYpsycsPALsr3aUEZDqGnvn/Qd/Woc6kNqLJX1CrOvexM4xcmJibdpzlsOolv0y +Llg80HY4PfDdsMwZPn55aObD1GJhPmA2NjqdmEOJBL8+0hzqXeLYZoGNJ26vCPjt +OUJYAuPdmKIQqLJtqcrn9hd1VcZyEueg2TF4jVhwA1mFfrQVYTJodmxrtB5NYXJr +IFdpZWxhYXJkIDxtandAcmVkaGF0LmNvbT6JAk4EEwEKADgWIQTsPP6I9soHiHdP +XB0apEvmSd52CgUCXE36pwIbAQULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAa +pEvmSd52CuiSD/4xqtmnQJJNSD7Fce1+Wq4Al2iOaN2kxvjegTzL4sxmOAsqkwZm +AIN6kT1jeFPsMTRYM0N5z36bSSuhAwQGOC8PpCkeKPKOcz8owI23Pf23uW708DBZ +jG81sRlqCeHIfVvsA+FvlvLLJyQ21YuQbae5CslIINyj+6FEKcWfTE4JihJj7nHv +czkO/KviyD25ISPcwkv9VQh5Hlcp/k65wAqB8e7CoCaDsI1ZXG1t0tLHQrmhoN/l +SyN79yKUOelFyF+kVXi1/c1Q2ZwKu9gIHuBx3MY1/e49eoi+WYWUXNuCebaUpCYB +7fkQEjihyRjyIrwqim0CoWHNRuDGxWxs3JWi018mt0OHpBc6OKIXdoGu5oIxtEif +miFOcAmMRFA7KiS5vrh/520M108SKEIR+crm+DoVvPM+i6cDxoS780tkrjySFwJW +xsqx+9P7kWVpMChf/JkIzArCxGJGfQ0QfNea1E3PQiZJHjpT10FG8a9nwwIItI98 +gFMZawu4xEjv81CayAm8QoWAMfSjFhv9j7Cm6xgADCogu/qupmNPUOtxf4NQxBdr +G/m4LjHVnO0hI+uIxVH/cCfr41NRd9tQZIf0FjAAb+p/uxBZMJzZMpQkeR9W6Dhz +tN0zU9I8i2wRAke/zLacLeOnOPp/RDwpkMr3VNzFTzkb2YHtYc77r36NtrQbTWFy +ayBXaWVsYWFyZCA8bWp3QGdudS5vcmc+iQJOBBMBCgA4FiEE7Dz+iPbKB4h3T1wd +GqRL5knedgoFAlxN+lMCGwEFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQGqRL +5knedgo1bhAArI7kReYq4YtaxS8Pxb5MdPxiQVtvfkbycWCZ4owzPeEIkJqcbadN +UiGSqCRR2xeT4kuzFZWILiZfBTwHwFM/bXRDK/FOn7F8aqUAV1tq2W70Z7BUpTwp +Av7Xm5YvsfbTBZmllJltEiIrKIzULCtRKKVXgtOKg0sd/W2aXwyl+OX+PVzu4mXX +NEkO10J7VpnCvjyaJNeKgeJYQLizSWdEf7i6RX31yC29+GsSqikaOHdfxJMM+bo/ +x/aCuYlgDB+OQ6LZzpXZO0C8B5SMgMfZaK1rxDtUtViajSyOFJ4Ig6bcgc5qDCLn +k407oEN1yBWps867uN/Bi4Dk+xh691feGsyq95DvPis2Ut+0X0/Wi/uLg3uu/X5E +cNHynwht7KaGCLeuOZKxvzfeudNeyKFX34HtFyE/2k9LR0mFX8XnXQGBD9psOxcd +2K8Rku9BjjKDZ/vf53sMh5vxUNo+zkd+5dLZWPnLrhkfQrepDBP+Tc/6W0VSZCP5 +/nKX6GjPwmELtZj4jGf33tgfNMJrmxGUjpDxtiJc7OroNC4he3F5AF4RNRa5VvHs +6ah57swVvKyJmLH5mxxKIn39PspOhzVxSbkWNPLS+km2InPum+fmYKQL6IrHcqt/ +ecrR7o9GRgI0cJjLJ+wv93ti+gxsUWPbAUBaJPk24omIpQafFT/YAEW5AQ0EXEO7 +ogEIAKBUkmdjzOHy4efx38TuniP7255O9McxFg5LSSQaEcELsmbELDr8S9udtOwj +QJB7IgkeWY8ioNWBFWOKNxNZpx3e8h1rPMf2yqzrmeXj3IycDbe0jJrhVaVscLcn +jH8svzgDgZok78VUXa+/qFWDcgZuimnkpf6mvqznpOJZ11IOoyCNvutLONa43JEr +vlOhy0vtj9mfqy3dmKg7stereCGRZ/wlHtlpQUhjo/WpLmF6IIc/Q/FAlKu2ljMf +esomgekiSPGewH+wPQLTlwB2XNcFNRVM0tj4M+VDsV5GQb5Ur3VuuIbi29DyiGES +IL0e4m7UAow1YFn2p5TCxdom83MAEQEAAYkCNgQYAQoAIBYhBOw8/oj2ygeId09c +HRqkS+ZJ3nYKBQJcQ7uiAhsgAAoJEBqkS+ZJ3nYKHxkP/3Aq4iVpExIHUAwLCEY9 +qpdlqGsnrj1jSMjgmqkUq/b9TmEoc4btuKFEB4SPulnOGWAGuRmDVIF1ne8ezW58 +SWd97lFACl0Ob3d1pTlI/b2ISK8lDEqMX3UR8R9+XS2vHHO0GKkjn/YP6RpLxyc1 +V/OjlkRbL9x3oBKG9FUcztjZAdz6aVpmFiEG9O3ALpq9c2cbnlZiChsYQ14DCTIP +TvYkXdevEVv5eRwrGVr3JF1Z0fEl3k9gmqwoz6dV4kzbbo7A7JTbfmB8iEg/ql8a +oX1RUfS4WgJiRWRRKNV33pD4KPSR2FM6u0tbU5jXV31MHGN7jYY61ztf1nPHWeHB +TysIISsX3+4kgkqWrsjTysxfesUNO2LPA3uDtkGQMOJk74EgpA+39rAD00z611rT +aHJ9CiQEGL6/xv+IqJ8oh9Rqo8OjU8Dm7GWN2W7JfwBcii0qMlcXoSWyLPttWlwh +zRlc44Wv3KWa1mbnVg2Y7MM3OcQGaiXagFl+yTYbnn9CBKEeYpSe/MoA0EZ+d9L9 +r8rse/ix9kBvnw+uXo6ZBKuSaHMWvL/gE0sqr6d3izxVeQk+nHc6B/cOgjKeqk0X +RvB/nZTkiAlI1wk38esDCFobVb5jcsN7tLX0zRxTN+0RR6rcl3z2GiKMLva11tr4 +FF9bSdx+8RyyT1CJ9JTW29nFuQENBFxDurcBCACpIzhbHhC+8Ih/yKz7nuYsmFx4 +HaQu3dVHrtQVkLTLByvlXSm9O67ZTWhQH4FVgL8D1R2e9ZPIN5/fFMLHSECKIWGU +x7oKQ4M5qWbEj4rA/EPbvr7vS1zF3y9HYUm+INArD3p/aGUsCfFHjsZSndw98iBV ++S8hedcsxQlC8GFd5eqBiE5wCmUjrvuf/NN4WMG138mq3IOgnQN7Wh0TIL5lkP8m +jmrzRLJ2G9v30EdAyAtMlMk9bWJFXYArjF8GPE4zCqaX0vHgdEilX8gezcxPKESk +QD4j94qk7pTECkdYdnvpmbwEvxHCd8VpeMy55GEgYwW0mcu40VzmY4tdre6HABEB +AAGJA2wEGAEKACAWIQTsPP6I9soHiHdPXB0apEvmSd52CgUCXEO6twIbAgFACRAa +pEvmSd52CsB0IAQZAQoAHRYhBBJ2ipZ5WZAQeg0v3/xX48ys2Zp4BQJcQ7q3AAoJ +EPxX48ys2Zp4S+4H/3aoyPaZA3cJdFBROWbNU1QkskDDONEOhK3eSoOsAInY3wkt +LFYV4eYSauuYU9SZd8FSRP4XZb46uwmVS3B6m5NhE6As1l5sVB2MHfyiqyPxEwpv +mKRae1FSRrbGFINEFrQiWnEcFYsdLycTHXHgcHi5hErcilZKEBWZaTuOIBMYksVg +kZWjhMF8zbvMK3Lz8ZA3/cDYMAnY4luInXYHJODPO0Z2Enr0f9BSW2Qrt4lQYyM/ +CGmanTuWuiXJS6tvNosxCjDhIuj9kjFrSc8L4CgxKTTq16JyEJnAjKJT/vRLRz+4 +vdEWGdNuBZx1CQBWlZ2TAWogRLjEblAtS7zn9ZPuUxAAskoq446ls54q/ItXXo6j +vQ5Oaz8tuZdT35uMKPPtAhK7OEjiu5rSieNDMFpFcViR8KMG51ZoSnL/A/nCTpCW +rEuR5k0KTROzCSwvFCPI7ZeAFw6etKxAgQntUgIb08O+1XNutIFgyOgOjnwDKeIQ +xUA3JScViXVgGUW3nTo8OHzpkSqWlttF4Cxh8S4FB0F8mFamH1ZmAkNW0QdQDFqK +qKy80RvPjFEgCzFf87GdAx0PT1eznTK+XfwREhp1px6O1CcAhh4RpQGyBCTeu3T6 +D2Wbq2sPs/gVdiFQP2+aXr+fxMYHdQmLeUqlfjUZJQLXL6g+dryn4QSaubcFsHh+ +CciR9iIQM2iC+bal7ufNQ/uw2cTxFzJhyNSgRDRSj4cHp+To14EYqpogpV7EJwTG +dYoe+XQNnMbJ28rHjWfLMUjWy56DfgtxbCkYdfMnKGamOE17UY4q1UYcIYqEqGmk +rie1RkhJyIaHfzC8q4UOiEc7clVn0CHJFYpO7KfMtqsGma+7XVMNu/SV+dlyCGVZ +Yc2XHzHwN1oS4VZdlMO5VeoZyWZ5XaFLQuiZffcsIHifReRm0L0uyZMiyv5l1UIB +dR5f+kk403E0XwbjuVksuAtYX1t64dane7UijfV/OHjhNnGbVnfXAJmM6uwv1u/L +fEfIMVoMv7/uLpNexLG2pNe5AQ0EXEO6GQEIALX1DTbW/uRO7BgrASZupALnC+Zs +QxPiV29DyBYJQgUv2RPEzrsgXRqeezKz6usDKqoVROraidWaCNyK726mXq4N1XfC +K8IEQM31ktkBUdNK+KJcOGcdRKDoSEJ1kqFqX0MoCL68ZItJ7Xh7Yp+h7hzpHTIN +Uj4OfQ59SGUxe7Y2gNIUsB0ewMdIKsTrEo74E2AvYw+4x5cuE2K00hWvKShkyQWt +Qxwyweu+uTTlqHztFA7V7aWN6efyrE9Et05VZzRMmKiyOLLTi/AMBg1QI8MvlbYy +nZu/YB5M8LMXWqQOcYpkSpXal5YoI8HrTyVLWJzDmgq06XnQ9KDNN1otVFcAEQEA +AYkCNgQYAQoAIBYhBOw8/oj2ygeId09cHRqkS+ZJ3nYKBQJcQ7oZAhsMAAoJEBqk +S+ZJ3nYKnLwP/22rgFDdXCsM0LHJwAupa9lI+/8CCxPqFG9CwtzpinQUS3P5+sU8 +ta3tvKUyvMoi2myvQbYWh9bDTI3Ic1g+YaUKL5KtYsmdRMSblNmDBP72Qu3+YngH +QnWAeSSddKj3VLzgM9qKT0IfQaZchDI8A2QMOWan1b8eTygrHG8LH5JKxnoA1dqR +w1WD/DgyENbYejBbiwG+2W04VKA9Gz3MhKI3D/8ZiN5it046eJ4yGzPCmNC4rldi +cOHCJJqnYPydCUP9WkBrYK8T984VXYInIpl8TQny/kNk5T5JTCe3LV/nZkDWz84L +KxorUst0JfPdtCLJtBmGhtwCd4FVkWU3N/rGlH6ka3Dc5VLItCjgtJB/iUWzM3Lw +V8T4EnX/JRYUGOWMvAgd3ghbtjXs+6ABzX19DbeSs4hzc7iqy5jOp2HNjOoZs+9/ +t9jdPPQE1xbnzzkoRAkftUkkuql/cQQuGaQsE41iIXXSKCAVKafxZJBZtebSQZER +O8DN/4VhwmwoO71ABINE1yTwnbRkkZUttk10/5W4s5cIMCRIYjGL3VMuLptjQxvb +I1GACrpycglRMBtyfDTkEvFFb57wBLceh2NkdbMAwM+lmflMV8k5d0OF1549UaCT +KnHCdt7JNPc6NQSHfu+v5ciCtMynP5k2kfEuvhslq1ARUrcfpDdltCQx +=swck +-----END PGP PUBLIC KEY BLOCK----- From 9670e707d6585e7483025b8928e4f4ca541af4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 28 Jan 2025 08:29:18 +0100 Subject: [PATCH 61/89] d/gbp.conf: add upstream-signatures = on --- debian/changelog | 1 + debian/gbp.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/debian/changelog b/debian/changelog index ab2519c..744b6e6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.26.0-4) UNRELEASED; urgency=medium * d/u/signing-key.asc: add Sergey Kandaurov public key, the key is used to sign the 1.26.2 release + * d/gbp.conf: add upstream-signatures = on -- Jan Mojžíš Tue, 28 Jan 2025 08:26:25 +0100 diff --git a/debian/gbp.conf b/debian/gbp.conf index 97cd209..44bfd7d 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -4,6 +4,7 @@ upstream-branch = upstream upstream-tag = upstream/%(version)s pristine-tar = True sign-tags = True +upstream-signatures = on [import-orig] merge-mode = replace From 65bcb0d8dd7e24d4914b3ce46015c97029cd4414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 28 Jan 2025 08:30:32 +0100 Subject: [PATCH 62/89] d/{control,copyright}: update my email to "janmojzis@debian.org" --- debian/changelog | 1 + debian/control | 2 +- debian/copyright | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 744b6e6..346d776 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ nginx (1.26.0-4) UNRELEASED; urgency=medium * d/u/signing-key.asc: add Sergey Kandaurov public key, the key is used to sign the 1.26.2 release * d/gbp.conf: add upstream-signatures = on + * d/{control,copyright}: update my email to "janmojzis@debian.org" -- Jan Mojžíš Tue, 28 Jan 2025 08:26:25 +0100 diff --git a/debian/control b/debian/control index 756f31f..4f36832 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: nginx Section: httpd Priority: optional Maintainer: Debian Nginx Maintainers -Uploaders: Jan Mojžíš +Uploaders: Jan Mojžíš Build-Depends: debhelper-compat (= 13), libexpat-dev, libgd-dev, diff --git a/debian/copyright b/debian/copyright index 7106e51..263e5db 100644 --- a/debian/copyright +++ b/debian/copyright @@ -16,7 +16,7 @@ Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause Files: debian/* -Copyright: 2022-2024, Jan Mojžíš +Copyright: 2022-2024, Jan Mojžíš 2020-2022, Ondřej Nový 2019-2022, Thomas Ward 2013-2016, Christos Trochalakis From f1e2f6cbb98e3572d9cb78815bd5099deb96c11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 28 Jan 2025 08:31:42 +0100 Subject: [PATCH 63/89] d/copyright: bump my copyright year --- debian/changelog | 1 + debian/copyright | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 346d776..f4c0043 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ nginx (1.26.0-4) UNRELEASED; urgency=medium the key is used to sign the 1.26.2 release * d/gbp.conf: add upstream-signatures = on * d/{control,copyright}: update my email to "janmojzis@debian.org" + * d/copyright: bump my copyright year -- Jan Mojžíš Tue, 28 Jan 2025 08:26:25 +0100 diff --git a/debian/copyright b/debian/copyright index 263e5db..0536a8c 100644 --- a/debian/copyright +++ b/debian/copyright @@ -16,7 +16,7 @@ Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause Files: debian/* -Copyright: 2022-2024, Jan Mojžíš +Copyright: 2022-2025, Jan Mojžíš 2020-2022, Ondřej Nový 2019-2022, Thomas Ward 2013-2016, Christos Trochalakis From 71f2059cf8c8d7dbbf9407f4635b9dcf1ac45315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 11:23:15 +0100 Subject: [PATCH 64/89] Add Sergey Kandaurov pgp public key --- debian/upstream/signing-key.asc | 788 ++++++++++---------------------- 1 file changed, 245 insertions(+), 543 deletions(-) diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc index 1014f9e..52abfd2 100644 --- a/debian/upstream/signing-key.asc +++ b/debian/upstream/signing-key.asc @@ -1,555 +1,257 @@ -# Previously used as signing key up through May 24, 2022 -# and may be used in future. Keep this around intentionally as such. -# gpg: pub rsa2048/520A9993A1C052F8 2011-11-27 Maxim Dounin -----BEGIN PGP PUBLIC KEY BLOCK----- -mQENBE7SKu8BCADQo6x4ZQfAcPlJMLmL8zBEBUS6GyKMMMDtrTh3Yaq481HB54oR -0cpKL05Ff9upjrIzLD5TJUCzYYM9GQOhguDUP8+ZU9JpSz3yO2TvH7WBbUZ8FADf -hblmmUBLNgOWgLo3W+FYhl3mz1GFS2Fvid6Tfn02L8CBAj7jxbjL1Qj/OA/WmLLc -m6BMTqI7IBlYW2vyIOIHasISGiAwZfp0ucMeXXvTtt14LGa8qXVcFnJTdwbf03AS -ljhYrQnKnpl3VpDAoQt8C68YCwjaNJW59hKqWB+XeIJ9CW98+EOAxLAFszSyGanp -rCqPd0numj9TIddjcRkTA/ZbmCWK+xjpVBGXABEBAAG0IU1heGltIERvdW5pbiA8 -bWRvdW5pbkBtZG91bmluLnJ1PokBOAQTAQIAIgUCTtIq7wIbAwYLCQgHAwIGFQgC -CQoLBBYCAwECHgECF4AACgkQUgqZk6HAUvj+iwf/b4FS6zVzJ5T0v1vcQGD4ZzXe -D5xMC4BJW414wVMU15rfX7aCdtoCYBNiApPxEd7SwiyxWRhRA9bikUq87JEgmnyV -0iYbHZvCvc1jOkx4WR7E45t1Mi29KBoPaFXA9X5adZkYcOQLDxa2Z8m6LGXnlF6N -tJkxQ8APrjZsdrbDvo3HxU9muPcq49ydzhgwfLwpUs11LYkwB0An9WRPuv3jporZ -/XgI6RfPMZ5NIx+FRRCjn6DnfHboY9rNF6NzrOReJRBhXCi6I+KkHHEnMoyg8XET -9lVkfHTOl81aIZqrAloX3/00TkYWyM2zO9oYpOg6eUFCX/Lw4MJZsTcT5EKVxLkB -DQRO0irvAQgA0LjCc8S6oZzjiap2MjRNhRFA5BYjXZRZBdKF2VP74avt2/RELq8G -W0n7JWmKn6vvrXabEGLyfkCngAhTq9tJ/K7LPx/bmlO5+jboO/1inH2BTtLiHjAX -vicXZk3oaZt2Sotx5mMI3yzpFQRVqZXsi0LpUTPJEh3oS8IdYRjslQh1A7P5hfCZ -wtzwb/hKm8upODe/ITUMuXeWfLuQj/uEU6wMzmfMHb+jlYMWtb+v98aJa2FODeKP -mWCXLa7bliXp1SSeBOEfIgEAmjM6QGlDx5sZhr2Ss2xSPRdZ8DqD7oiRVzmstX1Y -oxEzC0yXfaefC7SgM0nMnaTvYEOYJ9CH3wARAQABiQEfBBgBAgAJBQJO0irvAhsM -AAoJEFIKmZOhwFL4844H/jo8icCcS6eOWvnen7lg0FcCo1fIm4wW3tEmkQdchSHE -CJDq7pgTloN65pwB5tBoT47cyYNZA9eTfJVgRc74q5cexKOYrMC3KuAqWbwqXhkV -s0nkWxnOIidTHSXvBZfDFA4Idwte94Thrzf8Pn8UESudTiqrWoCBXk2UyVsl03gJ -blSJAeJGYPPeo+Yj6m63OWe2+/S2VTgmbPS/RObn0Aeg7yuff0n5+ytEt2KL51gO -QE2uIxTCawHr12PsllPkbqPk/PagIttfEJqn9b0CrqPC3HREePb2aMJ/Ctw/76CO -wn0mtXeIXLCTvBmznXfaMKllsqbsy2nCJ2P2uJjOntw= -=NeQn +mQINBGZXLBYBEACxv3nUIdUtFCpH1G4hBB+eVSsWwnHVTDtSYfINHmN8dQfyGy22 +XcX2DR6ZW9/I5e06McAz4e3hTuhD5+sF7zv4Dd/xEqxpra08liVvB3QlJ6kawBJa +Bn29s/N/A06yUrOVC1ZjhpDLshaHeyHjWDVLUX9ibLx1N3BQoeoH/5lgTmfF4JPk +LfnTMwHWQ5phT52MVE+B/XExldIPAn27m2ZfXHXnSUMKCRybQNypBiIp6OBfirwa +pyjaRO1AajwalSkbSV9o/fL3liluv1HimQ11/5y0rxMdi+aaeca9oA4Gvfdh/biO +MYcTeiZx72BKqDwMfJVXSjQ8XOYbfCjWp8dNkS5Yd4bmX+ITXRkZHqQxgmoKWr7B +9/i+asColt/qqsQ6PROa2y86TbQSfn/HM8L6c85BkJrI41abJ2QHShVzpk0e/464 +hqxvnAZCrmdM+GBSuYfDDqHHHgxhIzHnKnyRX/MtfhZA/CUFUOe+m6j214KKtkMQ +6EpZzgH52FFD6Vi1NkQvfYx5pqEdmJfRKR9ABf8fYI8U8ryNgIq7f13bwoX4haZy +ql/fC4lTG6OEppgdQe7afyAmdi7G/w1pMcbz5Wwp91R+1372XifynBdeTrUsbK25 +P42TH3OADC2Id+MaaGh1AjY1bFifOGRf48rnrcMn0Q4Lw3l56wgjou4MUQARAQAB +tCtuZ2lueCBzaWduaW5nIGtleSA8c2lnbmluZy1rZXktMkBuZ2lueC5jb20+iQIi +BBMBCgAWBQJmVywWCRAv0hMQtJ9rRgIbAwIZAQAAq08P/jeIVEj9/cJFzdOeBqjg +F9DNZljkR+2z5UAkQSHfkzWgHRbdAnjT1bc/ltLi6w/z/97kOZhaiSx6TLRg2mX/ +5nuC4KijhT9rNc/d5j/BHS4U7lFK8c5ED5wxGvJZcF0VCSfeaiuxoO3QiNYX1iiD +qEyJ1XL/XHd7LjJ4gKxsohKL1rRLSuvtOkK799YArNit5ueATDWW6EUSZaxOiMNz +MaQFMEkjoiPVlj7jNwZN7KHNXkaJjiER0kmJ9XWDtkgSHOZrUNX2PHJpxxCtQj7d +YpOFM/DHvNUZ9dHXm3Ioo3R/MUcC4mbZpAvs4YwZ/yRqov/MX4WEUtvcCY36EL5t +hUDK09huMMBLBdM0jgVLsJnXn5ksMdVkpgFyeR/SKEaUTmQrgkCIwqvRxDegAkNN +lmAiNhxdKD+CrWws+EzQYOeWVRUO9aHKC5ttwhhQuxyvmNgoAMhd8x8Tcm7grC/m +ZOqYWzpEWd1DEyi9jaTkhrSWMd5jc5lvCwOHDRzVi1HmIJy+cybPbQpkbFY6vj/7 +shx2Aa+QKRJs+33Ztg0drc3j+mDk9NJQy0KPIbqee0gy0pmaKNiJOxdIWI6ra3cM +3lh5OG+CGakga1X9YiCWv4/OgDYY/6cFTqEN0wXruFLNZ7P4iowJgPU1KZauvDZl +gfsgBoKJ35Nf6p9PdjcjcyW5iQEzBBABCAAdFiEEcziXMGntP0Q/TTffpk/VsXrb +OagFAmZXLlcACgkQpk/VsXrbOaiWowgAvU9HwLkK74VGjosmPpcjurRowUp+/KOA +HmIro2wQ6JVlUrSL2Rz+RIBJ1BKTgGnVZznkXywXHWK2LI4nL3aDoAuyyrzQk1pj +hO1ZJGJBvh9Zq/kGRgEdlTe2sXVX2G7fr4fhd6BcYYvUBQ5OWR6Hh6uS+G1QVw0y +Lu5Gp+7kyolyH6iYlgvxseche+EIqBPyHe5fyb1t8Zcu1uHoQHj9O90FvJSbq4dR +d0tTlqK1tDklT+Aod2UobBCurn45udjiAKtzH6Bg2dvF/oY4udSC9/HgNPbm7JuY +clEaLukWMdFOCEj9Xr6krHtUh7zTiU6pHvUL2SYMPhsJj6AKZRg52IkBMwQQAQgA +HRYhBFc7/Ws9j7xkEHmmq6v1vYJ72b9iBQJmVz0rAAoJEKv1vYJ72b9iVTwH/Awq +vgnXbJ5mCGbLdQgrDoUYe+1nw/qWbl7Hpn/px55BEIW5S0itI50c9sOS2QFQMdRh +YVqZ+YH4aH5pDNW2kFik4Y+CFoJI9QkrEUx66PYIMu3RVBEE7/HQEwND/IbEAeMg +PpGQdEfEDD8kevlinJTyDXJ3dfBa6HEDpK0wDYrBx3mbHP7ouACsZcxqSdx4kOyv +U2Xvlc5pVRsdvJ7AsVRhRaRdSO8YlqU1Ue/OM/Ejj+GZ1Qo8EDge5887HiY8gcjy +J4FS1n2+3839n990s5xDCFSB1G8KmwgkfbkS6gEpA5wf9nk3tiSPS+HMfjMb50GJ +SayUVrAyUupv/Sxvyo+JAjMEEAEIAB0WIQTWeGzjA9mpAimY3GzIRk1UmvdcCgUC +ZldKbQAKCRDIRk1UmvdcCn6EEACUhtMnJGtrunotTwywt/jfkqexA+lhQ+S9V5eF +IIK6Tlq1asFy0s+twYJBQzTXt+hmL8GrBgeQp26CA8wrbxmnUOrXO1K9ksaXXjj0 +SRo9Xr/flCmeFKFRSSVy18UZVwf1vftFwF2lQspU+xZmj7vgr+2vKa3Z+81J8tHw +3/Sc5pt3EGB8GeCiEThe3zr49KpANejy/7feASSS+BBBUbNqnCFImfwLJ2V99mGx +GdejudbTYEXsn6jyVWTeKBcaLM4ArS20O0DJkqBcVC1Ymq+K3AGmKnrLJXDSwaV/ ++yv5pyqApf6Lu9tx7wy6upBop8KroB9xiTN5UIiYhwtHBlpOLkmXB7K549CYX34y +aOHJjez8Txn1bDhbCOe8WOnPEDI8V4RQBr0/xePru6lfwSmSriquVuBGZSir6qxA +1folqrEuoF5aEuxFper6yC/zfVP85znqBOh8OaYTGBeb622UswzLTbW4y2M3E9Ws +KhaXzTqXgIn3INCJLCv4CHiGQQB6zN6meGdOkEV0IaZvq3O4iZOAVFmKbN3GZcKT +Kjxq295LNO15c0WCauik3FRjSppyvcAqoCEbr+LVAX3/ZV3oELhQPnkZCuAFQUB+ +LKxTcTEIdjFKrPEvDgXLL9CNe747ANcLCV02SRRGYnfQ1aoxJNQlzbFw0unHjyDk +vKcD44kBswQQAQgAHRYhBBPIKmO2A1dhVuMKTqDqmBtmsNlnBQJmV1HlAAoJEKDq +mBtmsNlni3gMALfZSqIL7v66dMyjLQR81G4o6rEAixTuFc3B8xDmWDHKIjmdRMTN +mm2KGz0CG7VjdHSe3oOBYok4fDVS0o636EOxndOHszuB9cfhMMXNDFi4T1xcZCLm +UTdXCH88cagwTf6REsbfuXF8WiFemNNiPzMzLmnTlUe7Va2t+gKD/Q9vSlDLKz66 +IZBMdDoAHDKHZTtvwlAKswnpO0cDIeZjO0C1+YFLLSJ1nYQbh6mH+hJvNLimWPKR +ZQCPAa5w0Gutz91cE9nv03yg3FMcjlEgklQ77g/nGGFJnQHAeMhfgUUfPLx1rI9/ +5NON5w7Wf3PXOlTYWO25ieUVKESu8dUCFktKRMnzauej2vjnQlMFG0upzw8dhytn +E83WanvRzVynanK38PCNYQ3INsydN3wvJNetHpBdpyPfOa61dOUtu1TBvV80qcBR +wIe6vbWZx0WB59b3KV8Sc68j8OJxF6i3E0IRby4f0hcoqogBkry0NPK/rtL2HHnN +vcV0wl+DODz9hw== +=oWlI -----END PGP PUBLIC KEY BLOCK----- - - -# First observed on May 24, 2022 -# -# pub rsa3072 2018-05-07 [SC] [expires: 2027-05-17] -# 13C82A63B603576156E30A4EA0EA981B66B0D967 -#uid [ unknown] Konstantin Pavlov -#uid [ unknown] Konstantin Pavlov -#sub rsa3072 2018-05-07 [E] [expires: 2027-05-17] - -----BEGIN PGP PUBLIC KEY BLOCK----- -mQGNBFrwMiUBDADo56OlDknN+ReCMP+8CN1biK5izmGd755TxktHLI9nAP8ociIq -Hjrps22pBtAIQ6eZpwCFBys2mR/441rOgZW+O6uqBYrttbxTMvE43EmKYGuFCmuR -u0JGMPuqnzF3Y+6uoKzqMzazSrZIBWsBKAkNYTw8+yPlxGgffhBp1ueME7Lskglh -EV9gmrEM0QlWod7wSQvyruExPm5INx3MG63Xfvc0bPiWUOGKyMb7kXA5VgnWuzmS -BCMm17+A32vMyxhYcvSEgUayQjGghI1uPDSqBQBMEFTgSK2wWzvAXf/M45nxKBgQ -IEDmvoC8RM9JTtUr7RE/E1mjsuefF2vYYYsWBstRFGAlUV1/lPNNibu3NqbCug6b -1IWJuV1DX9T9/f81GZJrsPgYYKC6Ai8C1B0NGWjos7/GzgEFENQgf5duOhFPadQz -QbRxBoId4Fe/Uwe2HxI8ESCQMwsq8bowcCn6XRA2EYkAt17Kab6LH6tTP54XG9TL -bV7bAhyrvZAk1lUAEQEAAbQjS29uc3RhbnRpbiBQYXZsb3YgPGsucGF2bG92QGY1 -LmNvbT6JAdcEEwEIAEECGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AWIQQT -yCpjtgNXYVbjCk6g6pgbZrDZZwUCYoTfvAUJEPqvFwAKCRCg6pgbZrDZZxFYDADK -R02XgC+AoyrqMwBNXC8Y6aiilEsyppsgj+KwZcGKDYN488gEmff+/KIEdtglw3I3 -tCMbo+FzFjHveeVCb0qrIMerWJg+o4YrxxqlQ9Q1InpduKLrIuGae0J1ybITS8+v -iYAmwzy1Wb2CDDuCnhCR/QDfOE1CvRILVqIKezC0tRrBTEvRO84m6YMBtJ1DP75Z -2cTNyjPos9+uxi4JcMKrMUBwZKya+z5i+Uxd66wuPj9KmggNG1x+bqMWmpTrSKUn -gbLabFUth+uWumpj3/7HBT8Ov7rPgzY/vn3Fn5mKdLQm+kRwSX9/FbtHAE3Qsm+f -6WW8CZ4XzL9ONfhQYwO2Jrq4HzgYloZkL+1Zs61X+zeEyr4o/mzt5DHbQRsD1UzQ -gnh7t3YdSAy6gBqevjPWkQlq9e8eoFRydN/htwjS7dleikOsYktSnTIKlRXAWGCm -jkRpQyZYuuPcWcGRt/0MVewRJmLemH6O+NviqhgGRePO9QR0R+yfdCwewPJEDk60 -JEtvbnN0YW50aW4gUGF2bG92IDx0aHJlc2hAbmdpbnguY29tPokB1AQTAQgAPgIb -AwULCQgHAwUVCgkICwUWAwIBAAIeAQIXgBYhBBPIKmO2A1dhVuMKTqDqmBtmsNln -BQJihN+8BQkQ+q8XAAoJEKDqmBtmsNlncQ0L/0Yk1QejO06gWwV1J2eK9LmjbMof -y2ujZBgW1IGt/goo5R4PzC8lBBcsBtsKyN0Rsh7QdLrtKKLQrE/gpwMTMdKhJTdP -/c5tUY3EwgIdBMYVaxArZQiWlPgSnoKuKydnn6Rb+Qtrhvb9pjn5XlGd/VSbAXZe -8YTj6B8qjUa2YY+IreyB6wkPN/ytV5vcocbS7mzXaibGPVT35e0Pl1Be+xbJkbTm -JTSJCSPwyHm9t2Vuq4e/c3fMwhOUbBjfssspR103vo91XO5sY+v2aQJOctNrv4Zp -HMrwBH7MeqDISCWg9PICUv0ewHzAEGB+K0v342rVAzVNEctwM3Jic7fEJYsItdw+ -Zk4r8NYqACoRCdSUEHqhP0DbYoWdthpUwD1J5ryWyKTCpTL4wNhKEMcNaiHH3qor -SssyMHMFRPoXKw9Pcay+Uo8NXc2KKxhEHTbQts0jYUNcq0yuWHoNQ4vhKkf9CHBr -b/vS22vfEJyd6FX6ZRYK56A3EFAV8hK0BvZAw7kBjQRa8DInAQwA2Rk7UdUgpCWl -+BMz9B9eKj0XtsNEciXHHKnSFYaSNCWNwib/FsiMfcPFh7xwUTof7e7HBFkvv0QE -MCEp7R1MVNBfMiGtG1ICFIt9nByznPsRk4VvbY/prK4DZy2AmlwhNcT2pQO3Aasc -gsCWdf6G+wcwnHg9tWCp0Xs9BNXuppmcRrpP4M1PPRIVeG1jeVXvuSHO2HjqPSXP -5DhGgSGN7uLOhiLTnPINd186vf6tqRdqYw3g0W1ImEjGXHeNQfnieIWdU3X4C8KT -EPsV3lvtmSAQCoge0CyKfz4cORi4j8Edp8JpDQlbAThe529+R3eKUw7I/3ESxJBd -qzLE/ItWvAcbGEserLDFrg9J1ojiKhsw3TVcDk+HIDzVakMz6HTd4ExSijMqTehz -gKSVHDL+l2jc0f4VSecI+xwC3/kNsNTBpiPoUYtXBbJllHgQAakREkSKQBas02eq -Ru8SlQ3yEn87zTtNW8L7xpe7ZVtxwUgp40PUrsb8uMDJG7ZP5rhLABEBAAGJAbwE -GAEIACYCGwwWIQQTyCpjtgNXYVbjCk6g6pgbZrDZZwUCYoTfwQUJEPqvGgAKCRCg -6pgbZrDZZ3oEDAC1J3BVwlkX+eoo8VsXAYxMXm8kIaTqOn/tHMOYepK+cWUdHaeC -H3N8LigwN4Ve2LtzLBqN3WRAxFNy0DIzdBfA7QdcAoDLnB2FNrWTmwvC9nXkCogF -fSCq7c+1oFHdn7M/VZNU4o0nhVOnqM8NLGcgzX3K3hr+WLYUgNQ9G6x0N9VU43tq -VwJhvNv4pyiRpRdLlmhOEf35a/sWE1dttSKdrBhyzTbptw4dXr4lUpvlswWs+dLp -SPPhWAuifORv/amWh3bxIxYEqE4o5NI/PQLJvJJLsJvMIIjpKlAGBJg5h3WCiIAk -l7H+BesOUIIg8ava5ZUyjlFdszBMaBosZvRgFAlfnYhSGqzhip6PvXfK1YokNv7k -qw43c0f1SmtSXZR43SRv/4vpXG7IqtTuqgSwn1qDJgr4yfs8QQykO/jG+cz7X+5O -KSAulWi9OoqLyDWlsm3WccPIcJfbm71P+I/ha7ESVQfOxC92fQ7HQAboj7NhecJ4 -RLqjzrWSHmPGClI= -=J2qy +mQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH +W6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I +QxnZZIbETgcSwFtDun0XiqPwPZgyuXVm9PAbLZRbfBzm8wR/3SWygqZBBLdQk5TE +fDR+Eny/M1RVR4xClECONF9UBB2ejFdI1LD45APbP2hsN/piFByU1t7yK2gpFyRt +97WzGHn9MV5/TL7AmRPM4pcr3JacmtCnxXeCZ8nLqedoSuHFuhwyDnlAbu8I16O5 +XRrfzhrHRJFM1JnIiGmzZi6zBvH0ItfyX6ttABEBAAG0KW5naW54IHNpZ25pbmcg +a2V5IDxzaWduaW5nLWtleUBuZ2lueC5jb20+iQE+BBMBAgAoBQJOTjJiAhsDBQkJ +ZgGABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCr9b2Ce9m/YpvjB/98uV4t +94d0oEh5XlqEZzVMrcTgPQ3BZt05N5xVuYaglv7OQtdlErMXmRWaFZEqDaMHdniC +sF63jWMd29vC4xpzIfmsLK3ce9oYo4t9o4WWqBUdf0Ff1LMz1dfLG2HDtKPfYg3C +8NESud09zuP5NohaE8Qzj/4p6rWDiRpuZ++4fnL3Dt3N6jXILwr/TM/Ma7jvaXGP +DO3kzm4dNKp5b5bn2nT2QWLPnEKxvOg5Zoej8l9+KFsUnXoWoYCkMQ2QTpZQFNwF +xwJGoAz8K3PwVPUrIL6b1lsiNovDgcgP0eDgzvwLynWKBPkRRjtgmWLoeaS9FAZV +ccXJMmANXJFuCf26iQFVBBMBCAA/AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIX +gBYhBFc7/Ws9j7xkEHmmq6v1vYJ72b9iBQJmULK1BQkdphrTAAoJEKv1vYJ72b9i +2+AH/RSX5voZXtSAl0fxVc9GDrGesOsykkSELnailOkWiFEHZS842U1EQst9Omki +OC14xk9fY36gK8bxXnLwww4hnnh/fpj7vJkJpVCi2uO3RKizyN6rp+7xbZ2lCKfp +5tsDg5U4iaaziTNtb4ISq79gLmLY/gqBwGksRozmChsl2QOVgg0KDTI5TP+41IwW +AFuO+XzHZ7OEegxwHta65KeVNipYjCarTRcRhGxA0rpLdBynkZ/OaI5+J6UZVfna +2eyDgHPlMo+v12+g/wOFOwShVWo4PwIsZw1jzBCLhspgezn7IolQFMHtVxCJAkgw +XhLgogChbe885HzTB6GlMowXclGJATMEEAEIAB0WIQRzOJcwae0/RD9NN9+mT9Wx +ets5qAUCZlcuRQAKCRCmT9Wxets5qD1GB/4/NIcvCRj3LvFbrtmtbExBoBP6Hv/8 +U4wUpuJbAAxImJ9uNKKaH+cmvoshkWTSUBXTvNjAQW3SM9oW+V3G7wicUtH+7cnd +xExuqf5e6f6IGqKCgrV25g0WWvJZG6ynMDDkgnyu3fTE7GkVKwoWQ6qV6Akar8oV +29P+xe2U7AWPvw+O+SBghl32x8DA/nUjIyLbvBQuXb6BjHOxrTw3WOJDfwHwOyMd +P7NHe7RE70cSj/TNabuNw9c31H0+PAj+UWfvgs5diPVJ9Fd/PK4pWQoh/4poMEbc +/1Ol0G7SItUKO6v4aHn89g00xnqUxrfwbCWCEF9EjnfFtlsDbGSWIdz8iQE+BBMB +AgAoAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCV2K1+AUJGB4fQQAKCRCr +9b2Ce9m/YloaB/9XGrolkocm7l/tsVjaBQCteXKuwsm4XhCuAQ6YAwA1L1UheGOG +/aa2xJvrXE8X32tgcTjrKoYoXWcdxaFjlXGTt6jV85qRguUzvMOxxSEM2Dn115et +N9piPl0Zz+4rkx8+2vJGF+eMlruPXg/zd88NvyLq5gGHEsFRBMVufYmHtNfcp4ok +C1klWiRIRSdp4QY1wdrN1O+/oCTl8Bzy6hcHjLIq3aoumcLxMjtBoclc/5OTioLD +wSDfVx7rWyfRhcBzVbwDoe/PD08AoAA6fxXvWjSxy+dGhEaXoTHjkCbz/l6NxrK3 +JFyauDgU4K4MytsZ1HDiMgMW8hZXxszoICTTiQEcBBABAgAGBQJOTkelAAoJEKZP +1bF62zmo79oH/1XDb29SYtWp+MTJTPFEwlWRiyRuDXy3wBd/BpwBRIWfWzMs1gnC +jNjk0EVBVGa2grvy9JtxJKMd6l/PWXVucSt+U/+GO8rBkw14SdhqxaS2l14v6gyM +eUrSbY3XfToGfwHC4sa/Thn8X4jFaQ2XN5dAIzJGU1s5JA0tjEzUwCnmrKmyMlXZ +aoQVrmORGjCuH0I0aAFkRS0UtnB9HPpxhGVbs24xXZQnZDNbUQeulFxS4uP3OLDB +AeCHl+v4t/uotIad8v6JSO93vc1evIje6lguE81HHmJn9noxPItvOvSMb2yPsE8m +H4cJHRTFNSEhPW6ghmlfWa9ZwiVX5igxcvaIRgQQEQIABgUCTk5b0gAKCRDs8OkL +LBcgg1G+AKCnacLb/+W6cflirUIExgZdUJqoogCeNPVwXiHEIVqithAM1pdY/gca +QZmIRgQQEQIABgUCTk5fYQAKCRCpN2E5pSTFPnNWAJ9gUozyiS+9jf2rJvqmJSeW +uCgVRwCcCUFhXRCpQO2YVa3l3WuB+rgKjsSJAjMEEAEIAB0WIQTWeGzjA9mpAimY +3GzIRk1UmvdcCgUCZldKdQAKCRDIRk1UmvdcCj1hEACv1XfhwpsBPVNzcfzMIpfY +xAQF28m/VFLwD8FYKoVgb4rF2wLBtt9kaoPZxphEvV/FWHhpa3Tyr3L320r6sVk2 +5Ou6G/AH6kNF6vYn98chEmbCc7DE2B03G1HFFuRSOmp0ZwafJ6MYUhjpDrf6fFDL +fmdkr/hjLwCYvFQsHXYiIWDFBPZ6RvVC6ozbdFr4eWj+CIPZM4jcGTgSI/u67tC6 +8tOdX4a8/ujdkLDjyf2xgbWT8ZxY3o0fvfLFEQVpNMUsYtiW/kTPBsq48Gq2BWow +/2Ld86KjgBOyElnVy9kMLCB4d/DPnSdBkjHzWWDx2c/PDGWIGnES6O7NYvRQ9Sr0 +bQwtr70nvai2OkpYVszVwOqyr4vDeTIt0GFKOMRDRrscVGmlGr2mpExiCEgGyAjR +Z/aZDCzEnsswfJ+6IARYzE5nB3+pbJnzQNvj9r/YL8T9HkWID4sWJnnNmaFoWEMF +m+yvI8vyVMGPSqfVtN9pEpx/pzV/Q525nFYuUlEsqGgaDydnwe6AV9gZsRyA+YjE +H3gI1gxGwRyupldmstzoYzTktb4o1KL/vGj/onUIk8mFKx8p1X9VPWW0+8LqnAYf +Ui3jDoXE/9avsF6ipS7y1k8ga81z01NOvuhai3c9pvMAIYrNTvoQVz8vTIOtJac1 +PEoU6jdm8blCt2UjGp8A4okBswQQAQgAHRYhBBPIKmO2A1dhVuMKTqDqmBtmsNln +BQJmV1HrAAoJEKDqmBtmsNlntoEMANBPdskGMrU4ZxHMlOTd1JX74ucp5jez0Y2o +bwlxOiWroraYVBnWT9v150kNf1Tb5mDxi820qebiSPZxhlI1Kj7NrPFNxQkhhNzN +7Xr/M9OGpkwxosEpcMAiWfofyAdrnwos+MA/edu/EoyVRs6zpo75nP9GKUZwVcjH +KtvPMojkZYpxjxsio0aK8LW8VwDtsbwPIXDIHzE7sxUvThrMdXumrh7gKqaC6gep +HZB2lL5ES0kVE3/yjZR1khmcmF1zELeC0IddJjX2R9HMcSLixdJ2V8/VFsWMb2KQ +pGtDzCuRyyxbugzBIxiGV2Xb7XwOByaikc1duqFv3gtk7Vk8wgQN3YwLkZ6pztlK +vCbqy2b2wlPviGjApQ2GVd6EEmlCk2gKPkjrn2lxS2BXWorM+ANSswJT+eILi9yW +Q5zzmYK2vFTzL7FAMeqS/671jNhZQ8O7jvbY/mRhl66k2MY7/JgI+coP0cY+HHr2 +ozw9yNdOZmnk2Prj7+mBuchbT3BJOQ== +=AgHy -----END PGP PUBLIC KEY BLOCK----- - -# Roman Arutyunyan’s PGP public key, -# the key is used to sign the 1.26.0 release - -----BEGIN PGP PUBLIC KEY BLOCK----- -mQINBGYXyiQBEAC4jm1y+ODV4+YDGj9vp2BgHB4FJeQdgrBiVX+Mb2qCrEqJgeKV -fVwKjkVYqnb76TTybdOKqCP5wdQrncKAKlXsMq6sdsiwPSrdRcjkeiE29WWrtbB4 -i+VObnoWklMblMxFQ1XQIkjs2wviidKjJw2VV3i4XnLSrHhWaWqviTLZCMQymoPs -F+Tfu1WX9OUfOquekZ5KjkyBxB4ep6+NPeuIkPnW0SiTUhU8tbi8v0aBZEHSZLqE -mq8KLROVuYSPvtU+NtaXAM09BHEVCfb409aDps9p6AFT+IN8yoOegGdEZjp6hJvS -HxbhuwqNEtg4dTEV515YUCgKabqU1QaqI/Y0+Pdkpep1KRFc9YUYttDkCw7Ybu2u -fwTGzwAbD+ThAIOdzmMDodzZaEMf+9fQG4bnO1PdNbXzyP7Kv9qzGa65+9oGCPOS -qTpISR8pvzoI8w/Z/vG71ob/nQ6Xm0L986ksErdGhu16ZI7lW2eDYqy2IoFfbeSz -HHxk484/pEibrlCRbP2Id+zULfxo1HGOGg+PAY9Q2uNzABsGDMnOhIvXHS+hP7oB -sO9A4Prqu6K6cMp3QI219tmmOUegJpmGGPzoNgxR7H30wNcjZPv4PWr/c0fP70Ny -ilgbdcEMDSHks30AmiuIvcUxo3A21p2nnpxsKAKYx42UJkyEK0HILMzcqwARAQAB -tCZSb21hbiBBcnV0eXVueWFuIDxyLmFydXR5dW55YW5AZjUuY29tPokCTgQTAQgA -OBYhBEM4eCXdsbuX7Da6XQB8jXwV2HNpBQJmF8pXAhsDBQsJCAcCBhUKCQgLAgQW -AgMBAh4BAheAAAoJEAB8jXwV2HNppvQP/AjzdPKkGRzJkb1ioto/IEP1YhA/Eayk -hvejJ0vyWVHXXH7FLW9fIZoApcsD1J8/7zIANm+62IfT3QNbL2R44IyhJB3AY22l -t0ToLxodfugegF3NPYYyFOSRUoPD4g2T/dMCPOBX4MNEAnAlCmxAMaJNmQUO76IY -GwELa3CH3Aqf7bthKy8P36G11hu7NgH6V9mVIRIpfnfpXFQIztj+vsWtswu4M5t7 -BNJwx4a2KTCVQpTdff5/0dO/5drQDxLbIg681WZk3Oe8Eu6nSc0Ud02NIkg1TQH/ -MryAp7o/ua3LRem+W/cktnT60p4uXPVZ3Rvg3zOmJSNJ+eIXY2+sDeZEPaROKldA -IbnBacTsZjdswIlrbzinY8ZVRosaFlvHg/ESTBRItALHWCRdzOR1Wv1qy/PQfEEL -qftDsCTQhssP1MHJWlejeqPlND3iT2vBDeOxqd6WhKuAc+L04iyBB6p867pwrgDF -ecg82DPehsAnO2XBAFuIE/SLewkYm0B9HK7/J4LZqPwTAksPf/dnbMAmHWoBDqsu -4U4U4SsJKsZ87R9ao8qO7IWCzHrXavHFmnbqweFfHToeKF/L4PB+tYoW3YmUOged -CglpJv13bNWmRwL7+x8b7BwpVwClxHBHteDX4RIN5iPH9h20J4jIpzRa1kNJsTu1 -v4ZkqLWJlkiitCFSb21hbiBBcnV0eXVueWFuIDxhcnV0QG5naW54LmNvbT6JAk4E -EwEIADgWIQRDOHgl3bG7l+w2ul0AfI18FdhzaQUCZhfKJAIbAwULCQgHAgYVCgkI -CwIEFgIDAQIeAQIXgAAKCRAAfI18FdhzaREXD/9UW4KdbcTCgsJZaBYKKSAj2RtU -OvT9CLJ/YZv2x87LME2r/5kaNOzsSpMdthSIJOCPLy3RI0qLOgJeNJYtOhMBeE55 -NjfAO4eR1zcLY48w+CYc8aZ2d+mWaxmOPrz2zLQxOeUuZT/zu17FH9/dEQAq1yFW -OjkCiO5nFcmL6vIG+jMpeLzYzUlpiUivXlP46JG19ndyB9ORvkJFrRhFXtBDXOE6 -IXQAUpVWKQXBG6q6mFPLZxIsgsvM6nAb8KMwnM7hU4BKYYmZ2Jwh9hKxlLPPftGt -x95jBHqq4nnlj1AX0hR+DkAda5+ldp/oVsyxbVTWY6rS0y/C91w767kjlIGPoiSo -7jNq+Zb+LnOTFqr3rAVCfr6hGSoec02fSGX8HgxZ0SMMmxoNd+RDdKefgF+XUk9P -pwfY0NVhCfWyIg6Kb9YbmWEYs0HVM4BUsduVDbEgtp0rRPffLqV9FRXcE5bTUEOg -XSd3J3suMbkOL9yN9KjWG+FORbtAkZ/NVXggADETIcqWaA41+CBmimWq6S4+yrt4 -01E+G+VmrrfZBciq3pjETjc2TQ7jWtf+1a0Ht41w+9805z6waWOcJLClFbLH3E7u -mUQtUP0p21zIesiCitoWWHsqxJumlJD+JQpE0/6V8JCwxrXKudDLFrOyzw4aUHti -lQkvi2tBbfl/+NcUP7kCDQRmF8okARAAubU+TrsrMu+QXMAIPIyCvgsOoTcvq4jq -AiM7DHp/KbOLcgxS5kXaSZlTqZrbxEmosdjB3x3P7fYTrEPC5hd5AxvyYrA13Af7 -9vBDog6aeVIP+VDhQZ27uA5MW2pCRfChf60PbYtvZbdN7Ghgn9l26s0yyOhb2dk0 -/IQ8AGReWjrQxB1dwoQT5+oKZZyQA4mfQ4qDGY4tR5y/GbuCGBzDToKcVC4ukzIQ -R/zJB28snDnbfxLEBWppyxnlfCkdn7m2I66Wx6S2c0kXqUMryiIRwBY+g1Hg8hLd -lwIrcSPGCONCFTu+WbvGWatKmBjC/AJvremYyd2UfPw1o8UVGHqPmFRHuX/qEZeR -kTZC7Rr0wA9/DW9v+0lGHUlwN8tznH6P28ksGqoIHhaQ6iuXh15qzuIb0amKBMjc -luFUJRsr2KuLNnC3ghf0tsOnVfDhbJLCKKvLqkdfyEPAaJ7H+4gGKbDAGWThioic -69NVtxgOCmtwfzJmT+QsrFIRZRcTLA69/01n4Kdwh3echgJ7lllpI6lUM8dLXLm9 -4Mg7Bwj7sLPD9jiidpczT6qadPDI2DDEWW+GOvURF5CsO5F1PMzOftSKVtlPs/Nz -VPOkEdPD06YwE89OZbXRqhfNmfmIJdp2r/KKlUajXf5PlhOtHtXiZoMpI5s+pz25 -tEto7dQu0C0AEQEAAYkCNgQYAQgAIBYhBEM4eCXdsbuX7Da6XQB8jXwV2HNpBQJm -F8okAhsMAAoJEAB8jXwV2HNpk4oQAKgfrL/ZcJEaKxOol8L749g7doiMu43NQIWU -Dh/4+weBh6VdxI/6bXVMLs4/2l+RJxHgz2diVLEistqtEaShinSjr4MuclX3fMar -o5GsF79ukFOd5oMn4EAmS4RRYatDCAKp8T2/IUgkHqJdfFqrPvi43gzMJIDKxyXj -YVtlNpZak0t+2H0TDqNFa9NtmR5TJZMjM9bEB/gtv585prZCOPr5T3nHKDft9t/W -M53VtflzPEt3VzXLBk8iwG5AqMH6bqkHSD9DGJQcMf14/X8QTQLqhlQo64xjIO5q -MzJHgg86wKGYmg9yrnfM0rPVaQMgMpqz0CUkkvem/r69pgym1ddUCXiWb/3dNp+C -TIyuwIv/94/06pCReFKGB+OYOYbxkq8ptVCq35/E6h3bUxY3MQDFy21iAh3Q5O/9 -KJXvAZfHLIkh8isv7BidG/+83AfPAkvDn7Edwjmpytd3png+qxzqfMBFgNfzwNSa -AAubLkv7iID1muboy2lYifaVuqIX8zKjrSwARQQfxYA/6oDxfrkzzy0GcN1zvEOt -ZBausdESRjYARDqbHqLp8fk+hQsWaq741pv1ilUFIkQbSSLw+2fFAj/jVM3Y94cC -wF6V6z89IJHGyPoXZUyRwguoutUH+TiFp4bcOpGb9sxHE7c5QGDRLpsvCqycyApj -y0uwRAvM -=atsZ +mQINBGZXO1wBEADEm061e/MGo2f7rpSqokI59in/egWbeQE26vwxB7vPu4e7j+cU +Vg3AezwCbf3nVRAE9DpJ+yuB0KVkM/0QszjOEEBuehZYJrUiwMyiY6jAk8xtqjpV +PsOMyZrypoJhwzg/sYNadUPw4UoHJ/xq4wNA2ZG9Xf0l8M3shYJPmKWLz/eefa5V +Ef/toQ7a55l0aJ7XyACTU6dv4bkHHqomDImK2C94s+KyCxaFyz6NgFz25V/j66Am +gB1m6UGGsvP4qYXW+KTsLz9XDvJeLLHWNcqQoyUO5Vs5C3hGozL7kEkyK/1qHcou +XXkeGN365z93ZeK+VdBZKJtsCswPk2wdDBByU9lAUNHYcLHf6S8fwCACeIqJ6LaY +MKmZUN2gR/boTyMERHEA8XnWXTDp7EsSNIc+LkU5AT8yesANcczH5k/XOI4hltJC +piEsSgg9V7FvO4eA2iQWGv/Y4nlUfw3lbRuRFvd7oqVQKlX4iIs++kVCCegBvtNA +1naxPbvTqrC4THvBSSZpOW/y/6XibAr/scCNNW1mEhwm5SPBHq9Sv35p6xKDTcgQ +8o3KLM8tKKt6kokAqlrXk9Nq6LYrZKwg5a9crFF7nCL2xgxZy1OJQVcPuhhZy5WT +WReE5RJdlF5VGRT9nMJ3B4Vlp5luQnMUFYXTAKQd6Cogbb99J4MjDttAlwARAQAB +tCtuZ2lueCBzaWduaW5nIGtleSA8c2lnbmluZy1rZXktM0BuZ2lueC5jb20+iQIi +BBMBCgAWBQJmVztcCRC83NijjYiiswIbAwIZAQAA9FMQAJ/e8F1egZGbRIV6qU/Q +bJD3EsKZZlitQSVXbBpxqDlkD+uzSFATGjiLGvJoTzfpJpJjI7FwrtO74lRkjCl9 +wQUNJ+wm2Kod6rEEQc6lWkDsgxpjqAAGVS0lmMf+VPBGQ+kc8S3ZdCOWEeq7nThZ +/xWR+UuQQcz1vCKmEgwTrr5MJVcqDg4wiH1Z4lRVfjTezf9IWk+xeE3mV8h7Ltbr +N5ZvOkiw88JLrbQsurxx+lYEaGIZyIk3huiDE/KpsMdw9KXUfoDcBqWc7oDjqKL+ +QEaq7TW6VetKyJaakP6Do+Opx0BtS3eH86PEZqtULEw9WifC86GtRr50iTXWBTfI +MFZo4AwigHXvZ5WrJvLfldY+scoU1rPMouYlZJ9W+6YHLjf/jpr4W1w6LKKXX3ah +h4VLtlOmrOLA21E7RQ0PwoE6nT7DAm1DsMFCXy7lyp3u5IXGahnJddWCb0Px3RTm +PZgOt+YAGJDsP46ngl5LxhilMK5f5R8v5n1lJ/XzFcXCEN4i/d8A1jx9DQx4CJN1 +wp/WZzJ6GjnCqMCdOBlQ2eNmhR+q1bAI79kSv86ahaM/aS1FvHMz8ppzwkRhv5jY +eR9aRlAwaCPOjbWhYJt/xveOWmxCdg5ta+Pj5g+41wHZyNf9aqR314aKwsxo2AYH +uUe+PgpsHbe1sQTkb/W1OfSCiQEzBBABCAAdFiEEcziXMGntP0Q/TTffpk/VsXrb +OagFAmZXO+kACgkQpk/VsXrbOajGgwf8CAXJwSIhGOWFSgV6vpvZPChTsgteZxhT +8NrJJLxL8X34Rw5YctSli4akkchTonm5RRp/SlvI2fPe0o6q2ymF4BASPJ/oSI3p +Gs/jwctHz8hwaVN0xQ4SBXgquIFWrLRNOjCxEV/vMRJRzuF9jrrdv3vxZEugETI+ +rnoEZu2Z2ZlMj7PPeiScf8dFXax67+Xi5S2KJCaXm1QGAJvttHrwsbBAIE9CVUg4 +UmXwADQ6HkOKjY+QS5AP8Ak1dg8/oadgyMqB4GrcE44KUpo4YafP37XnwXfQNKpk +Rb0bO9Qm9lM/LhPulBY8WIPkmrFCVhGTE6K5ZvI59R4nECHHx24/LYkBMwQQAQgA +HRYhBFc7/Ws9j7xkEHmmq6v1vYJ72b9iBQJmVzzzAAoJEKv1vYJ72b9iPPIIAJ5k +hTz2d7CaJefHzoraogKSIeBnA3OR+nDgdDl9Mp8i2WLGu9YYhIrPU0iSVw8jqa8t +GIjCw4/bS9HN8oub2Ip802xDLugCz1Yz6CXjCXN2rlNPsdBV8IIKNHOv93qMvnZS +DwyBUAvAs4XzF7zbYgfZ30B0gRI0g0+Nt44oDOn3PfO/kNUJyBVPT9m7l3JUHuZT +FPOD8a0oJPvW+iYlSkmPELBvgehsX7MVLoeQ5qtS1KkuWr+y1wqD5kxqabMPcfdU +jAr4ssXs/pSsYJVyS4CuUWkY4FiCJm4KtU+XPDs1RCTzMkW6HHgSebocTZzLETYw +XsDx80qd21UAdGc116qJAjMEEAEIAB0WIQTWeGzjA9mpAimY3GzIRk1UmvdcCgUC +ZldKYgAKCRDIRk1UmvdcCoG/D/9qLmHYOGnsmedUbgtLmuBJOuA6oqnaWxYI45eV ++vaAaI2+QfRoJTrjklTXv29Pi4LTzN5YBySSIkv/z9ry5Xsz5yroNY9Xb6JdrqOt +fLa/U0wddNuJbmIom4gUPXGInhHUBbP6mNz+s6e2ukBEWvb2XIsGe5v291QXMohQ +/PT8zTIwNYaw2zVF6Sa/0spA9/9XA5BdUcrtl7xPgYL7pLVmKYGJlCf5TOaWfLDJ +mIMeeUznVK9vK+vT+YqUPfFyIqO7dvio/+MRFjePoD6csT4UBT009ugy8vrYg2YR +K9uaRxP3laz9b6xdUM648ycUQLoI4fLhyKAHwPU9/Q+4rOFdrL72ZGVKzv1XOB0H +VXf0/E4JmJBydM7AyXHNxIPDtNFydosGn6VZsEvSPZdQSCsCeBs9UuBWgwFb1XBB +61XiHGnheb3U3ZRkajS1ZNdxfohHrBzHnd8tbDkv5Rq+XoUmDauoeM0VcN15hl4a +M/JzkeOrHuJicn3mg+HRHxQSCl3D37bVQT7O36n7cff22GykT7XQUBBxMlhKzygD +SgdQUtSEt0eu7AXIvr6yl0kobgZQS3wzUIaY0JEuv2ahtEXXjoPzCVWB2OHIpPbu +D58cpyyEVqr+ZecaI4HlaO9lVShf+K0rf/6DC12rC2gNzzv/fCIinDiqiMsPTfEM +fduRSYkBswQQAQgAHRYhBBPIKmO2A1dhVuMKTqDqmBtmsNlnBQJmV1HlAAoJEKDq +mBtmsNlnhI4L/0MHtfCZ2nuKTF/BkxJ7oB3Uule0tWiFj5SU97GjcVj1LgawGY7Y ++zoyEd6Twpl6H/+QkZBB55Bf8+cTzRbDzH1Og0fSORu0pGC0uxWdYu1sTLeTnn93 +mesXAvevHFNbsPchIWwsVJopTdzMWuAQS5hMMMtNb/14ZfnBadzhjvaJeH3DlZVK +0cGFp0qfbMfjr9yRJzQ1IkiXsS4G4uKg9T+KRsPr4+JalurWJgLnBXZGetNNjjUa +UCV1KZY/iWCAlZjkZ5z7yBRj5nUWLb5AVouEQPEDbn+i/0uEjukC+G6EMq2mgbrh +m0bFHbHAYBaf9EH0eP799HpoAx2aziDB5igAC516i3BnqxINI9mXHh92tU/H797I +oYZvpBsAHDWDHj6O74jwk5lXF5Qwri8gjA8aTudmuQX3uX4h0/FyGGQJW4/wWecH +/1fMuvHHyRtOSsJsheDwcSjrw5WlsyNjvSIbBPV2fIx60W2haVMUVX6CrxAeq44F +UYda9m8fOnaIew== +=TEOn -----END PGP PUBLIC KEY BLOCK----- - -# Sergey Kandaurov public key, -# the key is used to sign the 1.26.2 release - -----BEGIN PGP PUBLIC KEY BLOCK----- -mQINBFcok2QBEACt2nzM7Oqh6Tl/yNDzT9EXf4C5TTfxnKih6ehm0T0VWLFkWOxz -bmVqo7PgS0q3bcMoUl8CIbs4foC+GCAVj8DNoiMkxvfxBb+V+qdzve0sh9WHUpDP -dRBEHQb5T5KzTtGDarkhv1/15VqK1AOCSBroeFZXefr9bZqrGJCgixta/JZXSr6t -xbouELXWzdviUEtcrN9V9rNJy7QvS2n/UqhjgCKhX5bdLVUy8Abja20rHiVUdBww -aAee0+yZuS8Y/TksItquNwWce4qDtRrKxs2dmlLYsRULtoRKmTHPcpyrhVN7jIZX -glYumuG0e5plY/4TUHeEu3ReFC+AdQIESa+6+IxgdIT6szwMF4u+50HFAFDiYfdt -rjjAoD0fwEW7wSc8Ow9lA3m10yLqRuL+HbVQfb2F5iLsHa+TrSWOKfPboLo+Cg9o -g7fVRYmPhSogcnGbFdFr52GGp/YRk8M7kbbYzuHmQLuDyiG7kyifq6fOBil2Jgyg -MxRJcFl5G/sYw1naEKjAUKAMvCYaPdfFmOSJKDyFsR8ZaDO58rE/HUVsumCuN/kG -wAFmRp3AzT9CrWFSXuZW1tLdd9d+6uHx9BZZUdKaMICpgP62OW1r4h0W8FrEkywf -Tp/5FxEXjXE/xWRdeZ5sp9QbzJ6xm79c/N79vQQN+Jbq+T9o/p6pbUJ3rQARAQAB -tCRKYW4gTW9qxb7DrcWhIDxqYW5tb2p6aXNAZGViaWFuLm9yZz6JAk4EEwEKADgW -IQSq3y7fVSnxcCdyyKLexNJGkx70mwUCZyFKcQIbLwULCQgHAgYVCgkICwIEFgID -AQIeAQIXgAAKCRDexNJGkx70m/ymEACpUcHefaXAiGEEvJa8eBJ+9qZUdtVSWDwE -eP+GzlM/+6gbNRxFJAdcDDP3x3ALvAwA39vh8iIsrTONYcbCKi4uFMCH9/h08TzK -jT/2Z9PmXb0wGaVt/Jz+qe4SjDimnEB0cE8HMRB5Uo6NPhaSTDjMGXYpx49RVzsL -sJ9xsIDDd1it/KNVjpBMeLtyLRKQARjiAjVkLlWsy+PFxd7To0BnhmZ/9r42JrR9 -eBg3c8n+9hJ+ITA+nSV6RTuox4vADj5yPM0fNcITKpgbgvMv82C5S4DIs3KG/t/Q -Cth25DHrrm+S0oiHSr9cF85IbwuX07E1HAYTUPuW2X2jLzRwlVihp/txg81W9fkz -aJCv/tfvzo9oVecUx50WdkEFpJjjGTY+hMKE05dsU+SjY6Wi1kozcreSX4iAdlzV -Y4u2Z8BNz+29dFnJSs8DMMgYslqiSzLraBuJ1gXo/gKeYuobgxZS2Yk4lft4xbJG -STUjpLFbq29zGheUxjr9tGJKMrAyhK1X680KTjusR4sd4npAgBQgwYP9c8ozQ9+Q -IniSZX3mLMcaTBay5JoqK9jR6sc545ltd/NFA9jA0eP7lUJPVjEOcO05DvrLihw5 -KEVopWd50S6/OtJAvd4T7kOxabolG/3K6Mfcz1XL3BMPKUK8dc4k4gEyiUfbYZkj -05JdIMlO5rQkSmFuIE1vasW+w63FoSA8amFuLm1vanppc0BnbWFpbC5jb20+iQI3 -BBMBAgAiBQJXQ/pWAhsvBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDexNJG -kx70m8pSD/QPwKHIg4ke+Gj49tnogx5I78x/5wIrY7ekk+OsOI/EisUkle/wpz+W -nwEY0tVMGwg9G8XaWI3FWuUYnmHRaqIoeMlNaiYHJES00K5gWrrs4PrKNsHCMIct -XTla88fKjnEgZFJ5KSnLTQoeIgxogbtEtAZyceAWrDc5LuW025xtleU3NLUM0jxi -hlD4WAMz0Ov0qFH+FB0mTYvfFBKl/TpXnyMN0KSOmRQ8hqyAfeTi3hcz51PSH5uI -g8nVLSPs6No253FE0MqQoED/tZGHNrkAEz1FIlYJE8Ze27vXMHhfx9Ik7rEbyS4T -NQSJfVPxmiU/aI2gqN8Kom+vLP1qgrEoYXFPxFnYr73+iyq8UxIZcqGvQOx6XVHU -GhIxj7fahGD2Q5s0GPJPnlCNvt6X3AGlARBdLAb/qIRAYD456kWlWon2P3raheEa -EJBeFf1Z3s4/eOOCRP+ojQJPIr+g9MpKdfhlqvG43mrwRuO+ZPRPggixaK1LbWJk -yImd/DXnTriSHeCKvHwvD2O74xvrKYPbYBSCTdG/0FG/3fT8XGXL84mWObRd3/IF -fjjAnUugU75B+vE8dJh2B/fIzT8+TuXYCf5oyB1Q+INhwOSulJ2OUyizX8PhCJpR -ykfmgACSJtM/dMJn1Q5eofii8tAIOjCaPK2olHJTWkS4hkPxd9y6tCpKYW4gTW9q -xb7DrcWhIDxqYW4ubW9qemlzQGZpcm1hLnNlem5hbS5jej6JAjgEEwECACIFAlco -m9ACGy8GCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEN7E0kaTHvSbCwkQAIuw -/1e1jQkoGKEOJFtI1DMM85ByXwAwS8A4Xh7tOTYYYU59L6DeBFEGXXYsyb87U31p -9nFEPmst/EG75wmaPGqqIT2IL2QKuVZiD30OXdQ5aJ3JVAJ++nwb7FYLUFt4JDDk -jcB5f3dzHIy182EpbazDQwvlIn058n0b2Wm23nYsZOmXXd3b7KHJGU06jsnV6igC -4VP3r8jwlWMh48SebTrx/kTDPO7VSayk6PBrr6ZEDkVs11s9rVNyXmXNVzmBTOGQ -fllmsRdAFCUio4pTECrl1iAXLGsp+OJ80PsgDHSAVwiWmfhm6spHvDCGi0yMakmX -5f/BWtimwqdAv+75wDB7TnHre40Lafqyr6kCkCzwr1B5RyOk3QhYZbGaed2dmDID -lsF4MppiY46FxTu0kQroZOZtq/AwmPtxL+2R8cXgTBL2Jh7oQDmIxOKrvLK4hCbq -mv7kCmgBUtNqzZ3sZdN3Va/deIHaFAJen20jOSLlokAtfFzyXpiRJqVwY7B96yXh -dten5hRnAU+g2GcIPXd9BtDgDdyfbSDoREfh4fhUQzzwewegHjjiSJlGHKycDeFn -NkdjjKQ/QiL3yiqEEXDDBZlMrdyz62DGWRZQLv/ZWRmbBAi/ftIjuMzXsZfuU/E4 -sB7GPnEouoKEhCqIV83RPjPI/IqduHu7sUK9LhR1tB5KYW4gTW9qxb7DrcWhIDxq -YW5AbW9qemlzLmNvbT6JAjgEEwECACIFAlcok2QCGy8GCwkIBwMCBhUIAgkKCwQW -AgMBAh4BAheAAAoJEN7E0kaTHvSb6QEP/j0PUJRm7NN8svpHy5AFz74MhGQtkQlz -89WTZHX5kf+Bx6iGkOpCP5Z4iJBWWGn0XpMPwbDOw5R4LiBOhGwJvCpjxFLByOts -EEsgqPy1ZsX10zg6MG2JVjFOYHUh+BaWZzCtchh7cUUwUM6SDE3H9Iis2+7Fkfz/ -UP6ha0/zLZONIq6bIzIZHJ1VDvfgY7v68R+XEFsQZpr4EKrriBQQZ6dsZs5xDYLo -BoljD6KypOw6Cv9i7CCZnQnyctkVDLx4EOll/tRX+8tkl+5GpgRDGPzL83hBfm7q -QNqK2J3Ex+iPcTfMCN64DRyyq4HpmvEJsMG+jfHJay87jKcU2F8+P8kwL28eBDGV -ngl1hWOiOvZnSP13s6Ckjm95bLG+RyhcH30+sy9i75JxoWfh/sekYOVo4NmPFRls -SdcMOJ5Znk702wx24qa4EgjcgtID6yr2IsotM/I+Y2maKBAluYDkRFROqLz0jsed -1gMBNPse0oMEz2NRbzk6rfRJcYqX+s8jsS/VhzGd1JIgoGRkvFZlQTAfRe8NsDF2 -Yif504zarJABHRoGzLXvlYuhEPXZhpE5l/7i2PLVCG0rva+jBqwDValTaLyemVqb -mM1FJuHf6Bb6UND4ccgXCiOIH/cGBXiVeYQQxHuuw1JZ+UlDViduVrnpWw7mFD8x -BiMOjwL4PFp9uQINBFcok2QBEADPuwkLt5jAhIAjVVWNgDBNyqX5mW5bMvCFy7qy -QLPaCPrxpEGjKA+hvK8FG9i/KPUlsdReZH3JPAngUteU16iJo8HbDum93+4a555B -Ea4+Bzw5q0qREZPvybvhcrk/S93RpC7NAvwMUieAmJMZJnckjrcznQTYljTcX/NS -WODutapYbCwgPf76kCsYFLcbcFuOSDiRxL7iHBjx3eB/3D1+dZBTfoTRqHQ23f4g -M9q0DuBpifKI2KBaDU8z6LarT7wY+S2TsPESZ65vk9L5cMoZZkefTUlUEzYzL8DY -CmjFqyeji7WoM28ophaLJrsgqtAbmzZLrvlq5F1OwlQJW7fvOwyppnBgTTkdYM2x -gSLCtUfccgvjBpAcRPhP0MjAAyj7kFTwY6uaVMqyH4PL+e91OWMag2ZDtQ2y28RY -PFkNBwOlFKemYyhylwLdPT9hYUXcnwmKh8R3vpvR2lnxRomKkx5IpTFIBaapf9eh -9VBJ+Z2lEEhAprag2YaAgREGI4Ohp9WM1DtX6+bUf50TOllP78uKMUASGETtIeTN -UoxCktefm4kGAk11OR1cfiyAAnFXXbMGYPPH1/TtPZUSgasrwjW89ER1xrYqklam -BWEXbSEn4XCmeNJX2rVMhXZb0rJQuXEY0rIkVcyBXHHwnbUPgWeBtlsd4nxLxJeH -zBQTrwARAQABiQQ+BBgBAgAJBQJXKJNkAhsuAikJEN7E0kaTHvSbwV0gBBkBAgAG -BQJXKJNkAAoJEEXaUXSWk5/5mfUP/3cgCzFWd6QXk/oTqiXNJv5IxOM83XCyjoDu -Zuphw/rzj+kYiBkez9YMJ4G7eGqZZsxHLgBbLOrom/a+cS862os9iRTEE/N+uqWG -I6gSDPWihT/cnbBZaNcj+FKFtpe77WNcFKTw1K6vKGH/PkmlQgC9S4YJHFvLierr -XUWp+J8sQn+vSbT4ntvcdqxuxYtIvHf89liZI3gmPemkapfPJ1ZdS7nNDSw74ijO -rRzz45aZetm7hRY/BkujmJQ/27UVZaFHQ2AddUSLAA8keFLe4N47wL7UEVhPUTq0 -JCIZOSXnY/twMrlWv3OnVRRLtnph+WwAZ6O0qMV611kru77HHGCudAwiglkrkgvQ -je4uRIqRLmFA9LyE1726n7Z20H3r8aptQ7wj6N6Ir0ARMC2/mHhFv8bgOEKnx4Zb -8rLwfv/fqYF0brvyzaIUU3UqMYN4uSB37Y5HfBmtIp7yGqLWBslKLvbrizD4gFm2 -TqInaxClbfaX69dHYM5zZQK3GNsA6WXuIKTZFIWdnqYfzu6ihJmtLf5J6uX0PVt0 -728lL3fsXyi5K42kKnu3FBTY1iOTAGXDpGsYBcUney9mcrtbhr1V+/6y+B7UhNQp -fAO/lCTyNwsorPSAaAEGIpUKJ6YZ9+kzcDnhz6ZQG0C1/EFRUGn0Qf2xNv8+RtB5 -tpXmVyqUtPgQAKjTE4DS+Fe/7MYf5KjQC7pc3/sgJVmXfjO3z9vclp4zcm8wGQAJ -XZVCzY9xkyPJTWGtLBxdmyKUx39ZbXH3BBj6g8pVUiNER2JoHDleb2/YDnmC1hfe -PA6trfKEfQFRPY8OkQj1z/vTosbwLTZMD6zjGGkZZe/bUMEK3pvl52Du54vANz1c -+wEEK3+73lh3L8zcBN5mzlNZHSeAQMlkX+JG46y3RqQuli+NzF40/KLSh/LH7Wwm -7pn7ju0sR0NxWyRpwx1tKJeZf8AzqSTlUEqPSmGuy1sGwBwf0f2HxGpegctpfLM8 -4CF4fYMvmLj4rSReRnTblbKmTmmiPDN1Qnm5qYHVPnNtgrwap9/6Xr2akJGlxcvx -OyUV9xLDToPlde9PFgruWpzh7EiQbO38LNF0ckoV+1z9muPh0s9D3NP+IgYcKuc8 -pOa4U2Y+ExAfAmEmiSUpJ/7G6bCxrdaF0/DFtA5TIwnTOI0CTh9AOBtqPcTe0TGT -UARO0X5NqLsQy+sXn5gXdnrupzijgDrLU9v3ke4oXGAWZwuzsEtQpAuq/jPJF2Gu -HgYDQ2qkNDM5Jxxjo/QC9ZKSbkJy3oU1Qf0lJCum2XHDjbD8RAaqGkiR3etBCO93 -Pmp1UMXdYLNqHC32BUIqrBBEWyBvHBhvF5gdqeddGszTm8kD36VL44FBmQINBFX2 -5mMBEAC9NHGWvdZGzFJ85VLglbBRgqoaFMznC6Dz329M8Y+pVvPE/YY4rhX6FGxT -3lOLY7mSpRf3PpRBrGf1Iz6IpM/ZBs2fFfL1uXqtJ++VkOG5ZRpTzVoyFloDndqx -v6VpYjE2ljb0kxdyOkMPIRQHxRelQwHJyKZI01oG5vXr0Th8/1giPSTwJ7m0h04y -iweREuUr5Q1kBr1+Q1MgmErngVm1bKO/aJoWMW/aPA3Dp7kh5rGst7gp/wX7veH3 -K5KTaqM4NinGgCNhHJfaf4ANBjN4+Ot/cYehbPUDmdrI3gcz95DSS0N0R5YgpzFl -yHxJ3FGyCrtbNro88Qxn5/JErevx3GDsvhsGBWrywF4VnFvoG8R5O7wZGpd44Mpu -YngouH2n4O7oDq2n/0hIi2BZsVBO8MRxEBJPZEOwkRIBD86NXjZrA6LB2dQeg/uT -eNdPAkxhhxrA/nDgYILNVDIIMq91DpjQBPWp9OO+mHhcM0eeSJWfONdK1cT18kfV -v0r7fOGtFJvJ46EQvlHMORYVHsFZhtOsHbbybSVQeqqf86YtO1wDw2pEjRdz369V -3bMd76WsCx1g8p0PursJO5l2c7Mha8NzSRbM3yeKuP61L8JKHx1prp6o25UOMszR -JaQoYheyduhc49KfnKLj8i9593KzpIfvMJpoSCBV+OV6AwowfQARAQABtB9PbmTF -mWVqIE5vdsO9IDxub3Z5QG9uZHJlai5vcmc+iQJXBBMBCgBBAhsDBQsJCAcDBRUK -CQgLBRYCAwEAAh4BAheAAhkBFiEEPZg8UuuFmAxGpWCQNXMSVZ0eBksFAmch9N0F -CRTtdXoACgkQNXMSVZ0eBktE/g//VfuzVv6KmNZClp3nT9Z5tZ/keOUpV0aElRjh -TCO//OqigTVnsdApEIMGhkFmHPFRd8rJ6uhuYYtM6aS89/YhsGlPcDJOOqSipeSC -No9eBBTtPAuo9sXvQUlO5frEAWXT2MNRz56af6IoMVYpr6lLJPlXG4UJ6jpNwZPM -+d8L2PC+riDAIjXDQ+ZZv3sqBLsSMb1OCKCTu6uaSeSaA8hPfgMz/6oyjcFLsATR -wY9ixcRzjxHqpuiMWXK6yt8VK/+cyEYLT2p5Kc3sChjtqLSjcYM+rousYfBy+qUZ -eOhZPgtzbTdIu6RhZQitRDlf1HQb2dLGDl+AtCZQFXxY/lnSB4D3JHYGjadZ9q+4 -pU9v2shGear7lTXAwNq356I/6EooT3iwNGySiehBl2sIWB8PWBDa5bibLdhmlYCM -XLAFA8v4tgoU+/eY5elo0cweXVu0VVaou5XNTK4bVAUnoLCdd7kOtqUiapGxFFFg -8pa2VzB0G/Syscf4VS6uw312lUQUCggj01ZggRFkiqaCMq+ldp3zt/wVShuU4zlO -Ft6nf/wGEaFX6Nz/uWy14NZoFNO6i0SA2zL29Lh8VyHAeEqvwNvTQWyqXH/q0JJa -+/ANKpdOCYZoOGZK3kLzuexwGFz7v/Dhp61QeQXlPxKwk5BWR3zFuD1L4iECAUK/ -rSZBcFK0IE9uZMWZZWogTm92w70gPG9ub3Z5QGRlYmlhbi5vcmc+iQJUBBMBCgA+ -AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEEPZg8UuuFmAxGpWCQNXMSVZ0e -BksFAmch9N8FCRTtdXoACgkQNXMSVZ0eBkvNKw//aY3KISL+gJCDqxJw4jM1KG2R -+yCj3Pk/kd+Jn2V6w0zcdGZNUGlDKju4WC+pGfhNt0sPEFIBqVlvqo2g8LWzYMEY -ObHGmGGExdcNasSROEecEZCEO5tUkO0mIGVjj34Uz+2vEqA70cIrV9OTXjbCTu5/ -5wdMu3WhuOs5nos23wuuYtsSELW0rA34AH2E64YlNQj/kaa/NQbd0kmqENuRrrua -Btm37mht9rpazN4leGJ058/33F5MvgGvJlXiZeHPLWAGqcqvdV/S0DEoLnnA28kp -MjoTc5mdsqrlFzbKzGAmPT2GsAOId9NFR++A1ZwRHnEykQZPhpYynoJLBCRdHn6a -adrJmP3UlDEpNjr82Dwg1KljshhDrVQ+BpVDSuBjw7g1BzX2iFoym9Z+ZH8Sgsbq -4rbyyXXipO5vvrENCIm2K+h/Se6Gp370lIc7N1YIfdFxdNgf8Xm2gsjb/N+TLPYm -WA6+/0vAMA/SfQMo+8KzO2R/kpko5SPy7aVmc+/wI/X8FcYFe4dhHpp+pdGgxgUe -KJJF0TMBnSYbtUrsVgZL3eHMd6KhA7GioE/JknpuqDjVFQ9Pqxsrw+S98HhsJJll -KgUBMel5SF5nnealImOk+At7oqJOC3cMDdl1ljq3KA1OzMTQPQ2o9MqVZQCOqN+v -c1R0nTsLBeUqS9sDcWq0K09uZMWZZWogTm92w70gPG9uZHJlai5ub3Z5QGZpcm1h -LnNlem5hbS5jej6JAlQEEwEKAD4CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AW -IQQ9mDxS64WYDEalYJA1cxJVnR4GSwUCZyH03wUJFO11egAKCRA1cxJVnR4GS8I1 -D/9DHGPgpK1w5WF64fZ6OmksJlsXh95u4YHmP5skQoazHpurH/KxUqMPTZsJmZJ6 -hbbiEmuv8DJWdNH2+m1YbJZMsBFO6Yccf6KjiFhWHhqBX0VTBn+OoYpNZ30yxP4z -p7QdJtF5+JyhOa1FzKYPBL2xpNLSqOn0FJe3sjXpv3LuYKhWxVD9MZcLdxbILVIB -H9h/fzlSqA8eCa9Me09MVjVBcpHi7odtnyiJCEOmom1fjAGJxIBjWswc45pNXk9L -feaOtIAkP5wZykR5ja3KwnSKcwyef137UFmLXYWUslvUyN7iCWhcEbuS+naYZm84 -9a6+CXNt2CiLeNCN9aUqE5YB4A1hsVrXRPmdGUMqqwqDV32mtkWHm9fFKvlIBOmd -7DrziXp/TtOCwn7ssS09mVAywuk7emJbQ/TZW2ErTE9+GBvEVbDsiDS+O9/O9FL7 -EvLbZ9ZiQaT7Gaw/1sFpph5fzuKH/2QjbtNk4SrSWnSTaF9E0b1sw7PZ0V9so656 -Q3+xE8Bxk06r02QtHDMhe1bBVrm+mYHl0xGgOVPGP4JxyiGaSrv4m9tsGuKui+6R -UoGrD/+RofeJ3yprm15MwsZ/l677LVQOaJW8+g2ZHuxzgNBeFXzxgpmKOkIni8Er -5aBLXZZGunxMeix922d8veVIoBh26bI8KSJdAbfngkJzR7kCDQRV9uZjARAAqSfp -goyJefQfvRg/deF1BNZKc/c6Vc2E0Tdwe44xQiUlAKv7V45v/uCWuNDeW+LzslqV -bAtQZJJQhgOzPjwonUH9vb7DDCXZAUaYSFVu/9WAVCXa+LyNn3DlYZjnCQylGDDj -NephM+VlS5jj/8CcG7Jq849trN7Pu8miAzjp6xwC/kFiaUhkGHRX/9jBlD+BJIEe -0v0U79ztHU5jYRgpto7Wi2EKLjquUcM8fAhgqXyjBPgJUENcDBpv9xHDMG6iK0LJ -pje9a0rQQMjFPFpEJRrP2hZEdhANtaiHmPw4v7EZFMmKqlYA0rmA6xlgf1tQPvWB -zY5Sm4JWpPA6oloTHaHQp4cQAOyhkUIzs4lBfAI67izZ0f4OSV2YN316TyVVL52b -Z9hDxD8OEpMNJB+UMmyWj3E0/UT6LJpwia2++gShtEjmcAvLoSOp63Jpoc9kivdq -FJru+480XCZgCMfRw2AjXSh3oCH9EJKVK/7ZfCWunjlvTgz6JeLuPiBEhnGDtung -D7qjvJzj1TFwj3atRdO0Nvv+OnqZ313pCgLQ8xekmqG9ctSSekD31/U/iF09aIHd -saTzJoQqGnVmFXjKgmCTP2fa5pvsL5gwLaH9+oqTDasFaq6UdbOuLQWYld+8kLKM -2pxg8P92spjaOQMlyViiRztlmKa4jehpL3XPRX0AEQEAAYkCPAQYAQoAJgIbDBYh -BD2YPFLrhZgMRqVgkDVzElWdHgZLBQJnIfUPBQkU7XWsAAoJEDVzElWdHgZLB+QQ -AKCzJ+0EqJ8HvtpmuxmQYMuh80TMMDagGzA3Vg9XrVMCW55WpjfZrrp+31IeSIob -DMGiplsZaEkGZj7a+FIXH6Goh8aH05cdETZRWYPa3AMVj0suTZ8YEm/cXKh2BfRu -6zXuMBVXNpVhhBe9TJK0SFKNkbvTunDhvD7qIJJ6r6+btTYMRt6VCE/MGuR77kfo -N8orZq5tpAGyi6jLK0gDMEsNuPzXpzZJRUX5MCtnizDFMpM+7p83kiZqEEwU2emi -9HjyKfU1I3QekW7AmQAj/YR9zV+9cs5OtqR+cUGbcltbtwqexfLC9ySnCoxPxyqu -FqFVXmBXongIAWnnxqiYol5V7CLaVmBI57s6cjgvQt/Gj8jcfiPkBmFbzGx6ivIh -pG+KvdpMj4XUQ5cBQL7z6X1KYggk3UxEBigNC4MAyLeHsaEYpKowXLpRrgFYFUHD -vUSym0C9s7iMZFX677tt6nJs3dJScyJdkJOhFfnb0gDQE0A1WMkQx8XWqQehD5Pr -qv9ashfY8zaHlclnZ6QqYKHULkIaoVDNGZCkLiwBid0+PvdGvGhu7OL1TDPCng/6 -E727g6wZcxMYZTAmewva/KIuOpb+QWy4r0Rsg1eeF6ulTIEGfjOKPJd6/RsVd2eJ -zymVrCUVcPvLU8nVKsgJZLYsBeiq4mtaNJ3rvmUeaaZImQINBFilU2YBEADQf/CT -tDpsKjzVeGJa+PIJq+qjdEWU2KWAcarjyafNQEDjEaW/FSj5k1PLWuz/GLdPCH6s -bHRu92vYUZ1gU/GehUKirz+r/fPI3T0l4MVL+PqldE7j5TOf7WJ7y0OXzNzbUWWd -+7L9NkN++c7Dd0F1CbGsVsITn0lF6P0G1g5oee1i5RWs+l5JkYG4b5Yjzxs0Fn9E -Ie+Ka5bdxF3r4Gha/zc2BVScUCi8raYroLRd1wD84UunrTjxHmVkLujHzeIX130A -cKKZ/z025DeVkyGAO6d0gF5KaET+O/emlHQ7/dvY34ol6CHVCnnP7C9VDQL+3Qr8 -EBclXh9KHbASMgaU/iMYmF+7llDvtivc5l2A7NypLPOUW0RukmyGnLj8M8LtDzhV -yP7apG2tXEDVZ1VaHmvDcbwparCiDzAbmX4J9QD9m7s9r+V0yEFxGAKtsvVrb8Pc -ZHhtbuGJaFMrcco222pbPCGYOclqvSXQr59/8+qkP6lSKnYa6UAGIMVHW4LmOznA -vBm6akw3t8QYlKByb8C+j0w0lVpfkDwol5+VDnTLnE/aVGw0nDgvWwyq1PrJz1Mf -PrHi0nFKVizuZOD6mlncKFPuU3cNaSfkv0iNg5tnIalGIsKbxq2fjDhcHAfxXEFH -Qb1e0DkgLB+cApLBX+XsEDTCLiMPqUN0sggHHwARAQABtCRPbmTFmWVqIEtvYmxp -xb5layA8a29ibGFAZGViaWFuLm9yZz6JAlcEEwEKAEECGwMFCwkIBwIGFQoJCAsC -BBYCAwECHgECF4ACGQEWIQR0bN0YYYY0KGDrnrVj/hDq1V0P2wUCZl3cnwUJEXrw -OQAKCRBj/hDq1V0P2xxyEACu4krhemDHg6kxxr9mNPEf1sPcZGA286cpvNfr6+yB -sbpqLuu4QCSJbg4hkPhB/hJHhtNpg0gZJpITEdT2+J+GKEIYBQ5IkGLxZl8uSFJ8 -3MsGEzLKfFMHoBpiPwAE0ajWI6ZGhvOFkuWDBYVSrnIG7PKA6OiNCD8VlrOMwOU8 -X6jmjw+zmUni8iDlM2zGjgZcg99zdZnAPuj5VbrNMya4kTNZVAaA69QmxWyAGJI8 -DApwj4ATAAQCCB8MCzYwKEvyF+jdu9AFLeK1RoMQVZzxXvDBsSg0a4xHYMcHrrxP -YxkAlU1V1FcZ71Aw45rs/qJXKlFiPzOnEGezJUawbNm6Zujx4vyTihtBZxaHMuNU -4wcrF4zUck9puaIXzEFuTwkCLWkb6xWz+X9XNVsF8dYJ+2klM9q3rKtDBqsnS+WM -E1g9+TwpSyJrf174OTVztlgAfjeQfLeYmTMEl7FLDEnRgyHK0aHeFHwxKllZD0sI -9Qhda1MKR2yPnmbsY39cV4+cVzrDwW25SGC6X5fSZtK5PmfneiuHW5EDRtkSODXU -i81fYGCjtlEgCJ9y0Iv+Pb7aLulIWUfqTYWRbNZv7kSOgZ6uU5hcjLpO2xfcV/sD -Qs7iffX8Yp0/+Q4/wxU+Xb8XElpei8X3XO63/Mvjym2zpIWLptd06h8a27E5PjEy -KrQzT25kxZllaiBLb2JsacW+ZWsgPG9uZHJlai5rb2JsaXpla0BmaXJtYS5zZXpu -YW0uY3o+iQJUBBMBCgA+AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEEdGzd -GGGGNChg6561Y/4Q6tVdD9sFAmZd3LUFCRF68DkACgkQY/4Q6tVdD9sc/A/+Il+7 -/pixpTIXkQwqExrTAdJ+jfzwyJ0CDZc8Cei3crfZNOwLMZ2ZGPJkTOURHkDHp/+j -JUyJOBPwXeBWGR28ynGASZ/ydhLBGcTnVUpDE1h92D/D1zJx5i/yVwmsWxiP5ZyI -Ua+RX3cVUJfYjLvljNrYiD9/cm21+Us1Kgqm9q3omMZUnarIFRmj9uIJ2HNO1n+H -6HpifrRGl1oI8Ru/NA48wPaYfrB/Z9QqRmv8UhXRXp1q3REQ70d7odvd/KS7ssV8 -O90vdm1FSx38B21ZBgr0d+wDDVazzdrdi9Hby/4ONiAz2LoLDB+TuoUV8nfvyRhB -KQTS+pFfEPP8U9cM5gJeQzXB/5LFycopAjPzjFolVtXRgXTGzjFmoGiQ4QVXtGA2 -Rp3ohZnoViUJvkcRXZ+RWJ06tOg8IGpk1LhI9M6B7YXTVMQq3/L/89oES3Sro09R -wUw7gpglbuHdV4SrLeXotx15cnlKUOfU4oekgMEU3xY2ojbJOOJrchlBhw8s8tlH -MhOWoI8ea8Pf2RpuGK0sBFzenf9naE8Q9mdcsK7OQ8smEhlueGu2devbv1wpDt3e -UN+oxXN+b0hXg9T8v+NdmuX4fQ9NE6E1MU01K8XdHBtq+IrQAwT2IffdCS4Ghgqu -Tj/KRJmL/E7TZYhbvCXCMFCVlhZHroDx+3X6vlK0J09uZMWZZWogS29ibGnFvmVr -IDxrb2JsaXpla29AZ21haWwuY29tPokCVAQTAQoAPgIbAwULCQgHAwUVCgkICwUW -AgMBAAIeAQIXgBYhBHRs3RhhhjQoYOuetWP+EOrVXQ/bBQJmXdy0BQkRevA5AAoJ -EGP+EOrVXQ/blm4QAKlj9eJPZQA4nxda5qf8qMc9061mzs6vBsnYiE8PZF/zZR7e -AmVT6Nh+MQH3D6j4FrbRTC+KjJ5Hl0aFG//V1U2mEckK4VdkYHxWMTyJlZ91TFK/ -vPhdszmhOxdhT0gcA9CmbGhnYb62t4uWw3T5s6bH7GKPuiVBSLu18QryiiHHXzyu -jDB9znlJGwH5DUsO1jXirCVduiJ8+KSAU898s14D280ytMl26nxQE5n86jIe4s4z -xOW13nKOLSnF7YDWhkpDSegE6+Kd0X26PiqRuMHdknbV86nktn27wP+/woNyzaDF -4Ga3HXInW8s/5BHtQfhcuA++pHWrYZhPiBzNAcsFIim1Zv3GfxM4+lUbkwddIaHx -kfMmuRKBYVA9/3TIujuAK8ovBHl7/zB9WBeEnAML3wzSmnAFnQdyshc7WAMNh5nB -hWFTa4O9UmPRKdIfWdNVEp5TDor62r3R4Khjij6LPCnTzpX4OmwV6keRAikDYH6n -Kik4lrXwhTJCF/HsXFyNhJWYsLXai9b3oiWrayJ4hX1WE8eYc/Gq7cNlHHin4wDD -ftPpsyDBq6WYs43U4x4jaKsiRWgPnZdYPIbL0OkDtfH5Te3VQqHSRTeyuNtlVWJb -XHn568yDeIxA5bAlpQWIKlui1exTZtyZIVMxOSaEBa7AutGnSW0WjaCG9YV+uQIN -BFilU2YBEADWFWz8yy8cS3z+fnj++pL974UMe0X37GmZzw6EUHePOwI22Xl6DseC -E3LpbnRUHlbnKOwLm/R5tUy5fXgXgAi5REntWJ3iJNgQK2NxG58ow3la+8jRMGdk -GXhdtH6R8JG/jFCUUdIbT9FfhvKUKRT5Yja/Ai/Vy71abyzNuNBA0i8UejHntFHX -//LCwVyuSN4XgorXLWLg/Vg81j2C2kbznfDLfdEzM3OUyozm1i1InIwT/oRAyIRk -JbgmDLRY/qwED04YmDcteDemDGbDdTrmMSklMSSGR6M9V429EFjLdVEWA9YKX/BT -Y6ZNPL1R7E/IQtHS20JJzKvFAVeDz8fPD1N8sfulOaZvx6b+UE+G+fcv+mUP0wEG -2rlYgdIWD4rOQh2+eLIPoPDaVTfaPy34B0EYtk3T2sDGXlIEG3wqqRFkSxfEX4Qw -gT8/rvIbmzi0QFGrBKS5WtMA2sz8lKedXYlRqN4FaIAKRj6isErqgxvRyZRmhWyZ -khfKhwcoMZJDdjbvoIEp6cos18QQYKYczKz7nbnGTpjT1IFX2wik/vBxRYvgW1gP -u/ZkmnsbuG2RRxtXKiqs7GInoY16ptMWTjilAanv/XSXpCHGfmBmeBGnJHo7hCxo -TIpA5rDmFrIgGEKZhvaI3P7+BKuQ+SFq076NSOReGpnaaISmjo9kWQARAQABiQI8 -BBgBCgAmAhsMFiEEdGzdGGGGNChg6561Y/4Q6tVdD9sFAmZd3a4FCRF68UgACgkQ -Y/4Q6tVdD9vfPA/+IrezMN9C3FJEwDYuyJ5uvltgh97NdtCelvJ9lvwa370X8G5f -wRMdMMYa02InhuskSuArLuIsvKYETcLiEZyiQaeEWvuPqSQs1Y0gIjmAz6FIQBxY -JFZsc7GmOeuq5JKBLFNhN3g7bSWGvm9/+02swi6IuLwcyoUBbH+aPoGQF9yZlwgu -ylTGozu292ZtLlr9iS1foJVug+Hl0xacaiAAbRxNqR/EfHTVj7m63DS4kTJpfLb5 -ldGWZD5AGdvUTytJv8eDMdOGoUnADThIILgneXu33SUUoUwO3JiDPw9dicmez+yP -M6l3H8E1OqfeeCUQpaTLlAGLYSCrDVH9iMXANjW9/W+y9pioo14gsmBft/sIY88u -TxbKb3H2NSmk8IM4fc+XduKGsxYVEf9IWlLOpaxtD1r056NBJsjjbpMjaWywW+zn -aXWBRqRy8BTf1/XOtXXpqligXAXAzEbDIJVTuQ/KZql5/dRHMR2zF9kdjKJ+d7Sk -TEw772uVyhuKIMqtjp29jwqcw63BkmJ9k8jJC+yXUSLTj0WMKoI0DPl9cQSbE6z5 -LDGtZ1blbieh6whwYvkcOBJd6vSs/na6qqEIK9oMsUtG9mI/8q2zWV7xfGl5o1k+ -raM9hP1zGCymc3FdhrjqB8zB7wN7oBW7Or//Ct1ijdR69HN8aTRknIj6GPaZAQ0E -UiC0aQEIAMHzTknImxjohJjz+EIl1DB09sJ2vBmt0vL5wkM8KccaYA0MpmOMqooz -gyqKoxywdOO3Phqk6n5fLtjsqTgWoG7YivipiddPz77pnMvnm+1x5bbNCBKdGQZp -a2gkf5RbEYwjEjPgbzt5FHzpQT7++oVfVnWKg0oeyjsTXGxRHLoRxqAhDSWrFHij -K+iW1E7n9eE2DZuPO4ATZRr9zUoQT9pkCIoGKXO7+daCU4aViHwUfF295ukKWg+h -Ldigp/eq2xGICTo2zqOMmJU/PpVFv19ij8O/jOLKuQjlTBOgDZ9vv3OFLAp1YBeR -rUqWwcn7FZfRjaSl0lYV/3bXsp5+NYcAEQEAAbQrU3RlZmFuIFNhZmFyIDxTdGVm -YW4uU2FmYXJAZmlybWEuc2V6bmFtLmN6PokBOQQTAQIAIwUCUiC0aQIbLwcLCQgH -AwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEC8q9jUqRTyt9GwH/3BW2Su1m6H1z3ad -S3wrNZxgvF9mcsySFh6DTNzRzx1g7qlZb0Z3NATHgmYZ50Q5Ib4e4ga70kqUiiOW -zS8pZjrKU4cQ+dGj8XOdfJj1j+xD9lrbXFHw5w0B0adb8GM2R8Evh+1lv2LXLwaC -Iu75z2+uMdsTgJZV257tGKqb3avSvmo0BPNGAXcRrAo9ejJR2g1g0XwWjFSCOIah -fUEWA4vivy7+wrgAqYER1WyrYoQ54yGJuJgcQ1T6HjJ6dHkFfWmDMPz9VrrjMLWP -Wz+6ZPCsRUNM4K/u0do0gmxel0ewguEH269ImDyovYMi75TPmkeLLgM6EickFa+9 -gB4WEKG5AQ0EUiC0aQEIAMQGNvwuaaa+RXHMHMaRdocdgLP637RQqqEncy6b46A2 -BqZhLWf1i1kSrdaTgsgjIYlTWB6jxtWDEbwXeVsJK7gZebjZyb2sO2/26/aT2FQ/ -jrEnYXn6f5QGXjV2OEIaz7+jGKGRCE6HCjGbh2O7yCRFp6AM3tci/XV1LaszERb0 -f3KB7V8HDW/h2zAgQDOXabv/c2sTt4tQNSwPExg8gU1xWNpsnUNfJ/O0o6xLUUkj -7Z+VGHmag8EzUermS9TtF4/oNlrNZPD6GZTT/qw4Pff0t4alAsV9jc5J0tq7odS5 -X/38WGZNF9GAGCtSSAHZFhNoxetz11Z0ncQT9S+71K8AEQEAAYkCPgQYAQIACQUC -UiC0aQIbLgEpCRAvKvY1KkU8rcBdIAQZAQIABgUCUiC0aQAKCRCi0IsGAXXWCnEg -B/9fcao+ET8dLGl/ASL35sPv2W4Xn/sduwB+FdWtrgfmrK2a2RW1cY4KStgY3suT -8AYob0E2TVm4KSu6TQrtke0F6ViR+Aione98tDMaOn4gp2x8ZVe5ZiBkdNLbDvG/ -l5fjgl60WRibkiRJp4LiyXKvjXDxs+2y/cODZNutGL9cus/IYshMUXEgztCnr8AN -pjLobgWklRF77Vb2Gj0Xyok56E1U8hX5WMI5SgguV4mOg0wXpiQytgHah48ZquWx -9I56EuODmCsKdXJNl6xdcYZR21UkS0mWeU+p85nY0mRwE1MWPN7IH7S40vpRi3nV -aC++3YneSr1EGtQZxJmVZpInj74IAI1yP3KldOts74awN5YOXiDbbh/6Mtkelxpe -+FzSeiHX/olqZn+Om38Vme2ntU9V2Y9fbtxAo6VboITf5tXP3FclQxOhM10rN2gC -UOPDIRrNDXxRWoDjbbihpUJIKbVTYWtqbQgSCs+S0rUROK5/+sAkMX2WZ4NmyADU -XXCTLRpSJ7bNei4OFMSJtwhgFzXU5+YCaX9NRsnEdCQVga+IDFtSFSSo4cIfECND -FuyfEnjto0mI0sosCtOv2yeNBLkl3sS3X7/F9UdinPcsChfR+1Vrk/zwtP6EdjIv -B+5MMuXbP4f9mdDCCUSJ2Mte66kuds2AL42AME/4M2tE2aB2HTWZAg0EXEM+0gEQ -ALzF49pa+rlwMwFi2ul2ZHbRhfnGsNdR4eC55JUT0zDzIJqfYKrUBzWMdidfGngm -Peri0hL0mragBurHK8Ex0lioTPjPvT14OdgFpxlBwaqiMuHccjY/uWaYrGQvytLd -DdSDTmZhP4zCCZG8g7X6TBBNyrUB4H3P3/OKSBjUm/VHzqAfwbzg49slSjB0T+ZP -elD7ZRCdqsJU8ndYm1k0Nc9HOySTS3mH4yDlG1f4I6gd+y9YeIRROYcx/KfDj0Yb -9gXqMtJXMyUozPeN0548gCumbYE1S7wO8Sf1q3p1opHgCH66MN3TyX2PzAWEmd6e -f/34Q2Ob2Q4ZBY6Yf98Qg6UwABNV1kR8dV8BZuAgI9Ks/KL6/cAITi4ShrDzkuBs -ABuHN2zCUt7MvFLsstOl8NlQVl+SGjUxIZdoJDjvn+JUB67GLrUHZVyYfiU5Ifsd -g2QxjyCAaTb9Ybfl6rw9mZ7w+9dSYu75/aPPL1cV6Qiv78qzZNyEJNgLDpuFIs9r -X0dqkLG9ZeA1xjNnyNQuoFewB+Pg2fMFOfq7mewnWt4Dwag728tpB/csOCv5Rj/P -7o3jviUBV+vR4h1bORY+9fx9wEJ+IH3jis+v5DnRFR9z2eAgo/gmx+WFdOfrTVov -ivqqQJwFWo795GFvi8IBSjtyx6ZMrMj/TmigZ9C1nc7lABEBAAG0Hk1hcmsgV2ll -bGFhcmQgPG1hcmtAa2xvbXAub3JnPokCUQQTAQoAOwIbAQULCQgHAgYVCgkICwIE -FgIDAQIeAQIXgBYhBOw8/oj2ygeId09cHRqkS+ZJ3nYKBQJcTfuZAhkBAAoJEBqk -S+ZJ3nYK470P/0WLos6tT6JgeN8iT7BPyPKEXVg0BOeihrlbvL/hCVc4jIqaRcz/ -R9ofWFk0Z/ipUrh0FR7C6EAswTO52RcSHO52D0qkH1Jodk1HkNn5gejbTjMnzg/5 -olrsXwU5Jxs0CIbikUYLuxDG+0DPSyQzTIux2E2Da0zyUzef17+s7gQrtpHnmiPM -T2kJaFFLH8AphPvnjkrNe4JFOTLx9Fwjxh400s8ix6hXdA+R/uo2LpheXTJQdXmB -AwJaqBt90cCWN3b43VFm93N8Q4tU8tfj92DFvfqL04qS4IAcugvZRd/NwASWW0dC -6d02L/FjNKLPMRgF4htWtu6qIk/XOaI9QrEeJuRTdOFllRuicpE1U9B7WE7jsLHK -PVHFeXo23251rdb2jDoqv3oGOzdZUFKqy6iGpoCUDELpFxyyWsTD/s3uXxLjbcsk -jplX4W/InOZICqQs3P+24VIyPvq4fizV0ttG/wrh9zDW9mCrL/iMiEEXJyfb2Ew2 -8iYpsycsPALsr3aUEZDqGnvn/Qd/Woc6kNqLJX1CrOvexM4xcmJibdpzlsOolv0y -Llg80HY4PfDdsMwZPn55aObD1GJhPmA2NjqdmEOJBL8+0hzqXeLYZoGNJ26vCPjt -OUJYAuPdmKIQqLJtqcrn9hd1VcZyEueg2TF4jVhwA1mFfrQVYTJodmxrtB5NYXJr -IFdpZWxhYXJkIDxtandAcmVkaGF0LmNvbT6JAk4EEwEKADgWIQTsPP6I9soHiHdP -XB0apEvmSd52CgUCXE36pwIbAQULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAa -pEvmSd52CuiSD/4xqtmnQJJNSD7Fce1+Wq4Al2iOaN2kxvjegTzL4sxmOAsqkwZm -AIN6kT1jeFPsMTRYM0N5z36bSSuhAwQGOC8PpCkeKPKOcz8owI23Pf23uW708DBZ -jG81sRlqCeHIfVvsA+FvlvLLJyQ21YuQbae5CslIINyj+6FEKcWfTE4JihJj7nHv -czkO/KviyD25ISPcwkv9VQh5Hlcp/k65wAqB8e7CoCaDsI1ZXG1t0tLHQrmhoN/l -SyN79yKUOelFyF+kVXi1/c1Q2ZwKu9gIHuBx3MY1/e49eoi+WYWUXNuCebaUpCYB -7fkQEjihyRjyIrwqim0CoWHNRuDGxWxs3JWi018mt0OHpBc6OKIXdoGu5oIxtEif -miFOcAmMRFA7KiS5vrh/520M108SKEIR+crm+DoVvPM+i6cDxoS780tkrjySFwJW -xsqx+9P7kWVpMChf/JkIzArCxGJGfQ0QfNea1E3PQiZJHjpT10FG8a9nwwIItI98 -gFMZawu4xEjv81CayAm8QoWAMfSjFhv9j7Cm6xgADCogu/qupmNPUOtxf4NQxBdr -G/m4LjHVnO0hI+uIxVH/cCfr41NRd9tQZIf0FjAAb+p/uxBZMJzZMpQkeR9W6Dhz -tN0zU9I8i2wRAke/zLacLeOnOPp/RDwpkMr3VNzFTzkb2YHtYc77r36NtrQbTWFy -ayBXaWVsYWFyZCA8bWp3QGdudS5vcmc+iQJOBBMBCgA4FiEE7Dz+iPbKB4h3T1wd -GqRL5knedgoFAlxN+lMCGwEFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQGqRL -5knedgo1bhAArI7kReYq4YtaxS8Pxb5MdPxiQVtvfkbycWCZ4owzPeEIkJqcbadN -UiGSqCRR2xeT4kuzFZWILiZfBTwHwFM/bXRDK/FOn7F8aqUAV1tq2W70Z7BUpTwp -Av7Xm5YvsfbTBZmllJltEiIrKIzULCtRKKVXgtOKg0sd/W2aXwyl+OX+PVzu4mXX -NEkO10J7VpnCvjyaJNeKgeJYQLizSWdEf7i6RX31yC29+GsSqikaOHdfxJMM+bo/ -x/aCuYlgDB+OQ6LZzpXZO0C8B5SMgMfZaK1rxDtUtViajSyOFJ4Ig6bcgc5qDCLn -k407oEN1yBWps867uN/Bi4Dk+xh691feGsyq95DvPis2Ut+0X0/Wi/uLg3uu/X5E -cNHynwht7KaGCLeuOZKxvzfeudNeyKFX34HtFyE/2k9LR0mFX8XnXQGBD9psOxcd -2K8Rku9BjjKDZ/vf53sMh5vxUNo+zkd+5dLZWPnLrhkfQrepDBP+Tc/6W0VSZCP5 -/nKX6GjPwmELtZj4jGf33tgfNMJrmxGUjpDxtiJc7OroNC4he3F5AF4RNRa5VvHs -6ah57swVvKyJmLH5mxxKIn39PspOhzVxSbkWNPLS+km2InPum+fmYKQL6IrHcqt/ -ecrR7o9GRgI0cJjLJ+wv93ti+gxsUWPbAUBaJPk24omIpQafFT/YAEW5AQ0EXEO7 -ogEIAKBUkmdjzOHy4efx38TuniP7255O9McxFg5LSSQaEcELsmbELDr8S9udtOwj -QJB7IgkeWY8ioNWBFWOKNxNZpx3e8h1rPMf2yqzrmeXj3IycDbe0jJrhVaVscLcn -jH8svzgDgZok78VUXa+/qFWDcgZuimnkpf6mvqznpOJZ11IOoyCNvutLONa43JEr -vlOhy0vtj9mfqy3dmKg7stereCGRZ/wlHtlpQUhjo/WpLmF6IIc/Q/FAlKu2ljMf -esomgekiSPGewH+wPQLTlwB2XNcFNRVM0tj4M+VDsV5GQb5Ur3VuuIbi29DyiGES -IL0e4m7UAow1YFn2p5TCxdom83MAEQEAAYkCNgQYAQoAIBYhBOw8/oj2ygeId09c -HRqkS+ZJ3nYKBQJcQ7uiAhsgAAoJEBqkS+ZJ3nYKHxkP/3Aq4iVpExIHUAwLCEY9 -qpdlqGsnrj1jSMjgmqkUq/b9TmEoc4btuKFEB4SPulnOGWAGuRmDVIF1ne8ezW58 -SWd97lFACl0Ob3d1pTlI/b2ISK8lDEqMX3UR8R9+XS2vHHO0GKkjn/YP6RpLxyc1 -V/OjlkRbL9x3oBKG9FUcztjZAdz6aVpmFiEG9O3ALpq9c2cbnlZiChsYQ14DCTIP -TvYkXdevEVv5eRwrGVr3JF1Z0fEl3k9gmqwoz6dV4kzbbo7A7JTbfmB8iEg/ql8a -oX1RUfS4WgJiRWRRKNV33pD4KPSR2FM6u0tbU5jXV31MHGN7jYY61ztf1nPHWeHB -TysIISsX3+4kgkqWrsjTysxfesUNO2LPA3uDtkGQMOJk74EgpA+39rAD00z611rT -aHJ9CiQEGL6/xv+IqJ8oh9Rqo8OjU8Dm7GWN2W7JfwBcii0qMlcXoSWyLPttWlwh -zRlc44Wv3KWa1mbnVg2Y7MM3OcQGaiXagFl+yTYbnn9CBKEeYpSe/MoA0EZ+d9L9 -r8rse/ix9kBvnw+uXo6ZBKuSaHMWvL/gE0sqr6d3izxVeQk+nHc6B/cOgjKeqk0X -RvB/nZTkiAlI1wk38esDCFobVb5jcsN7tLX0zRxTN+0RR6rcl3z2GiKMLva11tr4 -FF9bSdx+8RyyT1CJ9JTW29nFuQENBFxDurcBCACpIzhbHhC+8Ih/yKz7nuYsmFx4 -HaQu3dVHrtQVkLTLByvlXSm9O67ZTWhQH4FVgL8D1R2e9ZPIN5/fFMLHSECKIWGU -x7oKQ4M5qWbEj4rA/EPbvr7vS1zF3y9HYUm+INArD3p/aGUsCfFHjsZSndw98iBV -+S8hedcsxQlC8GFd5eqBiE5wCmUjrvuf/NN4WMG138mq3IOgnQN7Wh0TIL5lkP8m -jmrzRLJ2G9v30EdAyAtMlMk9bWJFXYArjF8GPE4zCqaX0vHgdEilX8gezcxPKESk -QD4j94qk7pTECkdYdnvpmbwEvxHCd8VpeMy55GEgYwW0mcu40VzmY4tdre6HABEB -AAGJA2wEGAEKACAWIQTsPP6I9soHiHdPXB0apEvmSd52CgUCXEO6twIbAgFACRAa -pEvmSd52CsB0IAQZAQoAHRYhBBJ2ipZ5WZAQeg0v3/xX48ys2Zp4BQJcQ7q3AAoJ -EPxX48ys2Zp4S+4H/3aoyPaZA3cJdFBROWbNU1QkskDDONEOhK3eSoOsAInY3wkt -LFYV4eYSauuYU9SZd8FSRP4XZb46uwmVS3B6m5NhE6As1l5sVB2MHfyiqyPxEwpv -mKRae1FSRrbGFINEFrQiWnEcFYsdLycTHXHgcHi5hErcilZKEBWZaTuOIBMYksVg -kZWjhMF8zbvMK3Lz8ZA3/cDYMAnY4luInXYHJODPO0Z2Enr0f9BSW2Qrt4lQYyM/ -CGmanTuWuiXJS6tvNosxCjDhIuj9kjFrSc8L4CgxKTTq16JyEJnAjKJT/vRLRz+4 -vdEWGdNuBZx1CQBWlZ2TAWogRLjEblAtS7zn9ZPuUxAAskoq446ls54q/ItXXo6j -vQ5Oaz8tuZdT35uMKPPtAhK7OEjiu5rSieNDMFpFcViR8KMG51ZoSnL/A/nCTpCW -rEuR5k0KTROzCSwvFCPI7ZeAFw6etKxAgQntUgIb08O+1XNutIFgyOgOjnwDKeIQ -xUA3JScViXVgGUW3nTo8OHzpkSqWlttF4Cxh8S4FB0F8mFamH1ZmAkNW0QdQDFqK -qKy80RvPjFEgCzFf87GdAx0PT1eznTK+XfwREhp1px6O1CcAhh4RpQGyBCTeu3T6 -D2Wbq2sPs/gVdiFQP2+aXr+fxMYHdQmLeUqlfjUZJQLXL6g+dryn4QSaubcFsHh+ -CciR9iIQM2iC+bal7ufNQ/uw2cTxFzJhyNSgRDRSj4cHp+To14EYqpogpV7EJwTG -dYoe+XQNnMbJ28rHjWfLMUjWy56DfgtxbCkYdfMnKGamOE17UY4q1UYcIYqEqGmk -rie1RkhJyIaHfzC8q4UOiEc7clVn0CHJFYpO7KfMtqsGma+7XVMNu/SV+dlyCGVZ -Yc2XHzHwN1oS4VZdlMO5VeoZyWZ5XaFLQuiZffcsIHifReRm0L0uyZMiyv5l1UIB -dR5f+kk403E0XwbjuVksuAtYX1t64dane7UijfV/OHjhNnGbVnfXAJmM6uwv1u/L -fEfIMVoMv7/uLpNexLG2pNe5AQ0EXEO6GQEIALX1DTbW/uRO7BgrASZupALnC+Zs -QxPiV29DyBYJQgUv2RPEzrsgXRqeezKz6usDKqoVROraidWaCNyK726mXq4N1XfC -K8IEQM31ktkBUdNK+KJcOGcdRKDoSEJ1kqFqX0MoCL68ZItJ7Xh7Yp+h7hzpHTIN -Uj4OfQ59SGUxe7Y2gNIUsB0ewMdIKsTrEo74E2AvYw+4x5cuE2K00hWvKShkyQWt -Qxwyweu+uTTlqHztFA7V7aWN6efyrE9Et05VZzRMmKiyOLLTi/AMBg1QI8MvlbYy -nZu/YB5M8LMXWqQOcYpkSpXal5YoI8HrTyVLWJzDmgq06XnQ9KDNN1otVFcAEQEA -AYkCNgQYAQoAIBYhBOw8/oj2ygeId09cHRqkS+ZJ3nYKBQJcQ7oZAhsMAAoJEBqk -S+ZJ3nYKnLwP/22rgFDdXCsM0LHJwAupa9lI+/8CCxPqFG9CwtzpinQUS3P5+sU8 -ta3tvKUyvMoi2myvQbYWh9bDTI3Ic1g+YaUKL5KtYsmdRMSblNmDBP72Qu3+YngH -QnWAeSSddKj3VLzgM9qKT0IfQaZchDI8A2QMOWan1b8eTygrHG8LH5JKxnoA1dqR -w1WD/DgyENbYejBbiwG+2W04VKA9Gz3MhKI3D/8ZiN5it046eJ4yGzPCmNC4rldi -cOHCJJqnYPydCUP9WkBrYK8T984VXYInIpl8TQny/kNk5T5JTCe3LV/nZkDWz84L -KxorUst0JfPdtCLJtBmGhtwCd4FVkWU3N/rGlH6ka3Dc5VLItCjgtJB/iUWzM3Lw -V8T4EnX/JRYUGOWMvAgd3ghbtjXs+6ABzX19DbeSs4hzc7iqy5jOp2HNjOoZs+9/ -t9jdPPQE1xbnzzkoRAkftUkkuql/cQQuGaQsE41iIXXSKCAVKafxZJBZtebSQZER -O8DN/4VhwmwoO71ABINE1yTwnbRkkZUttk10/5W4s5cIMCRIYjGL3VMuLptjQxvb -I1GACrpycglRMBtyfDTkEvFFb57wBLceh2NkdbMAwM+lmflMV8k5d0OF1549UaCT -KnHCdt7JNPc6NQSHfu+v5ciCtMynP5k2kfEuvhslq1ARUrcfpDdltCQx -=swck +mQINBGKE4psBEADpHSM/IxFD1nXBmnODYXzcl2A+6b6m9m1m2Y4Dlr0ed+y5Lxne +QidE9I74A2KSm6+eHW2yh4i1ZwZbmwpmQqM+j5BMt7axoXOdKSyN+fYtUakzNbBN +EDRKT79q/zIzkgTJradHkCQkwF1W3go+qPXjR2ZEnLma9dZED9VNI6PmOpeYaASo +IkEfbKbwa/vPrvnDSSYY6Y02RXSRk5U1NvQgVUTJP9WGK7NlPUcTBDELLQv6fFPU +kjBOel6MecsQ+v8iq4RJF2cbVF0hNjbAiNldjLV74Xd7yWVRlCbdb2agyvQjMNrD +jHSvbEMiNB3R8yBHVW2Zldv8q0XjcwoDfdiZYFJe3lRUYmv6I2p+/DptD4r/3ILI +peGZtSeOdQEw+vvODL/Ehq03anTrzcpZ6sDLfLrYJhYcrltj0/LMUnLDAjciwRUq +XI46EfxwqsdLeqoZFQeO3LOFsh0kJKR2xOrUHIVy84NJ4Gmro6WmUkb1NfdjyHzF +z8Lfbo46NKoTcwFsFF0q74jVVIVNUyIS91DusiMqLCsP8jqDOz/kyP4bOJQ+aUXf +BANn4Ll1TFWsJ417moxz+Pi5sTaI0na8z2XB1N9WPsSml3FS75hJPJshN2T3VIea +zB7GFWqk33ynSDt+cAisG5nsK9fFdcH+t5wm59oobyFbFhKxwX6ROuxlZwARAQAB +tCRTZXJnZXkgS2FuZGF1cm92IDxwbHVrbmV0QG5naW54LmNvbT6JAk4EEwEKADgW +IQTWeGzjA9mpAimY3GzIRk1UmvdcCgUCYoTimwIbAwULCQgHAwUVCgkICwUWAwIB +AAIeAQIXgAAKCRDIRk1UmvdcCqbOD/9Htgk3mWvUFmrApkWQTIDNmLACZ1Sw1PXj +Uqte8StYB0bYY+nmAXs7O5eC2h1ViParl7En1joEEMQQmH0qSnw4X1CM/hA8TAYW +mBPITTNWo/R52WoyWeWGFnFNIperQmuIZc+pXm0VEFVPiX/2DXbCIu+jaXySvlCN +LekmOD4VC7dJS8/ohoaXOR2T8ufS+1CsyPXomEb+COhqRZ3EVBa+k7pnElkFft3Y +a1fR0AgatZFQpy+ukePhK7s/M5RGhDJWHgSAZFkf+X2jVV4NRJ+XsY80gU5DD2ZX +QT6Je6Knxqk7FnWNSxkhReH6Ss5flZSoGDCmJ2AsPtGeUhus2fGqeN+waGKTZC35 +die2V4/cro1SWswSI6Y5GFDZT1olIUztPmSXU/A3oyizJI7XZybwUbpk5kK83VXm +el3U/7Qr/VErlDWFefZWeUvT1RILZ8IRoNj4dv158RnKHt9G508A5qz4hUPKoSeq +SiXhYwfkc31WPzIJ4ev+X5Ka2sG/CKbEMJ7qwc0Kadiu+ePPfqqbXjpTWRyrbcRM +hRNcLNUi1SLWMBClOQG+5GNG1dPPHkbj4dO1OZuaUMwQdu8R8NlsGoVWS40bmVv5 +pXstzYCl7k/UnC/Ytlq61GeAoq8ILa6jGj0EWqlhvi0ZNMN+fROhzrRlTzIr/+WE +Xf8EiVNFSbQlU2VyZ2V5IEthbmRhdXJvdiA8cy5rYW5kYXVyb3ZAZjUuY29tPokC +TgQTAQoAOBYhBNZ4bOMD2akCKZjcbMhGTVSa91wKBQJihO2zAhsDBQsJCAcDBRUK +CQgLBRYDAgEAAh4BAheAAAoJEMhGTVSa91wKgLQQANaf4UMndkWoefDQPkJ5qR4K +fuV0WRz59riZEApTkVpPXzl8Y1i8Rgt9pa1v1i12vPyIXKav1rJXQcuDEzqrhQ2G +yvuAE2U/t2mYaMUmwxWO2d8JA3slvBSgOkiYpbLooDizAdKMT5UQWGyw31Wm51iz +HjoztebsyXeXgq9VDjv3D8LUBr/OY3Hguj6HV+zRtC95qgXYadW2FiCtvBK6RTDb +iShTuseLSheGh9dZIUSnzaOiJpDA61ZDYtFZxSpe67vEzhSfHVsF+ZdCjoWhhVv+ ++2wR4E0VQQtOM9uX1PMlZ5Ymr02/gidsXCM0ZjYXx4cDDhnq+nKomN64VloXWY9t +PIi86XmzcSWlGUd+Ac6LyW7/f64bUWs4Ih0Idl0PF0sAr/6axKUsIs1nbn5MEtXk +ZPAjcDLqLb9IIQaXRurm/il8v+bLXVBOJq33YUuGRuz8pu4vPA5Q97zglqhlIgbu +prHMJ9hl5q39JwS3As2rK0o6Q9VVKr29rqSEfk4wEttvk0QMMU5zEvVl8MtqPj42 +qURqpHOadFbYMTwhUmRBUszRZPa5/pWqq0gWOtpyCWFVAsHFWQGJM1Eo6gGEyHZM +YgBp+d29p2p409r1+06U67GBnXvUy0RyIpkLQtU+lyOJ6vvrBmmsDs/gc69GnlSC +tZmCt0pLesJ7ZJzGdDkduQINBGKE4psBEADQr/enuDeVT11v6ejuYrg7aaZaGFUe +3i28bQ4pRUKNfxs7zVYDDHi2i2bhS5j2yQnbsQtGcgoenw6lapmdQRzr4vjQAz9o +kT6l4qpqvFFQM0wZTnigVDmmO9vTHR8Uk3iCKTd2ax3oko/xPWWYJautJ6ex8cOA +coHSDeOjuIWSxCKq0BDFp6LoxkM8nuyLAX2cbhI3LncaZhVveMeN+Fmcsv+WpkKs +yhX92umZuGwlraSyFy23FiRWSZPu9qVIxMMHvVrQJIgfhyWaHFzoF4M4qDoSKx92 +uWfUWgFwPOxOJ6/YcPsX4T8qTl9htmwPN0BibPTlcWaIFXtiU5bE1MivUPeACrI/ +gwUfCR3Mg+GYc13C6jzepREUhI7PLi3+A203PlMZd/aaSZkP6j+h4cwdapH5P4uF +7T1EQ0MSdx3neAvu5p0IM6JpriwxfT3HsG+Y952T6MIeXcjNRebsBrygJhJ0/vyr +wV5t8jL0yQty4CiE/QFnBs42l+rngi7K7Y1AZRBGK7JA09XaoLrfLmS+PrbYPsaJ +flkM8GzUB7BBCLozxDHPzmPkf/A1w3XHZnYuZmS+pvjWCIoKpLQHI99oSUGho/TR +gMRO4v7EAzluqCiepMl0xwFfHB115ND/mATazc4Pt6FxUsqffzfZrN01e1UVPrp5 +4x6YLO80JnOY6QARAQABiQI2BBgBCgAgFiEE1nhs4wPZqQIpmNxsyEZNVJr3XAoF +AmKE4psCGwwACgkQyEZNVJr3XAp9ghAAgCgErxQYn/Lh/mzsxYXPnisggcBpceks +mGw7knj1EGkXqq9CHn3EjCw8dB5N857UFlUr++DHwpFL5O36PRQo33RIUFbmBypG +8C/xX1jWGu3xcaqS3P1ncsSSl6ckdvy9pjMxThm/RkXO0eJCn7FcanwPJXEB3Pbb +mm0wLI2OXl/m7l5QAr7kErnPvGNzcbX6G35Q/MY8mumBWQ9H53R5ZPpi+OS40Wfn +pZNKdh/Acwa7+2RokPqoOcJfxVdBOUigXTzb45qZgqEsSR7bkZAy2E80A/sJKPqs +OGjp9cog3rBYyNBn5dasfR9KeBtluKnjUbzutXsQoKUSECY00YGrtneSXMku5hoE +Dguk68w/L63ZApYHO/JTgJAYvqPOErAVUegPIw2CT1/2qi5vpClBcKkNS7RXrssA +X+lElE0zbzX3bNG+lQuXby7jNUFYltkEiz6vTtc4HuHy8u40DHMswzkoDr0T8IE0 +7ZRAWXwV1nlA/dI337cHCsWMJyqem5wZZO13iqe07qaCg1uvBPeqDo81hOCn1us7 +l5SYRUTlt7KSFEHZ+Sx4bmVneAuRi5okaQdmrepy/ss/vVpRwWuQxsPkvT8boS7s +mqOVsZFcNOuUJPUyOz1dHUL6FMYpk1dw+9n41gO4fLBzJekFTB/fxL6SRbYFWWn7 +x0VGHDmuaYQ= +=HmVo -----END PGP PUBLIC KEY BLOCK----- From 359eb3866f30aac127dc7e258d866729f8fea8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 11:23:45 +0100 Subject: [PATCH 65/89] New upstream version 1.26.2 --- CHANGES | 27 ++++++++++++++++++ CHANGES.ru | 28 +++++++++++++++++++ auto/lib/libatomic/conf | 2 +- src/core/nginx.h | 4 +-- src/core/ngx_output_chain.c | 10 +++++-- src/event/quic/ngx_event_quic_frames.c | 1 + src/event/quic/ngx_event_quic_ssl.c | 5 ++++ src/event/quic/ngx_event_quic_transport.c | 8 ++++++ src/http/modules/ngx_http_grpc_module.c | 5 +++- .../modules/ngx_http_gunzip_filter_module.c | 18 +++++++++--- .../modules/ngx_http_gzip_filter_module.c | 10 +++++-- src/http/modules/ngx_http_mp4_module.c | 14 ++++++++-- src/http/modules/ngx_http_ssi_filter_module.c | 8 ++++-- src/http/modules/ngx_http_sub_filter_module.c | 8 ++++-- src/http/v3/ngx_http_v3_parse.c | 3 ++ src/http/v3/ngx_http_v3_request.c | 20 +++++++++---- src/http/v3/ngx_http_v3_table.c | 2 +- src/http/v3/ngx_http_v3_uni.c | 4 +-- src/http/v3/ngx_http_v3_uni.h | 2 ++ 19 files changed, 149 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index f60c885..49e47de 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,31 @@ +Changes with nginx 1.26.2 14 Aug 2024 + + *) Security: processing of a specially crafted mp4 file by the + ngx_http_mp4_module might cause a worker process crash + (CVE-2024-7347). + Thanks to Nils Bars. + + +Changes with nginx 1.26.1 29 May 2024 + + *) Security: when using HTTP/3, processing of a specially crafted QUIC + session might cause a worker process crash, worker process memory + disclosure on systems with MTU larger than 4096 bytes, or might have + potential other impact (CVE-2024-32760, CVE-2024-31079, + CVE-2024-35200, CVE-2024-34161). + Thanks to Nils Bars of CISPA. + + *) Bugfix: reduced memory consumption for long-lived requests if "gzip", + "gunzip", "ssi", "sub_filter", or "grpc_pass" directives are used. + + *) Bugfix: nginx could not be built by gcc 14 if the --with-libatomic + option was used. + Thanks to Edgar Bonet. + + *) Bugfix: in HTTP/3. + + Changes with nginx 1.26.0 23 Apr 2024 *) 1.26.x stable branch. diff --git a/CHANGES.ru b/CHANGES.ru index 7e42b52..aaa0f5f 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,32 @@ +Изменения в nginx 1.26.2 14.08.2024 + + *) Безопасность: обработка специально созданного mp4-файла модулем + ngx_http_mp4_module могла приводить к падению рабочего процесса + (CVE-2024-7347). + Спасибо Nils Bars. + + +Изменения в nginx 1.26.1 29.05.2024 + + *) Безопасность: при использовании HTTP/3 обработка специально созданной + QUIC-сессии могла приводить к падению рабочего процесса, отправке + клиенту содержимого памяти рабочего процесса на системах с MTU больше + 4096 байт, а также потенциально могла иметь другие последствия + (CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161). + Спасибо Nils Bars из CISPA. + + *) Исправление: уменьшено потребление памяти для долгоживущих запросов, + если используются директивы gzip, gunzip, ssi, sub_filter или + grpc_pass. + + *) Исправление: nginx не собирался gcc 14, если использовался параметр + --with-libatomic. + Спасибо Edgar Bonet. + + *) Исправление: в HTTP/3. + + Изменения в nginx 1.26.0 23.04.2024 *) Стабильная ветка 1.26.x. diff --git a/auto/lib/libatomic/conf b/auto/lib/libatomic/conf index d1e484a..8c8cb43 100644 --- a/auto/lib/libatomic/conf +++ b/auto/lib/libatomic/conf @@ -19,7 +19,7 @@ else #include " ngx_feature_path= ngx_feature_libs="-latomic_ops" - ngx_feature_test="long n = 0; + ngx_feature_test="AO_t n = 0; if (!AO_compare_and_swap(&n, 0, 1)) return 1; if (AO_fetch_and_add(&n, 1) != 1) diff --git a/src/core/nginx.h b/src/core/nginx.h index 7ef5cfb..d29edd2 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1026000 -#define NGINX_VERSION "1.26.0" +#define nginx_version 1026002 +#define NGINX_VERSION "1.26.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 8570742..a46209c 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) ngx_debug_point(); - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); continue; } @@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) /* delete the completed buf from the ctx->in chain */ if (ngx_buf_size(ctx->in->buf) == 0) { - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in = cl->next; + + ngx_free_chain(ctx->pool, cl); } cl = ngx_alloc_chain_link(ctx->pool); diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c index 42b7d9f..6ea908c 100644 --- a/src/event/quic/ngx_event_quic_frames.c +++ b/src/event/quic/ngx_event_quic_frames.c @@ -648,6 +648,7 @@ ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb) ngx_quic_free_chain(c, qb->chain); qb->chain = NULL; + qb->last_chain = NULL; } diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c index 7872783..ba0b592 100644 --- a/src/event/quic/ngx_event_quic_ssl.c +++ b/src/event/quic/ngx_event_quic_ssl.c @@ -326,6 +326,11 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_crypto_frame_t *f; qc = ngx_quic_get_connection(c); + + if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) { + return NGX_OK; + } + ctx = ngx_quic_get_send_ctx(qc, pkt->level); f = &frame->u.crypto; diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c index 19670a6..fba098c 100644 --- a/src/event/quic/ngx_event_quic_transport.c +++ b/src/event/quic/ngx_event_quic_transport.c @@ -1750,6 +1750,14 @@ ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp, return NGX_ERROR; } + if ((size_t) (end - p) < len) { + ngx_log_error(NGX_LOG_INFO, log, 0, + "quic failed to parse" + " transport param id:0x%xL, data length %uL too long", + id, len); + return NGX_ERROR; + } + rc = ngx_quic_parse_transport_param(p, p + len, id, tp); if (rc == NGX_ERROR) { diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index dfe49c5..e7726f3 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) ngx_buf_t *b; ngx_int_t rc; ngx_uint_t next, last; - ngx_chain_t *cl, *out, **ll; + ngx_chain_t *cl, *out, *ln, **ll; ngx_http_upstream_t *u; ngx_http_grpc_ctx_t *ctx; ngx_http_grpc_frame_t *f; @@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) last = 1; } + ln = in; in = in->next; + + ngx_free_chain(r->pool, ln); } ctx->in = in; diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c index c1341f5..5d170a1 100644 --- a/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -333,6 +333,8 @@ static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { return NGX_OK; } @@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, return NGX_DECLINED; } - ctx->in_buf = ctx->in->buf; - ctx->in = ctx->in->next; + cl = ctx->in; + ctx->in_buf = cl->buf; + ctx->in = cl->next; + + ngx_free_chain(r->pool, cl); ctx->zstream.next_in = ctx->in_buf->pos; ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; @@ -374,6 +379,7 @@ static ngx_int_t ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { + ngx_chain_t *cl; ngx_http_gunzip_conf_t *conf; if (ctx->zstream.avail_out) { @@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); if (ctx->free) { - ctx->out_buf = ctx->free->buf; - ctx->free = ctx->free->next; + + cl = ctx->free; + ctx->out_buf = cl->buf; + ctx->free = cl->next; + + ngx_free_chain(r->pool, cl); ctx->out_buf->flush = 0; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index ed0de60..b555278 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -985,10 +985,14 @@ static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - ngx_chain_t *cl; + ngx_chain_t *cl, *ln; - for (cl = ctx->copied; cl; cl = cl->next) { - ngx_pfree(r->pool, cl->buf->start); + for (cl = ctx->copied; cl; /* void */) { + ln = cl; + cl = cl->next; + + ngx_pfree(r->pool, ln->buf->start); + ngx_free_chain(r->pool, ln); } ctx->copied = NULL; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 03175de..041ad26 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -3099,7 +3099,8 @@ 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, + uint64_t n; + uint32_t start_sample, chunk, samples, id, next_chunk, prev_samples; ngx_buf_t *data, *buf; ngx_uint_t entries, target_chunk, chunk_samples; @@ -3155,12 +3156,19 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, next_chunk = ngx_mp4_get_32value(entry->chunk); + if (next_chunk < chunk) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "unordered mp4 stsc chunks in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "sample:%uD, chunk:%uD, chunks:%uD, " "samples:%uD, id:%uD", start_sample, chunk, next_chunk - chunk, samples, id); - n = (next_chunk - chunk) * samples; + n = (uint64_t) (next_chunk - chunk) * samples; if (start_sample < n) { goto found; @@ -3182,7 +3190,7 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", start_sample, chunk, next_chunk - chunk, samples); - n = (next_chunk - chunk) * samples; + n = (uint64_t) (next_chunk - chunk) * samples; if (start_sample > n) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index 0b84bd3..47068f7 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->state == ssi_start_state) { diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index 6d3de59..456bb27 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { - ctx->buf = ctx->in->buf; - ctx->in = ctx->in->next; + + cl = ctx->in; + ctx->buf = cl->buf; + ctx->in = cl->next; ctx->pos = ctx->buf->pos; + + ngx_free_chain(r->pool, cl); } if (ctx->buf->flush || ctx->buf->recycled) { diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c index 5688163..436765c 100644 --- a/src/http/v3/ngx_http_v3_parse.c +++ b/src/http/v3/ngx_http_v3_parse.c @@ -810,6 +810,7 @@ ngx_http_v3_parse_field_lri(ngx_connection_t *c, st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } @@ -932,6 +933,7 @@ ngx_http_v3_parse_field_l(ngx_connection_t *c, st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } @@ -1072,6 +1074,7 @@ ngx_http_v3_parse_field_lpbi(ngx_connection_t *c, st->literal.length = st->pint.value; if (st->literal.length == 0) { + st->value.data = (u_char *) ""; goto done; } diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c index 87f5f32..0faddd2 100644 --- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -134,7 +134,17 @@ ngx_http_v3_init(ngx_connection_t *c) } } - return ngx_http_v3_send_settings(c); + if (ngx_http_v3_send_settings(c) != NGX_OK) { + return NGX_ERROR; + } + + if (h3scf->max_table_capacity > 0) { + if (ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER) == NULL) { + return NGX_ERROR; + } + } + + return NGX_OK; } @@ -398,14 +408,12 @@ ngx_http_v3_wait_request_handler(ngx_event_t *rev) void ngx_http_v3_reset_stream(ngx_connection_t *c) { - ngx_http_v3_session_t *h3c; - ngx_http_v3_srv_conf_t *h3scf; - - h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); + ngx_http_v3_session_t *h3c; h3c = ngx_http_v3_get_session(c); - if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq + if (!c->read->eof && !h3c->hq + && h3c->known_streams[NGX_HTTP_V3_STREAM_SERVER_DECODER] && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c index f49a8fc..428e732 100644 --- a/src/http/v3/ngx_http_v3_table.c +++ b/src/http/v3/ngx_http_v3_table.c @@ -308,7 +308,7 @@ ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity) prev_max = dt->capacity / 32; if (max > prev_max) { - elts = ngx_alloc(max * sizeof(void *), c->log); + elts = ngx_alloc((max + 1) * sizeof(void *), c->log); if (elts == NULL) { return NGX_ERROR; } diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c index 2fc5b07..302064b 100644 --- a/src/http/v3/ngx_http_v3_uni.c +++ b/src/http/v3/ngx_http_v3_uni.c @@ -20,8 +20,6 @@ static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); -static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, - ngx_uint_t type); void @@ -307,7 +305,7 @@ ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev) } -static ngx_connection_t * +ngx_connection_t * ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type) { u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; diff --git a/src/http/v3/ngx_http_v3_uni.h b/src/http/v3/ngx_http_v3_uni.h index 911e153..2805894 100644 --- a/src/http/v3/ngx_http_v3_uni.h +++ b/src/http/v3/ngx_http_v3_uni.h @@ -19,6 +19,8 @@ ngx_int_t ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type); ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id); +ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, + ngx_uint_t type); ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id); ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c, From 2fe36c4448b6e038d68a656883153c27aafd5052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 11:24:35 +0100 Subject: [PATCH 66/89] Drop upstream patches --- debian/patches/series | 2 -- 1 file changed, 2 deletions(-) diff --git a/debian/patches/series b/debian/patches/series index 56e7725..52e1dc4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,5 +1,3 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch -nginx-1.26.1.patch -CVE-2024-7347.patch From 1518af2753f3adf3b9a4f72f03396520ef9b4a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 11:24:45 +0100 Subject: [PATCH 67/89] Refresh patches --- debian/patches/nginx-fix-pidfile.patch | 4 ++-- debian/patches/nginx-ssl_cert_cb_yield.patch | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/patches/nginx-fix-pidfile.patch b/debian/patches/nginx-fix-pidfile.patch index 43c6e2f..83f7cf9 100644 --- a/debian/patches/nginx-fix-pidfile.patch +++ b/debian/patches/nginx-fix-pidfile.patch @@ -7,7 +7,7 @@ Last-Update: 2020-06-24 This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ --- a/src/core/nginx.c +++ b/src/core/nginx.c -@@ -339,14 +339,21 @@ +@@ -340,14 +340,21 @@ ngx_process = NGX_PROCESS_MASTER; } @@ -30,7 +30,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ return 1; } -@@ -359,8 +366,19 @@ +@@ -360,8 +367,19 @@ #endif diff --git a/debian/patches/nginx-ssl_cert_cb_yield.patch b/debian/patches/nginx-ssl_cert_cb_yield.patch index adb1ba5..dfcf55c 100644 --- a/debian/patches/nginx-ssl_cert_cb_yield.patch +++ b/debian/patches/nginx-ssl_cert_cb_yield.patch @@ -16,7 +16,7 @@ connections. --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c -@@ -1832,6 +1832,23 @@ +@@ -1914,6 +1914,23 @@ return NGX_AGAIN; } @@ -40,7 +40,7 @@ connections. err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; c->ssl->no_wait_shutdown = 1; -@@ -1968,6 +1985,21 @@ +@@ -2050,6 +2067,21 @@ c->read->handler = ngx_ssl_handshake_handler; c->write->handler = ngx_ssl_handshake_handler; From 215a9620ef32640b8a36bf830e889c842344f3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 11:33:47 +0100 Subject: [PATCH 68/89] Version 1.26.2 --- debian/changelog | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index f4c0043..09302b8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,19 @@ -nginx (1.26.0-4) UNRELEASED; urgency=medium +nginx (1.26.2-1) UNRELEASED; urgency=medium + [ Jan Mojžíš ] * d/u/signing-key.asc: add Sergey Kandaurov public key, the key is used to sign the 1.26.2 release * d/gbp.conf: add upstream-signatures = on * d/{control,copyright}: update my email to "janmojzis@debian.org" * d/copyright: bump my copyright year - -- Jan Mojžíš Tue, 28 Jan 2025 08:26:25 +0100 + [ Jérémy Lal ] + * Add Sergey Kandaurov pgp public key + * New upstream version 1.26.2 + * Drop upstream patches + * Refresh patches + + -- Jérémy Lal Sun, 02 Feb 2025 11:24:55 +0100 nginx (1.26.0-3) unstable; urgency=medium From 9fb3b99b3dd880c9518b0478d2c654452bb63ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 11:40:36 +0100 Subject: [PATCH 69/89] Bump abi --- debian/libnginx-mod.abisubstvars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index d793435..21d5511 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -8,4 +8,4 @@ # changes without upgrading the upstream nginx version, e.g. security updates # in oldstable -nginx:abi=nginx-abi-1.26.0-1 +nginx:abi=nginx-abi-1.26.2-1 From d2631d1b03e915d5544446fd939528754565904a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 2 Feb 2025 19:41:03 +0100 Subject: [PATCH 70/89] rm d/p/CVE-2024-7347.patch --- debian/patches/CVE-2024-7347.patch | 45 ------------------------------ 1 file changed, 45 deletions(-) delete mode 100644 debian/patches/CVE-2024-7347.patch diff --git a/debian/patches/CVE-2024-7347.patch b/debian/patches/CVE-2024-7347.patch deleted file mode 100644 index 1ca3e79..0000000 --- a/debian/patches/CVE-2024-7347.patch +++ /dev/null @@ -1,45 +0,0 @@ -Origin: https://nginx.org/download/patch.2024.mp4.txt - -diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c ---- a/src/http/modules/ngx_http_mp4_module.c -+++ b/src/http/modules/ngx_http_mp4_module.c -@@ -3099,7 +3099,8 @@ 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, -+ uint64_t n; -+ uint32_t start_sample, chunk, samples, id, next_chunk, - prev_samples; - ngx_buf_t *data, *buf; - ngx_uint_t entries, target_chunk, chunk_samples; -@@ -3155,12 +3156,19 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4 - - next_chunk = ngx_mp4_get_32value(entry->chunk); - -+ if (next_chunk < chunk) { -+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, -+ "unordered mp4 stsc chunks in \"%s\"", -+ mp4->file.name.data); -+ return NGX_ERROR; -+ } -+ - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "sample:%uD, chunk:%uD, chunks:%uD, " - "samples:%uD, id:%uD", - start_sample, chunk, next_chunk - chunk, samples, id); - -- n = (next_chunk - chunk) * samples; -+ n = (uint64_t) (next_chunk - chunk) * samples; - - if (start_sample < n) { - goto found; -@@ -3182,7 +3190,7 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4 - "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", - start_sample, chunk, next_chunk - chunk, samples); - -- n = (next_chunk - chunk) * samples; -+ n = (uint64_t) (next_chunk - chunk) * samples; - - if (start_sample > n) { - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, From 92496d21cf129e64f4435d9718a3ceadf029ff26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 2 Feb 2025 19:41:30 +0100 Subject: [PATCH 71/89] rm d/p/nginx-1.26.1.patch --- debian/patches/nginx-1.26.1.patch | 367 ------------------------------ 1 file changed, 367 deletions(-) delete mode 100644 debian/patches/nginx-1.26.1.patch diff --git a/debian/patches/nginx-1.26.1.patch b/debian/patches/nginx-1.26.1.patch deleted file mode 100644 index 8086ae8..0000000 --- a/debian/patches/nginx-1.26.1.patch +++ /dev/null @@ -1,367 +0,0 @@ -From: =?utf-8?b?SmFuIE1vasW+w63FoQ==?= -Date: Mon, 17 Jun 2024 18:40:09 +0200 -Subject: nginx-1.26.1 -Forwarded: not-needed - -Backport changes from the nginx 1.26.1 and fix -CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161 - ---- - auto/lib/libatomic/conf | 2 +- - src/core/ngx_output_chain.c | 10 ++++++++-- - src/event/quic/ngx_event_quic_frames.c | 1 + - src/event/quic/ngx_event_quic_ssl.c | 5 +++++ - src/event/quic/ngx_event_quic_transport.c | 8 ++++++++ - src/http/modules/ngx_http_grpc_module.c | 5 ++++- - src/http/modules/ngx_http_gunzip_filter_module.c | 18 ++++++++++++++---- - src/http/modules/ngx_http_gzip_filter_module.c | 10 +++++++--- - src/http/modules/ngx_http_ssi_filter_module.c | 8 ++++++-- - src/http/modules/ngx_http_sub_filter_module.c | 8 ++++++-- - src/http/v3/ngx_http_v3_parse.c | 3 +++ - src/http/v3/ngx_http_v3_request.c | 20 ++++++++++++++------ - src/http/v3/ngx_http_v3_table.c | 2 +- - src/http/v3/ngx_http_v3_uni.c | 4 +--- - src/http/v3/ngx_http_v3_uni.h | 2 ++ - 15 files changed, 81 insertions(+), 25 deletions(-) - -diff --git a/auto/lib/libatomic/conf b/auto/lib/libatomic/conf -index d1e484a..8c8cb43 100644 ---- a/auto/lib/libatomic/conf -+++ b/auto/lib/libatomic/conf -@@ -19,7 +19,7 @@ else - #include " - ngx_feature_path= - ngx_feature_libs="-latomic_ops" -- ngx_feature_test="long n = 0; -+ ngx_feature_test="AO_t n = 0; - if (!AO_compare_and_swap(&n, 0, 1)) - return 1; - if (AO_fetch_and_add(&n, 1) != 1) -diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c -index 8570742..a46209c 100644 ---- a/src/core/ngx_output_chain.c -+++ b/src/core/ngx_output_chain.c -@@ -117,7 +117,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) - - ngx_debug_point(); - -- ctx->in = ctx->in->next; -+ cl = ctx->in; -+ ctx->in = cl->next; -+ -+ ngx_free_chain(ctx->pool, cl); - - continue; - } -@@ -203,7 +206,10 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) - /* delete the completed buf from the ctx->in chain */ - - if (ngx_buf_size(ctx->in->buf) == 0) { -- ctx->in = ctx->in->next; -+ cl = ctx->in; -+ ctx->in = cl->next; -+ -+ ngx_free_chain(ctx->pool, cl); - } - - cl = ngx_alloc_chain_link(ctx->pool); -diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c -index 42b7d9f..6ea908c 100644 ---- a/src/event/quic/ngx_event_quic_frames.c -+++ b/src/event/quic/ngx_event_quic_frames.c -@@ -648,6 +648,7 @@ ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb) - ngx_quic_free_chain(c, qb->chain); - - qb->chain = NULL; -+ qb->last_chain = NULL; - } - - -diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c -index 7872783..ba0b592 100644 ---- a/src/event/quic/ngx_event_quic_ssl.c -+++ b/src/event/quic/ngx_event_quic_ssl.c -@@ -326,6 +326,11 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, - ngx_quic_crypto_frame_t *f; - - qc = ngx_quic_get_connection(c); -+ -+ if (!ngx_quic_keys_available(qc->keys, pkt->level, 0)) { -+ return NGX_OK; -+ } -+ - ctx = ngx_quic_get_send_ctx(qc, pkt->level); - f = &frame->u.crypto; - -diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c -index 19670a6..fba098c 100644 ---- a/src/event/quic/ngx_event_quic_transport.c -+++ b/src/event/quic/ngx_event_quic_transport.c -@@ -1750,6 +1750,14 @@ ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp, - return NGX_ERROR; - } - -+ if ((size_t) (end - p) < len) { -+ ngx_log_error(NGX_LOG_INFO, log, 0, -+ "quic failed to parse" -+ " transport param id:0x%xL, data length %uL too long", -+ id, len); -+ return NGX_ERROR; -+ } -+ - rc = ngx_quic_parse_transport_param(p, p + len, id, tp); - - if (rc == NGX_ERROR) { -diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c -index dfe49c5..e7726f3 100644 ---- a/src/http/modules/ngx_http_grpc_module.c -+++ b/src/http/modules/ngx_http_grpc_module.c -@@ -1231,7 +1231,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) - ngx_buf_t *b; - ngx_int_t rc; - ngx_uint_t next, last; -- ngx_chain_t *cl, *out, **ll; -+ ngx_chain_t *cl, *out, *ln, **ll; - ngx_http_upstream_t *u; - ngx_http_grpc_ctx_t *ctx; - ngx_http_grpc_frame_t *f; -@@ -1459,7 +1459,10 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) - last = 1; - } - -+ ln = in; - in = in->next; -+ -+ ngx_free_chain(r->pool, ln); - } - - ctx->in = in; -diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c -index c1341f5..5d170a1 100644 ---- a/src/http/modules/ngx_http_gunzip_filter_module.c -+++ b/src/http/modules/ngx_http_gunzip_filter_module.c -@@ -333,6 +333,8 @@ static ngx_int_t - ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, - ngx_http_gunzip_ctx_t *ctx) - { -+ ngx_chain_t *cl; -+ - if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { - return NGX_OK; - } -@@ -344,8 +346,11 @@ ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, - return NGX_DECLINED; - } - -- ctx->in_buf = ctx->in->buf; -- ctx->in = ctx->in->next; -+ cl = ctx->in; -+ ctx->in_buf = cl->buf; -+ ctx->in = cl->next; -+ -+ ngx_free_chain(r->pool, cl); - - ctx->zstream.next_in = ctx->in_buf->pos; - ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; -@@ -374,6 +379,7 @@ static ngx_int_t - ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, - ngx_http_gunzip_ctx_t *ctx) - { -+ ngx_chain_t *cl; - ngx_http_gunzip_conf_t *conf; - - if (ctx->zstream.avail_out) { -@@ -383,8 +389,12 @@ ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, - conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); - - if (ctx->free) { -- ctx->out_buf = ctx->free->buf; -- ctx->free = ctx->free->next; -+ -+ cl = ctx->free; -+ ctx->out_buf = cl->buf; -+ ctx->free = cl->next; -+ -+ ngx_free_chain(r->pool, cl); - - ctx->out_buf->flush = 0; - -diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c -index ed0de60..b555278 100644 ---- a/src/http/modules/ngx_http_gzip_filter_module.c -+++ b/src/http/modules/ngx_http_gzip_filter_module.c -@@ -985,10 +985,14 @@ static void - ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, - ngx_http_gzip_ctx_t *ctx) - { -- ngx_chain_t *cl; -+ ngx_chain_t *cl, *ln; -+ -+ for (cl = ctx->copied; cl; /* void */) { -+ ln = cl; -+ cl = cl->next; - -- for (cl = ctx->copied; cl; cl = cl->next) { -- ngx_pfree(r->pool, cl->buf->start); -+ ngx_pfree(r->pool, ln->buf->start); -+ ngx_free_chain(r->pool, ln); - } - - ctx->copied = NULL; -diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c -index 0b84bd3..47068f7 100644 ---- a/src/http/modules/ngx_http_ssi_filter_module.c -+++ b/src/http/modules/ngx_http_ssi_filter_module.c -@@ -482,9 +482,13 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) - while (ctx->in || ctx->buf) { - - if (ctx->buf == NULL) { -- ctx->buf = ctx->in->buf; -- ctx->in = ctx->in->next; -+ -+ cl = ctx->in; -+ ctx->buf = cl->buf; -+ ctx->in = cl->next; - ctx->pos = ctx->buf->pos; -+ -+ ngx_free_chain(r->pool, cl); - } - - if (ctx->state == ssi_start_state) { -diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c -index 6d3de59..456bb27 100644 ---- a/src/http/modules/ngx_http_sub_filter_module.c -+++ b/src/http/modules/ngx_http_sub_filter_module.c -@@ -335,9 +335,13 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) - while (ctx->in || ctx->buf) { - - if (ctx->buf == NULL) { -- ctx->buf = ctx->in->buf; -- ctx->in = ctx->in->next; -+ -+ cl = ctx->in; -+ ctx->buf = cl->buf; -+ ctx->in = cl->next; - ctx->pos = ctx->buf->pos; -+ -+ ngx_free_chain(r->pool, cl); - } - - if (ctx->buf->flush || ctx->buf->recycled) { -diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c -index 5688163..436765c 100644 ---- a/src/http/v3/ngx_http_v3_parse.c -+++ b/src/http/v3/ngx_http_v3_parse.c -@@ -810,6 +810,7 @@ ngx_http_v3_parse_field_lri(ngx_connection_t *c, - - st->literal.length = st->pint.value; - if (st->literal.length == 0) { -+ st->value.data = (u_char *) ""; - goto done; - } - -@@ -932,6 +933,7 @@ ngx_http_v3_parse_field_l(ngx_connection_t *c, - - st->literal.length = st->pint.value; - if (st->literal.length == 0) { -+ st->value.data = (u_char *) ""; - goto done; - } - -@@ -1072,6 +1074,7 @@ ngx_http_v3_parse_field_lpbi(ngx_connection_t *c, - - st->literal.length = st->pint.value; - if (st->literal.length == 0) { -+ st->value.data = (u_char *) ""; - goto done; - } - -diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c -index 87f5f32..0faddd2 100644 ---- a/src/http/v3/ngx_http_v3_request.c -+++ b/src/http/v3/ngx_http_v3_request.c -@@ -134,7 +134,17 @@ ngx_http_v3_init(ngx_connection_t *c) - } - } - -- return ngx_http_v3_send_settings(c); -+ if (ngx_http_v3_send_settings(c) != NGX_OK) { -+ return NGX_ERROR; -+ } -+ -+ if (h3scf->max_table_capacity > 0) { -+ if (ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER) == NULL) { -+ return NGX_ERROR; -+ } -+ } -+ -+ return NGX_OK; - } - - -@@ -398,14 +408,12 @@ ngx_http_v3_wait_request_handler(ngx_event_t *rev) - void - ngx_http_v3_reset_stream(ngx_connection_t *c) - { -- ngx_http_v3_session_t *h3c; -- ngx_http_v3_srv_conf_t *h3scf; -- -- h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); -+ ngx_http_v3_session_t *h3c; - - h3c = ngx_http_v3_get_session(c); - -- if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq -+ if (!c->read->eof && !h3c->hq -+ && h3c->known_streams[NGX_HTTP_V3_STREAM_SERVER_DECODER] - && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) - { - (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); -diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c -index f49a8fc..428e732 100644 ---- a/src/http/v3/ngx_http_v3_table.c -+++ b/src/http/v3/ngx_http_v3_table.c -@@ -308,7 +308,7 @@ ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity) - prev_max = dt->capacity / 32; - - if (max > prev_max) { -- elts = ngx_alloc(max * sizeof(void *), c->log); -+ elts = ngx_alloc((max + 1) * sizeof(void *), c->log); - if (elts == NULL) { - return NGX_ERROR; - } -diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c -index 2fc5b07..302064b 100644 ---- a/src/http/v3/ngx_http_v3_uni.c -+++ b/src/http/v3/ngx_http_v3_uni.c -@@ -20,8 +20,6 @@ static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); - static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); - static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); - static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); --static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, -- ngx_uint_t type); - - - void -@@ -307,7 +305,7 @@ ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev) - } - - --static ngx_connection_t * -+ngx_connection_t * - ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type) - { - u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; -diff --git a/src/http/v3/ngx_http_v3_uni.h b/src/http/v3/ngx_http_v3_uni.h -index 911e153..2805894 100644 ---- a/src/http/v3/ngx_http_v3_uni.h -+++ b/src/http/v3/ngx_http_v3_uni.h -@@ -19,6 +19,8 @@ ngx_int_t ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type); - - ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id); - -+ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, -+ ngx_uint_t type); - ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); - ngx_int_t ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id); - ngx_int_t ngx_http_v3_send_ack_section(ngx_connection_t *c, From 2939b5f2428f79794f89ff4946846c557e2d79b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 2 Feb 2025 19:41:56 +0100 Subject: [PATCH 72/89] d/changelog: remove duplicit lines --- debian/changelog | 2 -- 1 file changed, 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 09302b8..ad1798d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,6 @@ nginx (1.26.2-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] - * d/u/signing-key.asc: add Sergey Kandaurov public key, - the key is used to sign the 1.26.2 release * d/gbp.conf: add upstream-signatures = on * d/{control,copyright}: update my email to "janmojzis@debian.org" * d/copyright: bump my copyright year From 215777eecbceae05ed05a9f64cf6eef074239df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 2 Feb 2025 21:09:05 +0100 Subject: [PATCH 73/89] Release to experimental --- debian/changelog | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index ad1798d..469fb8b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,17 +1,16 @@ -nginx (1.26.2-1) UNRELEASED; urgency=medium +nginx (1.26.2-1) experimental; urgency=medium + + * Team upload + * New upstream version 1.26.2 + * Add Sergey Kandaurov pgp public key + * Drop upstream patches [ Jan Mojžíš ] * d/gbp.conf: add upstream-signatures = on * d/{control,copyright}: update my email to "janmojzis@debian.org" * d/copyright: bump my copyright year - [ Jérémy Lal ] - * Add Sergey Kandaurov pgp public key - * New upstream version 1.26.2 - * Drop upstream patches - * Refresh patches - - -- Jérémy Lal Sun, 02 Feb 2025 11:24:55 +0100 + -- Jérémy Lal Sun, 02 Feb 2025 21:08:45 +0100 nginx (1.26.0-3) unstable; urgency=medium From be95fff10182255b961868e900115fb116ca3318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Wed, 5 Feb 2025 19:03:32 +0100 Subject: [PATCH 74/89] New upstream version 1.26.3 --- .hgtags | 483 ++++++++++++++++++ CHANGES | 24 + CHANGES.ru | 25 + auto/lib/libatomic/conf | 4 +- auto/lib/libatomic/make | 11 +- auto/lib/pcre/make | 3 +- src/core/nginx.h | 4 +- .../quic/ngx_event_quic_openssl_compat.c | 1 + src/event/quic/ngx_event_quic_output.c | 4 +- src/event/quic/ngx_event_quic_streams.c | 18 +- src/event/quic/ngx_event_quic_transport.c | 5 + .../modules/ngx_http_gzip_filter_module.c | 8 +- src/http/modules/ngx_http_mp4_module.c | 18 +- src/http/ngx_http_request.c | 27 +- src/stream/ngx_stream_ssl_module.c | 27 +- 15 files changed, 639 insertions(+), 23 deletions(-) create mode 100644 .hgtags diff --git a/.hgtags b/.hgtags new file mode 100644 index 0000000..0dc64a5 --- /dev/null +++ b/.hgtags @@ -0,0 +1,483 @@ +551102312e19b704cd22bd7254a9444b9ea14e96 release-0.1.0 +23fb87bddda14ce9faec90f774085634106aded4 release-0.1.1 +295d97d70c698585705345f1a8f92b02e63d6d0d release-0.1.2 +ded1284520cc939ad5ae6ddab39925375e64237d release-0.1.3 +0491b909ef7612d8411f1f59054186c1f3471b52 release-0.1.4 +a88a3e4e158fade0aaa6f3eb25597d5ced2c1075 release-0.1.5 +1f31dc6d33a3a4e65240b08066bf186df9e33b79 release-0.1.6 +5aecc125bc33d81d6214c91d73eb44230a903dde release-0.1.7 +bbd6b0b4a2b15ef8c8f1aaf7b027b6da47303524 release-0.1.8 +2ff194b74f1e60cd04670986973e3b1a6aa3bece release-0.1.9 +31ee1b50354fb829564b81a6f34e8d6ceb2d3f48 release-0.1.10 +8e8f3af115b5b903b2b8f3335de971f18891246f release-0.1.11 +c3c2848fc081e19aec5ffa97e468ad20ddb81df0 release-0.1.12 +ad1e9ebf93bb5ae4c748d471fad2de8a0afc4d2a release-0.1.13 +c5240858380136a67bec261c59b1532560b57885 release-0.1.14 +fd661d14a7fad212e326a7dad6234ea0de992fbf release-0.1.15 +621229427cba1b0af417ff2a101fc4f17a7d93c8 release-0.1.16 +4ebe09b07e3021f1a63b459903ec58f162183b26 release-0.1.17 +31ff3e943e1675a2caf745ba7a981244445d4c98 release-0.1.18 +45a460f82aec80b0f61136aa09f412436d42203a release-0.1.19 +0f836f0288eee4980f57736d50a7a60fa082d8e9 release-0.1.20 +975f62e77f0244f1b631f740be77c72c8f2da1de release-0.1.21 +fc9909c369b2b4716304ac8e38da57b8fb781211 release-0.1.22 +d7c90bb5ce83dab08715e98f9c7b81c7df4b37be release-0.1.23 +64d9afb209da0cd4a917202b7b77e51cc23e2229 release-0.1.24 +d4ea69372b946dc4ec37fc3f5ddd93ff7c3da675 release-0.1.25 +b1648294f6935e993e436fd8a68bca75c74c826d release-0.1.26 +ee66921ecd47a7fa459f70f4a9d660f91f6a1b94 release-0.1.27 +cd3117ad9aab9c58c6f7e677e551e1adbdeaba54 release-0.1.28 +9b8c906f6e63ec2c71cecebfff35819a7d32227d release-0.1.29 +c12967aadd8726daf2d85e3f3e622d89c42db176 release-0.1.30 +fbbf16224844e7d560c00043e8ade8a560415bba release-0.1.31 +417a087c9c4d9abb9b0b9b3f787aff515c43c035 release-0.1.32 +dadfa78d227027348d7f9d1e7b7093d06ba545a0 release-0.1.33 +12234c998d83bfbbaa305273b3dd1b855ca325dc release-0.1.34 +6f00349b98e5f706b82115c6e4dc84456fc0d770 release-0.1.35 +2019117e6b38cc3e89fe4f56a23b271479c627a6 release-0.1.36 +09b42134ac0c42625340f16628e29690a04f8db5 release-0.1.37 +7fa11e5c6e9612ecff5eb58274cc846ae742d1d2 release-0.1.38 +e5d7d0334fdb946133c17523c198800142ac9fe9 release-0.1.39 +c3bd8cdabb8f73e5600a91f198eb7df6fac65e92 release-0.1.40 +d6e48c08d718bf5a9e58c20a37e8ae172bff1139 release-0.1.41 +563ad09abf5042eb41e8ecaf5b4e6c9deaa42731 release-0.1.42 +c9ad0d9c7d59b2fa2a5fe669f1e88debd03e6c04 release-0.1.43 +371c1cee100d7a1b0e6cad4d188e05c98a641ee7 release-0.1.44 +b09ee85d0ac823e36861491eedfc4dfafe282997 release-0.1.45 +511a89da35ada16ae806667d699f9610b4f8499a release-0.2.0 +0148586012ab3dde69b394ec5a389d44bb11c869 release-0.2.1 +818fbd4750b99d14d2736212c939855a11b1f1ef release-0.2.2 +e16a8d574da511622b97d6237d005f40f2cddb30 release-0.2.3 +483cca23060331f2078b1c2984870d80f288ad41 release-0.2.4 +45033d85b30e3f12c407b7cfc518d76e0eda0263 release-0.2.5 +7bd37aef1e7e87858c12b124e253e98558889b50 release-0.2.6 +ecd9c160f25b7a7075dd93383d98a0fc8d8c0a41 release-0.3.0 +c1f965ef97188fd7ef81342dcf8719da18c554d2 release-0.3.1 +e48ebafc69393fc94fecfdf9997c4179fd1ce473 release-0.3.2 +9c2f3ed7a24711d3b42b124d5f831155c8beff95 release-0.3.3 +7c1369d37c7eb0017c28ebcaa0778046f5aafdcc release-0.3.4 +1af2fcb3be8a63796b6b23a488049c92a6bc12f4 release-0.3.5 +174f1e853e1e831b01000aeccfd06a9c8d4d95a2 release-0.3.6 +458b6c3fea65a894c99dd429334a77bb164c7e83 release-0.3.7 +58475592100cb792c125101b6d2d898f5adada30 release-0.3.8 +fcd6fc7ff7f9b132c35193d834e6e7d05026c716 release-0.3.9 +4d9ea73a627a914d364e83e20c58eb1283f4031d release-0.3.10 +4c5c2c55975c1152b5ca5d5d55b32d4dd7945f7a release-0.3.11 +326634fb9d47912ad94221dc2f8fa4bec424d40c release-0.3.12 +4e296b7d25bf62390ca2afb599e395426b94f785 release-0.3.13 +401de5a43ba5a8acdb9c52465193c0ea7354afe7 release-0.3.14 +284cc140593bb16ac71094acd509ab415ff4837d release-0.3.15 +d4e858a5751a7fd08e64586795ed7d336011fbc0 release-0.3.16 +8c0cdd81580eb76d774cfc5724de68e7e5cbbdc2 release-0.3.17 +425af804d968f30eeff01e33b808bc2e8c467f2c release-0.3.18 +ebc68d8ca4962fe3531b7e13444f7ac4395d9c6e release-0.3.19 +9262f520ce214d3d5fd7c842891519336ef85ca6 release-0.3.20 +869b6444d2341a587183859d4df736c7f3381169 release-0.3.21 +77f77f53214a0e3a68fef8226c15532b54f2c365 release-0.3.22 +858700ae46b453ea111b966b6d03f2c21ddcb94e release-0.3.23 +5dac8c7fb71b86aafed8ea352305e7f85759f72e release-0.3.24 +77cdfe394a94a625955e7585e09983b3af9b889b release-0.3.25 +608cf78b24ef7baaf9705e4715a361f26bb16ba9 release-0.3.26 +3f8a2132b93d66ac19bec006205a304a68524a0b release-0.3.27 +c73c5c58c619c22dd3a5a26c91bb0567a62c6930 release-0.3.28 +5ef026a2ac7481f04154f29ab49377bf99aaf96f release-0.3.29 +51b27717f140b71a2e9158807d79da17c888ce4c release-0.3.30 +7a16e281c01f1c7ab3b79c64b43ddb754ea7935e release-0.3.31 +93e85a79757c49d502e42a1cb8264a0f133b0b00 release-0.3.32 +0216fd1471f386168545f772836156761eddec08 release-0.3.33 +fbed40ce7cb4fd7203fecc22a617b9ce5b950fb3 release-0.3.34 +387450de0b4d21652f0b6242a5e26a31e3be8d8c release-0.3.35 +65bf042c0b4f39f18a235464c52f980e9fa24f6b release-0.3.36 +5d2b8078c1c2593b95ec50acfeeafbefa65be344 release-0.3.37 +f971949ffb585d400e0f15508a56232a0f897c80 release-0.3.38 +18268abd340cb351e0c01b9c44e9f8cc05492364 release-0.3.39 +e60fe4cf1d4ea3c34be8c49047c712c6d46c1727 release-0.3.40 +715d243270806d38be776fc3ed826d97514a73d6 release-0.3.41 +5e8fb59c18c19347a5607fb5af075fe1e2925b9a release-0.3.42 +947c6fd27699e0199249ad592151f844c8a900b0 release-0.3.43 +4946078f0a79e6cc952d3e410813aac9b8bda650 release-0.3.44 +95d7da23ea5315a6e9255ce036ed2c51f091f180 release-0.3.45 +1e720b0be7ecd92358da8a60944669fa493e78cd release-0.3.46 +39b7d7b33c918d8f4abc86c4075052d8c19da3c7 release-0.3.47 +7cbef16c71a1f43a07f8141f02e0135c775f0f5b release-0.3.48 +4c8cd5ae5cc100add5c08c252d991b82b1838c6b release-0.3.49 +400711951595aef7cd2ef865b84b31df52b15782 release-0.3.50 +649c9063d0fda23620eaeaf0f6393be0a672ebe7 release-0.3.51 +9079ee4735aefa98165bb2cb26dee4f58d58c1d7 release-0.3.52 +6d5c1535bb9dcd891c5963971f767421a334a728 release-0.3.53 +5fd7a5e990477189c40718c8c3e01002a2c20b81 release-0.3.54 +63a820b0bc6ca629c8e45a069b52d622ddc27a2d release-0.3.55 +562806624c4afb1687cba83bc1852f5d0fecbac3 release-0.3.56 +cec32b3753acf610ac1a6227d14032c1a89d6319 release-0.3.57 +b80f94fa2197b99db5e033fec92e0426d1fe5026 release-0.3.58 +e924670896abe2769ea0fcfd2058b405bed8e8ec release-0.3.59 +921a7ce4baf42fd1091b7e40f89c858c6b23053e release-0.3.60 +df95dcff753a6dc5e94257302aea02c18c7a7c87 release-0.3.61 +7e24168b0853ee7e46c9c7b943ef077dc64f17f5 release-0.4.0 +8183d4ba50f8500465efb27e66dd23f98775dd21 release-0.4.1 +610267a772c7bf911b499d37f66c21ce8f2ebaf7 release-0.4.2 +39dd0b045441e21512e0a6061a03d0df63414d8b release-0.4.3 +5e42c1615f4de0079bd4d8913886d588ce6a295d release-0.4.4 +40266f92b829a870808b3d4ee54c8fccdecbd2d6 release-0.4.5 +56e33c6efee7ff63cdc52bd1cf172bde195079df release-0.4.6 +119bad43bfd493400c57a05848eada2c35a46810 release-0.4.7 +0f404f82a1343cb4e4b277a44e3417385798e5e5 release-0.4.8 +d24a717314365c857b9f283d6072c2a427d5e342 release-0.4.9 +d6f0a00015fdef861fd67fb583b9690638650656 release-0.4.10 +e372368dadd7b2ecd0182b2f1b11db86fc27b2c3 release-0.4.11 +fd57967d850d2361072c72562d1ed03598473478 release-0.4.12 +979045fdcbd20cf7188545c1c589ff240251f890 release-0.4.13 +93c94cfa9f78f0a5740595dde4466ec4fba664f8 release-0.4.14 +589ee12e8d7c2ae5e4f4676bcc7a1279a76f9e8e release-0.5.0 +13416db8a807e5acb4021bc3c581203de57e2f50 release-0.5.1 +06c58edc88831fb31c492a8eddcf2c6056567f18 release-0.5.2 +e2ac5fa41bcba14adbbb722d45c083c30c07bb5c release-0.5.3 +393dbc659df15ccd411680b5c1ce87ed86d4c144 release-0.5.4 +38cc7bd8e04f2c519fd4526c12841a876be353cb release-0.5.5 +6d1fcec2ea79101c756316c015f72e75f601a5ab release-0.5.6 +aed8a9de62456c4b360358bc112ccca32ce02e8d release-0.5.7 +7642f45af67d805452df2667486201c36efaff85 release-0.5.8 +779216610662c3a459935d506f66a9b16b9c9576 release-0.5.9 +9eeb585454f3daa30cf768e95c088a092fe229b9 release-0.5.10 +bb491c8197e38ca10ae63b1f1ecb36bf6fdaf950 release-0.5.11 +613369e08810f36bbcc9734ef1059a03ccbf5e16 release-0.5.12 +bd796ef5c9c9dd34bfac20261b98685e0410122a release-0.5.13 +8a730c49f906d783b47e4b44d735efd083936c64 release-0.5.14 +cb447039152d85e9145139ff2575a6199b9af9d4 release-0.5.15 +64854c7c95d04f838585ca08492823000503fa61 release-0.5.16 +d1ffcf84ea1244f659145c36ff28de6fcdf528b2 release-0.5.17 +796a6e30ca9d29504195c10210dbc8deced0ae83 release-0.5.18 +1f81c711d2a039e1f93b9b515065a2235372d455 release-0.5.19 +8e8f6082654aedb4438c8fca408cfc316c7c5a2a release-0.5.20 +e9551132f7dd40da5719dd5bcf924c86f1436f85 release-0.5.21 +533a252896c4d1cff1586ae42129d610f7497811 release-0.5.22 +f461a49b6c747e0b67f721f2be172902afea5528 release-0.5.23 +2d5ef73671f690b65bf6d9e22e7155f68f484d5a release-0.5.24 +77bf42576050862c268e267ef3e508b145845a25 release-0.5.25 +2aefee4d4ed69eb7567680bf27a2efd212232488 release-0.6.0 +7ac0fe9bec9a2b5f8e191f6fdd6922bfd916a6cb release-0.6.1 +4882735ebc71eeec0fbfe645bdfdb31306872d82 release-0.6.2 +b94731c73d0922f472ff938b9d252ba29020f20c release-0.6.3 +13e649b813d6ccba5db33a61e08ebe09d683cd5b release-0.6.4 +80de622646b0059fd4c553eff47c391bf7503b89 release-0.6.5 +3b05edb2619d5935023b979ee7a9611b61b6c9e5 release-0.6.6 +1dcfd375100c4479611f71efb99271d0a3059215 release-0.6.7 +0228185d4c5772947b842e856ad74cf7f7fd52f3 release-0.6.8 +d1879c52326ecac45c713203670f54220879911e release-0.6.9 +5a80c6ccbe2ad24fa3d4ff6f9fe4a2b07408d19d release-0.6.10 +f88a8b0b39601b19cd740e4db614ab0b5b874686 release-0.6.11 +5557460a7247a1602ae96efd1d0ccf781344cb58 release-0.6.12 +451b02cc770a794cd41363461b446948ae1d8bc8 release-0.6.13 +537b6ef014c4a133e0ab0b7dc817508e0647e315 release-0.6.14 +5e68764f0d6e91a983170fa806e7450a9e9b33fe release-0.6.15 +158aa4e8cc46fcf9504a61469d22daf3476b17bf release-0.6.16 +d8fcca555542619228d9fab89e1665b993f8c3ee release-0.6.17 +60707ebc037086cf004736a0d4979e2a608da033 release-0.6.18 +3c2a99d3a71af846855be35e62edb9a12f363f44 release-0.6.19 +3e0a27f9358ffc1b5249e0ea2311ce7da5c8967e release-0.6.20 +143f4d65b1c875d6563ccb7f653d9157afc72194 release-0.6.21 +95e6160d2b7d0af8ffd1b95a23cadadf8f0b3f6d release-0.6.22 +69a03d5e3b6e6660079ef1ef172db7ac08d8370e release-0.6.23 +3e2a58fb48f1e1a99ebf851e0d47a7034c52ae22 release-0.6.24 +3b8607c05a8bebcfa59235c2126a70d737f0ccf5 release-0.6.25 +07ad5b2606614c4be4ee720c46cf4af126059d31 release-0.6.26 +be531addfabe5214f409d457140c1038af10d199 release-0.6.27 +58f05255d3a345d04baef5cff0ca1ae0ac7ecebb release-0.6.28 +eb2bd21dc8d03f6c94016f04ffb9adaf83a2b606 release-0.6.29 +55408deb3cd171efa9b81d23d7a1dd1ccde0b839 release-0.6.30 +d4288915bba73c4c3c9cf5d39d34e86879eb2b45 release-0.6.31 +0a189588830b8629c4dfea68feb49af36b59e4a9 release-0.7.0 +6ab27a06f3346cf9ec8737f5dbcc82dd4031e30f release-0.7.1 +a07e258cef3b0a0b6e76a6ff4ba4651c5facc85a release-0.7.2 +9992c4583513d2804fc2e7fec860fbc7ab043009 release-0.7.3 +4dc24d50230fbadfc037a414a86390db2de69dd2 release-0.7.4 +9527137b4354a648a229c7169850c7c65272c00d release-0.7.5 +c2f0f7cf306f302254beae512bda18713922375c release-0.7.6 +bbcf6d75556fdcee8bd4aba8f6c27014be9920ee release-0.7.7 +43bde71f0bbe5a33b161760d7f9f980d50386597 release-0.7.8 +769f0dd7081e9011394f264aa22aa66fd79730d8 release-0.7.9 +511edfa732da637f5f0c9476335df7dca994706d release-0.7.10 +0e7023bf6b2461309c29885935443449a41be807 release-0.7.11 +9ad1bd2b21d93902863807528e426862aedee737 release-0.7.12 +d90ea21e24ea35379aef50c5d70564158e110a15 release-0.7.13 +c07d2d20d95c83d804079bbdcecbce4a0c8282f0 release-0.7.14 +0cd7bb051f67eac2b179fb9f9cc988b9ba18ed76 release-0.7.15 +eab2e87deba73ae6abd9cc740e8d4365bed96322 release-0.7.16 +91d7a9eb8ade90e9421d7b1e3c2e47a6bc427876 release-0.7.17 +fc10f7b5cb1305fb930f8ac40b46882d0828d61e release-0.7.18 +9dba9779e37e5969a2d408c792084fd7acfec062 release-0.7.19 +61838d1bcbddc7bc4dd9f30d535573a6fddca8f9 release-0.7.20 +5f665d0fa6a5f6e748157f2ccbc445b2db8125d0 release-0.7.21 +24763afa5efe91e54f00b2ae5b87666eb6c08c3b release-0.7.22 +0562fb355a25266150cbe8c8d4e00f55e3654df3 release-0.7.23 +19c452ecd083550816873a8a31eb3ed9879085e6 release-0.7.24 +46b68faf271d6fdcaaf3ad2c69f6167ea9e9fa28 release-0.7.25 +d04bfca0c7e3ae2e4422bc1d383553139d6f0a19 release-0.7.26 +9425d9c7f8ead95b00a3929a9a5e487e0e3c8499 release-0.7.27 +fbc3e7e8b3ee756568a875f87d8a954a2f9d3bf6 release-0.7.28 +5176dfdf153fc785b18604197d58806f919829ad release-0.7.29 +87e07ccdf0a4ec53458d9d7a4ea66e1239910968 release-0.7.30 +9fddd7e1a7a27f8463867f41a461aad57df461b2 release-0.7.31 +780b2ba1ec6daf6e3773774e26b05b9ff0d5483e release-0.7.32 +83027471a25385b1c671968be761e9aa7a8591a7 release-0.7.33 +1e9a362c3dcee221ca6e34308c483ed93867aca2 release-0.7.34 +c7ee9e15717b54ead5f4a554686e74abe66c6b07 release-0.7.35 +b84548abe9b9d4f4e203f848696e52c8c82c308f release-0.7.36 +3286f0bab8e77dbc7ebb370b1dc379592ccff123 release-0.7.37 +11a4e2ed5b166b9c9f119171aa399a9e3aa4684a release-0.7.38 +f822655d4120629977794c32d3b969343b6c30db release-0.7.39 +8a350e49d2b6751296db6d8e27277ccf63ed412a release-0.7.40 +c4a56c197eeafd71fc1caef7a9d890a330e3c23d release-0.7.41 +a9575a57a5443df39611774cf3840e9088132b0e release-0.7.42 +7503d95d6eadad14c28b2db183ba09848265274b release-0.7.43 +9be652e9114435fc6f1fdec84c0458d56702db91 release-0.7.44 +797e070d480a34b31ddac0d364784773f1bbbcf9 release-0.7.45 +9b5037e7ec7db25875c40f9d1cf20a853388b124 release-0.7.46 +d1d0e6d7ff0ca3c0dd1be1ef1cfff2e3fd0b4e1c release-0.7.47 +9816fb28eda599bfd53940e6d3b6617d1ecb6323 release-0.7.48 +452b9d09df8e3f2fb04b2a33d04d2f3a6436eb34 release-0.7.49 +e4350efa7cf7a0e868c2236a1137de8a33bd8ec6 release-0.7.50 +f51f2bec766c8b6d7e1799d904f18f8ea631bd44 release-0.7.51 +18e39e566781c9c187e2eb62bebd9d669d68f08c release-0.7.52 +b073eaa1dcea296a3488b83d455fab6621a73932 release-0.7.53 +01c6fe6c2a55998434cd3b05dd10ca487ac3fb6c release-0.7.54 +3ed9377e686f2521e6ec15873084381033fb490d release-0.7.55 +a1e44954549c35023b409f728c678be8bf898148 release-0.7.56 +fbb1918a85e38a7becdb1a001dbaf5933f23a919 release-0.7.57 +87f4a49a9cc34a5b11c8784cc5ea89e97b4b2bd8 release-0.7.58 +0c22cb4862c8beb4ee1b9e4627125162a29a5304 release-0.7.59 +82d56c2425ef857cd430b8530a3f9e1127145a67 release-0.8.0 +f4acb784b53cd952559567971b97dde1e818a2b6 release-0.8.1 +b3503597c1a0f0f378afdc5e5e5b85e2c095a4be release-0.8.2 +c98da980514a02ba81c421b25bf91803ffffddf3 release-0.8.3 +db34ec0c53c4b9dec12ffdf70caf89a325ab9577 release-0.8.4 +0914802433b8678ba2cdf91280766f00f4b9b76e release-0.8.5 +ff52ee9e6422f3759f43a442b7ba615595b3a3d4 release-0.8.6 +7607237b4829fff1f60999f4663c50ed9d5182f7 release-0.8.7 +1cef1807bc12cb05ac52fb0e7a0f111d3760b569 release-0.8.8 +a40f8475511d74a468ade29c1505e8986600d7a3 release-0.8.9 +2d9faf2260df6c3e5d4aa1781493c31f27a557d0 release-0.8.10 +d0d61c32331a6505381b5218318f7b69db167ca8 release-0.8.11 +ca7a1c6c798a7eb5b294d4ac3179ec87ecf297d3 release-0.8.12 +81c8277cd8ed55febcb2dd9d9213076f6c0ccb09 release-0.8.13 +3089486a8dc5844b5b6e9f78d536b4b26f7ffa16 release-0.8.14 +d364c2c12dd9723a2dfac3f096f5e55d4cfe6838 release-0.8.15 +52163a1027c3efd6b4c461b60a2ca6266c23e193 release-0.8.16 +06564e9a2d9ec5852132c212e85eda0bf1300307 release-0.8.17 +7aaa959da85e09e29bcac3b1cadec35b0a25b64d release-0.8.18 +4bc73c644329a510da4e96b7241b80ead7772f83 release-0.8.19 +ea3d168fb99c32a5c3545717ecc61e85a375e5dd release-0.8.20 +27951ca037e63dae45ff5b6279124c224ae1255a release-0.8.21 +d56c8b5df517c2bf6e7bc2827b8bf3e08cda90e1 release-0.8.22 +3c6ac062b379b126212cbb27e98a3c8275ef381a release-0.8.23 +89b9173476de14688b1418fbf7df10f91d1719ef release-0.8.24 +aa550cb4159ae0d566006e091fb1c7a888771050 release-0.8.25 +06ce92293f6a65651b08c466f90f55bd69984b98 release-0.8.26 +ea50b0d79ef1d7d901cd0e4dcd7373447849d719 release-0.8.27 +e68b1c35cad86105ff1c5b240f53442f4c36356e release-0.8.28 +78d3582a30afe63fc0adb17c3ac8891a64e47146 release-0.8.29 +9852c5965a3292a1b6127dbb4da9fce4912d898a release-0.8.30 +4f84115914490e572bcbee5069157b7334df2744 release-0.8.31 +59dee6f7f3afeb1fad6ed5983756e48c81ad2a5c release-0.8.32 +a4456378d234c07038456cf32bfe3c651f1d5e82 release-0.8.33 +21cb50799a20575a42f9733342d37a426f79db4d release-0.8.34 +7cb3cb8d78ef7ae63561733ed91fd07933896bc8 release-0.8.35 +aed68639d4eb6afe944b7fb50499c16f7f3f503c release-0.8.36 +265b7fd2ae21c75bbffa5115b83a0123d6c4acb4 release-0.8.37 +fa5f1ca353c0c5aa5415f51d72fd7bbcc02d1ed7 release-0.8.38 +af10bf9d4c6532850aa1f70cdf7504bd109b284c release-0.8.39 +4846ec9f83cb5bc4c8519d5641b35fb9b190430c release-0.8.40 +718b4cb3faf7efe4e0648140f064bf7a92c3f7e8 release-0.8.41 +b5a3065749093282ddd19845e0b77ffc2e54333e release-0.8.42 +34df9fb22fed415cdad52def04095dc6d4b48222 release-0.8.43 +00ec8cd76fb89af27363b76c40d9f88bf4679c3b release-0.8.44 +e16dd52a0d226c23dcae9a11252564a04753bbed release-0.8.45 +f034d9173df0a433e0bbcf5974f12ea9eb9076c0 release-0.8.46 +4434dc967087315efcd0658206a67fe6c85528f3 release-0.8.47 +0b65c962e0cd6783a854877b52c903cb058eec8c release-0.8.48 +a2b7e94b9807e981866bf07e37b715847d1b7120 release-0.8.49 +e7bdb8edc1bab2bc352a9fb6ce765c46575c35bf release-0.8.50 +21dacebd12f65cb57ceb8d2688db5b07fad6e06d release-0.8.51 +67dd7533b99c8945b5b8b5b393504d4e003a1c50 release-0.8.52 +010468d890dbac33a4cae6dfb2017db70721b2fe release-0.8.53 +62b599022a2fa625b526c2ad1711dc6db7d66786 release-0.9.0 +71281dd73b17a0ead5535d531afaee098da723cb release-0.9.1 +16cff36b0e49fc9fdeee13b2e92690286bcc1b3d release-0.9.2 +b7b306325972661117694879d3e22faf4cf0df32 release-0.9.3 +fe671505a8ea86a76f0358b3ec4de84a9037ac2b release-0.9.4 +70542931bc5436d1bbd38f152245d93ac063968d release-0.9.5 +27e2f3b7a3db1819c5d0ba28327ceaba84a13c4e release-0.9.6 +657d05d63915ce2f6c4d763091059f5f85bb10e5 release-0.9.7 +e0fd9f36005923b8f98d1ba1ea583cb7625f318f release-1.0.0 +f8f89eb4e0c27e857ec517d893d4f9a454985084 release-1.0.1 +c50df367648e53d55e80b60a447c9c66caa0d326 release-1.0.2 +80d586db316512b5a9d39f00fe185f7f91523f52 release-1.0.3 +c9c2805ac9245cc48ce6efeba2b4a444f859d6aa release-1.0.4 +fa2c37b1122c2c983b6e91d1188e387d72dde4d6 release-1.0.5 +f31aea5b06654c9163be5acd6d9b7aaf0fdf6b33 release-1.1.0 +44bf95f670656fae01ccb266b3863843ea13d324 release-1.1.1 +da1289482a143dfa016769649bdff636c26f53c8 release-1.1.2 +bac8ba08a6570bac2ecd3bf2ad64b0ac3030c903 release-1.1.3 +911060bc8221d4113a693ae97952a1fa88663ca8 release-1.1.4 +e47531dfabbf8e5f8b8aff9ff353642ea4aa7abb release-1.1.5 +f9ddecfe331462f870a95e4c1c3ba1bb8f19f2d3 release-1.1.6 +378c297bb7459fb99aa9c77decac0d35391a3932 release-1.1.7 +71600ce67510af093d4bc0117a78b3b4678c6b3a release-1.1.8 +482d7d907f1ab92b78084d8b8631ed0eb7dd08f7 release-1.1.9 +c7e65deabf0db5109e8d8f6cf64cd3fb7633a3d1 release-1.1.10 +9590f0cf5aab8e6e0b0c8ae59c70187b2b97d886 release-1.1.11 +ade8fc136430cfc04a8d0885c757968b0987d56c release-1.1.12 +6a6836e65827fd3cb10a406e7bbbe36e0dad8736 release-1.1.13 +6845f4ac909233f5a08ed8a51de137713a888328 release-1.1.14 +2397e9c72f1bc5eac67006e12ad3e33e0ea9ba74 release-1.1.15 +7b7c49639a7bceecabf4963c60b26b65a77d6ce0 release-1.1.16 +f7e1113a9a1648cad122543e7080e895cf2d88f4 release-1.1.17 +2b22743c3079b41233ded0fc35af8aa89bcfab91 release-1.1.18 +0f0b425659e0b26f5bc8ea14a42dbf34de2eaba6 release-1.1.19 +f582d662cc408eb7a132c21f4b298b71d0701abb release-1.2.0 +9ee68d629722f583d43d92271f2eb84281afc630 release-1.3.0 +61b6a3438afef630774e568eefd89c53e3b93287 release-1.3.1 +7ccd50a0a455f2f2d3b241f376e1193ad956196d release-1.2.1 +0000000000000000000000000000000000000000 release-1.2.1 +50107e2d96bbfc2c59e46f889b1a5f68dd10cf19 release-1.3.2 +2c5e1e88c8cf710caf551c5c67eba00443601efe release-1.3.3 +a43447fb82aa03eabcd85352758ae14606a84d35 release-1.3.4 +90f3b4ea7992a7bf9385851a3e77173363091eea release-1.3.5 +3aeb14f88daeb973e4708310daa3dc68ac1200f7 release-1.3.6 +dafd375f1c882b15fa4a9b7aa7c801c55082395e release-1.3.7 +ab7ce0eb4cf78a656750ab1d8e55ef61f7e535ec release-1.3.8 +1b1a9337a7399ad3cdc5e3a2f9fbaaec990271d5 release-1.3.9 +2c053b2572694eb9cd4aed26a498b6cb1f51bbcc release-1.3.10 +36409ac209872ce53019f084e4e07467c5d9d25e release-1.3.11 +560dc55e90c13860a79d8f3e0d67a81c7b0257bb release-1.3.12 +dc195ffe0965b2b9072f8e213fe74ecce38f6773 release-1.3.13 +e04428778567dd4de329bbbe97ad653e22801612 release-1.3.14 +cd84e467c72967b9f5fb4d96bfc708c93edeb634 release-1.3.15 +23159600bdea695db8f9d2890aaf73424303e49c release-1.3.16 +7809529022b83157067e7d1e2fb65d57db5f4d99 release-1.4.0 +48a84bc3ff074a65a63e353b9796ff2b14239699 release-1.5.0 +99eed1a88fc33f32d66e2ec913874dfef3e12fcc release-1.5.1 +5bdca4812974011731e5719a6c398b54f14a6d61 release-1.5.2 +644a079526295aca11c52c46cb81e3754e6ad4ad release-1.5.3 +376a5e7694004048a9d073e4feb81bb54ee3ba91 release-1.5.4 +60e0409b9ec7ee194c6d8102f0656598cc4a6cfe release-1.5.5 +70c5cd3a61cb476c2afb3a61826e59c7cda0b7a7 release-1.5.6 +9ba2542d75bf62a3972278c63561fc2ef5ec573a release-1.5.7 +eaa76f24975948b0ce8be01838d949122d44ed67 release-1.5.8 +5a1759f33b7fa6270e1617c08d7e655b7b127f26 release-1.5.9 +b798fc020e3a84ef68e6c9f47865a319c826d33c release-1.5.10 +f995a10d4c7e9a817157a6ce7b753297ad32897e release-1.5.11 +97b47d95e4449cbde976657cf8cbbc118351ffe0 release-1.5.12 +fd722b890eabc600394349730a093f50dac31639 release-1.5.13 +d161d68df8be32e5cbf72b07db1a707714827803 release-1.7.0 +0351a6d89c3dbcc7a76295024ba6b70e27b9a497 release-1.7.1 +0bd223a546192fdf2e862f33938f4ec2a3b5b283 release-1.7.2 +fe7cd01828d5ca7491059f0690bb4453645eb28b release-1.7.3 +cbb146b120296852e781079d5138b04495bab6df release-1.7.4 +fe129aa02db9001d220f1db7c3c056f79482c111 release-1.7.5 +a8d111bb68847f61d682a3c8792fecb2e52efa2c release-1.7.6 +6d2fbc30f8a7f70136cf08f32d5ff3179d524873 release-1.7.7 +d5ea659b8bab2d6402a2266efa691f705e84001e release-1.7.8 +34b201c1abd1e2d4faeae4650a21574771a03c0e release-1.7.9 +860cfbcc4606ee36d898a9cd0c5ae8858db984d6 release-1.7.10 +2b3b737b5456c05cd63d3d834f4fb4d3776953d0 release-1.7.11 +3ef00a71f56420a9c3e9cec311c9a2109a015d67 release-1.7.12 +53d850fe292f157d2fb999c52788ec1dc53c91ed release-1.9.0 +884a967c369f73ab16ea859670d690fb094d3850 release-1.9.1 +3a32d6e7404a79a0973bcd8d0b83181c5bf66074 release-1.9.2 +e27a215601292872f545a733859e06d01af1017d release-1.9.3 +5cb7e2eed2031e32d2e5422caf9402758c38a6ad release-1.9.4 +942475e10cb47654205ede7ccbe7d568698e665b release-1.9.5 +b78018cfaa2f0ec20494fccb16252daa87c48a31 release-1.9.6 +54117529e40b988590ea2d38aae909b0b191663f release-1.9.7 +1bdc497c81607d854e3edf8b9a3be324c3d136b6 release-1.9.8 +ef107f3ddc237a3007e2769ec04adde0dcf627fa release-1.9.9 +be00ca08e41a69e585b6aff70a725ed6c9e1a876 release-1.9.10 +fe66cff450a95beed36a2515210eb2d7ef62c9d3 release-1.9.11 +ead3907d74f90a14d1646f1b2b56ba01d3d11702 release-1.9.12 +5936b7ed929237f1a73b467f662611cdc0309e51 release-1.9.13 +4106db71cbcb9c8274700199ac17e520902c6c0f release-1.9.14 +13070ecfda67397985f0e986eb9c42ecb46d05b5 release-1.9.15 +271ee30c6791847980cd139d31807541f5e569bf release-1.11.0 +cb783d9cc19761e14e1285d91c38f4b84d0b8756 release-1.11.1 +4d3b3a13a8cf5fc3351a7f167d1c13325e00f21c release-1.11.2 +b83a067949a3384a49fd3d943eb8d0997b31f87b release-1.11.3 +953512ca02c6f63b4fcbbc3e10d0d9835896bf99 release-1.11.4 +5253015a339aaca0a3111473d3e931b6d4752393 release-1.11.5 +5e371426b3bcba4312ce08606194b89b758927d1 release-1.11.6 +5c8f60faf33ca8926473d2da27b4c3c417bd4630 release-1.11.7 +4591da489a30f790def29bc5987f43409b503cae release-1.11.8 +20a45c768e5ed26b740679d0e22045c98727c3cc release-1.11.9 +1ad0999a7ded3d4fb01c7acf8ff57c80b643da7e release-1.11.10 +d8b321a876d6254e9e98795e3b194ef053290354 release-1.11.11 +7f394e433f0003222aa6531931ecc0b24740d5e4 release-1.11.12 +3d0e8655f897959e48cc74e87670bb5492a58871 release-1.11.13 +3671096a45bce570a2afa20b9faf42c7fb0f7e66 release-1.13.0 +539f7893ecb96bee60965528c8958d7eb2f1ce6b release-1.13.1 +5be2b25bdc65775a85f18f68a4be4f58c7384415 release-1.13.2 +8457ce87640f9bfe6221c4ac4466ced20e03bebe release-1.13.3 +bbc642c813c829963ce8197c0ca237ab7601f3d4 release-1.13.4 +0d45b4cf7c2e4e626a5a16e1fe604402ace1cea5 release-1.13.5 +f87da7d9ca02b8ced4caa6c5eb9013ccd47b0117 release-1.13.6 +47cca243d0ed39bf5dcb9859184affc958b79b6f release-1.13.7 +20ca4bcff108d3e66977f4d97508637093492287 release-1.13.8 +fb1212c7eca4c5328fe17d6cd95b010c67336aac release-1.13.9 +31c929e16910c38492581ef474e72fa67c28f124 release-1.13.10 +64179f242cb55fc206bca59de9bfdc4cf5ebcec7 release-1.13.11 +051e5fa03b92b8a564f6b12debd483d267391e82 release-1.13.12 +990b3e885636d763b97ed02d0d2cfc161a4e0c09 release-1.15.0 +4189160cb946bb38d0bc0a452b5eb4cdd8979fb5 release-1.15.1 +b234199c7ed8a156a6bb98f7ff58302c857c954f release-1.15.2 +28b3e17ca7eba1e6a0891afde0e4bc5bcc99c861 release-1.15.3 +49d49835653857daa418e68d6cbfed4958c78fca release-1.15.4 +f062e43d74fc2578bb100a9e82a953efa1eb9e4e release-1.15.5 +2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6 +051a039ce1c7e09144de4a4846669ec7116cecea release-1.15.7 +ee551e3f6dba336c0d875e266d7d55385f379b42 release-1.15.8 +d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9 +75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10 +5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11 +0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 +054c1c46395caff79bb4caf16f40b331f71bb6dd release-1.17.0 +7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1 +2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2 +ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3 +ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4 +9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5 +de68d0d94320cbf033599c6f3ca37e5335c67fd7 release-1.17.6 +e56295fe0ea76bf53b06bffa77a2d3a9a335cb8c release-1.17.7 +fdacd273711ddf20f778c1fb91529ab53979a454 release-1.17.8 +5e8d52bca714d4b85284ddb649d1ba4a3ca978a8 release-1.17.9 +c44970de01474f6f3e01b0adea85ec1d03e3a5f2 release-1.17.10 +cbe6ba650211541310618849168631ce0b788f35 release-1.19.0 +062920e2f3bf871ef7a3d8496edec1b3065faf80 release-1.19.1 +a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2 +3cbc2602325f0ac08917a4397d76f5155c34b7b1 release-1.19.3 +dc0cc425fa63a80315f6efb68697cadb6626cdf2 release-1.19.4 +8e5b068f761cd512d10c9671fbde0b568c1fd08b release-1.19.5 +f618488eb769e0ed74ef0d93cd118d2ad79ef94d release-1.19.6 +3fa6e2095a7a51acc630517e1c27a7b7ac41f7b3 release-1.19.7 +8c65d21464aaa5923775f80c32474adc7a320068 release-1.19.8 +da571b8eaf8f30f36c43b3c9b25e01e31f47149c release-1.19.9 +ffcbb9980ee2bad27b4d7b1cd680b14ff47b29aa release-1.19.10 +df34dcc9ac072ffd0945e5a1f3eb7987e8275375 release-1.21.0 +a68ac0677f8553b1f84d357bc9da114731ab5f47 release-1.21.1 +bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2 +2217a9c1d0b86026f22700b3c089545db1964f55 release-1.21.3 +39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4 +d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5 +714eb4b2c09e712fb2572a2164ce2bf67638ccac release-1.21.6 +5da2c0902e8e2aa4534008a582a60c61c135960e release-1.23.0 +a63d0a70afea96813ba6667997bc7d68b5863f0d release-1.23.1 +aa901551a7ebad1e8b0f8c11cb44e3424ba29707 release-1.23.2 +ff3afd1ce6a6b65057741df442adfaa71a0e2588 release-1.23.3 +ac779115ed6ee4f3039e9aea414a54e560450ee2 release-1.23.4 +12dcf92b0c2c68552398f19644ce3104459807d7 release-1.25.0 +f8134640e8615448205785cf00b0bc810489b495 release-1.25.1 +1d839f05409d1a50d0f15a2bf36547001f99ae40 release-1.25.2 +294a3d07234f8f65d7b0e0b0e2c5b05c12c5da0a release-1.25.3 +173a0a7dbce569adbb70257c6ec4f0f6bc585009 release-1.25.4 +8618e4d900cc71082fbe7dc72af087937d64faf5 release-1.25.5 +a58202a8c41bf0bd97eef1b946e13105a105520d release-1.26.0 +a63c124e34bcf2d1d1feb8d40ff075103b967c4c release-1.26.1 +e4c5da06073ca24e2ffc5c8f8b8d7833a926356f release-1.26.2 diff --git a/CHANGES b/CHANGES index 49e47de..9c2fb00 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,28 @@ +Changes with nginx 1.26.3 05 Feb 2025 + + *) Security: insufficient check in virtual servers handling with TLSv1.3 + SNI allowed to reuse SSL sessions in a different virtual server, to + bypass client SSL certificates verification (CVE-2025-23419). + + *) Bugfix: in the ngx_http_mp4_module. + Thanks to Nils Bars. + + *) Workaround: "gzip filter failed to use preallocated memory" alerts + appeared in logs when using zlib-ng. + + *) Bugfix: nginx could not build libatomic library using the library + sources if the --with-libatomic=DIR option was used. + + *) Bugfix: nginx now ignores QUIC version negotiation packets from + clients. + + *) Bugfix: nginx could not be built on Solaris 10 and earlier with the + ngx_http_v3_module. + + *) Bugfixes in HTTP/3. + + Changes with nginx 1.26.2 14 Aug 2024 *) Security: processing of a specially crafted mp4 file by the diff --git a/CHANGES.ru b/CHANGES.ru index aaa0f5f..0d1ba20 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,29 @@ +Изменения в nginx 1.26.3 05.02.2025 + + *) Безопасность: недостаточная проверка в обработке виртуальных серверов + при использовании SNI в TLSv1.3 позволяла повторно использовать + SSL-сессию в контексте другого виртуального сервера, чтобы обойти + проверку клиентских SSL-сертификатов (CVE-2025-23419). + + *) Исправление: в модуле ngx_http_mp4_module. + Спасибо Nils Bars. + + *) Изменение: при использовании zlib-ng в логах появлялись сообщения + "gzip filter failed to use preallocated memory". + + *) Исправление: nginx не мог собрать библиотеку libatomic из исходных + текстов, если использовался параметр --with-libatomic=DIR. + + *) Исправление: теперь nginx игнорирует пакеты согласования версий QUIC + от клиентов. + + *) Исправление: nginx не собирался на Solaris 10 и более ранних с + модулем ngx_http_v3_module. + + *) Исправления в HTTP/3. + + Изменения в nginx 1.26.2 14.08.2024 *) Безопасность: обработка специально созданного mp4-файла модулем diff --git a/auto/lib/libatomic/conf b/auto/lib/libatomic/conf index 8c8cb43..dfdc1a6 100644 --- a/auto/lib/libatomic/conf +++ b/auto/lib/libatomic/conf @@ -7,8 +7,8 @@ if [ $NGX_LIBATOMIC != YES ]; then have=NGX_HAVE_LIBATOMIC . auto/have CORE_INCS="$CORE_INCS $NGX_LIBATOMIC/src" - LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/src/libatomic_ops.a" - CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/src/libatomic_ops.a" + LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/build/lib/libatomic_ops.a" + CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/build/lib/libatomic_ops.a" else diff --git a/auto/lib/libatomic/make b/auto/lib/libatomic/make index c90318e..530c746 100644 --- a/auto/lib/libatomic/make +++ b/auto/lib/libatomic/make @@ -3,14 +3,19 @@ # Copyright (C) Nginx, Inc. + case $NGX_LIBATOMIC in + /*) ngx_prefix="$NGX_LIBATOMIC/build" ;; + *) ngx_prefix="$PWD/$NGX_LIBATOMIC/build" ;; + esac + cat << END >> $NGX_MAKEFILE -$NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile - cd $NGX_LIBATOMIC && \$(MAKE) +$NGX_LIBATOMIC/build/lib/libatomic_ops.a: $NGX_LIBATOMIC/Makefile + cd $NGX_LIBATOMIC && \$(MAKE) && \$(MAKE) install $NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE cd $NGX_LIBATOMIC \\ && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ - && ./configure + && ./configure --prefix=$ngx_prefix END diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make index 839ef29..182590a 100644 --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -36,7 +36,8 @@ if [ $PCRE_LIBRARY = PCRE2 ]; then pcre2_valid_utf.c \ pcre2_xclass.c" - ngx_pcre_test="pcre2_convert.c \ + ngx_pcre_test="pcre2_chkdint.c \ + pcre2_convert.c \ pcre2_extuni.c \ pcre2_find_bracket.c \ pcre2_script_run.c \ diff --git a/src/core/nginx.h b/src/core/nginx.h index d29edd2..ef000e0 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1026002 -#define NGINX_VERSION "1.26.2" +#define nginx_version 1026003 +#define NGINX_VERSION "1.26.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/event/quic/ngx_event_quic_openssl_compat.c b/src/event/quic/ngx_event_quic_openssl_compat.c index c7412e8..6052bc6 100644 --- a/src/event/quic/ngx_event_quic_openssl_compat.c +++ b/src/event/quic/ngx_event_quic_openssl_compat.c @@ -391,6 +391,7 @@ SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) wbio = BIO_new(BIO_s_null()); if (wbio == NULL) { + BIO_free(rbio); return 0; } diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c index ce6aaab..f087e2b 100644 --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -411,7 +411,7 @@ ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, size_t len, ngx_memzero(msg_control, sizeof(msg_control)); iov.iov_len = len; - iov.iov_base = buf; + iov.iov_base = (void *) buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; @@ -699,7 +699,7 @@ ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, ngx_memzero(&msg, sizeof(struct msghdr)); iov.iov_len = len; - iov.iov_base = buf; + iov.iov_base = (void *) buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c index 178b805..a9a21f5 100644 --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -174,7 +174,7 @@ ngx_int_t ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) { ngx_pool_t *pool; - ngx_queue_t *q; + ngx_queue_t *q, posted_events; ngx_rbtree_t *tree; ngx_connection_t *sc; ngx_rbtree_node_t *node; @@ -197,6 +197,8 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) return NGX_OK; } + ngx_queue_init(&posted_events); + node = ngx_rbtree_min(tree->root, tree->sentinel); while (node) { @@ -213,15 +215,21 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) } sc->read->error = 1; + sc->read->ready = 1; sc->write->error = 1; - - ngx_quic_set_event(sc->read); - ngx_quic_set_event(sc->write); + sc->write->ready = 1; sc->close = 1; - sc->read->handler(sc->read); + + if (sc->read->posted) { + ngx_delete_posted_event(sc->read); + } + + ngx_post_event(sc->read, &posted_events); } + ngx_event_process_posted((ngx_cycle_t *) ngx_cycle, &posted_events); + if (tree->root == tree->sentinel) { return NGX_OK; } diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c index fba098c..bb13447 100644 --- a/src/event/quic/ngx_event_quic_transport.c +++ b/src/event/quic/ngx_event_quic_transport.c @@ -295,6 +295,11 @@ ngx_quic_parse_packet(ngx_quic_header_t *pkt) return NGX_ERROR; } + if (pkt->version == 0) { + /* version negotiation */ + return NGX_ERROR; + } + if (!ngx_quic_supported_version(pkt->version)) { return NGX_ABORT; } diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index b555278..7113df6 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -516,8 +516,10 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) /* * Another zlib variant, https://github.com/zlib-ng/zlib-ng. * It used to force window bits to 13 for fast compression level, - * uses (64 + sizeof(void*)) additional space on all allocations - * for alignment, 16-byte padding in one of window-sized buffers, + * used (64 + sizeof(void*)) additional space on all allocations + * for alignment and 16-byte padding in one of window-sized buffers, + * uses a single allocation with up to 200 bytes for alignment and + * internal pointers, 5/4 times more memory for the pending buffer, * and 128K hash. */ @@ -526,7 +528,7 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) - + 131072 + (1 << (memlevel + 8)) + + 131072 + (5 << (memlevel + 6)) + 4 * (64 + sizeof(void*)); ctx->zlib_ng = 1; } diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 041ad26..b7bd192 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -3176,7 +3176,10 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, start_sample -= n; - prev_samples = samples; + if (next_chunk > chunk) { + prev_samples = samples; + } + chunk = next_chunk; samples = ngx_mp4_get_32value(entry->samples); id = ngx_mp4_get_32value(entry->id); @@ -3186,6 +3189,13 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, next_chunk = trak->chunks + 1; + if (next_chunk < chunk) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "unordered mp4 stsc chunks in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", start_sample, chunk, next_chunk - chunk, samples); @@ -3211,6 +3221,12 @@ found: return NGX_ERROR; } + if (chunk == 0) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "zero chunk in \"%s\"", mp4->file.name.data); + return NGX_ERROR; + } + target_chunk = chunk - 1; target_chunk += start_sample / samples; chunk_samples = start_sample % samples; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 3cca57c..9593b7f 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -932,6 +932,31 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) goto done; } + sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module); + +#if (defined TLS1_3_VERSION \ + && !defined LIBRESSL_VERSION_NUMBER && !defined OPENSSL_IS_BORINGSSL) + + /* + * SSL_SESSION_get0_hostname() is only available in OpenSSL 1.1.1+, + * but servername being negotiated in every TLSv1.3 handshake + * is only returned in OpenSSL 1.1.1+ as well + */ + + if (sscf->verify) { + const char *hostname; + + hostname = SSL_SESSION_get0_hostname(SSL_get0_session(ssl_conn)); + + if (hostname != NULL && ngx_strcmp(hostname, servername) != 0) { + c->ssl->handshake_rejected = 1; + *ad = SSL_AD_ACCESS_DENIED; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + +#endif + hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); if (hc->ssl_servername == NULL) { goto error; @@ -945,8 +970,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) ngx_set_connection_log(c, clcf->error_log); - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - c->ssl->buffer_size = sscf->buffer_size; if (sscf->ssl.ctx) { diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index ba44477..6dee106 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -521,12 +521,35 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) goto done; } + sscf = ngx_stream_get_module_srv_conf(cscf->ctx, ngx_stream_ssl_module); + +#if (defined TLS1_3_VERSION \ + && !defined LIBRESSL_VERSION_NUMBER && !defined OPENSSL_IS_BORINGSSL) + + /* + * SSL_SESSION_get0_hostname() is only available in OpenSSL 1.1.1+, + * but servername being negotiated in every TLSv1.3 handshake + * is only returned in OpenSSL 1.1.1+ as well + */ + + if (sscf->verify) { + const char *hostname; + + hostname = SSL_SESSION_get0_hostname(SSL_get0_session(ssl_conn)); + + if (hostname != NULL && ngx_strcmp(hostname, servername) != 0) { + c->ssl->handshake_rejected = 1; + *ad = SSL_AD_ACCESS_DENIED; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + +#endif + s->srv_conf = cscf->ctx->srv_conf; ngx_set_connection_log(c, cscf->error_log); - sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); - if (sscf->ssl.ctx) { if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) { goto error; From c5cca14382978b08a86f6aecf0767c0ee49c3a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Wed, 5 Feb 2025 19:07:54 +0100 Subject: [PATCH 75/89] Bump ABI --- debian/libnginx-mod.abisubstvars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/libnginx-mod.abisubstvars b/debian/libnginx-mod.abisubstvars index 21d5511..57261d4 100644 --- a/debian/libnginx-mod.abisubstvars +++ b/debian/libnginx-mod.abisubstvars @@ -8,4 +8,4 @@ # changes without upgrading the upstream nginx version, e.g. security updates # in oldstable -nginx:abi=nginx-abi-1.26.2-1 +nginx:abi=nginx-abi-1.26.3-1 From 58f592a8ab0e66fc979a6552e0d770b2cfbad015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Wed, 5 Feb 2025 19:08:06 +0100 Subject: [PATCH 76/89] Release --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 469fb8b..0597f2f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.26.3-1) experimental; urgency=medium + + * Team upload + * New upstream version 1.26.3 + + -- Jérémy Lal Wed, 05 Feb 2025 19:08:02 +0100 + nginx (1.26.2-1) experimental; urgency=medium * Team upload From c789199d370d353157519250d7ef5930defe1942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Fri, 7 Feb 2025 12:53:15 +0100 Subject: [PATCH 77/89] Release to unstable --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0597f2f..d75820b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.26.3-2) unstable; urgency=medium + + * Team upload + * Upload to unstable + + -- Jérémy Lal Fri, 07 Feb 2025 12:53:11 +0100 + nginx (1.26.3-1) experimental; urgency=medium * Team upload From 3ef9946d9dbc44bd19cd5e193d7cc80072e9acfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 12 Feb 2025 19:36:44 +0100 Subject: [PATCH 78/89] d/changelog: fix whitespace in 1.26.3-2 record --- debian/changelog | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index d75820b..0870922 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,13 @@ +nginx (1.26.3-3) UNRELEASED; urgency=medium + + * d/changelog: fix whitespace in 1.26.3-2 record + + -- Jan Mojžíš Wed, 12 Feb 2025 19:37:40 +0100 + nginx (1.26.3-2) unstable; urgency=medium * Team upload - * Upload to unstable + * Upload to unstable -- Jérémy Lal Fri, 07 Feb 2025 12:53:11 +0100 From 6c57927b8d95a6c61c855e24b29132567f122ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 12 Feb 2025 19:43:05 +0100 Subject: [PATCH 79/89] d/control: add libnginx-mod-http-lua dependency for nginx-extras package for riscv64 platform --- debian/changelog | 2 ++ debian/control | 2 +- debian/tests/control | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0870922..0f2ce75 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,8 @@ nginx (1.26.3-3) UNRELEASED; urgency=medium * d/changelog: fix whitespace in 1.26.3-2 record + * d/control: add libnginx-mod-http-lua dependency for nginx-extras package + for riscv64 platform -- Jan Mojžíš Wed, 12 Feb 2025 19:37:40 +0100 diff --git a/debian/control b/debian/control index 4f36832..47749f4 100644 --- a/debian/control +++ b/debian/control @@ -198,7 +198,7 @@ Depends: nginx (= ${binary:Version}), libnginx-mod-http-fancyindex, libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, - libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x riscv64 powerpc], libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, diff --git a/debian/tests/control b/debian/tests/control index 880cc6d..b8c6569 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -31,7 +31,7 @@ Depends: nginx-core, libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, - libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x riscv64 powerpc], libnginx-mod-http-perl, libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, @@ -62,7 +62,7 @@ Depends: nginx-full, libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, - libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x riscv64 powerpc], libnginx-mod-http-perl, libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, @@ -93,7 +93,7 @@ Depends: nginx-light, libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, - libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x riscv64 powerpc], libnginx-mod-http-perl, libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, @@ -124,7 +124,7 @@ Depends: nginx-extras, libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, - libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x riscv64 powerpc], libnginx-mod-http-perl, libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, From 54cc7989701eb5d8ff561c6891f0a819cc54dcae Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sun, 23 Feb 2025 18:17:04 +0000 Subject: [PATCH 80/89] Fix DebBug #1098477, salsa issue nginx-team/nginx:#23 --- debian/changelog | 7 +++++++ debian/nginx-common.nginx.service | 1 + 2 files changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0f2ce75..c1224e3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,16 @@ nginx (1.26.3-3) UNRELEASED; urgency=medium + [ Jan Mojžíš ] * d/changelog: fix whitespace in 1.26.3-2 record * d/control: add libnginx-mod-http-lua dependency for nginx-extras package for riscv64 platform + [ Thomas Ward ] + * d/nginx-common.nginx.service: Add ConditionFileIsExecutable to + SystemD service file, prevents starting of service if nginx is + not installed (which can happen if nginx-common is installed + independently from `nginx` itself (Closes: #1098477) + -- Jan Mojžíš Wed, 12 Feb 2025 19:37:40 +0100 nginx (1.26.3-2) unstable; urgency=medium diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index a63fa0f..510c542 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -25,6 +25,7 @@ ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed +ConditionFileIsExecutable=/usr/sbin/nginx [Install] WantedBy=multi-user.target From bfbdc5aef2d486391f4ca542c23d6ecf52b34d72 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 24 Feb 2025 20:42:35 +0000 Subject: [PATCH 81/89] Move ConditionFileIsExecutable to proper section --- debian/nginx-common.nginx.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index 510c542..cb759f6 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -15,6 +15,7 @@ Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target +ConditionFileIsExecutable=/usr/sbin/nginx [Service] Type=forking @@ -25,7 +26,6 @@ ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed -ConditionFileIsExecutable=/usr/sbin/nginx [Install] WantedBy=multi-user.target From b1b8bf71fb3bd2d8f28e651ed2aaf1fec4e3447d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Thu, 6 Mar 2025 07:10:51 +0100 Subject: [PATCH 82/89] release nginx 1.22.1-9+deb12u1, upload to bookworm pu --- debian/changelog | 6 +++ debian/patches/CVE-2025-23419.patch | 70 +++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 77 insertions(+) create mode 100644 debian/patches/CVE-2025-23419.patch diff --git a/debian/changelog b/debian/changelog index 3bf98db..0b727cb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.22.1-9+deb12u1) bookworm; urgency=medium + + * d/p/CVE-2025-23419.patch add, backport CVE-2025-23419 fix. + + -- Jan Mojžíš Mon, 17 Feb 2025 20:40:29 +0100 + nginx (1.22.1-9) unstable; urgency=medium * d/control: nginx-common Breaks+Replaces: nginx (<< 1.22.1-8) diff --git a/debian/patches/CVE-2025-23419.patch b/debian/patches/CVE-2025-23419.patch new file mode 100644 index 0000000..b26bdc2 --- /dev/null +++ b/debian/patches/CVE-2025-23419.patch @@ -0,0 +1,70 @@ +From: =?utf-8?b?SmFuIE1vasW+w63FoQ==?= +Date: Mon, 17 Feb 2025 20:39:22 +0100 +Subject: CVE-2025-23419 +Origin: https://github.com/nginx/nginx/commit/13935cf9fdc3c8d8278c70716417d3b71c36140e + +SNI: added restriction for TLSv1.3 cross-SNI session resumption. +In OpenSSL, session resumption always happens in the default SSL context, +prior to invoking the SNI callback. Further, unlike in TLSv1.2 and older +protocols, SSL_get_servername() returns values received in the resumption +handshake, which may be different from the value in the initial handshake. +Notably, this makes the restriction added in b720f65 insufficient for +sessions resumed with different SNI server name. + +Considering the example from b720f65, previously, a client was able to +request example.org by presenting a certificate for example.org, then to +resume and request example.com. + +The fix is to reject handshakes resumed with a different server name, if +verification of client certificates is enabled in a corresponding server +configuration. + +--- + src/http/ngx_http_request.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c +index a999ff5..4708719 100644 +--- a/src/http/ngx_http_request.c ++++ b/src/http/ngx_http_request.c +@@ -909,6 +909,31 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) + goto done; + } + ++ sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module); ++ ++#if (defined TLS1_3_VERSION \ ++ && !defined LIBRESSL_VERSION_NUMBER && !defined OPENSSL_IS_BORINGSSL) ++ ++ /* ++ * SSL_SESSION_get0_hostname() is only available in OpenSSL 1.1.1+, ++ * but servername being negotiated in every TLSv1.3 handshake ++ * is only returned in OpenSSL 1.1.1+ as well ++ */ ++ ++ if (sscf->verify) { ++ const char *hostname; ++ ++ hostname = SSL_SESSION_get0_hostname(SSL_get0_session(ssl_conn)); ++ ++ if (hostname != NULL && ngx_strcmp(hostname, servername) != 0) { ++ c->ssl->handshake_rejected = 1; ++ *ad = SSL_AD_ACCESS_DENIED; ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ } ++ ++#endif ++ + hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); + if (hc->ssl_servername == NULL) { + goto error; +@@ -922,8 +947,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) + + ngx_set_connection_log(c, clcf->error_log); + +- sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); +- + c->ssl->buffer_size = sscf->buffer_size; + + if (sscf->ssl.ctx) { diff --git a/debian/patches/series b/debian/patches/series index 21a2a69..3ef6676 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -3,3 +3,4 @@ nginx-fix-pidfile.patch nginx-ssl_cert_cb_yield.patch bug-1024605.patch bug-973861.patch +CVE-2025-23419.patch From 653827e5a861000e0700f2d837dec6262e2188f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Thu, 15 May 2025 15:32:06 +0200 Subject: [PATCH 83/89] release nginx 1.26.3-3, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index c1224e3..8ec0edd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.26.3-3) UNRELEASED; urgency=medium +nginx (1.26.3-3) unstable; urgency=medium [ Jan Mojžíš ] * d/changelog: fix whitespace in 1.26.3-2 record @@ -11,7 +11,7 @@ nginx (1.26.3-3) UNRELEASED; urgency=medium not installed (which can happen if nginx-common is installed independently from `nginx` itself (Closes: #1098477) - -- Jan Mojžíš Wed, 12 Feb 2025 19:37:40 +0100 + -- Jan Mojžíš Thu, 15 May 2025 15:31:38 +0200 nginx (1.26.3-2) unstable; urgency=medium From 0d711082008fdbc30db3ddd50252db6c61a5900b Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Wed, 12 Mar 2025 18:55:08 +0100 Subject: [PATCH 84/89] Import Debian changes 1.22.1-9+deb12u2 nginx (1.22.1-9+deb12u2) bookworm; urgency=medium . * Non-maintainer upload by the LTS Team. * Add upstream patches for CVE-2024-7347: - mp4: fix buffer underread while updating stsz atom - mp4: reject unordered chunks in stsc atom --- debian/changelog | 9 +++++ debian/patches/CVE-2024-7347-1.patch | 49 ++++++++++++++++++++++++++++ debian/patches/CVE-2024-7347-2.patch | 31 ++++++++++++++++++ debian/patches/series | 2 ++ 4 files changed, 91 insertions(+) create mode 100644 debian/patches/CVE-2024-7347-1.patch create mode 100644 debian/patches/CVE-2024-7347-2.patch diff --git a/debian/changelog b/debian/changelog index 0b727cb..6b37bd7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.22.1-9+deb12u2) bookworm; urgency=medium + + * Non-maintainer upload by the LTS Team. + * Add upstream patches for CVE-2024-7347: + - mp4: fix buffer underread while updating stsz atom + - mp4: reject unordered chunks in stsc atom + + -- Andrej Shadura Wed, 12 Mar 2025 18:55:08 +0100 + nginx (1.22.1-9+deb12u1) bookworm; urgency=medium * d/p/CVE-2025-23419.patch add, backport CVE-2025-23419 fix. diff --git a/debian/patches/CVE-2024-7347-1.patch b/debian/patches/CVE-2024-7347-1.patch new file mode 100644 index 0000000..a392404 --- /dev/null +++ b/debian/patches/CVE-2024-7347-1.patch @@ -0,0 +1,49 @@ +From: Roman Arutyunyan +Date: Mon, 12 Aug 2024 18:20:43 +0400 +Subject: Mp4: fixed buffer underread while updating stsz atom. + +While cropping an stsc atom in ngx_http_mp4_crop_stsc_data(), a 32-bit integer +overflow could happen, which could result in incorrect seeking and a very large +value stored in "samples". This resulted in a large invalid value of +trak->end_chunk_samples. This value is further used to calculate the value of +trak->end_chunk_samples_size in ngx_http_mp4_update_stsz_atom(). While doing +this, a large invalid value of trak->end_chunk_samples could result in reading +memory before stsz atom start. This could potentially result in a segfault. + +Origin: upstream, https://github.com/nginx/nginx/commit/7362d01658b61184108c21278443910da68f93b4 +--- + src/http/modules/ngx_http_mp4_module.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c +index 4eff01e..460d091 100644 +--- a/src/http/modules/ngx_http_mp4_module.c ++++ b/src/http/modules/ngx_http_mp4_module.c +@@ -3098,7 +3098,8 @@ 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, ++ uint64_t n; ++ uint32_t start_sample, chunk, samples, id, next_chunk, + prev_samples; + ngx_buf_t *data, *buf; + ngx_uint_t entries, target_chunk, chunk_samples; +@@ -3159,7 +3160,7 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, + "samples:%uD, id:%uD", + start_sample, chunk, next_chunk - chunk, samples, id); + +- n = (next_chunk - chunk) * samples; ++ n = (uint64_t) (next_chunk - chunk) * samples; + + if (start_sample < n) { + goto found; +@@ -3181,7 +3182,7 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, + "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", + start_sample, chunk, next_chunk - chunk, samples); + +- n = (next_chunk - chunk) * samples; ++ n = (uint64_t) (next_chunk - chunk) * samples; + + if (start_sample > n) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, diff --git a/debian/patches/CVE-2024-7347-2.patch b/debian/patches/CVE-2024-7347-2.patch new file mode 100644 index 0000000..7ea27a2 --- /dev/null +++ b/debian/patches/CVE-2024-7347-2.patch @@ -0,0 +1,31 @@ +From: Roman Arutyunyan +Date: Mon, 12 Aug 2024 18:20:45 +0400 +Subject: Mp4: rejecting unordered chunks in stsc atom. + +Unordered chunks could result in trak->end_chunk smaller than trak->start_chunk +in ngx_http_mp4_crop_stsc_data(). Later in ngx_http_mp4_update_stco_atom() +this caused buffer overread while trying to calculate trak->end_offset. + +Origin: upstream, https://github.com/nginx/nginx/commit/88955b1044ef38315b77ad1a509d63631a790a0f +--- + src/http/modules/ngx_http_mp4_module.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c +index 460d091..dfada7c 100644 +--- a/src/http/modules/ngx_http_mp4_module.c ++++ b/src/http/modules/ngx_http_mp4_module.c +@@ -3155,6 +3155,13 @@ ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4, + + next_chunk = ngx_mp4_get_32value(entry->chunk); + ++ if (next_chunk < chunk) { ++ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, ++ "unordered mp4 stsc chunks in \"%s\"", ++ mp4->file.name.data); ++ return NGX_ERROR; ++ } ++ + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "sample:%uD, chunk:%uD, chunks:%uD, " + "samples:%uD, id:%uD", diff --git a/debian/patches/series b/debian/patches/series index 3ef6676..54d8c4b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -4,3 +4,5 @@ nginx-ssl_cert_cb_yield.patch bug-1024605.patch bug-973861.patch CVE-2025-23419.patch +CVE-2024-7347-1.patch +CVE-2024-7347-2.patch From 67b2e7933cd9823cc8a5a1627cc90ecacb1b891d Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 15 Jul 2025 15:05:37 +0700 Subject: [PATCH 85/89] sid init --- .gitignore | 9 ++++++ configure.docker.sh | 69 +++++++++++++++++++++++++++++++++++++++++++++ configure.sh | 66 +++++++++++++++++++++++++++++++++++++++++++ modules/PLACEHOLDER | 0 4 files changed, 144 insertions(+) create mode 100644 .gitignore create mode 100755 configure.docker.sh create mode 100755 configure.sh create mode 100644 modules/PLACEHOLDER diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f04d13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +objs/* +!objs/ndk_* +.pc/ +.vscode/ +modules/media-framework/ +modules/nginx-srt-module/ +modules/nginx-vod-module/ +Makefile +*.orig \ No newline at end of file diff --git a/configure.docker.sh b/configure.docker.sh new file mode 100755 index 0000000..f99417d --- /dev/null +++ b/configure.docker.sh @@ -0,0 +1,69 @@ +#!/bin/bash +./configure \ + --with-cc-opt="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -fPIC -D_FORTIFY_SOURCE=2 -I/tmp/build/quickjs/" \ + --with-ld-opt="-Wl,-z,relro -Wl,-z,now -fPIC -L/tmp/build/quickjs/" \ + --sbin-path=/usr/local/sbin/nginx \ + --conf-path=/video_server/nginx/nginx.conf \ + --error-log-path=/var/log/nginx/error.log \ + --pid-path=/var/run/nginx/nginx.pid \ + --lock-path=/var/lock/nginx/nginx.lock \ + --http-log-path=/var/log/nginx/access.log \ + --http-client-body-temp-path=/tmp/nginx-client-body \ + --with-compat \ + --with-debug \ + --with-pcre-jit \ + --with-http_ssl_module \ + --with-http_stub_status_module \ + --with-http_realip_module \ + --with-http_auth_request_module \ + --with-http_v2_module \ + --with-http_dav_module \ + --with-http_slice_module \ + --with-threads \ + --with-http_addition_module \ + --with-http_flv_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_mp4_module \ + --with-http_random_index_module \ + --with-http_secure_link_module \ + --with-http_sub_module \ + --with-mail_ssl_module \ + --with-stream_ssl_module \ + --with-stream_ssl_preread_module \ + --with-stream_realip_module \ + --with-http_geoip_module=dynamic \ + --with-http_image_filter_module=dynamic \ + --with-http_perl_module=dynamic \ + --with-http_xslt_module=dynamic \ + --with-mail=dynamic \ + --with-stream=dynamic \ + --with-stream_geoip_module=dynamic \ + --add-module=./modules_deb/libnginx-mod-http-ndk-0.3.2 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-brotli-1.0.0~rc \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-cache-purge-2.3 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-echo-0.63 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-geoip2-3.4 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-headers-more-filter-0.34\ + --add-dynamic-module=./modules_deb/libnginx-mod-http-memc-0.19 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-set-misc-0.33 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-srcache-filter-0.33 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-subs-filter-0.6.4 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409 \ + --add-dynamic-module=./modules_deb/libnginx-mod-nchan-1.3.6+dfsg \ + --add-dynamic-module=./modules/njs/nginx \ + --add-module=./modules/media-framework/nginx-common \ + --add-dynamic-module=./modules/nginx-stream-preread-str-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-in-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-out-module \ + --add-dynamic-module=./modules/media-framework/nginx-rtmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-rtmp-kmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-mpegts-module \ + --add-dynamic-module=./modules/media-framework/nginx-mpegts-kmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-cc-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-rtmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-live-module \ + --add-dynamic-module=./modules/nginx-srt-module \ + --add-dynamic-module=./modules/media-framework/nginx-pckg-module \ + --add-dynamic-module=./modules/nginx-vod-module \ + --add-dynamic-module=./modules/nginx-secure-token-module \ No newline at end of file diff --git a/configure.sh b/configure.sh new file mode 100755 index 0000000..6d76886 --- /dev/null +++ b/configure.sh @@ -0,0 +1,66 @@ +#!/bin/bash +./configure \ + --with-cc-opt="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -fPIC -D_FORTIFY_SOURCE=2 -I/usr/local/include/quickjs/" \ + --with-ld-opt="-Wl,-z,relro -Wl,-z,now -fPIC -L/usr/local/lib/quickjs/" \ + --prefix=/usr/local/temp/nginx/ \ + --error-log-path=stderr \ + --lock-path=/var/lock/nginx.lock \ + --pid-path=/run/nginx.pid \ + --with-compat \ + --with-debug \ + --with-pcre-jit \ + --with-http_ssl_module \ + --with-http_stub_status_module \ + --with-http_realip_module \ + --with-http_auth_request_module \ + --with-http_v2_module \ + --with-http_dav_module \ + --with-http_slice_module \ + --with-threads \ + --with-http_addition_module \ + --with-http_flv_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_mp4_module \ + --with-http_random_index_module \ + --with-http_secure_link_module \ + --with-http_sub_module \ + --with-mail_ssl_module \ + --with-stream_ssl_module \ + --with-stream_ssl_preread_module \ + --with-stream_realip_module \ + --with-http_geoip_module=dynamic \ + --with-http_image_filter_module=dynamic \ + --with-http_perl_module=dynamic \ + --with-http_xslt_module=dynamic \ + --with-mail=dynamic \ + --with-stream=dynamic \ + --with-stream_geoip_module=dynamic \ + --add-module=./modules_deb/libnginx-mod-http-ndk-0.3.2 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-brotli-1.0.0~rc \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-cache-purge-2.3 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-echo-0.63 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-geoip2-3.4 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-headers-more-filter-0.34\ + --add-dynamic-module=./modules_deb/libnginx-mod-http-memc-0.19 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-set-misc-0.33 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-srcache-filter-0.33 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-subs-filter-0.6.4 \ + --add-dynamic-module=./modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409 \ + --add-dynamic-module=./modules_deb/libnginx-mod-nchan-1.3.6+dfsg \ + --add-dynamic-module=./modules/njs/nginx \ + --add-module=./modules/media-framework/nginx-common \ + --add-dynamic-module=./modules/nginx-stream-preread-str-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-in-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-out-module \ + --add-dynamic-module=./modules/media-framework/nginx-rtmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-rtmp-kmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-mpegts-module \ + --add-dynamic-module=./modules/media-framework/nginx-mpegts-kmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-cc-module \ + --add-dynamic-module=./modules/media-framework/nginx-kmp-rtmp-module \ + --add-dynamic-module=./modules/media-framework/nginx-live-module \ + --add-dynamic-module=./modules/nginx-srt-module \ + --add-dynamic-module=./modules/media-framework/nginx-pckg-module \ + --add-dynamic-module=./modules/nginx-vod-module \ + --add-dynamic-module=./modules/nginx-secure-token-module \ No newline at end of file diff --git a/modules/PLACEHOLDER b/modules/PLACEHOLDER new file mode 100644 index 0000000..e69de29 From bf4e347d840944f38946e4c7a8b83f62f76ea4e9 Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 15 Jul 2025 15:11:13 +0700 Subject: [PATCH 86/89] sid 2 --- .../.gitmodules | 3 + .../.travis.yml | 46 + .../CONTRIBUTING.md | 27 + .../libnginx-mod-http-brotli-1.0.0~rc/LICENSE | 27 + .../README.md | 177 + .../libnginx-mod-http-brotli-1.0.0~rc/config | 34 + .../debian/changelog | 49 + .../debian/control | 41 + .../debian/copyright | 72 + .../debian/gbp.conf | 9 + .../libnginx-mod-http-brotli-filter.install | 1 + .../libnginx-mod-http-brotli-static.install | 1 + .../debian/patches/0001-Fix-Vary-header.patch | 38 + .../debian/patches/series | 1 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 22 + .../debian/tests/filter | 44 + .../debian/tests/generic | 73 + .../debian/tests/static | 36 + .../debian/upstream/metadata | 4 + .../debian/watch | 6 + .../filter/config | 132 + .../filter/ngx_http_brotli_filter_module.c | 770 +++ .../script/.travis-before-test.sh | 24 + .../script/.travis-compile.sh | 29 + .../script/.travis-test.sh | 168 + .../script/test.conf | 32 + .../script/test_h2.conf | 32 + .../static/config | 54 + .../static/ngx_http_brotli_static_module.c | 323 + .../.astylerc | 22 + .../.format.sh | 14 + .../.gitattributes | 1 + .../.travis.yml | 49 + .../CHANGES | 103 + .../LICENSE | 26 + .../README.md | 283 + .../config | 31 + .../debian/changelog | 74 + .../debian/control | 23 + .../debian/copyright | 36 + .../debian/gbp.conf | 12 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 13 + .../debian/tests/generic | 73 + .../debian/tests/purgetest | 34 + .../debian/upstream/metadata | 4 + .../debian/watch | 6 + .../ngx_cache_purge_module.c | 2163 +++++++ .../t/proxy1.t | 136 + .../t/proxy1_vars.t | 138 + .../t/proxy2.t | 349 ++ .../t/proxy2_vars.t | 353 ++ .../t/proxy3.t | 140 + .../t/proxy4.t | 168 + .../t/resptype1.t | 245 + .../.gitattributes | 1 + .../libnginx-mod-http-echo-0.63/.gitignore | 65 + .../libnginx-mod-http-echo-0.63/.travis.yml | 48 + .../libnginx-mod-http-echo-0.63/LICENSE | 25 + .../README.markdown | 1851 ++++++ .../libnginx-mod-http-echo-0.63/config | 63 + .../debian/changelog | 53 + .../debian/control | 36 + .../debian/copyright | 71 + .../debian/fix.scanned.copyright | 2 + .../debian/gbp.conf | 9 + .../libnginx-mod-http-echo-0.63/debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 13 + .../debian/tests/generic | 73 + .../debian/tests/helloworld | 32 + .../debian/upstream/metadata | 4 + .../libnginx-mod-http-echo-0.63/debian/watch | 6 + .../libnginx-mod-http-echo-0.63/src/ddebug.h | 114 + .../src/ngx_http_echo_echo.c | 342 ++ .../src/ngx_http_echo_echo.h | 25 + .../src/ngx_http_echo_filter.c | 282 + .../src/ngx_http_echo_filter.h | 15 + .../src/ngx_http_echo_foreach.c | 183 + .../src/ngx_http_echo_foreach.h | 16 + .../src/ngx_http_echo_handler.c | 433 ++ .../src/ngx_http_echo_handler.h | 18 + .../src/ngx_http_echo_location.c | 182 + .../src/ngx_http_echo_location.h | 13 + .../src/ngx_http_echo_module.c | 682 +++ .../src/ngx_http_echo_module.h | 151 + .../src/ngx_http_echo_request_info.c | 522 ++ .../src/ngx_http_echo_request_info.h | 36 + .../src/ngx_http_echo_sleep.c | 208 + .../src/ngx_http_echo_sleep.h | 16 + .../src/ngx_http_echo_subrequest.c | 791 +++ .../src/ngx_http_echo_subrequest.h | 19 + .../src/ngx_http_echo_timer.c | 95 + .../src/ngx_http_echo_timer.h | 13 + .../src/ngx_http_echo_util.c | 302 + .../src/ngx_http_echo_util.h | 58 + .../src/ngx_http_echo_var.c | 110 + .../src/ngx_http_echo_var.h | 9 + .../t/abort-parent.t | 63 + .../t/blocking-sleep.t | 156 + .../t/echo-after-body.t | 261 + .../t/echo-before-body.t | 278 + .../t/echo-duplicate.t | 89 + .../t/echo-timer.t | 107 + .../libnginx-mod-http-echo-0.63/t/echo.t | 416 ++ .../libnginx-mod-http-echo-0.63/t/exec.t | 228 + .../t/filter-used.t | 59 + .../t/foreach-split.t | 283 + .../libnginx-mod-http-echo-0.63/t/gzip.t | 31 + .../libnginx-mod-http-echo-0.63/t/if.t | 150 + .../libnginx-mod-http-echo-0.63/t/incr.t | 32 + .../t/location-async.t | 439 ++ .../libnginx-mod-http-echo-0.63/t/location.t | 567 ++ .../libnginx-mod-http-echo-0.63/t/mixed.t | 82 + .../t/request-body.t | 58 + .../t/request-info.t | 870 +++ .../libnginx-mod-http-echo-0.63/t/sleep.t | 200 + .../libnginx-mod-http-echo-0.63/t/status.t | 142 + .../t/subrequest-async.t | 604 ++ .../t/subrequest.t | 725 +++ .../libnginx-mod-http-echo-0.63/t/unused.t | 119 + .../libnginx-mod-http-echo-0.63/util/build.sh | 44 + .../util/wiki2pod.pl | 131 + .../valgrind.suppress | 53 + .../libnginx-mod-http-geoip2-3.4/LICENSE | 23 + .../libnginx-mod-http-geoip2-3.4/README.md | 153 + .../libnginx-mod-http-geoip2-3.4/config | 43 + .../debian/changelog | 52 + .../debian/control | 41 + .../debian/copyright | 46 + .../debian/gbp.conf | 9 + .../debian/libnginx-mod-http-geoip2.install | 1 + .../debian/libnginx-mod-stream-geoip2.install | 1 + .../libnginx-mod-http-geoip2-3.4/debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 6 + .../debian/tests/generic | 73 + .../debian/upstream/metadata | 4 + .../libnginx-mod-http-geoip2-3.4/debian/watch | 6 + .../ngx_http_geoip2_module.c | 803 +++ .../ngx_stream_geoip2_module.c | 694 +++ .../.gitattributes | 1 + .../.gitignore | 54 + .../.travis.yml | 58 + .../LICENSE | 20 + .../README.markdown | 538 ++ .../config | 32 + .../debian/changelog | 72 + .../debian/control | 26 + .../debian/copyright | 62 + .../debian/gbp.conf | 12 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 13 + .../debian/tests/generic | 73 + .../debian/tests/helloworld | 34 + .../debian/upstream/metadata | 4 + .../debian/watch | 6 + .../src/ddebug.h | 124 + .../src/ngx_http_headers_more_filter_module.c | 348 ++ .../src/ngx_http_headers_more_filter_module.h | 81 + .../src/ngx_http_headers_more_headers_in.c | 959 +++ .../src/ngx_http_headers_more_headers_in.h | 26 + .../src/ngx_http_headers_more_headers_out.c | 814 +++ .../src/ngx_http_headers_more_headers_out.h | 26 + .../src/ngx_http_headers_more_util.c | 382 ++ .../src/ngx_http_headers_more_util.h | 52 + .../t/bug.t | 416 ++ .../t/builtin.t | 338 + .../t/eval.t | 36 + .../t/input-conn.t | 137 + .../t/input-cookie.t | 183 + .../t/input-ua.t | 628 ++ .../t/input.t | 1331 ++++ .../t/phase.t | 25 + .../t/sanity.t | 628 ++ .../t/subrequest.t | 68 + .../t/unused.t | 174 + .../t/vars.t | 58 + .../util/build.sh | 38 + .../valgrind.suppress | 135 + .../libnginx-mod-http-ndk-0.3.4/.gitignore | 4 + .../libnginx-mod-http-ndk-0.3.4/LICENSE | 13 + .../libnginx-mod-http-ndk-0.3.4/README.md | 254 + .../README_AUTO_LIB.md | 394 ++ .../auto/actions/array | 10 + .../auto/actions/palloc | 8 + .../libnginx-mod-http-ndk-0.3.4/auto/build | 597 ++ .../auto/data/action_replacements | 5 + .../auto/data/action_types | 12 + .../auto/data/conf_args | 22 + .../auto/data/conf_locs | 25 + .../auto/data/conf_macros | 35 + .../auto/data/contexts | 22 + .../auto/data/header_files | 3 + .../auto/data/headers | 4 + .../auto/data/module_dependencies | 5 + .../auto/data/modules_optional | 15 + .../auto/data/prefixes | 2 + .../auto/src/array.h | 7 + .../auto/src/conf_cmd_basic.h | 43 + .../auto/src/conf_merge.h | 78 + .../auto/src/palloc.h | 6 + .../auto/text/autogen | 12 + .../libnginx-mod-http-ndk-0.3.4/config | 65 + .../debian/changelog | 58 + .../debian/control | 47 + .../debian/copyright | 155 + .../debian/copyright-scan-patterns.yml | 4 + .../debian/fix.scanned.copyright | 1 + .../debian/gbp.conf | 12 + .../debian/libnginx-mod-http-ndk-dev.install | 5 + .../debian/libnginx-mod-http-ndk.install | 1 + .../debian/libnginx-mod-http-ndk.nginx | 1 + .../debian/mod-http-ndk.conf | 1 + .../libnginx-mod-http-ndk-0.3.4/debian/rules | 35 + .../debian/source/format | 1 + .../debian/tests/control | 6 + .../debian/tests/generic | 73 + .../debian/upstream/metadata | 4 + .../libnginx-mod-http-ndk-0.3.4/debian/watch | 6 + .../docs/core/action_macros | 63 + .../docs/core/conf_cmds | 62 + .../docs/modules/set_var | 124 + .../docs/patches/more_logging_info | 48 + .../docs/upstream/list | 45 + .../examples/README | 12 + .../examples/http/set_var/config | 4 + .../ngx_http_set_var_examples_module.c | 136 + .../ngx_auto_lib_core | 797 +++ .../libnginx-mod-http-ndk-0.3.4/notes/CHANGES | 17 + .../libnginx-mod-http-ndk-0.3.4/notes/LICENSE | 24 + .../objs/ndk_array.h | 113 + .../objs/ndk_conf_cmd_basic.h | 2203 +++++++ .../objs/ndk_conf_cmd_extra.h | 5423 +++++++++++++++++ .../objs/ndk_conf_merge.h | 227 + .../objs/ndk_config.c | 72 + .../objs/ndk_config.h | 98 + .../objs/ndk_includes.h | 66 + .../objs/ndk_palloc.h | 112 + .../patches/auto_config | 16 + .../patches/expose_rewrite_functions | 291 + .../patches/rewrite_phase_handler | 19 + .../src/hash/md5.h | 117 + .../src/hash/murmurhash2.c | 77 + .../src/hash/sha.h | 200 + .../libnginx-mod-http-ndk-0.3.4/src/ndk.c | 155 + .../libnginx-mod-http-ndk-0.3.4/src/ndk.h | 53 + .../libnginx-mod-http-ndk-0.3.4/src/ndk_buf.c | 43 + .../libnginx-mod-http-ndk-0.3.4/src/ndk_buf.h | 5 + .../src/ndk_complex_path.c | 129 + .../src/ndk_complex_path.h | 30 + .../src/ndk_complex_value.c | 192 + .../src/ndk_complex_value.h | 21 + .../src/ndk_conf_file.c | 396 ++ .../src/ndk_conf_file.h | 44 + .../src/ndk_debug.c | 72 + .../src/ndk_debug.h | 171 + .../src/ndk_encoding.c | 57 + .../src/ndk_encoding.h | 12 + .../src/ndk_hash.c | 82 + .../src/ndk_hash.h | 45 + .../src/ndk_http.c | 138 + .../src/ndk_http.h | 3 + .../src/ndk_http_headers.h | 35 + .../libnginx-mod-http-ndk-0.3.4/src/ndk_log.c | 3 + .../libnginx-mod-http-ndk-0.3.4/src/ndk_log.h | 165 + .../src/ndk_parse.h | 67 + .../src/ndk_path.c | 583 ++ .../src/ndk_path.h | 22 + .../src/ndk_process.c | 20 + .../src/ndk_process.h | 12 + .../src/ndk_regex.c | 215 + .../src/ndk_regex.h | 7 + .../src/ndk_rewrite.c | 103 + .../src/ndk_rewrite.h | 26 + .../src/ndk_set_var.c | 602 ++ .../src/ndk_set_var.h | 44 + .../src/ndk_string.c | 434 ++ .../src/ndk_string.h | 37 + .../src/ndk_string_util.h | 14 + .../src/ndk_upstream_list.c | 205 + .../src/ndk_upstream_list.h | 27 + .../libnginx-mod-http-ndk-0.3.4/src/ndk_uri.c | 45 + .../libnginx-mod-http-ndk-0.3.4/src/ndk_uri.h | 6 + .../.gitattributes | 1 + .../.gitignore | 72 + .../.travis.yml | 54 + .../README.markdown | 1451 +++++ .../libnginx-mod-http-set-misc-0.33/config | 79 + .../debian/changelog | 53 + .../debian/control | 27 + .../debian/copyright | 49 + .../debian/copyright-scan-patterns.yml | 4 + .../debian/fix.scanned.copyright | 2 + .../debian/gbp.conf | 9 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 13 + .../debian/tests/generic | 73 + .../debian/tests/setifempty | 36 + .../debian/upstream/metadata | 4 + .../debian/watch | 6 + .../src/ddebug.h | 74 + .../src/ngx_http_set_base32.c | 263 + .../src/ngx_http_set_base32.h | 18 + .../src/ngx_http_set_base64.c | 48 + .../src/ngx_http_set_base64.h | 10 + .../src/ngx_http_set_base64url.c | 50 + .../src/ngx_http_set_base64url.h | 10 + .../src/ngx_http_set_default_value.c | 48 + .../src/ngx_http_set_default_value.h | 15 + .../src/ngx_http_set_escape_uri.c | 210 + .../src/ngx_http_set_escape_uri.h | 10 + .../src/ngx_http_set_hash.c | 83 + .../src/ngx_http_set_hash.h | 15 + .../src/ngx_http_set_hashed_upstream.c | 141 + .../src/ngx_http_set_hashed_upstream.h | 27 + .../src/ngx_http_set_hex.c | 62 + .../src/ngx_http_set_hex.h | 9 + .../src/ngx_http_set_hmac.c | 62 + .../src/ngx_http_set_hmac.h | 9 + .../src/ngx_http_set_local_today.c | 110 + .../src/ngx_http_set_local_today.h | 13 + .../src/ngx_http_set_misc_module.c | 586 ++ .../src/ngx_http_set_misc_module.h | 30 + .../src/ngx_http_set_quote_json.c | 165 + .../src/ngx_http_set_quote_json.h | 16 + .../src/ngx_http_set_quote_sql.c | 382 ++ .../src/ngx_http_set_quote_sql.h | 21 + .../src/ngx_http_set_random.c | 57 + .../src/ngx_http_set_random.h | 12 + .../src/ngx_http_set_rotate.c | 113 + .../src/ngx_http_set_rotate.h | 18 + .../src/ngx_http_set_secure_random.c | 104 + .../src/ngx_http_set_secure_random.h | 15 + .../src/ngx_http_set_unescape_uri.c | 184 + .../src/ngx_http_set_unescape_uri.h | 16 + .../t/base32.t | 556 ++ .../t/base32_no_padding.t | 531 ++ .../t/base64.t | 40 + .../t/base64url.t | 40 + .../t/default-value.t | 88 + .../t/escape-uri.t | 139 + .../t/formatted-time.t | 84 + .../libnginx-mod-http-set-misc-0.33/t/hash.t | 94 + .../t/hashed-upstream.t | 70 + .../libnginx-mod-http-set-misc-0.33/t/hex.t | 57 + .../libnginx-mod-http-set-misc-0.33/t/hmac.t | 78 + .../t/local-today.t | 29 + .../t/quote-json.t | 69 + .../t/quote-sql.t | 195 + .../libnginx-mod-http-set-misc-0.33/t/rand.t | 168 + .../t/rotate.t | 270 + .../t/secure-random.t | 107 + .../t/unescape-uri.t | 58 + .../util/build.sh | 35 + .../valgrind.suppress | 105 + .../.gitattributes | 1 + .../.gitignore | 79 + .../.travis.yml | 87 + .../Changes | 16 + .../README.markdown | 1258 ++++ .../config | 50 + .../debian/changelog | 60 + .../debian/control | 24 + .../debian/copyright | 56 + .../debian/fix.scanned.copyright | 2 + .../debian/gbp.conf | 9 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 6 + .../debian/tests/generic | 73 + .../debian/upstream/metadata | 4 + .../debian/watch | 9 + .../src/ddebug.h | 124 + .../src/ngx_http_srcache_fetch.c | 470 ++ .../src/ngx_http_srcache_fetch.h | 22 + .../src/ngx_http_srcache_filter_module.c | 623 ++ .../src/ngx_http_srcache_filter_module.h | 152 + .../src/ngx_http_srcache_headers.c | 359 ++ .../src/ngx_http_srcache_headers.h | 30 + .../src/ngx_http_srcache_store.c | 675 ++ .../src/ngx_http_srcache_store.h | 23 + .../src/ngx_http_srcache_util.c | 1296 ++++ .../src/ngx_http_srcache_util.h | 61 + .../src/ngx_http_srcache_var.c | 180 + .../src/ngx_http_srcache_var.h | 19 + .../t/000_init.t | 158 + .../t/access.t | 84 + .../t/bugs.t | 668 ++ .../t/conditional-get.t | 302 + .../t/content-length.t | 96 + .../t/content-type.t | 90 + .../t/disk.t | 68 + .../t/drizzle-main.t | 105 + .../t/drizzle-sub.t | 113 + .../t/empty-resp.t | 88 + .../t/err-page.t | 82 + .../t/etag.t | 186 + .../t/eval.t | 96 + .../t/expire-var.t | 592 ++ .../t/expires.t | 377 ++ .../t/fetch-header.t | 232 + .../t/fetch-skip.t | 528 ++ .../t/gzip.t | 160 + .../t/header-buf-size.t | 145 + .../t/main-req.t | 146 + .../t/max-age.t | 305 + .../t/methods.t | 389 ++ .../t/no-cache.t | 309 + .../t/no-store.t | 305 + .../t/postgres-main.t | 138 + .../t/private.t | 528 ++ .../t/proxy.t | 65 + .../t/ranges.t | 410 ++ .../t/redis.t | 246 + .../t/req-cache-control.t | 394 ++ .../t/satisfy.t | 118 + .../t/static.t | 162 + .../t/status.t | 723 +++ .../t/store-hide-headers.t | 389 ++ .../t/store-max-size.t | 356 ++ .../t/store-pass-headers.t | 173 + .../t/store-skip.t | 434 ++ .../t/sub-req.t | 448 ++ .../t/timeout.t | 119 + .../t/unused.t | 113 + .../util/build.sh | 75 + .../valgrind.suppress | 93 + .../CHANGES | 37 + .../README | 141 + .../config | 15 + .../debian/changelog | 52 + .../debian/control | 24 + .../debian/copyright | 116 + .../debian/gbp.conf | 9 + ...Feature-nginx-dynamic-module-support.patch | 36 + ...ntent-encoding-header-more-carefully.patch | 29 + .../patches/0003-PCRE2-support-added.patch | 30 + .../debian/patches/series | 3 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 6 + .../debian/tests/generic | 73 + .../debian/upstream/metadata | 4 + .../debian/watch | 6 + .../doc/README.google_code_home_page.wiki | 120 + .../doc/README.html | 199 + .../doc/README.wiki | 123 + .../ngx_http_subs_filter_module.c | 1302 ++++ .../test/README | 275 + .../test/inc/Module/AutoInstall.pm | 820 +++ .../test/inc/Module/Install.pm | 470 ++ .../test/inc/Module/Install/AutoInstall.pm | 82 + .../test/inc/Module/Install/Base.pm | 83 + .../test/inc/Module/Install/Can.pm | 81 + .../test/inc/Module/Install/Fetch.pm | 93 + .../test/inc/Module/Install/Include.pm | 34 + .../test/inc/Module/Install/Makefile.pm | 415 ++ .../test/inc/Module/Install/Metadata.pm | 716 +++ .../test/inc/Module/Install/TestBase.pm | 29 + .../test/inc/Module/Install/Win32.pm | 64 + .../test/inc/Module/Install/WriteAll.pm | 63 + .../test/inc/Spiffy.pm | 539 ++ .../test/inc/Test/Base.pm | 682 +++ .../test/inc/Test/Base/Filter.pm | 341 ++ .../test/inc/Test/Builder.pm | 1413 +++++ .../test/inc/Test/Builder/Module.pm | 81 + .../test/inc/Test/More.pm | 735 +++ .../test/lib/Test/Nginx.pm | 315 + .../test/lib/Test/Nginx/LWP.pm | 524 ++ .../test/lib/Test/Nginx/Socket.pm | 1749 ++++++ .../test/lib/Test/Nginx/Util.pm | 874 +++ .../test/t/subs.t | 136 + .../test/t/subs_capture.t | 32 + .../test/t/subs_fix_string.t | 32 + .../test/t/subs_regex.t | 108 + .../test/t/subs_types.t | 59 + .../test/test.sh | 5 + .../util/update-readme.sh | 7 + .../util/wiki2google_code_homepage.pl | 29 + .../util/wiki2pod.pl | 129 + .../.gdbinit | 39 + .../README | 53 + .../config | 12 + .../debian/changelog | 44 + .../debian/control | 23 + .../debian/copyright | 39 + .../debian/gbp.conf | 9 + .../debian/patches/drop-default-port.patch | 37 + .../debian/patches/dynamic-module.patch | 29 + .../debian/patches/openssl-1.1.0.patch | 50 + .../debian/patches/series | 3 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/tests/control | 6 + .../debian/tests/generic | 73 + .../debian/upstream/metadata | 4 + .../debian/watch | 7 + .../ngx_http_upstream_fair_module.c | 1354 ++++ .../libnginx-mod-nchan-1.3.7+dfsg/LICENCE | 24 + .../libnginx-mod-nchan-1.3.7+dfsg/README.md | 1745 ++++++ .../changelog.txt | 595 ++ .../cloc-exclude.txt | 16 + .../libnginx-mod-nchan-1.3.7+dfsg/config | 170 + .../debian/changelog | 81 + .../debian/control | 32 + .../debian/copyright | 246 + .../debian/fix.scanned.copyright | 3 + .../debian/gbp.conf | 12 + .../debian/rules | 6 + .../debian/source/format | 1 + .../debian/source/options | 1 + .../debian/tests/control | 9 + .../debian/tests/generic | 73 + .../debian/upstream/metadata | 4 + .../debian/watch | 9 + .../src/.gitignore | 2 + .../src/nchan_commands.rb | 1188 ++++ .../src/nchan_config_commands.c | 1046 ++++ .../src/nchan_defs.c | 97 + .../src/nchan_defs.h | 150 + .../src/nchan_module.c | 1336 ++++ .../src/nchan_module.h | 73 + .../src/nchan_setup.c | 1747 ++++++ .../src/nchan_types.h | 542 ++ .../src/nchan_variables.c | 319 + .../src/nchan_variables.h | 1 + .../src/nchan_version.h | 1 + .../src/nchan_websocket_publisher.c | 82 + .../src/nchan_websocket_publisher.h | 2 + .../src/store/memory/groups.c | 570 ++ .../src/store/memory/groups.h | 55 + .../src/store/memory/ipc-handlers.c | 1213 ++++ .../src/store/memory/ipc-handlers.h | 28 + .../src/store/memory/ipc.c | 558 ++ .../src/store/memory/ipc.h | 66 + .../src/store/memory/memstore.c | 3498 +++++++++++ .../src/store/memory/recycloc.c | 47 + .../src/store/memory/store-private.h | 180 + .../src/store/memory/store.h | 13 + .../src/store/ngx_rwlock.c | 178 + .../src/store/ngx_rwlock.h | 5 + .../src/store/redis/cmp.c | 3352 ++++++++++ .../src/store/redis/cmp.h | 526 ++ .../src/store/redis/hiredis/.gitignore | 9 + .../src/store/redis/hiredis/.travis.yml | 131 + .../src/store/redis/hiredis/CHANGELOG.md | 364 ++ .../src/store/redis/hiredis/COPYING | 29 + .../src/store/redis/hiredis/README.md | 664 ++ .../src/store/redis/hiredis/alloc.c | 86 + .../src/store/redis/hiredis/alloc.h | 91 + .../src/store/redis/hiredis/async.c | 890 +++ .../src/store/redis/hiredis/async.h | 147 + .../src/store/redis/hiredis/async_private.h | 75 + .../src/store/redis/hiredis/dict.c | 357 ++ .../src/store/redis/hiredis/dict.h | 126 + .../src/store/redis/hiredis/fmacros.h | 12 + .../src/store/redis/hiredis/hiredis.c | 1174 ++++ .../src/store/redis/hiredis/hiredis.h | 339 ++ .../src/store/redis/hiredis/hiredis_ssl.h | 127 + .../src/store/redis/hiredis/net.c | 615 ++ .../src/store/redis/hiredis/net.h | 56 + .../src/store/redis/hiredis/read.c | 739 +++ .../src/store/redis/hiredis/read.h | 129 + .../src/store/redis/hiredis/sds.c | 1294 ++++ .../src/store/redis/hiredis/sds.h | 278 + .../src/store/redis/hiredis/sdsalloc.h | 44 + .../src/store/redis/hiredis/sockcompat.c | 248 + .../src/store/redis/hiredis/sockcompat.h | 92 + .../src/store/redis/hiredis/ssl.c | 526 ++ .../src/store/redis/hiredis/test.c | 1387 +++++ .../src/store/redis/hiredis/win32.h | 56 + .../src/store/redis/rdsstore.c | 2721 +++++++++ .../store/redis/redis-lua-scripts/.gitignore | 1 + .../src/store/redis/redis-lua-scripts/Gemfile | 11 + .../redis/redis-lua-scripts/add_fakesub.lua | 52 + .../redis-lua-scripts/channel_keepalive.lua | 45 + .../store/redis/redis-lua-scripts/delete.lua | 91 + .../redis/redis-lua-scripts/find_channel.lua | 92 + .../redis/redis-lua-scripts/get_message.lua | 155 + .../get_message_from_key.lua | 8 + .../get_subscriber_info_id.lua | 18 + ...nostore_publish_multiexec_channel_info.lua | 56 + .../store/redis/redis-lua-scripts/publish.lua | 296 + .../request_subscriber_info.lua | 15 + .../store/redis/redis-lua-scripts/rsck.lua | 216 + .../redis-lua-scripts/subscriber_register.lua | 61 + .../subscriber_unregister.lua | 50 + .../redis/redis-lua-scripts/testscripts.rb | 269 + .../src/store/redis/redis_lua_commands.c | 1185 ++++ .../src/store/redis/redis_lua_commands.h | 83 + .../src/store/redis/redis_nginx_adapter.c | 165 + .../src/store/redis/redis_nginx_adapter.h | 22 + .../src/store/redis/redis_nodeset.c | 3824 ++++++++++++ .../src/store/redis/redis_nodeset.h | 469 ++ .../src/store/redis/redis_nodeset_parser.c | 248 + .../src/store/redis/redis_nodeset_parser.h | 40 + .../src/store/redis/redis_nodeset_stats.c | 578 ++ .../src/store/redis/store-private.h | 114 + .../src/store/redis/store.h | 26 + .../src/store/spool.c | 1293 ++++ .../src/store/spool.h | 117 + .../src/store/store_common.c | 8 + .../src/store/store_common.h | 12 + .../src/subscribers/benchmark.c | 72 + .../src/subscribers/benchmark.h | 3 + .../src/subscribers/common.c | 456 ++ .../src/subscribers/common.h | 27 + .../src/subscribers/eventsource.c | 414 ++ .../src/subscribers/eventsource.h | 4 + .../src/subscribers/getmsg_proxy.c | 106 + .../src/subscribers/getmsg_proxy.h | 1 + .../src/subscribers/http-chunked.c | 259 + .../src/subscribers/http-chunked.h | 4 + .../src/subscribers/http-multipart-mixed.c | 291 + .../src/subscribers/http-multipart-mixed.h | 3 + .../src/subscribers/http-raw-stream.c | 157 + .../src/subscribers/http-raw-stream.h | 1 + .../src/subscribers/internal.c | 298 + .../src/subscribers/internal.h | 32 + .../src/subscribers/intervalpoll.c | 33 + .../src/subscribers/intervalpoll.h | 1 + .../src/subscribers/longpoll-private.h | 38 + .../src/subscribers/longpoll.c | 551 ++ .../src/subscribers/longpoll.h | 2 + .../src/subscribers/memstore_ipc.c | 197 + .../src/subscribers/memstore_ipc.h | 5 + .../src/subscribers/memstore_multi.c | 174 + .../src/subscribers/memstore_multi.h | 2 + .../src/subscribers/memstore_redis.c | 261 + .../src/subscribers/memstore_redis.h | 3 + .../src/subscribers/websocket.c | 2065 +++++++ .../src/subscribers/websocket.h | 5 + .../src/uthash.h | 1208 ++++ .../src/util/hdr_histogram.c | 1015 +++ .../src/util/hdr_histogram.h | 427 ++ .../src/util/nchan_accumulator.c | 212 + .../src/util/nchan_accumulator.h | 45 + .../src/util/nchan_benchmark.c | 804 +++ .../src/util/nchan_benchmark.h | 91 + .../src/util/nchan_bufchainpool.c | 237 + .../src/util/nchan_bufchainpool.h | 56 + .../src/util/nchan_channel_id.c | 316 + .../src/util/nchan_channel_id.h | 6 + .../src/util/nchan_debug.c | 81 + .../src/util/nchan_debug.h | 13 + .../src/util/nchan_fake_request.c | 524 ++ .../src/util/nchan_fake_request.h | 58 + .../src/util/nchan_list.c | 175 + .../src/util/nchan_list.h | 54 + .../src/util/nchan_msg.c | 773 +++ .../src/util/nchan_msg.h | 35 + .../src/util/nchan_output.c | 670 ++ .../src/util/nchan_output.h | 30 + .../src/util/nchan_output_info.c | 284 + .../src/util/nchan_output_info.h | 6 + .../src/util/nchan_rbtree.c | 379 ++ .../src/util/nchan_rbtree.h | 64 + .../src/util/nchan_reaper.c | 320 + .../src/util/nchan_reaper.h | 33 + .../src/util/nchan_reuse_queue.c | 151 + .../src/util/nchan_reuse_queue.h | 24 + .../src/util/nchan_slist.c | 164 + .../src/util/nchan_slist.h | 41 + .../src/util/nchan_stats.c | 103 + .../src/util/nchan_stats.h | 48 + .../src/util/nchan_subrequest.c | 325 + .../src/util/nchan_subrequest.h | 6 + .../src/util/nchan_thingcache.c | 209 + .../src/util/nchan_thingcache.h | 4 + .../src/util/nchan_timequeue.c | 137 + .../src/util/nchan_timequeue.h | 37 + .../src/util/nchan_util.c | 1334 ++++ .../src/util/nchan_util.h | 86 + .../src/util/ngx_nchan_hacked_slab.c | 770 +++ .../src/util/ngx_nchan_hacked_slab.h | 26 + .../src/util/shmem.c | 223 + .../src/util/shmem.h | 33 + src/core/nginx.c | 24 +- src/event/ngx_event_openssl.c | 32 + src/os/unix/ngx_daemon.c | 8 +- src/os/unix/ngx_posix_config.h | 5 +- 687 files changed, 145455 insertions(+), 6 deletions(-) create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.gitmodules create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.travis.yml create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/CONTRIBUTING.md create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/LICENSE create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/README.md create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/config create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/control create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/gbp.conf create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-filter.install create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-static.install create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/0001-Fix-Vary-header.patch create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/series create mode 100755 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/rules create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/filter create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/static create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/watch create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/config create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/ngx_http_brotli_filter_module.c create mode 100755 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-before-test.sh create mode 100755 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-compile.sh create mode 100755 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-test.sh create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test.conf create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test_h2.conf create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/config create mode 100644 modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/ngx_http_brotli_static_module.c create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/.astylerc create mode 100755 modules_deb/libnginx-mod-http-cache-purge-2.5.3/.format.sh create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/.gitattributes create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/.travis.yml create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/CHANGES create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/LICENSE create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/README.md create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/config create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/control create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/gbp.conf create mode 100755 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/rules create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/purgetest create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/watch create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/ngx_cache_purge_module.c create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1.t create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1_vars.t create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2.t create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2_vars.t create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy3.t create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy4.t create mode 100644 modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/resptype1.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/.gitattributes create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/.gitignore create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/.travis.yml create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/LICENSE create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/README.markdown create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/config create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/control create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/fix.scanned.copyright create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/gbp.conf create mode 100755 modules_deb/libnginx-mod-http-echo-0.63/debian/rules create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/tests/helloworld create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/debian/watch create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ddebug.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.c create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.h create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/abort-parent.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/blocking-sleep.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/echo-after-body.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/echo-before-body.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/echo-duplicate.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/echo-timer.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/echo.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/exec.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/filter-used.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/foreach-split.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/gzip.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/if.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/incr.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/location-async.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/location.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/mixed.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/request-body.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/request-info.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/sleep.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/status.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/subrequest-async.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/subrequest.t create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/t/unused.t create mode 100755 modules_deb/libnginx-mod-http-echo-0.63/util/build.sh create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/util/wiki2pod.pl create mode 100644 modules_deb/libnginx-mod-http-echo-0.63/valgrind.suppress create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/LICENSE create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/README.md create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/config create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/control create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/gbp.conf create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-http-geoip2.install create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-stream-geoip2.install create mode 100755 modules_deb/libnginx-mod-http-geoip2-3.4/debian/rules create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/debian/watch create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/ngx_http_geoip2_module.c create mode 100644 modules_deb/libnginx-mod-http-geoip2-3.4/ngx_stream_geoip2_module.c create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitattributes create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitignore create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/.travis.yml create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/LICENSE create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/README.markdown create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/config create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/control create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/gbp.conf create mode 100755 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/rules create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/helloworld create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/watch create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ddebug.h create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.c create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.h create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.c create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.h create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.c create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.h create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.c create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.h create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/bug.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/builtin.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/eval.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-conn.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-cookie.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-ua.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/phase.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/sanity.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/subrequest.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/unused.t create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/vars.t create mode 100755 modules_deb/libnginx-mod-http-headers-more-filter-0.38/util/build.sh create mode 100644 modules_deb/libnginx-mod-http-headers-more-filter-0.38/valgrind.suppress create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/.gitignore create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/LICENSE create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/README.md create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/README_AUTO_LIB.md create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/array create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/palloc create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/build create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_replacements create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_types create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_args create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_locs create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_macros create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/contexts create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/header_files create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/headers create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/module_dependencies create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/modules_optional create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/prefixes create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/array.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_cmd_basic.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_merge.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/palloc.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/auto/text/autogen create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/config create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/control create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright-scan-patterns.yml create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/fix.scanned.copyright create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/gbp.conf create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk-dev.install create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.install create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.nginx create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/mod-http-ndk.conf create mode 100755 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/rules create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/debian/watch create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/action_macros create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/conf_cmds create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/docs/modules/set_var create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/docs/patches/more_logging_info create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/docs/upstream/list create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/examples/README create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/config create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/ngx_http_set_var_examples_module.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/ngx_auto_lib_core create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/notes/CHANGES create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/notes/LICENSE create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_array.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_basic.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_extra.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_merge.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_includes.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_palloc.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/patches/auto_config create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/patches/expose_rewrite_functions create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/patches/rewrite_phase_handler create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/md5.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/murmurhash2.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/sha.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http_headers.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_parse.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string_util.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.h create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.c create mode 100644 modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/.gitattributes create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/.gitignore create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/.travis.yml create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/README.markdown create mode 100755 modules_deb/libnginx-mod-http-set-misc-0.33/config create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/control create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright-scan-patterns.yml create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/fix.scanned.copyright create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/gbp.conf create mode 100755 modules_deb/libnginx-mod-http-set-misc-0.33/debian/rules create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/setifempty create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/debian/watch create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ddebug.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.c create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.h create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/base32.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/base32_no_padding.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/base64.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/base64url.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/default-value.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/escape-uri.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/formatted-time.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/hash.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/hashed-upstream.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/hex.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/hmac.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/local-today.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-json.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-sql.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/rand.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/rotate.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/secure-random.t create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/t/unescape-uri.t create mode 100755 modules_deb/libnginx-mod-http-set-misc-0.33/util/build.sh create mode 100644 modules_deb/libnginx-mod-http-set-misc-0.33/valgrind.suppress create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitattributes create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitignore create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/.travis.yml create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/Changes create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/README.markdown create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/config create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/control create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/fix.scanned.copyright create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/gbp.conf create mode 100755 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/rules create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/debian/watch create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ddebug.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_fetch.c create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_fetch.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_filter_module.c create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_filter_module.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_headers.c create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_headers.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_store.c create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_store.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_util.c create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_util.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_var.c create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/src/ngx_http_srcache_var.h create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/000_init.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/access.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/bugs.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/conditional-get.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/content-length.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/content-type.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/disk.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/drizzle-main.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/drizzle-sub.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/empty-resp.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/err-page.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/etag.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/eval.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/expire-var.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/expires.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/fetch-header.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/fetch-skip.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/gzip.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/header-buf-size.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/main-req.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/max-age.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/methods.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/no-cache.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/no-store.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/postgres-main.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/private.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/proxy.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/ranges.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/redis.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/req-cache-control.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/satisfy.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/static.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/status.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/store-hide-headers.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/store-max-size.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/store-pass-headers.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/store-skip.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/sub-req.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/timeout.t create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/t/unused.t create mode 100755 modules_deb/libnginx-mod-http-srcache-filter-0.33/util/build.sh create mode 100644 modules_deb/libnginx-mod-http-srcache-filter-0.33/valgrind.suppress create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/CHANGES create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/README create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/config create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/control create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/gbp.conf create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/patches/0001-Feature-nginx-dynamic-module-support.patch create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/patches/0002-check-content-encoding-header-more-carefully.patch create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/patches/0003-PCRE2-support-added.patch create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/patches/series create mode 100755 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/rules create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/debian/watch create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/doc/README.google_code_home_page.wiki create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/doc/README.html create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/doc/README.wiki create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/ngx_http_subs_filter_module.c create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/README create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/AutoInstall.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/AutoInstall.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Base.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Can.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Fetch.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Include.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Makefile.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Metadata.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/TestBase.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/Win32.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Module/Install/WriteAll.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Spiffy.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Test/Base.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Test/Base/Filter.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Test/Builder.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Test/Builder/Module.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/inc/Test/More.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/lib/Test/Nginx.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/lib/Test/Nginx/LWP.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/lib/Test/Nginx/Socket.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/lib/Test/Nginx/Util.pm create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/t/subs.t create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/t/subs_capture.t create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/t/subs_fix_string.t create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/t/subs_regex.t create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/t/subs_types.t create mode 100755 modules_deb/libnginx-mod-http-subs-filter-0.6.4/test/test.sh create mode 100755 modules_deb/libnginx-mod-http-subs-filter-0.6.4/util/update-readme.sh create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/util/wiki2google_code_homepage.pl create mode 100644 modules_deb/libnginx-mod-http-subs-filter-0.6.4/util/wiki2pod.pl create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/.gdbinit create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/README create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/config create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/changelog create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/control create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/copyright create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/gbp.conf create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/patches/drop-default-port.patch create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/patches/dynamic-module.patch create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/patches/openssl-1.1.0.patch create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/patches/series create mode 100755 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/rules create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/source/format create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/tests/control create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/debian/watch create mode 100644 modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409/ngx_http_upstream_fair_module.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/LICENCE create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/README.md create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/changelog.txt create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/cloc-exclude.txt create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/config create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/changelog create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/control create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/copyright create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/fix.scanned.copyright create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/gbp.conf create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/rules create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/source/format create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/source/options create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/tests/control create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/tests/generic create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/upstream/metadata create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/debian/watch create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/.gitignore create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_commands.rb create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_config_commands.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_defs.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_defs.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_module.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_module.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_setup.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_types.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_variables.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_variables.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_version.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_websocket_publisher.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/nchan_websocket_publisher.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/groups.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/groups.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/ipc-handlers.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/ipc-handlers.h create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/ipc.c create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/ipc.h create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/memstore.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/recycloc.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/store-private.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/memory/store.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/ngx_rwlock.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/ngx_rwlock.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/cmp.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/cmp.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/.gitignore create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/.travis.yml create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/CHANGELOG.md create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/COPYING create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/README.md create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/alloc.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/alloc.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/async.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/async.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/async_private.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/dict.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/dict.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/fmacros.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/hiredis.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/hiredis.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/hiredis_ssl.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/net.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/net.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/read.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/read.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/sds.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/sds.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/sdsalloc.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/sockcompat.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/sockcompat.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/ssl.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/test.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/hiredis/win32.h create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/rdsstore.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/.gitignore create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/Gemfile create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/add_fakesub.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/channel_keepalive.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/delete.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/find_channel.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/get_message.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/get_message_from_key.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/get_subscriber_info_id.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/nostore_publish_multiexec_channel_info.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/publish.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/request_subscriber_info.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/rsck.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/subscriber_register.lua create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/subscriber_unregister.lua create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis-lua-scripts/testscripts.rb create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_lua_commands.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_lua_commands.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nginx_adapter.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nginx_adapter.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nodeset.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nodeset.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nodeset_parser.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nodeset_parser.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/redis_nodeset_stats.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/store-private.h create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/redis/store.h create mode 100755 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/spool.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/spool.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/store_common.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/store/store_common.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/benchmark.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/benchmark.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/common.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/common.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/eventsource.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/eventsource.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/getmsg_proxy.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/getmsg_proxy.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/http-chunked.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/http-chunked.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/http-multipart-mixed.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/http-multipart-mixed.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/http-raw-stream.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/http-raw-stream.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/internal.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/internal.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/intervalpoll.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/intervalpoll.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/longpoll-private.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/longpoll.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/longpoll.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/memstore_ipc.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/memstore_ipc.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/memstore_multi.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/memstore_multi.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/memstore_redis.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/memstore_redis.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/websocket.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/subscribers/websocket.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/uthash.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/hdr_histogram.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/hdr_histogram.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_accumulator.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_accumulator.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_benchmark.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_benchmark.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_bufchainpool.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_bufchainpool.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_channel_id.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_channel_id.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_debug.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_debug.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_fake_request.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_fake_request.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_list.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_list.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_msg.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_msg.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_output.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_output.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_output_info.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_output_info.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_rbtree.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_rbtree.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_reaper.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_reaper.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_reuse_queue.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_reuse_queue.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_slist.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_slist.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_stats.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_stats.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_subrequest.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_subrequest.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_thingcache.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_thingcache.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_timequeue.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_timequeue.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_util.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/nchan_util.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/ngx_nchan_hacked_slab.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/ngx_nchan_hacked_slab.h create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/shmem.c create mode 100644 modules_deb/libnginx-mod-nchan-1.3.7+dfsg/src/util/shmem.h diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.gitmodules b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.gitmodules new file mode 100644 index 0000000..694f088 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/brotli"] + path = deps/brotli + url = https://github.com/google/brotli.git diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.travis.yml b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.travis.yml new file mode 100644 index 0000000..57d2b8a --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/.travis.yml @@ -0,0 +1,46 @@ +# required for http2 support in curl. +dist: bionic +language: c +sudo: false +matrix: + include: + # unfortunately, gcc-4.9 is dropped in bionic + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: + - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + + +script: +- script/.travis-compile.sh +- script/.travis-before-test.sh +- script/.travis-test.sh +after_success: +- killall nginx +after_failure: +- killall nginx + diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/CONTRIBUTING.md b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/CONTRIBUTING.md new file mode 100644 index 0000000..a9eabff --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing + +Want to contribute? Great! First, read this page (including the small print at the end). + +### Before you contribute +Before we can use your code, you must sign the +[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) +(CLA), which you can do online. The CLA is necessary mainly because you own the +copyright to your changes, even after your contribution becomes part of our +codebase, so we need your permission to use and distribute your code. We also +need to be sure of various other things—for instance that you'll tell us if you +know that your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Code reviews +All submissions, including submissions by project members, require review. We +use Github pull requests for this purpose. + +### The small print +Contributions made by corporations are covered by a different agreement than +the one above, the +[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/LICENSE b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/LICENSE new file mode 100644 index 0000000..db3aca7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/LICENSE @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2002-2015 Igor Sysoev + * Copyright (C) 2011-2015 Nginx, Inc. + * Copyright (C) 2015-2019 Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/README.md b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/README.md new file mode 100644 index 0000000..80428e9 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/README.md @@ -0,0 +1,177 @@ +# ngx_brotli + +Brotli is a generic-purpose lossless compression algorithm that compresses data +using a combination of a modern variant of the LZ77 algorithm, Huffman coding +and 2nd order context modeling, with a compression ratio comparable to the best +currently available general-purpose compression methods. It is similar in speed +with deflate but offers more dense compression. + +ngx_brotli is a set of two nginx modules: + +- ngx_brotli filter module - used to compress responses on-the-fly, +- ngx_brotli static module - used to serve pre-compressed files. + +[![TravisCI Build Status](https://travis-ci.org/google/ngx_brotli.svg?branch=master)](https://travis-ci.org/google/ngx_brotli) + +## Table of Contents + +- [Status](#status) +- [Installation](#installation) +- [Configuration directives](#configuration-directives) + - [`brotli_static`](#brotli_static) + - [`brotli`](#brotli) + - [`brotli_types`](#brotli_types) + - [`brotli_buffers`](#brotli_buffers) + - [`brotli_comp_level`](#brotli_comp_level) + - [`brotli_window`](#brotli_window) + - [`brotli_min_length`](#brotli_min_length) +- [Variables](#variables) + - [`$brotli_ratio`](#brotli_ratio) +- [Sample configuration](#sample-configuration) +- [Contributing](#contributing) +- [License](#license) + +## Status + +Both Brotli library and nginx module are under active development. + +## Installation + +### Dynamically loaded + + $ cd nginx-1.x.x + $ ./configure --with-compat --add-dynamic-module=/path/to/ngx_brotli + $ make modules + +You will need to use **exactly** the same `./configure` arguments as your Nginx configuration and append `--with-compat --add-dynamic-module=/path/to/ngx_brotli` to the end, otherwise you will get a "module is not binary compatible" error on startup. You can run `nginx -V` to get the configuration arguments for your Nginx installation. + +`make modules` will result in `ngx_http_brotli_filter_module.so` and `ngx_http_brotli_static_module.so` in the `objs` directory. Copy these to `/usr/lib/nginx/modules/` then add the `load_module` directives to `nginx.conf` (above the http block): +```nginx +load_module modules/ngx_http_brotli_filter_module.so; +load_module modules/ngx_http_brotli_static_module.so; +``` + +### Statically compiled + + $ cd nginx-1.x.x + $ ./configure --add-module=/path/to/ngx_brotli + $ make && make install + +This will compile the module directly into Nginx. + +## Configuration directives + +### `brotli_static` + +- **syntax**: `brotli_static on|off|always` +- **default**: `off` +- **context**: `http`, `server`, `location` + +Enables or disables checking of the existence of pre-compressed files with`.br` +extension. With the `always` value, pre-compressed file is used in all cases, +without checking if the client supports it. + +### `brotli` + +- **syntax**: `brotli on|off` +- **default**: `off` +- **context**: `http`, `server`, `location`, `if` + +Enables or disables on-the-fly compression of responses. + +### `brotli_types` + +- **syntax**: `brotli_types [..]` +- **default**: `text/html` +- **context**: `http`, `server`, `location` + +Enables on-the-fly compression of responses for the specified MIME types +in addition to `text/html`. The special value `*` matches any MIME type. +Responses with the `text/html` MIME type are always compressed. + +### `brotli_buffers` + +- **syntax**: `brotli_buffers ` +- **default**: `32 4k|16 8k` +- **context**: `http`, `server`, `location` + +**Deprecated**, ignored. + +### `brotli_comp_level` + +- **syntax**: `brotli_comp_level ` +- **default**: `6` +- **context**: `http`, `server`, `location` + +Sets on-the-fly compression Brotli quality (compression) `level`. +Acceptable values are in the range from `0` to `11`. + +### `brotli_window` + +- **syntax**: `brotli_window ` +- **default**: `512k` +- **context**: `http`, `server`, `location` + +Sets Brotli window `size`. Acceptable values are `1k`, `2k`, `4k`, `8k`, `16k`, +`32k`, `64k`, `128k`, `256k`, `512k`, `1m`, `2m`, `4m`, `8m` and `16m`. + +### `brotli_min_length` + +- **syntax**: `brotli_min_length ` +- **default**: `20` +- **context**: `http`, `server`, `location` + +Sets the minimum `length` of a response that will be compressed. +The length is determined only from the `Content-Length` response header field. + +## Variables + +### `$brotli_ratio` + +Achieved compression ratio, computed as the ratio between the original +and compressed response sizes. + +## Sample configuration + +``` +brotli on; +brotli_comp_level 6; +brotli_static on; +brotli_types application/atom+xml application/javascript application/json application/rss+xml + application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype + application/x-font-ttf application/x-javascript application/xhtml+xml application/xml + font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon + image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; +``` + +## Contributing + +See [Contributing](CONTRIBUTING.md). + +## License + + Copyright (C) 2002-2015 Igor Sysoev + Copyright (C) 2011-2015 Nginx, Inc. + Copyright (C) 2015 Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/config b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/config new file mode 100644 index 0000000..42162a6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/config @@ -0,0 +1,34 @@ +# Copyright (C) 2019 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# Make sure the module knows it is a submodule. +ngx_addon_name=ngx_brotli +. $ngx_addon_dir/filter/config + +# Make sure the module knows it is a submodule. +ngx_addon_name=ngx_brotli +. $ngx_addon_dir/static/config + +# The final name for reporting. +ngx_addon_name=ngx_brotli diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/changelog b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/changelog new file mode 100644 index 0000000..c7021b7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/changelog @@ -0,0 +1,49 @@ +libnginx-mod-http-brotli (1.0.0~rc-6) unstable; urgency=medium + + * d/control: update my email to janmojzis@debian.org + * d/copyright: update my email to janmojzis@debian.org + * d/control: bump Standards-Version: 4.7.2, no changes + * d/copyright: bump debian/* copyright year + * d/watch: use more generic template + + -- Jan Mojžíš Fri, 11 Apr 2025 14:26:55 +0200 + +libnginx-mod-http-brotli (1.0.0~rc-5) unstable; urgency=medium + + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + + -- Jan Mojžíš Sat, 07 Oct 2023 15:31:24 +0200 + +libnginx-mod-http-brotli (1.0.0~rc-4) unstable; urgency=medium + + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Tue, 27 Jun 2023 23:16:35 +0200 + +libnginx-mod-http-brotli (1.0.0~rc-3) unstable; urgency=medium + + * d/watch: updated uversionmangle to be more generic + * d/copyright: reformat text to be compatible with 'cme update dpkg-copyright' + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 12:56:11 +0100 + +libnginx-mod-http-brotli (1.0.0~rc-2) unstable; urgency=medium + + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/p/0001-Fix-Vary-header.patch added (Closes: 1028153) + "brotli_static on;" causes "Vary: Accept-Encoding" to be added to every + file (including images, ...) + The patch fixes the problem and adds "Vary: Accept-Encoding" only to + responses when brotli static compression is used. + * d/changelog: bump my copyright year + + -- Jan Mojžíš Fri, 13 Jan 2023 17:45:13 +0100 + +libnginx-mod-http-brotli (1.0.0~rc-1) unstable; urgency=medium + + * Initial release. (Closes: 1025515) + + -- Jan Mojžíš Tue, 06 Dec 2022 10:25:40 +0100 diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/control b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/control new file mode 100644 index 0000000..6e5752d --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/control @@ -0,0 +1,41 @@ +Source: libnginx-mod-http-brotli +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jan Mojžíš , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, + libbrotli-dev, +Standards-Version: 4.7.2 +Homepage: https://github.com/google/ngx_brotli +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-brotli.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-brotli +Rules-Requires-Root: no + +Package: libnginx-mod-http-brotli-filter +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Description: Brotli lossless compression support for Nginx - filter + Brotli is a generic-purpose lossless compression algorithm that compresses + data using a combination of a modern variant of the LZ77 algorithm, Huffman + coding and 2nd order context modeling, with a compression ratio comparable + to the best currently available general-purpose compression methods. It is + similar in speed with deflate but offers more dense compression. + . + ngx_brotli filter module - used to compress responses on-the-fly + +Package: libnginx-mod-http-brotli-static +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Description: Brotli lossless compression support for Nginx - static + Brotli is a generic-purpose lossless compression algorithm that compresses + data using a combination of a modern variant of the LZ77 algorithm, Huffman + coding and 2nd order context modeling, with a compression ratio comparable + to the best currently available general-purpose compression methods. It is + similar in speed with deflate but offers more dense compression. + . + ngx_brotli static module - used to serve pre-compressed files diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/copyright b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/copyright new file mode 100644 index 0000000..2ecfff5 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/copyright @@ -0,0 +1,72 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ngx-brotli +Source: https://github.com/google/ngx_brotli + +Files: * +Copyright: 2015-2019, Google Inc. + 2011-2015, Nginx, Inc. + 2002-2015, Igor Sysoev +License: BSD-2-clause + +Files: CONTRIBUTING.md +Copyright: Copyright (C) 2015 Google Inc. + Copyright (C) 2011-2015 Nginx, Inc. + Copyright (C) 2002-2015 Igor Sysoev +License: BSD-2-clause + +Files: config +Copyright: 2015-2019, Google Inc. +License: BSD-2-clause + +Files: debian/* +Copyright: 2022, Miao Wang + 2022-2025, Jan Mojzis +License: BSD-2-clause + +Files: filter/* +Copyright: 2015-2019, Google Inc. +License: BSD-2-clause + +Files: filter/ngx_http_brotli_filter_module.c +Copyright: Nginx, Inc. + Igor Sysoev + Google Inc. +License: BSD-2-clause + +Files: script/* +Copyright: Copyright (C) 2015 Google Inc. + Copyright (C) 2011-2015 Nginx, Inc. + Copyright (C) 2002-2015 Igor Sysoev +License: BSD-2-clause + +Files: static/* +Copyright: 2015-2019, Google Inc. +License: BSD-2-clause + +Files: static/ngx_http_brotli_static_module.c +Copyright: Nginx, Inc. + Igor Sysoev + Google Inc. +License: BSD-2-clause + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/gbp.conf b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/gbp.conf new file mode 100644 index 0000000..38c12c1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/gbp.conf @@ -0,0 +1,9 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-filter.install b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-filter.install new file mode 100644 index 0000000..5fcd39d --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-filter.install @@ -0,0 +1 @@ +/usr/lib/nginx/modules/ngx_http_brotli_filter_module.so diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-static.install b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-static.install new file mode 100644 index 0000000..dd4a44e --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/libnginx-mod-http-brotli-static.install @@ -0,0 +1 @@ +/usr/lib/nginx/modules/ngx_http_brotli_static_module.so diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/0001-Fix-Vary-header.patch b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/0001-Fix-Vary-header.patch new file mode 100644 index 0000000..09735a7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/0001-Fix-Vary-header.patch @@ -0,0 +1,38 @@ +From: Jan Mojzis +Date: Fri, 13 Jan 2023 12:59:07 +0100 +Subject: Fix 'Vary' header + +The patch fixes problem described here: +https://github.com/google/ngx_brotli/issues/97 + +"brotli_static on;" causes "Vary: Accept-Encoding" to be added to every +file (including images, ...) +The patch fixes the problem and adds "Vary: Accept-Encoding" only to +responses when brotli static compression is used. +--- + static/ngx_http_brotli_static_module.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/static/ngx_http_brotli_static_module.c b/static/ngx_http_brotli_static_module.c +index 8f96177..44f0cb0 100644 +--- a/static/ngx_http_brotli_static_module.c ++++ b/static/ngx_http_brotli_static_module.c +@@ -168,7 +168,6 @@ static ngx_int_t handler(ngx_http_request_t* req) { + /* Ignore request properties (e.g. Accept-Encoding). */ + } else { + /* NGX_HTTP_BROTLI_STATIC_ON */ +- req->gzip_vary = 1; + rc = check_eligility(req); + if (rc != NGX_OK) return NGX_DECLINED; + } +@@ -227,6 +226,10 @@ static ngx_int_t handler(ngx_http_request_t* req) { + return NGX_DECLINED; + } + ++ if (cfg->enable == NGX_HTTP_BROTLI_STATIC_ON) { ++ req->gzip_vary = 1; ++ } ++ + /* So far so good. */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", + file_info.fd); diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/series b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/series new file mode 100644 index 0000000..dfd7340 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/patches/series @@ -0,0 +1 @@ +0001-Fix-Vary-header.patch diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/rules b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/rules new file mode 100755 index 0000000..d8309f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/source/format b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/control b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/control new file mode 100644 index 0000000..de69689 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/control @@ -0,0 +1,22 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, + +Tests: static +Restrictions: allow-stderr isolation-container needs-root +Depends: brotli, + curl, + libnginx-mod-http-brotli-static, + nginx, + nginx-core, + +Tests: filter +Restrictions: allow-stderr isolation-container needs-root +Depends: brotli, + curl, + libnginx-mod-http-brotli-filter, + nginx, + nginx-core, diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/filter b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/filter new file mode 100644 index 0000000..16ac356 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/filter @@ -0,0 +1,44 @@ +#!/bin/sh +set -e + +cat < "/etc/nginx/sites-enabled/default" +server { + listen 80 default_server; + root /var/www/html; + + location /helloworld { + default_type text/plain; + brotli on; + brotli_types text/plain; + brotli_min_length 10; + brotli_comp_level 11; + } +} +EOF + +mkdir -p /var/www/html +echo 'hello world' > /var/www/html/helloworld + +exp="content-encoding: br +hello world +response_code: 200" + +nginx -t +invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; } + +out=`curl --compressed --fail -D- -w "response_code: %{http_code}\n" http://127.0.0.1/helloworld` +out=`echo "${out}" | sed 's/\r//'` +out=`echo "${out}" | awk '{print tolower($0)}'` +out=`echo "${out}" | grep '^content-encoding: \|^hello world$\|response_code: '` + +if [ x"${out}" != x"${exp}" ]; then + echo "output:" + echo "=====================" + echo "${out}" + echo "=====================" + echo "expected output:" + echo "=====================" + echo "${exp}" + echo "=====================" + exit 1 +fi diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/generic b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/static b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/static new file mode 100644 index 0000000..bce1fbc --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/tests/static @@ -0,0 +1,36 @@ +#!/bin/sh +set -e + +cat < "/etc/nginx/sites-enabled/default" +server { + listen 80 default_server; + root /var/www/html; + + location /helloworld { + brotli_static on; + } +} +EOF + +mkdir -p /var/www/html +echo 'hello world' | brotli -9 > /var/www/html/helloworld.br + +exp="hello world +response_code: 200" + +nginx -t +invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; } + +out=`curl --compressed --fail -w "response_code: %{http_code}\n" http://127.0.0.1/helloworld` + +if [ x"${out}" != x"${exp}" ]; then + echo "output:" + echo "=====================" + echo "${out}" + echo "=====================" + echo "expected output:" + echo "=====================" + echo "${exp}" + echo "=====================" + exit 1 +fi diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/upstream/metadata b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/upstream/metadata new file mode 100644 index 0000000..30627c6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/google/ngx_brotli/issues +Bug-Submit: https://github.com/google/ngx_brotli/issues/new +Repository-Browse: https://github.com/google/ngx_brotli diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/watch b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/watch new file mode 100644 index 0000000..08b8983 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/google/ngx_brotli/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/config b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/config new file mode 100644 index 0000000..9c27fc7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/config @@ -0,0 +1,132 @@ +# Copyright (C) 2015-2016 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +if [ "$ngx_addon_name" = "ngx_brotli" ]; then + BROTLI_MODULE_SRC_DIR="$ngx_addon_dir/filter" +else + BROTLI_MODULE_SRC_DIR="$ngx_addon_dir" +fi + +ngx_addon_name=ngx_brotli_filter + +if [ -z "$ngx_module_link" ]; then +cat << END + +$0: error: Brotli module requires recent version of NGINX (1.9.11+). + +END + exit 1 +fi + +ngx_module_type=HTTP_FILTER +ngx_module_name=ngx_http_brotli_filter_module + +brotli="$ngx_addon_dir/deps/brotli/c" +if [ ! -f "$brotli/include/brotli/encode.h" ]; then + brotli="/usr/local" +fi +if [ ! -f "$brotli/include/brotli/encode.h" ]; then + brotli="/usr" +fi +if [ ! -f "$brotli/include/brotli/encode.h" ]; then +cat << END + +$0: error: \ +Brotli library is missing from the $brotli directory. + +Please make sure that the git submodule has been checked out: + + cd $ngx_addon_dir && git submodule update --init && cd $PWD + +END + exit 1 +fi + +BROTLI_LISTS_FILE="$brotli/../scripts/sources.lst" + +if [ -f "$BROTLI_LISTS_FILE" ]; then + +BROTLI_LISTS=`cat "$BROTLI_LISTS_FILE" | grep -v "#" | tr '\n' '#' | \ + sed 's/\\\\#//g' | tr -s ' ' '+' | tr -s '#' ' ' | \ + sed 's/+c/+$brotli/g' | sed 's/+=+/=/g'` +for ITEM in ${BROTLI_LISTS}; do + VAR=`echo $ITEM | sed 's/=.*//'` + VAL=`echo $ITEM | sed 's/.*=//' | tr '+' ' '` + eval ${VAR}=\"$VAL\" +done + +else # BROTLI_LISTS_FILE + +BROTLI_ENC_H="$brotli/include/brotli/encode.h \ + $brotli/include/brotli/port.h \ + $brotli/include/brotli/types.h" +BROTLI_ENC_LIB="-lbrotlienc" + +fi + +ngx_module_incs="$brotli/include" +ngx_module_deps="$BROTLI_COMMON_H $BROTLI_ENC_H" +ngx_module_srcs="$BROTLI_COMMON_C $BROTLI_ENC_C \ + $BROTLI_MODULE_SRC_DIR/ngx_http_brotli_filter_module.c" +ngx_module_libs="$BROTLI_ENC_LIB -lm" +ngx_module_order="$ngx_module_name \ + ngx_pagespeed \ + ngx_http_postpone_filter_module \ + ngx_http_ssi_filter_module \ + ngx_http_charset_filter_module \ + ngx_http_xslt_filter_module \ + ngx_http_image_filter_module \ + ngx_http_sub_filter_module \ + ngx_http_addition_filter_module \ + ngx_http_gunzip_filter_module \ + ngx_http_userid_filter_module \ + ngx_http_headers_filter_module \ + ngx_http_copy_filter_module \ + ngx_http_range_body_filter_module \ + ngx_http_not_modified_filter_module \ + ngx_http_slice_filter_module" + +. auto/module + +if [ "$ngx_module_link" != DYNAMIC ]; then + # ngx_module_order doesn't work with static modules, + # so we must re-order filters here. + + if [ "$HTTP_GZIP" = YES ]; then + next=ngx_http_gzip_filter_module + elif echo $HTTP_FILTER_MODULES | grep pagespeed_etag_filter >/dev/null; then + next=ngx_pagespeed_etag_filter + else + next=ngx_http_range_header_filter_module + fi + + HTTP_FILTER_MODULES=`echo $HTTP_FILTER_MODULES \ + | sed "s/$ngx_module_name//" \ + | sed "s/$next/$next $ngx_module_name/"` +fi + +CFLAGS="$CFLAGS -Wno-deprecated-declarations" + +have=NGX_HTTP_BROTLI_FILTER . auto/have +have=NGX_HTTP_BROTLI_FILTER_MODULE . auto/have # deprecated diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/ngx_http_brotli_filter_module.c b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/ngx_http_brotli_filter_module.c new file mode 100644 index 0000000..592b767 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/filter/ngx_http_brotli_filter_module.c @@ -0,0 +1,770 @@ +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + * Copyright (C) Google Inc. + */ + +#include +#include +#include + +#if (NGX_HAVE_BROTLI_ENC_ENCODE_H) +#include +#else +#include +#endif + +/* Brotli and GZip modules never stack, i.e. when one of them sets + "Content-Encoding" the other becomes a pass-through filter. Consequently, + it is almost legal to reuse this "buffered" bit. + IIUC, buffered == some data passed to filter has not been pushed further. */ +#define NGX_HTTP_BROTLI_BUFFERED NGX_HTTP_GZIP_BUFFERED + +/* Module configuration. */ +typedef struct { + ngx_flag_t enable; + + /* Supported MIME types. */ + ngx_hash_t types; + ngx_array_t* types_keys; + + /* Minimal required length for compression (if known). */ + ssize_t min_length; + + ngx_bufs_t deprecated_unused_bufs; + + /* Brotli encoder parameter: quality */ + ngx_int_t quality; + + /* Brotli encoder parameter: (max) lg_win */ + size_t lg_win; +} ngx_http_brotli_conf_t; + +/* Instance context. */ +typedef struct { + /* Brotli encoder instance. */ + BrotliEncoderState* encoder; + + /* Payload length; -1, if unknown. */ + off_t content_length; + + /* (uncompressed) bytes pushed to encoder. */ + size_t bytes_in; + /* (compressed) bytes pulled from encoder. */ + size_t bytes_out; + + /* Input buffer chain. */ + ngx_chain_t* in; + + /* Output chain. */ + ngx_chain_t* out_chain; + + /* Output buffer. */ + ngx_buf_t* out_buf; + + /* Various state flags. */ + + /* 1 if encoder is initialized, output chain and buffer are allocated. */ + unsigned initialized : 1; + /* 1 if compression is finished / failed. */ + unsigned closed : 1; + /* 1 if compression is finished. */ + unsigned success : 1; + + /* 1 if out_chain is ready to be committed, 0 otherwise. */ + unsigned output_ready : 1; + /* 1 if output buffer is committed to the next filter and not yet fully used. + 0 otherwise. */ + unsigned output_busy : 1; + + unsigned end_of_input : 1; + unsigned end_of_block : 1; + + ngx_http_request_t* request; +} ngx_http_brotli_ctx_t; + +/* Forward declarations. */ + +/* Initializes encoder, output chain and buffer, if necessary. Returns NGX_OK + if encoder is successfully initialized (have been already initialized), + and requires objects are allocated. Returns NGX_ERROR otherwise. */ +static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized( + ngx_http_request_t* r, ngx_http_brotli_ctx_t* ctx); +/* Marks instance as closed and performs cleanup. */ +static void ngx_http_brotli_filter_close(ngx_http_brotli_ctx_t* ctx); + +static void* ngx_http_brotli_filter_alloc(void* opaque, size_t size); +static void ngx_http_brotli_filter_free(void* opaque, void* address); + +static ngx_int_t ngx_http_brotli_check_request(ngx_http_request_t* r); + +static ngx_int_t ngx_http_brotli_add_variables(ngx_conf_t* cf); +static ngx_int_t ngx_http_brotli_ratio_variable(ngx_http_request_t* r, + ngx_http_variable_value_t* v, + uintptr_t data); + +static void* ngx_http_brotli_create_conf(ngx_conf_t* cf); +static char* ngx_http_brotli_merge_conf(ngx_conf_t* cf, void* parent, + void* child); +static ngx_int_t ngx_http_brotli_filter_init(ngx_conf_t* cf); + +static char* ngx_http_brotli_parse_wbits(ngx_conf_t* cf, void* post, + void* data); + +/* Configuration literals. */ + +static ngx_conf_num_bounds_t ngx_http_brotli_comp_level_bounds = { + ngx_conf_check_num_bounds, BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY}; + +static ngx_conf_post_handler_pt ngx_http_brotli_parse_wbits_p = + ngx_http_brotli_parse_wbits; + +static ngx_command_t ngx_http_brotli_filter_commands[] = { + {ngx_string("brotli"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | + NGX_HTTP_LIF_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_brotli_conf_t, enable), NULL}, + + /* Deprecated, unused. */ + {ngx_string("brotli_buffers"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | + NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_brotli_conf_t, deprecated_unused_bufs), NULL}, + + {ngx_string("brotli_types"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | + NGX_CONF_1MORE, + ngx_http_types_slot, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_brotli_conf_t, types_keys), + &ngx_http_html_default_types[0]}, + + {ngx_string("brotli_comp_level"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | + NGX_CONF_TAKE1, + ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_brotli_conf_t, quality), + &ngx_http_brotli_comp_level_bounds}, + + {ngx_string("brotli_window"), + 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_brotli_conf_t, lg_win), &ngx_http_brotli_parse_wbits_p}, + + {ngx_string("brotli_min_length"), + 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_brotli_conf_t, min_length), NULL}, + + ngx_null_command}; + +/* Module context hooks. */ +static ngx_http_module_t ngx_http_brotli_filter_module_ctx = { + ngx_http_brotli_add_variables, /* pre-configuration */ + ngx_http_brotli_filter_init, /* post-configuration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_brotli_create_conf, /* create location configuration */ + ngx_http_brotli_merge_conf /* merge location configuration */ +}; + +/* Module descriptor. */ +ngx_module_t ngx_http_brotli_filter_module = { + NGX_MODULE_V1, + &ngx_http_brotli_filter_module_ctx, /* module context */ + ngx_http_brotli_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING}; + +/* Variable names. */ +static ngx_str_t ngx_http_brotli_ratio = ngx_string("brotli_ratio"); + +/* Next filter in the filter chain. */ +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 /* const */ char kEncoding[] = "br"; +static const size_t kEncodingLen = 2; + +static ngx_int_t check_accept_encoding(ngx_http_request_t* req) { + ngx_table_elt_t* accept_encoding_entry; + ngx_str_t* accept_encoding; + u_char* cursor; + u_char* end; + u_char before; + u_char after; + + accept_encoding_entry = req->headers_in.accept_encoding; + if (accept_encoding_entry == NULL) return NGX_DECLINED; + accept_encoding = &accept_encoding_entry->value; + + cursor = accept_encoding->data; + end = cursor + accept_encoding->len; + while (1) { + u_char digit; + /* It would be an idiotic idea to rely on compiler to produce performant + binary, that is why we just do -1 at every call site. */ + cursor = ngx_strcasestrn(cursor, kEncoding, kEncodingLen - 1); + if (cursor == NULL) return NGX_DECLINED; + before = (cursor == accept_encoding->data) ? ' ' : cursor[-1]; + cursor += kEncodingLen; + after = (cursor >= end) ? ' ' : *cursor; + if (before != ',' && before != ' ') continue; + if (after != ',' && after != ' ' && after != ';') continue; + + /* Check for ";q=0[.[0[0[0]]]]" */ + while (*cursor == ' ') cursor++; + if (*(cursor++) != ';') break; + while (*cursor == ' ') cursor++; + if (*(cursor++) != 'q') break; + while (*cursor == ' ') cursor++; + if (*(cursor++) != '=') break; + while (*cursor == ' ') cursor++; + if (*(cursor++) != '0') break; + if (*(cursor++) != '.') return NGX_DECLINED; /* ;q=0, */ + digit = *(cursor++); + if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0., */ + if (digit > '0') break; + digit = *(cursor++); + if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.0, */ + if (digit > '0') break; + digit = *(cursor++); + if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.00, */ + if (digit > '0') break; + return NGX_DECLINED; /* ;q=0.000 */ + } + return NGX_OK; +} + +/* Process headers and decide if request is eligible for brotli compression. */ +static ngx_int_t ngx_http_brotli_header_filter(ngx_http_request_t* r) { + ngx_table_elt_t* h; + ngx_http_brotli_ctx_t* ctx; + ngx_http_brotli_conf_t* conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module); + + /* Filter only if enabled. */ + if (!conf->enable) { + return ngx_http_next_header_filter(r); + } + + /* Only compress OK / forbidden / not found responses. */ + if (r->headers_out.status != NGX_HTTP_OK && + r->headers_out.status != NGX_HTTP_FORBIDDEN && + r->headers_out.status != NGX_HTTP_NOT_FOUND) { + return ngx_http_next_header_filter(r); + } + + /* Bypass "header only" responses. */ + if (r->header_only) { + return ngx_http_next_header_filter(r); + } + + /* Bypass already compressed responses. */ + if (r->headers_out.content_encoding && + r->headers_out.content_encoding->value.len) { + return ngx_http_next_header_filter(r); + } + + /* If response size is known, do not compress tiny responses. */ + if (r->headers_out.content_length_n != -1 && + r->headers_out.content_length_n < conf->min_length) { + return ngx_http_next_header_filter(r); + } + + /* Compress only certain MIME-typed responses. */ + if (ngx_http_test_content_type(r, &conf->types) == NULL) { + return ngx_http_next_header_filter(r); + } + + r->gzip_vary = 1; + + /* Check if client support brotli encoding. */ + if (ngx_http_brotli_check_request(r) != NGX_OK) { + return ngx_http_next_header_filter(r); + } + + /* Prepare instance context. */ + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_brotli_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + ctx->request = r; + ctx->content_length = r->headers_out.content_length_n; + ngx_http_set_ctx(r, ctx, ngx_http_brotli_filter_module); + + /* Prepare response headers, so that following filters in the chain will + notice that response body is compressed. */ + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->hash = 1; + ngx_str_set(&h->key, "Content-Encoding"); + ngx_str_set(&h->value, "br"); + r->headers_out.content_encoding = h; + + r->main_filter_need_in_memory = 1; + + ngx_http_clear_content_length(r); + ngx_http_clear_accept_ranges(r); + ngx_http_weak_etag(r); + + return ngx_http_next_header_filter(r); +} + +/* Response body filtration (compression). */ +static ngx_int_t ngx_http_brotli_body_filter(ngx_http_request_t* r, + ngx_chain_t* in) { + int rc; + ngx_http_brotli_ctx_t* ctx; + size_t available_output; + ptrdiff_t available_busy_output; + size_t input_size; + size_t available_input; + const uint8_t* next_input_byte; + size_t consumed_input; + BROTLI_BOOL ok; + u_char* out; + ngx_chain_t* link; + + ctx = ngx_http_get_module_ctx(r, ngx_http_brotli_filter_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http brotli filter"); + + if (ctx == NULL || ctx->closed || r->header_only) { + return ngx_http_next_body_filter(r, in); + } + + if (ngx_http_brotli_filter_ensure_stream_initialized(r, ctx) != NGX_OK) { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + + /* If more input is provided - append it to our input chain. */ + if (in) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED; + } + + /* Main loop: + - if output is not yet consumed - stop; encoder should not be touched, + until all the output is consumed + - if encoder has output - wrap it and send to consumer + - if encoder is finished (and all output is consumed) - stop + - if there is more input - push it to encoder */ + for (;;) { + if (ctx->output_busy || ctx->output_ready) { + if (ctx->output_busy) { + available_busy_output = ngx_buf_size(ctx->out_buf); + } else { + available_busy_output = 0; + } + + rc = ngx_http_next_body_filter(r, + ctx->output_ready ? ctx->out_chain : NULL); + if (ctx->output_ready) { + ctx->output_ready = 0; + ctx->output_busy = 1; + } + if (ngx_buf_size(ctx->out_buf) == 0) { + ctx->output_busy = 0; + } + if (rc == NGX_OK) { + if (ctx->output_busy && + available_busy_output == ngx_buf_size(ctx->out_buf)) { + r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED; + return NGX_AGAIN; + } + continue; + } else if (rc == NGX_AGAIN) { + if (ctx->output_busy) { + /* Can't continue compression, let the outer filer decide. */ + if (ctx->in != NULL) { + r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED; + } + return NGX_AGAIN; + } else { + /* Inner filter has given up, but we can continue processing. */ + continue; + } + } else { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + } + + if (BrotliEncoderHasMoreOutput(ctx->encoder)) { + available_output = 0; + out = (u_char*)BrotliEncoderTakeOutput(ctx->encoder, &available_output); + if (out == NULL || available_output == 0) { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + ctx->out_buf->start = out; + ctx->out_buf->pos = out; + ctx->out_buf->last = out + available_output; + ctx->out_buf->end = out + available_output; + ctx->bytes_out += available_output; + ctx->out_buf->last_buf = 0; + ctx->out_buf->flush = 0; + if (ctx->end_of_input && BrotliEncoderIsFinished(ctx->encoder)) { + ctx->out_buf->last_buf = 1; + r->connection->buffered &= ~NGX_HTTP_BROTLI_BUFFERED; + } else if (ctx->end_of_block) { + ctx->out_buf->flush = 1; + r->connection->buffered &= ~NGX_HTTP_BROTLI_BUFFERED; + } + ctx->end_of_block = 0; + ctx->output_ready = 1; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "brotli out: %p, size:%uz", ctx->out_buf, + ngx_buf_size(ctx->out_buf)); + continue; + } + + if (BrotliEncoderIsFinished(ctx->encoder)) { + ctx->success = 1; + r->connection->buffered &= ~NGX_HTTP_BROTLI_BUFFERED; + ngx_http_brotli_filter_close(ctx); + return NGX_OK; + } + + if (ctx->end_of_input) { + // Ask the encoder to dump the leftover. + available_input = 0; + available_output = 0; + ok = BrotliEncoderCompressStream(ctx->encoder, BROTLI_OPERATION_FINISH, + &available_input, NULL, + &available_output, NULL, NULL); + r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED; + if (!ok) { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + continue; + } + + if (ctx->in == NULL) { + return NGX_OK; + } + + /* TODO: coalesce tiny inputs, if they are not last/flush. */ + input_size = ngx_buf_size(ctx->in->buf); + if (input_size == 0) { + if (!ctx->in->buf->last_buf && !ctx->in->buf->flush) { + link = ctx->in; + ctx->in = ctx->in->next; + ngx_free_chain(r->pool, link); + continue; + } + } + + available_input = input_size; + next_input_byte = (const uint8_t*)ctx->in->buf->pos; + available_output = 0; + ok = BrotliEncoderCompressStream( + ctx->encoder, + ctx->in->buf->last_buf ? BROTLI_OPERATION_FINISH + : ctx->in->buf->flush ? BROTLI_OPERATION_FLUSH + : BROTLI_OPERATION_PROCESS, + &available_input, &next_input_byte, &available_output, NULL, NULL); + r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED; + if (!ok) { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + + consumed_input = input_size - available_input; + ctx->bytes_in += consumed_input; + ctx->in->buf->pos += consumed_input; + + if (consumed_input == input_size) { + if (ctx->in->buf->last_buf) { + ctx->end_of_input = 1; + } else if (ctx->in->buf->flush) { + ctx->end_of_block = 1; + } + link = ctx->in; + ctx->in = ctx->in->next; + ngx_free_chain(r->pool, link); + continue; + } + + /* Should never happen, just to make sure we don't enter infinite loop. */ + if (consumed_input == 0) { + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; + } + } + + /* unreachable */ + ngx_http_brotli_filter_close(ctx); + return NGX_ERROR; +} + +static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized( + ngx_http_request_t* r, ngx_http_brotli_ctx_t* ctx) { + ngx_http_brotli_conf_t* conf; + BROTLI_BOOL ok; + size_t wbits; + + if (ctx->initialized) { + return NGX_OK; + } + ctx->initialized = 1; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module); + + /* Tune lg_win, if size is known. */ + if (ctx->content_length > 0) { + wbits = BROTLI_MIN_WINDOW_BITS; + while ((wbits < conf->lg_win) && (ctx->content_length > (1 << wbits))) { + wbits++; + } + } else { + wbits = conf->lg_win; + } + + ctx->encoder = BrotliEncoderCreateInstance( + ngx_http_brotli_filter_alloc, ngx_http_brotli_filter_free, r->pool); + if (ctx->encoder == NULL) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "OOM / BrotliEncoderCreateInstance"); + return NGX_ERROR; + } + + ok = BrotliEncoderSetParameter(ctx->encoder, BROTLI_PARAM_QUALITY, + (uint32_t)conf->quality); + if (!ok) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "BrotliEncoderSetParameter(QUALITY, %uD) failed", + (uint32_t)conf->quality); + return NGX_ERROR; + } + + ok = BrotliEncoderSetParameter(ctx->encoder, BROTLI_PARAM_LGWIN, + (uint32_t)wbits); + if (!ok) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "BrotliEncoderSetParameter(LGWIN, %uD) failed", + (uint32_t)wbits); + return NGX_ERROR; + } + + ctx->out_buf = ngx_calloc_buf(r->pool); + if (ctx->out_buf == NULL) { + return NGX_ERROR; + } + ctx->out_buf->temporary = 1; + + ctx->out_chain = ngx_alloc_chain_link(r->pool); + if (ctx->out_chain == NULL) { + return NGX_ERROR; + } + ctx->out_chain->buf = ctx->out_buf; + ctx->out_chain->next = NULL; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "brotli encoder initialized: lvl:%i win:%d", conf->quality, + (1 << wbits)); + + return NGX_OK; +} + +static void* ngx_http_brotli_filter_alloc(void* opaque, size_t size) { + ngx_pool_t* pool = opaque; + void* p; + + p = ngx_palloc(pool, size); + +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0, "brotli alloc: %p, size:%uz", + p, size); +#endif + + return p; +} + +static void ngx_http_brotli_filter_free(void* opaque, void* address) { + ngx_pool_t* pool = opaque; + +#if (NGX_DEBUG) + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "brotli free: %p", address); +#endif + + ngx_pfree(pool, address); +} + +static void ngx_http_brotli_filter_close(ngx_http_brotli_ctx_t* ctx) { + ctx->closed = 1; + if (ctx->encoder) { + BrotliEncoderDestroyInstance(ctx->encoder); + ctx->encoder = NULL; + } + if (ctx->out_chain) { + ngx_free_chain(ctx->request->pool, ctx->out_chain); + ctx->out_chain = NULL; + } + if (ctx->out_buf) { + ngx_pfree(ctx->request->pool, ctx->out_buf); + ctx->out_buf = NULL; + } +} + +static ngx_int_t ngx_http_brotli_check_request(ngx_http_request_t* req) { + if (req != req->main) return NGX_DECLINED; + if (check_accept_encoding(req) != NGX_OK) return NGX_DECLINED; + req->gzip_tested = 1; + req->gzip_ok = 0; + return NGX_OK; +} + +static ngx_int_t ngx_http_brotli_add_variables(ngx_conf_t* cf) { + ngx_http_variable_t* var; + + var = ngx_http_add_variable(cf, &ngx_http_brotli_ratio, 0); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = ngx_http_brotli_ratio_variable; + + return NGX_OK; +} + +static ngx_int_t ngx_http_brotli_ratio_variable(ngx_http_request_t* r, + ngx_http_variable_value_t* v, + uintptr_t data) { + ngx_uint_t ratio_int; + ngx_uint_t ratio_frac; + ngx_http_brotli_ctx_t* ctx; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_brotli_filter_module); + + /* Only report variable on non-failing streams. */ + if (ctx == NULL || !ctx->success) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3); + if (v->data == NULL) { + return NGX_ERROR; + } + + ratio_int = (ngx_uint_t)(ctx->bytes_in / ctx->bytes_out); + ratio_frac = (ngx_uint_t)((ctx->bytes_in * 100 / ctx->bytes_out) % 100); + + /* Rounding; e.g. 2.125 to 2.13 */ + if ((ctx->bytes_in * 1000 / ctx->bytes_out) % 10 > 4) { + ratio_frac++; + if (ratio_frac > 99) { + ratio_int++; + ratio_frac = 0; + } + } + + v->len = ngx_sprintf(v->data, "%ui.%02ui", ratio_int, ratio_frac) - v->data; + + return NGX_OK; +} + +static void* ngx_http_brotli_create_conf(ngx_conf_t* cf) { + ngx_http_brotli_conf_t* conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_brotli_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* ngx_pcalloc fills result with zeros -> + conf->bufs.num = 0; + conf->types = { NULL }; + conf->types_keys = NULL; */ + + conf->enable = NGX_CONF_UNSET; + + conf->quality = NGX_CONF_UNSET; + conf->lg_win = NGX_CONF_UNSET_SIZE; + conf->min_length = NGX_CONF_UNSET; + + return conf; +} + +static char* ngx_http_brotli_merge_conf(ngx_conf_t* cf, void* parent, + void* child) { + ngx_http_brotli_conf_t* prev = parent; + ngx_http_brotli_conf_t* conf = child; + char* rc; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + ngx_conf_merge_value(conf->quality, prev->quality, 6); + ngx_conf_merge_size_value(conf->lg_win, prev->lg_win, 19); + ngx_conf_merge_value(conf->min_length, prev->min_length, 20); + + rc = ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, + ngx_http_html_default_types); + if (rc != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +/* Prepend to filter chain. */ +static ngx_int_t ngx_http_brotli_filter_init(ngx_conf_t* cf) { + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_brotli_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_brotli_body_filter; + + return NGX_OK; +} + +/* Translate "window size" to window bits (log2), and check bounds. */ +static char* ngx_http_brotli_parse_wbits(ngx_conf_t* cf, void* post, + void* data) { + size_t* parameter = data; + size_t bits; + size_t wsize; + + for (bits = BROTLI_MIN_WINDOW_BITS; bits <= BROTLI_MAX_WINDOW_BITS; bits++) { + wsize = 1u << bits; + if (*parameter == wsize) { + *parameter = bits; + return NGX_CONF_OK; + } + } + + return "must be 1k, 2k, 4k, 8k, 16k, 32k, 64k, 128k, 256k, 512k, 1m, 2m, 4m, " + "8m or 16m"; +} diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-before-test.sh b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-before-test.sh new file mode 100755 index 0000000..9f69164 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-before-test.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -ex + +# Setup shortcuts. +ROOT=`pwd` +FILES=$ROOT/script/test + +# Setup directory structure. +cd $ROOT/script +if [ ! -d test ]; then + mkdir test +fi +cd test +if [ ! -d logs ]; then + mkdir logs +fi + +# Download sample texts. +curl --compressed -o $FILES/war-and-peace.txt http://www.gutenberg.org/files/2600/2600-0.txt +echo "Kot lomom kolol slona!" > $FILES/small.txt +echo "Kot lomom kolol slona!" > $FILES/small.html + +# Restore status-quo. +cd $ROOT diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-compile.sh b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-compile.sh new file mode 100755 index 0000000..2fa01d6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-compile.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -ex + +# Setup shortcuts. +ROOT=`pwd` + +# Clone nginx read-only git repository. +if [ ! -d "nginx" ]; then + git clone https://github.com/nginx/nginx.git +fi + +# Build nginx + filter module. +cd $ROOT/nginx +# Pro memoria: --with-debug +./auto/configure \ + --prefix=$ROOT/script/test \ + --with-http_v2_module \ + --add-module=$ROOT +make -j 16 + +# Build brotli CLI. +cd $ROOT/deps/brotli +mkdir out +cd out +cmake .. +make -j 16 brotli + +# Restore status-quo. +cd $ROOT diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-test.sh b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-test.sh new file mode 100755 index 0000000..1db8d15 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/.travis-test.sh @@ -0,0 +1,168 @@ +#!/bin/bash + +# Setup shortcuts. +ROOT=`pwd` +NGINX=$ROOT/nginx/objs/nginx +BROTLI=$ROOT/deps/brotli/out/brotli +SERVER=http://localhost:8080 +FILES=$ROOT/script/test +HR="---------------------------------------------------------------------------" + +if [ ! -d tmp ]; then + mkdir tmp +fi + +rm tmp/* + +add_result() { + echo $1 >&2 + echo $1 >> tmp/results.log +} + +get_failed() { + echo `cat tmp/results.log | grep -v OK | wc -l` +} + +get_count() { + echo `cat tmp/results.log | wc -l` +} + +expect_equal() { + expected=$1 + actual=$2 + if cmp $expected $actual; then + add_result "OK" + else + add_result "FAIL (equality)" + fi +} + +expect_br_equal() { + expected=$1 + actual_br=$2 + if $BROTLI -dfk ./${actual_br}.br; then + expect_equal $expected $actual_br + else + add_result "FAIL (decompression)" + fi +} + +################################################################################ + +# Start default server. +echo "Statring NGINX" +$NGINX -c $ROOT/script/test.conf +# Fetch vanilla 404 response. +curl -s -o tmp/notfound.txt $SERVER/notfound + +CURL="curl -s" + +# Run tests. +echo $HR + +echo "Test: long file with rate limit" +$CURL -H 'Accept-encoding: br' -o tmp/war-and-peace.br --limit-rate 300K $SERVER/war-and-peace.txt +expect_br_equal $FILES/war-and-peace.txt tmp/war-and-peace + +echo "Test: compressed 404" +$CURL -H 'Accept-encoding: br' -o tmp/notfound.br $SERVER/notfound +expect_br_equal tmp/notfound.txt tmp/notfound + +echo "Test: A-E: 'gzip, br'" +$CURL -H 'Accept-encoding: gzip, br' -o tmp/ae-01.br $SERVER/small.txt +expect_br_equal $FILES/small.txt tmp/ae-01 + +echo "Test: A-E: 'gzip, br, deflate'" +$CURL -H 'Accept-encoding: gzip, br, deflate' -o tmp/ae-02.br $SERVER/small.txt +expect_br_equal $FILES/small.txt tmp/ae-02 + +echo "Test: A-E: 'gzip, br;q=1, deflate'" +$CURL -H 'Accept-encoding: gzip, br;q=1, deflate' -o tmp/ae-03.br $SERVER/small.txt +expect_br_equal $FILES/small.txt tmp/ae-03 + +echo "Test: A-E: 'br;q=0.001'" +$CURL -H 'Accept-encoding: br;q=0.001' -o tmp/ae-04.br $SERVER/small.txt +expect_br_equal $FILES/small.txt tmp/ae-04 + +echo "Test: A-E: 'bro'" +$CURL -H 'Accept-encoding: bro' -o tmp/ae-05.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-05.txt + +echo "Test: A-E: 'bo'" +$CURL -H 'Accept-encoding: bo' -o tmp/ae-06.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-06.txt + +echo "Test: A-E: 'br;q=0'" +$CURL -H 'Accept-encoding: br;q=0' -o tmp/ae-07.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-07.txt + +echo "Test: A-E: 'br;q=0.'" +$CURL -H 'Accept-encoding: br;q=0.' -o tmp/ae-08.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-08.txt + +echo "Test: A-E: 'br;q=0.0'" +$CURL -H 'Accept-encoding: br;q=0.0' -o tmp/ae-09.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-09.txt + +echo "Test: A-E: 'br;q=0.00'" +$CURL -H 'Accept-encoding: br;q=0.00' -o tmp/ae-10.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-10.txt + +echo "Test: A-E: 'br ; q = 0.000'" +$CURL -H 'Accept-encoding: br ; q = 0.000' -o tmp/ae-11.txt $SERVER/small.txt +expect_equal $FILES/small.txt tmp/ae-11.txt + +echo "Test: A-E: 'bar'" +$CURL -H 'Accept-encoding: bar' -o tmp/ae-12.txt $SERVER/small.html +expect_equal $FILES/small.html tmp/ae-12.txt + +echo "Test: A-E: 'b'" +$CURL -H 'Accept-encoding: b' -o tmp/ae-13.txt $SERVER/small.html +expect_equal $FILES/small.html tmp/ae-13.txt + +echo $HR +echo "Stopping default NGINX" +# Stop server. +$NGINX -c $ROOT/script/test.conf -s stop + +################################################################################ + +# Start default server. +echo "Statring h2 NGINX" +$NGINX -c $ROOT/script/test_h2.conf + +CURL="curl --http2-prior-knowledge -s" + +# Run tests. +echo $HR + +echo "Test: long file with rate limit" +$CURL -H 'Accept-encoding: br' -o tmp/h2-war-and-peace.br --limit-rate 300K $SERVER/war-and-peace.txt +expect_br_equal $FILES/war-and-peace.txt tmp/h2-war-and-peace + +echo "Test: A-E: 'gzip, br'" +$CURL -H 'Accept-encoding: gzip, br' -o tmp/h2-ae-01.br $SERVER/small.txt +expect_br_equal $FILES/small.txt tmp/h2-ae-01 + +echo "Test: A-E: 'b'" +$CURL -H 'Accept-encoding: b' -o tmp/h2-ae-13.txt $SERVER/small.html +expect_equal $FILES/small.html tmp/h2-ae-13.txt + +echo $HR +echo "Stopping h2 NGINX" +# Stop server. +$NGINX -c $ROOT/script/test_h2.conf -s stop + +################################################################################ + +# Report. + +FAILED=$(get_failed $STATUS) +COUNT=$(get_count $STATUS) +echo $HR +echo "Results: $FAILED of $COUNT tests failed" + +# Restore status-quo. +cd $ROOT + +exit $FAILED diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test.conf b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test.conf new file mode 100644 index 0000000..93957f9 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test.conf @@ -0,0 +1,32 @@ +events { + worker_connections 4; +} + +daemon on; +error_log /dev/stdout info; + +http { + access_log ./access.log; + error_log ./error.log; + + gzip on; + gzip_comp_level 1; + gzip_types text/plain text/css; + + brotli on; + brotli_comp_level 1; + brotli_types text/plain text/css; + + server { + listen 8080 default_server; + listen [::]:8080 default_server; + + root ./; + + index index.html; + + location / { + try_files $uri $uri/ =404; + } + } +} diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test_h2.conf b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test_h2.conf new file mode 100644 index 0000000..0f2c791 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/script/test_h2.conf @@ -0,0 +1,32 @@ +events { + worker_connections 4; +} + +daemon on; +error_log /dev/stdout info; + +http { + access_log ./access.log; + error_log ./error.log; + + gzip on; + gzip_comp_level 1; + gzip_types text/plain text/css; + + brotli on; + brotli_comp_level 1; + brotli_types text/plain text/css; + + server { + listen 8080 http2; + listen [::]:8080 http2; + + root ./; + + index index.html; + + location / { + try_files $uri $uri/ =404; + } + } +} diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/config b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/config new file mode 100644 index 0000000..de07d1c --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/config @@ -0,0 +1,54 @@ +# Copyright (C) 2015-2019 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +if [ "$ngx_addon_name" = "ngx_brotli" ]; then + BROTLI_MODULE_SRC_DIR="$ngx_addon_dir/static" +else + BROTLI_MODULE_SRC_DIR="$ngx_addon_dir" +fi + +ngx_addon_name=ngx_brotli_static + +if [ -z "$ngx_module_link" ]; then +cat << END + +$0: error: Brotli module requires recent version of NGINX (1.9.11+). + +END + exit 1 +fi + +ngx_module_type=HTTP +ngx_module_name=ngx_http_brotli_static_module +ngx_module_incs= +ngx_module_deps= +ngx_module_srcs="$BROTLI_MODULE_SRC_DIR/ngx_http_brotli_static_module.c" +ngx_module_libs= +ngx_module_order= + +. auto/module + +have=NGX_HTTP_GZIP . auto/have +have=NGX_HTTP_BROTLI_STATIC . auto/have +have=NGX_HTTP_BROTLI_STATIC_MODULE . auto/have # deprecated diff --git a/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/ngx_http_brotli_static_module.c b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/ngx_http_brotli_static_module.c new file mode 100644 index 0000000..44f0cb0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-brotli-1.0.0~rc/static/ngx_http_brotli_static_module.c @@ -0,0 +1,323 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + * Copyright (C) Google Inc. + */ + +#include +#include +#include + +/* >> Configuration */ + +#define NGX_HTTP_BROTLI_STATIC_OFF 0 +#define NGX_HTTP_BROTLI_STATIC_ON 1 +#define NGX_HTTP_BROTLI_STATIC_ALWAYS 2 + +typedef struct { + ngx_uint_t enable; +} configuration_t; + +static ngx_conf_enum_t kBrotliStaticEnum[] = { + {ngx_string("off"), NGX_HTTP_BROTLI_STATIC_OFF}, + {ngx_string("on"), NGX_HTTP_BROTLI_STATIC_ON}, + {ngx_string("always"), NGX_HTTP_BROTLI_STATIC_ALWAYS}, + {ngx_null_string, 0}}; + +/* << Configuration */ + +/* >> Forward declarations */ + +static ngx_int_t handler(ngx_http_request_t* req); +static void* create_conf(ngx_conf_t* root_cfg); +static char* merge_conf(ngx_conf_t* root_cfg, void* parent, void* child); +static ngx_int_t init(ngx_conf_t* root_cfg); + +/* << Forward declarations*/ + +/* >> Module definition */ + +static ngx_command_t kCommands[] = { + {ngx_string("brotli_static"), + 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(configuration_t, enable), &kBrotliStaticEnum}, + ngx_null_command}; + +static ngx_http_module_t kModuleContext = { + NULL, /* preconfiguration */ + init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + create_conf, /* create location configuration */ + merge_conf /* merge location configuration */ +}; + +ngx_module_t ngx_http_brotli_static_module = { + NGX_MODULE_V1, + &kModuleContext, /* module context */ + kCommands, /* 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}; + +/* << Module definition*/ + +static const u_char kContentEncoding[] = "Content-Encoding"; +static /* const */ char kEncoding[] = "br"; +static const size_t kEncodingLen = 2; +static /* const */ u_char kSuffix[] = ".br"; +static const size_t kSuffixLen = 3; + +static ngx_int_t check_accept_encoding(ngx_http_request_t* req) { + ngx_table_elt_t* accept_encoding_entry; + ngx_str_t* accept_encoding; + u_char* cursor; + u_char* end; + u_char before; + u_char after; + + accept_encoding_entry = req->headers_in.accept_encoding; + if (accept_encoding_entry == NULL) return NGX_DECLINED; + accept_encoding = &accept_encoding_entry->value; + + cursor = accept_encoding->data; + end = cursor + accept_encoding->len; + while (1) { + u_char digit; + /* It would be an idiotic idea to rely on compiler to produce performant + binary, that is why we just do -1 at every call site. */ + cursor = ngx_strcasestrn(cursor, kEncoding, kEncodingLen - 1); + if (cursor == NULL) return NGX_DECLINED; + before = (cursor == accept_encoding->data) ? ' ' : cursor[-1]; + cursor += kEncodingLen; + after = (cursor >= end) ? ' ' : *cursor; + if (before != ',' && before != ' ') continue; + if (after != ',' && after != ' ' && after != ';') continue; + + /* Check for ";q=0[.[0[0[0]]]]" */ + while (*cursor == ' ') cursor++; + if (*(cursor++) != ';') break; + while (*cursor == ' ') cursor++; + if (*(cursor++) != 'q') break; + while (*cursor == ' ') cursor++; + if (*(cursor++) != '=') break; + while (*cursor == ' ') cursor++; + if (*(cursor++) != '0') break; + if (*(cursor++) != '.') return NGX_DECLINED; /* ;q=0, */ + digit = *(cursor++); + if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0., */ + if (digit > '0') break; + digit = *(cursor++); + if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.0, */ + if (digit > '0') break; + digit = *(cursor++); + if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.00, */ + if (digit > '0') break; + return NGX_DECLINED; /* ;q=0.000 */ + } + return NGX_OK; +} + +/* Test if this request is allowed to have the brotli response. */ +static ngx_int_t check_eligility(ngx_http_request_t* req) { + if (req != req->main) return NGX_DECLINED; + if (check_accept_encoding(req) != NGX_OK) return NGX_DECLINED; + req->gzip_tested = 1; + req->gzip_ok = 0; + return NGX_OK; +} + +static ngx_int_t handler(ngx_http_request_t* req) { + configuration_t* cfg; + ngx_int_t rc; + u_char* last; + ngx_str_t path; + size_t root; + ngx_log_t* log; + ngx_http_core_loc_conf_t* location_cfg; + ngx_open_file_info_t file_info; + ngx_table_elt_t* content_encoding_entry; + ngx_buf_t* buf; + ngx_chain_t out; + + /* Only GET and HEAD requensts are supported. */ + if (!(req->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) return NGX_DECLINED; + + /* Only files are supported. */ + if (req->uri.data[req->uri.len - 1] == '/') return NGX_DECLINED; + + /* Get configuration and check if module is disabled. */ + cfg = ngx_http_get_module_loc_conf(req, ngx_http_brotli_static_module); + if (cfg->enable == NGX_HTTP_BROTLI_STATIC_OFF) return NGX_DECLINED; + + if (cfg->enable == NGX_HTTP_BROTLI_STATIC_ALWAYS) { + /* Ignore request properties (e.g. Accept-Encoding). */ + } else { + /* NGX_HTTP_BROTLI_STATIC_ON */ + rc = check_eligility(req); + if (rc != NGX_OK) return NGX_DECLINED; + } + + /* Get path and append the suffix. */ + last = ngx_http_map_uri_to_path(req, &path, &root, kSuffixLen); + if (last == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; + /* +1 for reinstating the terminating 0. */ + ngx_cpystrn(last, kSuffix, kSuffixLen + 1); + path.len += kSuffixLen; + + log = req->connection->log; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", + path.data); + + /* Prepare to read the file. */ + location_cfg = ngx_http_get_module_loc_conf(req, ngx_http_core_module); + ngx_memzero(&file_info, sizeof(ngx_open_file_info_t)); + file_info.read_ahead = location_cfg->read_ahead; + file_info.directio = location_cfg->directio; + file_info.valid = location_cfg->open_file_cache_valid; + file_info.min_uses = location_cfg->open_file_cache_min_uses; + file_info.errors = location_cfg->open_file_cache_errors; + file_info.events = location_cfg->open_file_cache_events; + rc = ngx_http_set_disable_symlinks(req, location_cfg, &path, &file_info); + if (rc != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR; + + /* Try to fetch file and process errors. */ + rc = ngx_open_cached_file(location_cfg->open_file_cache, &path, &file_info, + req->pool); + if (rc != NGX_OK) { + ngx_uint_t level; + switch (file_info.err) { + case 0: + return NGX_HTTP_INTERNAL_SERVER_ERROR; + + case NGX_ENOENT: + case NGX_ENOTDIR: + case NGX_ENAMETOOLONG: + return NGX_DECLINED; + +#if (NGX_HAVE_OPENAT) + case NGX_EMLINK: + case NGX_ELOOP: +#endif + case NGX_EACCES: + level = NGX_LOG_ERR; + break; + + default: + level = NGX_LOG_CRIT; + break; + } + ngx_log_error(level, log, file_info.err, "%s \"%s\" failed", + file_info.failed, path.data); + return NGX_DECLINED; + } + + if (cfg->enable == NGX_HTTP_BROTLI_STATIC_ON) { + req->gzip_vary = 1; + } + + /* So far so good. */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", + file_info.fd); + + /* Only files are supported. */ + if (file_info.is_dir) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); + return NGX_DECLINED; + } +#if !(NGX_WIN32) + if (!file_info.is_file) { + ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", + path.data); + return NGX_HTTP_NOT_FOUND; + } +#endif + + /* Prepare request push the body. */ + req->root_tested = !req->error_page; + rc = ngx_http_discard_request_body(req); + if (rc != NGX_OK) return rc; + log->action = "sending response to client"; + req->headers_out.status = NGX_HTTP_OK; + req->headers_out.content_length_n = file_info.size; + req->headers_out.last_modified_time = file_info.mtime; + rc = ngx_http_set_etag(req); + if (rc != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = ngx_http_set_content_type(req); + if (rc != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR; + + /* Set "Content-Encoding" header. */ + content_encoding_entry = ngx_list_push(&req->headers_out.headers); + if (content_encoding_entry == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; + content_encoding_entry->hash = 1; + ngx_str_set(&content_encoding_entry->key, kContentEncoding); + ngx_str_set(&content_encoding_entry->value, kEncoding); + req->headers_out.content_encoding = content_encoding_entry; + + /* Setup response body. */ + buf = ngx_pcalloc(req->pool, sizeof(ngx_buf_t)); + if (buf == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; + buf->file = ngx_pcalloc(req->pool, sizeof(ngx_file_t)); + if (buf->file == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; + buf->file_pos = 0; + buf->file_last = file_info.size; + buf->in_file = buf->file_last ? 1 : 0; + buf->last_buf = (req == req->main) ? 1 : 0; + buf->last_in_chain = 1; + buf->file->fd = file_info.fd; + buf->file->name = path; + buf->file->log = log; + buf->file->directio = file_info.is_directio; + out.buf = buf; + out.next = NULL; + + /* Push the response header. */ + rc = ngx_http_send_header(req); + if (rc == NGX_ERROR || rc > NGX_OK || req->header_only) { + return rc; + } + + /* Push the response body. */ + return ngx_http_output_filter(req, &out); +} + +static void* create_conf(ngx_conf_t* root_cfg) { + configuration_t* cfg; + cfg = ngx_palloc(root_cfg->pool, sizeof(configuration_t)); + if (cfg == NULL) return NULL; + cfg->enable = NGX_CONF_UNSET_UINT; + return cfg; +} + +static char* merge_conf(ngx_conf_t* root_cfg, void* parent, void* child) { + configuration_t* prev = parent; + configuration_t* cfg = child; + ngx_conf_merge_uint_value(cfg->enable, prev->enable, + NGX_HTTP_BROTLI_STATIC_OFF); + return NGX_CONF_OK; +} + +static ngx_int_t init(ngx_conf_t* root_cfg) { + ngx_http_core_main_conf_t* core_cfg; + ngx_http_handler_pt* handler_slot; + core_cfg = ngx_http_conf_get_module_main_conf(root_cfg, ngx_http_core_module); + handler_slot = + ngx_array_push(&core_cfg->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (handler_slot == NULL) return NGX_ERROR; + *handler_slot = handler; + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.astylerc b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.astylerc new file mode 100644 index 0000000..3c009b3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.astylerc @@ -0,0 +1,22 @@ +# astylerc +align-pointer=name +align-reference=name +break-after-logical +#indent=spaces=2 +max-code-length=120 +style=google +suffix=none + +# Indent +indent-preproc-block + +# Padding +pad-header +unpad-paren + +# Formatting: +add-brackets +#convert-tabs + +# Output: +formatted \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.format.sh b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.format.sh new file mode 100755 index 0000000..75209eb --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.format.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +# Search in the script folder +pushd "$(dirname $0)" >/dev/null +CWD="$(pwd -P)" +popd >/dev/null +FILES='ngx_cache_purge_module.c' + +# The file format in accordance with the style defined in .astylerc +astyle -v --options='.astylerc' ${FILES} || (echo 'astyle failed'; exit 1); + +# To correct this, the issuance dos2unix on each file +# sometimes adds in Windows as a string-endins (\r\n). +dos2unix --quiet ${FILES} || (echo 'dos2unix failed'; exit 2); \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.gitattributes b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.gitattributes new file mode 100644 index 0000000..9b27d9f --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.gitattributes @@ -0,0 +1 @@ +*.t linguist-language=Text \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.travis.yml b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.travis.yml new file mode 100644 index 0000000..3714921 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/.travis.yml @@ -0,0 +1,49 @@ +sudo: required +os: linux +dist: trusty +language: c +compiler: + - gcc + - clang +cache: + apt: true + directories: + - download-cache +env: + global: + - JOBS=4 + - NGINX_PREFIX=/opt/nginx + matrix: + - NGINX_VERSION=1.18.0 + - NGINX_VERSION=1.19.2 + +before_install: + - mkdir --parents download-cache + - sudo apt-get update -qq + - sudo apt-get install -qq zlib1g-dev libpcre3-dev cpanminus + # Get OpenSSL 1.0.2 from Ubuntu Xenial + # https://packages.ubuntu.com/xenial-updates/libssl1.0.0 + - test -f download-cache/libssl1.0.0_1.0.2g-1ubuntu4.16_amd64.deb || wget -O download-cache/libssl1.0.0_1.0.2g-1ubuntu4.17_amd64.deb "http://de.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.0.0_1.0.2g-1ubuntu4.17_amd64.deb" + # https://packages.ubuntu.com/xenial/libssl-dev + - test -f download-cache/libssl-dev_1.0.2g-1ubuntu4.16_amd64.deb || wget -O download-cache/libssl-dev_1.0.2g-1ubuntu4.17_amd64.deb "http://de.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl-dev_1.0.2g-1ubuntu4.17_amd64.deb" + - sudo dpkg -i download-cache/libssl*_amd64.deb + # Test::Nginx + - git clone https://github.com/openresty/test-nginx.git test-nginx + - cd test-nginx/ && sudo cpanm . && cd .. + # NGINX source + - test -f download-cache/nginx-$NGINX_VERSION.tar.gz || wget -O download-cache/nginx-$NGINX_VERSION.tar.gz http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz + +install: + - tar -xzf download-cache/nginx-${NGINX_VERSION}.tar.gz + - cd nginx-${NGINX_VERSION}/ + - ./configure --prefix=${NGINX_PREFIX} --with-debug --with-http_ssl_module --add-module=${PWD}/.. + - make -j${JOBS} + - sudo make install + - cd .. + - export PATH="${NGINX_PREFIX}/sbin:$PATH" +# - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH} + +script: + - nginx -V + - ldd $(which nginx) + - prove t diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/CHANGES b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/CHANGES new file mode 100644 index 0000000..7495742 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/CHANGES @@ -0,0 +1,103 @@ +2020-06-27 VERSION 2.5.1 + * fix: empty key check - it coredumps when cache key is empty, Tuğrul Topuz + * fix: purge report calloc fix - Report template has not cache file path but it's length is use in buffer memory allocation, Tuğrul Topuz + +2018-08-04 VERSION 2.5 + * feat/docs: cache_purge_response_type directive, selecting response type (html|json|xml|text) + * break: changed status of HTTP code 404 (Not Found) to 412 (Precondition Failed) + * fix: remove path information of response body (#4, 3a8c08a, #11) + +2020-06-27 VERSION 2.4.3 + * fix: empty key check - it coredumps when cache key is empty, Tuğrul Topuz + +2017-09-28 VERSION 2.4.2 + * fix: segfault in call to `ngx_read_file` of partial key purge, Frankie Dintino + * fix: segfault in `cplcf->conf->purge_all` with separate location syntax, Frankie Dintino + +2017-02-21 VERSION 2.4.1 + * Fix compatibility with nginx-1.11.6+, Sułowicz Paweł + +2016-11-20 VERSION 2.4 + * Fix compatibility with nginx-1.7.12+. + * explain the purge logic + * feat(purge all): Include option to purge all the cached files + This option can be slow if a lot of content is cached, or if the + storage used for the cache is slow. But you really should be using + RAM as your cache storage. + * feat(partial keys): Support partial keys to purge multiple keys. + Put an '*' at the end of your purge cache URL. + e.g: + proxy_cache_key $scheme$host$uri$is_args$args$cookie_JSESSIONID; + curl -X PURGE https://example.com/pass* + This will remove every cached page whose key cache starting with: + httpsexample.com/pass* + Be careful not passing any value for the values after the $uri, or put + it at the end of your cache key. + * Convert a config file to build a dynamic module + +2014-12-23 VERSION 2.3 + * Fix compatibility with nginx-1.7.9+. + +2014-12-02 VERSION 2.2 + * Fix compatibility with nginx-1.7.8+. + +2014-05-19 + * Fix build on Solaris with SunCC (Solaris Studio). + Reported by Jussi Sallinen. + +2013-03-19 VERSION 2.1 + * When enabled, cache purge will now catch all requests with + PURGE (or specified) method, even if cache isn't configured. + Previously, it would pass such requests to the upstream. + +2012-12-07 VERSION 2.0 + * Add alternative "same location" syntax. + From CloudFlare. + +2012-07-02 VERSION 1.6 + * Fix compatibility with nginx-1.3.2+. + Reported by MagicBear, patch from Ruslan Ermilov. + +2011-12-20 VERSION 1.5 + * Fix on-disk cache size calculation. + Since the initial release, recorded on-disk cache size was + decreased twice for purged content (once during cache purge + and once during subsequent cache update). + This resulted in recorded on-disk cache size being much + smaller than in reality, which could lead to on-disk cache + outgrowing defined "max_size" parameter. + Patch from Pyry Hakulinen. + +2011-10-05 VERSION 1.4 + * Add AIO support. + Requested by Emin Hasanov. + +2011-05-03 VERSION 1.3 + * Fix compatibility with nginx-1.0.1. + Reported by Sergey A. Osokin and Markus Linnala. + +2010-08-29 + * Fix compatibility with nginx-0.8.0 and versions older than + nginx-0.7.60. + +2010-08-11 VERSION 1.2 + * Fix various build scenarios with disabled upstream modules. + Reported by Johan Bergstroem. + + * Add ability to purge content from SCGI's cache. + Requested by Johan Bergstroem. + +2010-06-08 VERSION 1.1 + * Fix compatibility with nginx-0.8.40+. + + * Add ability to purge content from uWSGI's cache. + +2010-01-10 VERSION 1.0 + * Initial module release. + +2009-11-17 + * Fix patch compatibility with nginx-0.8.11+. + Reported by Bing Ran. + +2009-08-11 + * Initial patch release. diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/LICENSE b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/LICENSE new file mode 100644 index 0000000..0047538 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2009-2014, FRiCKLE +Copyright (c) 2009-2014, Piotr Sikora +All rights reserved. + +This project was fully funded by yo.se. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/README.md b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/README.md new file mode 100644 index 0000000..e3d92b4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/README.md @@ -0,0 +1,283 @@ +About +===== +`ngx_cache_purge` is `nginx` module which adds ability to purge content from +`FastCGI`, `proxy`, `SCGI` and `uWSGI` caches. A purge operation removes the +content with the same cache key as the purge request has. + + +Sponsors +======== +Work on the original patch was fully funded by [yo.se](http://yo.se). + + +Status +====== +This module is production-ready. + + +Configuration directives (same location syntax) +=============================================== +fastcgi_cache_purge +------------------- +* **syntax**: `fastcgi_cache_purge on|off| [purge_all] [from all| [.. ]]` +* **default**: `none` +* **context**: `http`, `server`, `location` + +Allow purging of selected pages from `FastCGI`'s cache. + + +proxy_cache_purge +----------------- +* **syntax**: `proxy_cache_purge on|off| [purge_all] [from all| [.. ]]` +* **default**: `none` +* **context**: `http`, `server`, `location` + +Allow purging of selected pages from `proxy`'s cache. + + +scgi_cache_purge +---------------- +* **syntax**: `scgi_cache_purge on|off| [purge_all] [from all| [.. ]]` +* **default**: `none` +* **context**: `http`, `server`, `location` + +Allow purging of selected pages from `SCGI`'s cache. + + +uwsgi_cache_purge +----------------- +* **syntax**: `uwsgi_cache_purge on|off| [purge_all] [from all| [.. ]]` +* **default**: `none` +* **context**: `http`, `server`, `location` + +Allow purging of selected pages from `uWSGI`'s cache. + + +Configuration directives (separate location syntax) +=================================================== +fastcgi_cache_purge +------------------- +* **syntax**: `fastcgi_cache_purge zone_name key` +* **default**: `none` +* **context**: `location` + +Sets area and key used for purging selected pages from `FastCGI`'s cache. + + +proxy_cache_purge +----------------- +* **syntax**: `proxy_cache_purge zone_name key` +* **default**: `none` +* **context**: `location` + +Sets area and key used for purging selected pages from `proxy`'s cache. + + +scgi_cache_purge +---------------- +* **syntax**: `scgi_cache_purge zone_name key` +* **default**: `none` +* **context**: `location` + +Sets area and key used for purging selected pages from `SCGI`'s cache. + + +uwsgi_cache_purge +----------------- +* **syntax**: `uwsgi_cache_purge zone_name key` +* **default**: `none` +* **context**: `location` + +Sets area and key used for purging selected pages from `uWSGI`'s cache. + +Configuration directives (Optional) +=================================================== + +cache_purge_response_type +----------------- +* **syntax**: `cache_purge_response_type html|json|xml|text` +* **default**: `html` +* **context**: `http`, `server`, `location` + +Sets a response type of purging result. + + + +Partial Keys +============ +Sometimes it's not possible to pass the exact key cache to purge a page. For example; when the content of a cookie or the params are part of the key. +You can specify a partial key adding an asterisk at the end of the URL. + + curl -X PURGE /page* + +The asterisk must be the last character of the key, so you **must** put the $uri variable at the end. + + + +Sample configuration (same location syntax) +=========================================== + http { + proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; + + server { + location / { + proxy_pass http://127.0.0.1:8000; + proxy_cache tmpcache; + proxy_cache_key "$uri$is_args$args"; + proxy_cache_purge PURGE from 127.0.0.1; + } + } + } + + +Sample configuration (same location syntax - purge all cached files) +==================================================================== + http { + proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; + + server { + location / { + proxy_pass http://127.0.0.1:8000; + proxy_cache tmpcache; + proxy_cache_key "$uri$is_args$args"; + proxy_cache_purge PURGE purge_all from 127.0.0.1 192.168.0.0/8; + } + } + } + + +Sample configuration (separate location syntax) +=============================================== + http { + proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; + + server { + location / { + proxy_pass http://127.0.0.1:8000; + proxy_cache tmpcache; + proxy_cache_key "$uri$is_args$args"; + } + + location ~ /purge(/.*) { + allow 127.0.0.1; + deny all; + proxy_cache tmpcache; + proxy_cache_key "$1$is_args$args"; + } + } + } + +Sample configuration (Optional) +=============================================== + http { + proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; + + cache_purge_response_type text; + + server { + + cache_purge_response_type json; + + location / { #json + proxy_pass http://127.0.0.1:8000; + proxy_cache tmpcache; + proxy_cache_key "$uri$is_args$args"; + } + + location ~ /purge(/.*) { #xml + allow 127.0.0.1; + deny all; + proxy_cache tmpcache; + proxy_cache_key "$1$is_args$args"; + cache_purge_response_type xml; + } + + location ~ /purge2(/.*) { # json + allow 127.0.0.1; + deny all; + proxy_cache tmpcache; + proxy_cache_key "$1$is_args$args"; + } + } + + server { + + location / { #text + proxy_pass http://127.0.0.1:8000; + proxy_cache tmpcache; + proxy_cache_key "$uri$is_args$args"; + } + + location ~ /purge(/.*) { #text + allow 127.0.0.1; + deny all; + proxy_cache tmpcache; + proxy_cache_key "$1$is_args$args"; + } + + location ~ /purge2(/.*) { #html + allow 127.0.0.1; + deny all; + proxy_cache tmpcache; + proxy_cache_key "$1$is_args$args"; + cache_purge_response_type html; + } + } + } + + + +Solve problems +============== +* Enabling [`gzip_vary`](https://nginx.org/r/gzip_vary) can lead to different results when clearing, when enabling it, you may have problems clearing the cache. For reliable operation, you can disable [`gzip_vary`](https://nginx.org/r/gzip_vary) inside the location [#20](https://github.com/nginx-modules/ngx_cache_purge/issues/20). + + +Testing +======= +`ngx_cache_purge` comes with complete test suite based on [Test::Nginx](http://github.com/agentzh/test-nginx). + +You can test it by running: + +`$ prove` + + +License +======= + Copyright (c) 2009-2014, FRiCKLE + Copyright (c) 2009-2014, Piotr Sikora + All rights reserved. + + This project was fully funded by yo.se. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +See also +======== +- [ngx_slowfs_cache](http://github.com/FRiCKLE/ngx_slowfs_cache). +- http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#purger +- http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache_purge +- https://github.com/wandenberg/nginx-selective-cache-purge-module +- https://github.com/wandenberg/nginx-sorted-querystring-module +- https://github.com/ledgetech/ledge +- [Faking Surrogate Cache-Keys for Nginx Plus](https://www.innoq.com/en/blog/faking-surrogate-cache-keys-for-nginx-plus/) ([gist](https://gist.github.com/titpetric/2f142e89eaa0f36ba4e4383b16d61474)) +- [Delete NGINX cached md5 items with a PURGE with wildcard support](https://gist.github.com/nosun/0cfb58d3164f829e2f027fd37b338ede) diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/config b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/config new file mode 100644 index 0000000..b900680 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/config @@ -0,0 +1,31 @@ +if [ "$HTTP_PROXY" = "YES" ]; then + have=NGX_HTTP_PROXY . auto/have +fi + +if [ "$HTTP_FASTCGI" = "YES" ]; then + have=NGX_HTTP_FASTCGI . auto/have +fi + +if [ "$HTTP_SCGI" = "YES" ]; then + have=NGX_HTTP_SCGI . auto/have +fi + +if [ "$HTTP_UWSGI" = "YES" ]; then + have=NGX_HTTP_UWSGI . auto/have +fi + +ngx_addon_name=ngx_http_cache_purge_module +CACHE_PURGE_SRCS="$ngx_addon_dir/ngx_cache_purge_module.c" + +if [ -n "$ngx_module_link" ]; then + ngx_module_type=HTTP + ngx_module_name="$ngx_addon_name" + ngx_module_srcs="$CACHE_PURGE_SRCS" + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $CACHE_PURGE_SRCS" +fi + +have=NGX_CACHE_PURGE_MODULE . auto/have diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/changelog b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/changelog new file mode 100644 index 0000000..9e03744 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/changelog @@ -0,0 +1,74 @@ +libnginx-mod-http-cache-purge (1:2.5.3-3) unstable; urgency=medium + + * d/control: update my email to janmojzis@debian.org + * d/copyright: update my email to janmojzis@debian.org + * d/control: bump Standards-Version: 4.7.2, no changes + * d/copyright: bump debian/* copyright year + * d/watch: use more generic template + + -- Jan Mojžíš Fri, 11 Apr 2025 14:26:56 +0200 + +libnginx-mod-http-cache-purge (1:2.5.3-2) unstable; urgency=medium + + * d/changelog fix closed bug number 1019003 -> 1055742 (Closes: 1055742) + + -- Jan Mojžíš Fri, 21 Jun 2024 19:34:05 +0200 + +libnginx-mod-http-cache-purge (1:2.5.3-1) unstable; urgency=medium + + * switch to a new upstream + https://github.com/nginx-modules/ngx_cache_purge + (Closes: 1072836) (Closes: 1055742) + * d/p/dynamic-module.patch remove, fixed in upstream + * d/p/segfault-1.11.6.patch remove, fixed in upstream + * d/t/purgetest added + * d/copyright: bump my copyright year + * d/gbp.conf: add [pull] track-missing = True + * d/control: bump Standards-Version: 4.7.0, no changes + + -- Jan Mojžíš Fri, 21 Jun 2024 13:36:53 +0200 + +libnginx-mod-http-cache-purge (1:2.3-6) unstable; urgency=medium + + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + + -- Jan Mojžíš Sat, 07 Oct 2023 15:31:25 +0200 + +libnginx-mod-http-cache-purge (1:2.3-5) unstable; urgency=medium + + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Tue, 27 Jun 2023 23:16:35 +0200 + +libnginx-mod-http-cache-purge (1:2.3-4) unstable; urgency=medium + + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/gbb.conf: switched to debian branch main (debian-branch = main) + * d/copyright: bump my copyright year + * d/copyright: reformat text to be compatible with 'cme update dpkg-copyright' + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 12:56:14 +0100 + +libnginx-mod-http-cache-purge (1:2.3-3) unstable; urgency=medium + + * d/copyright: fixed typo (empty line ngx_cache_purge_module.c) + + -- Jan Mojžíš Fri, 09 Dec 2022 14:50:48 +0100 + +libnginx-mod-http-cache-purge (1:2.3-2) experimental; urgency=medium + + * d/control: added Multi-Arch: foreign + * d/copyright: add Igor Sysoev + Nginx, Inc. + + -- Jan Mojžíš Mon, 05 Dec 2022 21:15:13 +0100 + +libnginx-mod-http-cache-purge (1:2.3-1) experimental; urgency=medium + + * Initial release. (Closes: 1024213) + * Additional info: The separate package libnginx-mod-http-cache-purge ships + newest version of ngx_cache_purge (Closes: 911099) + + -- Jan Mojžíš Wed, 30 Nov 2022 14:46:45 +0100 diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/control b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/control new file mode 100644 index 0000000..3936731 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/control @@ -0,0 +1,23 @@ +Source: libnginx-mod-http-cache-purge +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jan Mojžíš , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, +Standards-Version: 4.7.2 +Homepage: https://github.com/FRiCKLE/ngx_cache_purge +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-cache-purge.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-cache-purge +Rules-Requires-Root: no + +Package: libnginx-mod-http-cache-purge +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: Purge content from Nginx caches + Cache Purge module adds purging capabilities to Nginx. It allows purging + content from caches used by all of Nginx proxy modules, like FastCGI, Proxy, + SCGI and uWSGI. diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/copyright b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/copyright new file mode 100644 index 0000000..a0ef36d --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/copyright @@ -0,0 +1,36 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ngx_cache_purge +Upstream-Contact: FRiCKLE +Source: https://github.com/FRiCKLE/ngx_cache_purge + +Files: * +Copyright: 2009-2014, Piotr Sikora + 2009-2014, FRiCKLE +License: BSD-2-clause + +Files: debian/* +Copyright: 2022, Miao Wang + 2022-2025, Jan Mojzis +License: BSD-2-clause + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/gbp.conf b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/gbp.conf new file mode 100644 index 0000000..97cd209 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/gbp.conf @@ -0,0 +1,12 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace + +[pull] +track-missing = True diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/rules b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/rules new file mode 100755 index 0000000..d8309f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/source/format b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/control b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/control new file mode 100644 index 0000000..dd4e1a3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/control @@ -0,0 +1,13 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, + +Tests: purgetest +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/generic b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/purgetest b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/purgetest new file mode 100644 index 0000000..1574080 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/tests/purgetest @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +cat < "/etc/nginx/sites-enabled/default" +proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; +proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; + +server { + listen 127.0.0.1:80 default_server; + + location /proxy { + proxy_pass \$scheme://127.0.0.1:\$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key \$uri\$is_args\$args; + proxy_cache_valid 3m; + add_header X-Cache-Status \$upstream_cache_status; + } + + location ~ /purge(/.*) { + proxy_cache_purge test_cache \$1\$is_args\$args; + } + + location = /etc/passwd { + root /; + } +} +EOF + +nginx -t +invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; } + +curl --fail -s -o /dev/null -w "GET key: %{http_code}\n" http://127.0.0.1/proxy/passwd +curl --fail -s -o /dev/null -w "PURGE existing key: %{http_code}\n" -X PURGE http://127.0.0.1/purge/proxy/passwd +curl -s -o /dev/null -w "PURGE non-existing key: %{http_code}\n" -X PURGE http://127.0.0.1/purge/proxy/passwd diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/upstream/metadata b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/upstream/metadata new file mode 100644 index 0000000..ca2631c --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/FRiCKLE/ngx_cache_purge/issues +Bug-Submit: https://github.com/FRiCKLE/ngx_cache_purge/issues/new +Repository-Browse: https://github.com/FRiCKLE/ngx_cache_purge \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/watch b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/watch new file mode 100644 index 0000000..11bd9bf --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/nginx-modules/ngx_cache_purge/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/ngx_cache_purge_module.c b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/ngx_cache_purge_module.c new file mode 100644 index 0000000..251d3fe --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/ngx_cache_purge_module.c @@ -0,0 +1,2163 @@ +/* + * Copyright (c) 2009-2014, FRiCKLE + * Copyright (c) 2009-2014, Piotr Sikora + * All rights reserved. + * + * This project was fully funded by yo.se. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + + +#ifndef nginx_version + #error This module cannot be build against an unknown nginx version. +#endif + +#define NGX_REPONSE_TYPE_HTML 1 +#define NGX_REPONSE_TYPE_XML 2 +#define NGX_REPONSE_TYPE_JSON 3 +#define NGX_REPONSE_TYPE_TEXT 4 + +static const char ngx_http_cache_purge_content_type_json[] = "application/json"; +static const char ngx_http_cache_purge_content_type_html[] = "text/html"; +static const char ngx_http_cache_purge_content_type_xml[] = "text/xml"; +static const char ngx_http_cache_purge_content_type_text[] = "text/plain"; + +static size_t ngx_http_cache_purge_content_type_json_size = sizeof(ngx_http_cache_purge_content_type_json); +static size_t ngx_http_cache_purge_content_type_html_size = sizeof(ngx_http_cache_purge_content_type_html); +static size_t ngx_http_cache_purge_content_type_xml_size = sizeof(ngx_http_cache_purge_content_type_xml); +static size_t ngx_http_cache_purge_content_type_text_size = sizeof(ngx_http_cache_purge_content_type_text); + +static const char ngx_http_cache_purge_body_templ_json[] = "{\"Key\": \"%s\"}"; +static const char ngx_http_cache_purge_body_templ_html[] = "Successful purge

Successful purge

Key : %s

"; +static const char ngx_http_cache_purge_body_templ_xml[] = ""; +static const char ngx_http_cache_purge_body_templ_text[] = "Key:%s\n"; + +static size_t ngx_http_cache_purge_body_templ_json_size = sizeof(ngx_http_cache_purge_body_templ_json); +static size_t ngx_http_cache_purge_body_templ_html_size = sizeof(ngx_http_cache_purge_body_templ_html); +static size_t ngx_http_cache_purge_body_templ_xml_size = sizeof(ngx_http_cache_purge_body_templ_xml); +static size_t ngx_http_cache_purge_body_templ_text_size = sizeof(ngx_http_cache_purge_body_templ_text); + +#if (NGX_HTTP_CACHE) + +typedef struct { + ngx_flag_t enable; + ngx_str_t method; + ngx_flag_t purge_all; + ngx_array_t *access; /* array of ngx_in_cidr_t */ + ngx_array_t *access6; /* array of ngx_in6_cidr_t */ +} ngx_http_cache_purge_conf_t; + +typedef struct { +# if (NGX_HTTP_FASTCGI) + ngx_http_cache_purge_conf_t fastcgi; +# endif /* NGX_HTTP_FASTCGI */ +# if (NGX_HTTP_PROXY) + ngx_http_cache_purge_conf_t proxy; +# endif /* NGX_HTTP_PROXY */ +# if (NGX_HTTP_SCGI) + ngx_http_cache_purge_conf_t scgi; +# endif /* NGX_HTTP_SCGI */ +# if (NGX_HTTP_UWSGI) + ngx_http_cache_purge_conf_t uwsgi; +# endif /* NGX_HTTP_UWSGI */ + + ngx_http_cache_purge_conf_t *conf; + ngx_http_handler_pt handler; + ngx_http_handler_pt original_handler; + + ngx_uint_t resptype; /* response content-type */ +} ngx_http_cache_purge_loc_conf_t; + +# if (NGX_HTTP_FASTCGI) +char *ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +ngx_int_t ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r); +# endif /* NGX_HTTP_FASTCGI */ + +# if (NGX_HTTP_PROXY) +char *ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +ngx_int_t ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r); +# endif /* NGX_HTTP_PROXY */ + +# if (NGX_HTTP_SCGI) +char *ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +ngx_int_t ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r); +# endif /* NGX_HTTP_SCGI */ + +# if (NGX_HTTP_UWSGI) +char *ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r); +# endif /* NGX_HTTP_UWSGI */ + +char *ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static ngx_int_t +ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static ngx_int_t +ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); + +ngx_int_t ngx_http_cache_purge_access_handler(ngx_http_request_t *r); +ngx_int_t ngx_http_cache_purge_access(ngx_array_t *a, ngx_array_t *a6, + struct sockaddr *s); + +ngx_int_t ngx_http_cache_purge_send_response(ngx_http_request_t *r); +# if (nginx_version >= 1007009) +ngx_int_t ngx_http_cache_purge_cache_get(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); +# endif /* nginx_version >= 1007009 */ +ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, + ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key); +void ngx_http_cache_purge_handler(ngx_http_request_t *r); + +ngx_int_t ngx_http_file_cache_purge(ngx_http_request_t *r); + + +void ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache); +void ngx_http_cache_purge_partial(ngx_http_request_t *r, ngx_http_file_cache_t *cache); +ngx_int_t ngx_http_cache_purge_is_partial(ngx_http_request_t *r); + +char *ngx_http_cache_purge_conf(ngx_conf_t *cf, + ngx_http_cache_purge_conf_t *cpcf); + +void *ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf); +char *ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + +static ngx_command_t ngx_http_cache_purge_module_commands[] = { + +# if (NGX_HTTP_FASTCGI) + { + ngx_string("fastcgi_cache_purge"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_fastcgi_cache_purge_conf, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, +# endif /* NGX_HTTP_FASTCGI */ + +# if (NGX_HTTP_PROXY) + { + ngx_string("proxy_cache_purge"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_proxy_cache_purge_conf, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, +# endif /* NGX_HTTP_PROXY */ + +# if (NGX_HTTP_SCGI) + { + ngx_string("scgi_cache_purge"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_scgi_cache_purge_conf, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, +# endif /* NGX_HTTP_SCGI */ + +# if (NGX_HTTP_UWSGI) + { + ngx_string("uwsgi_cache_purge"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_uwsgi_cache_purge_conf, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, +# endif /* NGX_HTTP_UWSGI */ + + + { ngx_string("cache_purge_response_type"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_cache_purge_response_type_conf, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + +static ngx_http_module_t ngx_http_cache_purge_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_cache_purge_create_loc_conf, /* create location configuration */ + ngx_http_cache_purge_merge_loc_conf /* merge location configuration */ +}; + +ngx_module_t ngx_http_cache_purge_module = { + NGX_MODULE_V1, + &ngx_http_cache_purge_module_ctx, /* module context */ + ngx_http_cache_purge_module_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 +}; + +# if (NGX_HTTP_FASTCGI) +extern ngx_module_t ngx_http_fastcgi_module; + +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_fastcgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_fastcgi_params_t; + +# endif /* nginx_version >= 1007008 */ + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_str_t index; + +# if (nginx_version >= 1007008) + ngx_http_fastcgi_params_t params; + ngx_http_fastcgi_params_t params_cache; +# else + ngx_array_t *flushes; + ngx_array_t *params_len; + ngx_array_t *params; +# endif /* nginx_version >= 1007008 */ + + ngx_array_t *params_source; + ngx_array_t *catch_stderr; + + ngx_array_t *fastcgi_lengths; + ngx_array_t *fastcgi_values; + +# if (nginx_version >= 8040) && (nginx_version < 1007008) + ngx_hash_t headers_hash; + ngx_uint_t header_params; +# endif /* nginx_version >= 8040 && nginx_version < 1007008 */ + +# if (nginx_version >= 1001004) + ngx_flag_t keep_conn; +# endif /* nginx_version >= 1001004 */ + + ngx_http_complex_value_t cache_key; + +# if (NGX_PCRE) + ngx_regex_t *split_regex; + ngx_str_t split_name; +# endif /* NGX_PCRE */ +} ngx_http_fastcgi_loc_conf_t; + +char * +ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) { + ngx_http_compile_complex_value_t ccv; + ngx_http_cache_purge_loc_conf_t *cplcf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_fastcgi_loc_conf_t *flcf; + ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ + + cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); + + /* check for duplicates / collisions */ + if (cplcf->fastcgi.enable != NGX_CONF_UNSET) { + return "is duplicate"; + } + + if (cf->args->nelts != 3) { + return ngx_http_cache_purge_conf(cf, &cplcf->fastcgi); + } + + if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { + return "(separate location syntax) is not allowed here"; + } + + flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); + +# if (nginx_version >= 1007009) + if (flcf->upstream.cache > 0) +# else + if (flcf->upstream.cache != NGX_CONF_UNSET_PTR + && flcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ + { + return "is incompatible with \"fastcgi_cache\""; + } + + if (flcf->upstream.upstream || flcf->fastcgi_lengths) { + return "is incompatible with \"fastcgi_pass\""; + } + + if (flcf->upstream.store > 0 +# if (nginx_version < 1007009) + || flcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) { + return "is incompatible with \"fastcgi_store\""; + } + + value = cf->args->elts; + + /* set fastcgi_cache part */ +# if (nginx_version >= 1007009) + + flcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + flcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (flcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *flcf->upstream.cache_value = cv; + + } else { + + flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_fastcgi_module); + if (flcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + + flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_fastcgi_module); + if (flcf->upstream.cache == NULL) { + return NGX_CONF_ERROR; + } + +# endif /* nginx_version >= 1007009 */ + + /* set fastcgi_cache_key part */ + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &flcf->cache_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* set handler */ + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + cplcf->fastcgi.enable = 0; + cplcf->conf = &cplcf->fastcgi; + clcf->handler = ngx_http_fastcgi_cache_purge_handler; + + return NGX_CONF_OK; +} + +ngx_int_t +ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r) { + ngx_http_file_cache_t *cache; + ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_cache_purge_loc_conf_t *cplcf; +# if (nginx_version >= 1007009) + ngx_http_fastcgi_main_conf_t *fmcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + r->upstream->conf = &flcf->upstream; + +# if (nginx_version >= 1007009) + + fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module); + + r->upstream->caches = &fmcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = flcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &flcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* Purge-all option */ + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + if (cplcf->conf->purge_all) { + ngx_http_cache_purge_all(r, cache); + } else { + if (ngx_http_cache_purge_is_partial(r)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache purge with partial enabled"); + + ngx_http_cache_purge_partial(r, cache); + } + } + +# if (nginx_version >= 8011) + r->main->count++; +# endif + + ngx_http_cache_purge_handler(r); + + return NGX_DONE; +} +# endif /* NGX_HTTP_FASTCGI */ + +# if (NGX_HTTP_PROXY) +extern ngx_module_t ngx_http_proxy_module; + +typedef struct { + ngx_str_t key_start; + ngx_str_t schema; + ngx_str_t host_header; + ngx_str_t port; + ngx_str_t uri; +} ngx_http_proxy_vars_t; + +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_proxy_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_hash_t hash; +} ngx_http_proxy_headers_t; + +# endif /* nginx_version >= 1007008 */ + +typedef struct { + ngx_http_upstream_conf_t upstream; + +# if (nginx_version >= 1007008) + ngx_array_t *body_flushes; + ngx_array_t *body_lengths; + ngx_array_t *body_values; + ngx_str_t body_source; + + ngx_http_proxy_headers_t headers; + ngx_http_proxy_headers_t headers_cache; +# else + ngx_array_t *flushes; + ngx_array_t *body_set_len; + ngx_array_t *body_set; + ngx_array_t *headers_set_len; + ngx_array_t *headers_set; + ngx_hash_t headers_set_hash; +# endif /* nginx_version >= 1007008 */ + + ngx_array_t *headers_source; +# if (nginx_version < 8040) + ngx_array_t *headers_names; +# endif /* nginx_version < 8040 */ + + ngx_array_t *proxy_lengths; + ngx_array_t *proxy_values; + + ngx_array_t *redirects; +# if (nginx_version >= 1001015) + ngx_array_t *cookie_domains; + ngx_array_t *cookie_paths; +# endif /* nginx_version >= 1001015 */ +# if (nginx_version >= 1019003) + ngx_array_t *cookie_flags; +# endif /* nginx_version >= 1019003 */ +# if (nginx_version < 1007008) + ngx_str_t body_source; +# endif /* nginx_version < 1007008 */ + +# if (nginx_version >= 1011006) + ngx_http_complex_value_t *method; +# else + ngx_str_t method; +# endif /* nginx_version >= 1011006 */ + ngx_str_t location; + ngx_str_t url; + + ngx_http_complex_value_t cache_key; + + ngx_http_proxy_vars_t vars; + + ngx_flag_t redirect; + +# if (nginx_version >= 1001004) + ngx_uint_t http_version; +# endif /* nginx_version >= 1001004 */ + + ngx_uint_t headers_hash_max_size; + ngx_uint_t headers_hash_bucket_size; + +# if (NGX_HTTP_SSL) +# if (nginx_version >= 1005006) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +# endif /* nginx_version >= 1005006 */ +# if (nginx_version >= 1007000) + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +# endif /* nginx_version >= 1007000 */ +# if ((nginx_version >= 1007008) && (nginx_version < 1021000)) + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; +# endif /* nginx_version >= 1007008 && nginx_version < 1021000 */ +# if (nginx_version >= 1019004) + ngx_array_t *ssl_conf_commands; +# endif /*nginx_version >= 1019004 */ +# endif +} ngx_http_proxy_loc_conf_t; + +char * +ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_compile_complex_value_t ccv; + ngx_http_cache_purge_loc_conf_t *cplcf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_proxy_loc_conf_t *plcf; + ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ + + cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); + + /* check for duplicates / collisions */ + if (cplcf->proxy.enable != NGX_CONF_UNSET) { + return "is duplicate"; + } + + if (cf->args->nelts != 3) { + return ngx_http_cache_purge_conf(cf, &cplcf->proxy); + } + + if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { + return "(separate location syntax) is not allowed here"; + } + + plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); + +# if (nginx_version >= 1007009) + if (plcf->upstream.cache > 0) +# else + if (plcf->upstream.cache != NGX_CONF_UNSET_PTR + && plcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ + { + return "is incompatible with \"proxy_cache\""; + } + + if (plcf->upstream.upstream || plcf->proxy_lengths) { + return "is incompatible with \"proxy_pass\""; + } + + if (plcf->upstream.store > 0 +# if (nginx_version < 1007009) + || plcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) { + return "is incompatible with \"proxy_store\""; + } + + value = cf->args->elts; + + /* set proxy_cache part */ +# if (nginx_version >= 1007009) + + plcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + plcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (plcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *plcf->upstream.cache_value = cv; + + } else { + + plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_proxy_module); + if (plcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + + plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_proxy_module); + if (plcf->upstream.cache == NULL) { + return NGX_CONF_ERROR; + } + +# endif /* nginx_version >= 1007009 */ + + /* set proxy_cache_key part */ + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &plcf->cache_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* set handler */ + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + cplcf->proxy.enable = 0; + cplcf->conf = &cplcf->proxy; + clcf->handler = ngx_http_proxy_cache_purge_handler; + + return NGX_CONF_OK; +} + +ngx_int_t +ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) { + ngx_http_file_cache_t *cache; + ngx_http_proxy_loc_conf_t *plcf; + ngx_http_cache_purge_loc_conf_t *cplcf; +# if (nginx_version >= 1007009) + ngx_http_proxy_main_conf_t *pmcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + r->upstream->conf = &plcf->upstream; + +# if (nginx_version >= 1007009) + + pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); + + r->upstream->caches = &pmcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = plcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &plcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* Purge-all option */ + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + if (cplcf->conf->purge_all) { + ngx_http_cache_purge_all(r, cache); + } else { + if (ngx_http_cache_purge_is_partial(r)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache purge with partial enabled"); + + ngx_http_cache_purge_partial(r, cache); + } + } + +# if (nginx_version >= 8011) + r->main->count++; +# endif + + ngx_http_cache_purge_handler(r); + + return NGX_DONE; +} +# endif /* NGX_HTTP_PROXY */ + +# if (NGX_HTTP_SCGI) +extern ngx_module_t ngx_http_scgi_module; + +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_scgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_scgi_params_t; + +# endif /* nginx_version >= 1007008 */ + +typedef struct { + ngx_http_upstream_conf_t upstream; + +# if (nginx_version >= 1007008) + ngx_http_scgi_params_t params; + ngx_http_scgi_params_t params_cache; + ngx_array_t *params_source; +# else + ngx_array_t *flushes; + ngx_array_t *params_len; + ngx_array_t *params; + ngx_array_t *params_source; + + ngx_hash_t headers_hash; + ngx_uint_t header_params; +# endif /* nginx_version >= 1007008 */ + + ngx_array_t *scgi_lengths; + ngx_array_t *scgi_values; + + ngx_http_complex_value_t cache_key; +} ngx_http_scgi_loc_conf_t; + +char * +ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_compile_complex_value_t ccv; + ngx_http_cache_purge_loc_conf_t *cplcf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_scgi_loc_conf_t *slcf; + ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ + + cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); + + /* check for duplicates / collisions */ + if (cplcf->scgi.enable != NGX_CONF_UNSET) { + return "is duplicate"; + } + + if (cf->args->nelts != 3) { + return ngx_http_cache_purge_conf(cf, &cplcf->scgi); + } + + if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { + return "(separate location syntax) is not allowed here"; + } + + slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); + +# if (nginx_version >= 1007009) + if (slcf->upstream.cache > 0) +# else + if (slcf->upstream.cache != NGX_CONF_UNSET_PTR + && slcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ + { + return "is incompatible with \"scgi_cache\""; + } + + if (slcf->upstream.upstream || slcf->scgi_lengths) { + return "is incompatible with \"scgi_pass\""; + } + + if (slcf->upstream.store > 0 +# if (nginx_version < 1007009) + || slcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) { + return "is incompatible with \"scgi_store\""; + } + + value = cf->args->elts; + + /* set scgi_cache part */ +# if (nginx_version >= 1007009) + + slcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + slcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (slcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *slcf->upstream.cache_value = cv; + + } else { + + slcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_scgi_module); + if (slcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + + slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_scgi_module); + if (slcf->upstream.cache == NULL) { + return NGX_CONF_ERROR; + } + +# endif /* nginx_version >= 1007009 */ + + /* set scgi_cache_key part */ + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &slcf->cache_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* set handler */ + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + cplcf->scgi.enable = 0; + cplcf->conf = &cplcf->scgi; + clcf->handler = ngx_http_scgi_cache_purge_handler; + + return NGX_CONF_OK; +} + +ngx_int_t +ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) { + ngx_http_file_cache_t *cache; + ngx_http_scgi_loc_conf_t *slcf; + ngx_http_cache_purge_loc_conf_t *cplcf; +# if (nginx_version >= 1007009) + ngx_http_scgi_main_conf_t *smcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); + + r->upstream->conf = &slcf->upstream; + +# if (nginx_version >= 1007009) + + smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); + + r->upstream->caches = &smcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = slcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &slcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* Purge-all option */ + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + if (cplcf->conf->purge_all) { + ngx_http_cache_purge_all(r, cache); + } else { + if (ngx_http_cache_purge_is_partial(r)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache purge with partial enabled"); + + ngx_http_cache_purge_partial(r, cache); + } + } + +# if (nginx_version >= 8011) + r->main->count++; +# endif + + ngx_http_cache_purge_handler(r); + + return NGX_DONE; +} +# endif /* NGX_HTTP_SCGI */ + +# if (NGX_HTTP_UWSGI) +extern ngx_module_t ngx_http_uwsgi_module; + +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_uwsgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_uwsgi_params_t; + +# endif /* nginx_version >= 1007008 */ + +typedef struct { + ngx_http_upstream_conf_t upstream; + +# if (nginx_version >= 1007008) + ngx_http_uwsgi_params_t params; + ngx_http_uwsgi_params_t params_cache; + ngx_array_t *params_source; +# else + ngx_array_t *flushes; + ngx_array_t *params_len; + ngx_array_t *params; + ngx_array_t *params_source; + + ngx_hash_t headers_hash; + ngx_uint_t header_params; +# endif /* nginx_version >= 1007008 */ + + ngx_array_t *uwsgi_lengths; + ngx_array_t *uwsgi_values; + + ngx_http_complex_value_t cache_key; + + ngx_str_t uwsgi_string; + + ngx_uint_t modifier1; + ngx_uint_t modifier2; + +# if (NGX_HTTP_SSL) +# if (nginx_version >= 1005008) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +# endif /* nginx_version >= 1005008 */ +# if (nginx_version >= 1007000) + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +# endif /* nginx_version >= 1007000 */ +# if ((nginx_version >= 1007008) && (nginx_version < 1021000)) + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; +# endif /* nginx_version >= 1007008 && nginx_version < 1021000 */ +# if (nginx_version >= 1019004) + ngx_array_t *ssl_conf_commands; +# endif /*nginx_version >= 1019004 */ +# endif +} ngx_http_uwsgi_loc_conf_t; + +char * +ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_compile_complex_value_t ccv; + ngx_http_cache_purge_loc_conf_t *cplcf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_uwsgi_loc_conf_t *ulcf; + ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ + + cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); + + /* check for duplicates / collisions */ + if (cplcf->uwsgi.enable != NGX_CONF_UNSET) { + return "is duplicate"; + } + + if (cf->args->nelts != 3) { + return ngx_http_cache_purge_conf(cf, &cplcf->uwsgi); + } + + if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { + return "(separate location syntax) is not allowed here"; + } + + ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); + +# if (nginx_version >= 1007009) + if (ulcf->upstream.cache > 0) +# else + if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR + && ulcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ + { + return "is incompatible with \"uwsgi_cache\""; + } + + if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { + return "is incompatible with \"uwsgi_pass\""; + } + + if (ulcf->upstream.store > 0 +# if (nginx_version < 1007009) + || ulcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) { + return "is incompatible with \"uwsgi_store\""; + } + + value = cf->args->elts; + + /* set uwsgi_cache part */ +# if (nginx_version >= 1007009) + + ulcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + ulcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (ulcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *ulcf->upstream.cache_value = cv; + + } else { + + ulcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_uwsgi_module); + if (ulcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + + ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_uwsgi_module); + if (ulcf->upstream.cache == NULL) { + return NGX_CONF_ERROR; + } + +# endif /* nginx_version >= 1007009 */ + + /* set uwsgi_cache_key part */ + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &ulcf->cache_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* set handler */ + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + cplcf->uwsgi.enable = 0; + cplcf->conf = &cplcf->uwsgi; + clcf->handler = ngx_http_uwsgi_cache_purge_handler; + + return NGX_CONF_OK; +} + + +ngx_int_t +ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) { + ngx_http_file_cache_t *cache; + ngx_http_uwsgi_loc_conf_t *ulcf; + ngx_http_cache_purge_loc_conf_t *cplcf; +# if (nginx_version >= 1007009) + ngx_http_uwsgi_main_conf_t *umcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); + + r->upstream->conf = &ulcf->upstream; + +# if (nginx_version >= 1007009) + + umcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); + + r->upstream->caches = &umcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = ulcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &ulcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* Purge-all option */ + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + if (cplcf->conf->purge_all) { + ngx_http_cache_purge_all(r, cache); + } else { + if (ngx_http_cache_purge_is_partial(r)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache purge with partial enabled"); + + ngx_http_cache_purge_partial(r, cache); + } + } + +# if (nginx_version >= 8011) + r->main->count++; +# endif + + ngx_http_cache_purge_handler(r); + + return NGX_DONE; +} +# endif /* NGX_HTTP_UWSGI */ + + +char * +ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_cache_purge_loc_conf_t *cplcf; + ngx_str_t *value; + + cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); + + /* check for duplicates / collisions */ + if (cplcf->resptype != NGX_CONF_UNSET_UINT && cf->cmd_type == NGX_HTTP_LOC_CONF ) { + return "is duplicate"; + } + + /* sanity check */ + if (cf->args->nelts < 2) { + return "is invalid paramter, ex) cache_purge_response_type (html|json|xml|text)"; + } + + if (cf->args->nelts > 2 ) { + return "is required only 1 option, ex) cache_purge_response_type (html|json|xml|text)"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "html") != 0 && ngx_strcmp(value[1].data, "json") != 0 + && ngx_strcmp(value[1].data, "xml") != 0 && ngx_strcmp(value[1].data, "text") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\", expected" + " \"(html|json|xml|text)\" keyword", &value[1]); + return NGX_CONF_ERROR; + } + + if (cf->cmd_type == NGX_HTTP_MODULE) { + return "(separate server or location syntax) is not allowed here"; + } + + if (ngx_strcmp(value[1].data, "html") == 0) { + cplcf->resptype = NGX_REPONSE_TYPE_HTML; + } else if (ngx_strcmp(value[1].data, "xml") == 0) { + cplcf->resptype = NGX_REPONSE_TYPE_XML; + } else if (ngx_strcmp(value[1].data, "json") == 0) { + cplcf->resptype = NGX_REPONSE_TYPE_JSON; + } else if (ngx_strcmp(value[1].data, "text") == 0) { + cplcf->resptype = NGX_REPONSE_TYPE_TEXT; + } + + return NGX_CONF_OK; +} + +static ngx_int_t +ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) { + return NGX_OK; +} + +static ngx_int_t +ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "http file cache delete: \"%s\"", path->data); + + if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", path->data); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_purge_file_cache_delete_partial_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { + u_char *key_partial; + u_char *key_in_file; + ngx_uint_t len; + ngx_flag_t remove_file = 0; + + key_partial = ctx->data; + len = ngx_strlen(key_partial); + + /* if key_partial is empty always match, because is a '*' */ + if (len == 0) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "empty key_partial, forcing deletion"); + remove_file = 1; + } else { + ngx_file_t file; + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.offset = file.sys_offset = 0; + file.fd = ngx_open_file(path->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, + NGX_FILE_DEFAULT_ACCESS); + if (file.fd == -1) { + return NGX_OK; + } + file.log = ctx->log; + + /* I don't know if it's a good idea to use the ngx_cycle pool for this, + but the request is not available here */ + key_in_file = ngx_pcalloc(ngx_cycle->pool, sizeof(u_char) * (len + 1)); + + /* KEY: /proxy/passwd */ + /* since we don't need the "KEY: " ignore 5 + 1 extra u_char from last + intro */ + /* Optimization: we don't need to read the full key only the n chars + included in key_partial */ + ngx_read_file(&file, key_in_file, sizeof(u_char) * len, + sizeof(ngx_http_file_cache_header_t) + sizeof(u_char) * 6); + ngx_close_file(file.fd); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "http cache file \"%s\" key read: \"%s\"", path->data, key_in_file); + + if (ngx_strncasecmp(key_in_file, key_partial, len) == 0) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "match found, deleting file \"%s\"", path->data); + remove_file = 1; + } + } + + if (remove_file && ngx_delete_file(path->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", path->data); + } + + return NGX_OK; +} + +ngx_int_t +ngx_http_cache_purge_access_handler(ngx_http_request_t *r) { + ngx_http_cache_purge_loc_conf_t *cplcf; + + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + + if (r->method_name.len != cplcf->conf->method.len + || (ngx_strncmp(r->method_name.data, cplcf->conf->method.data, + r->method_name.len))) { + return cplcf->original_handler(r); + } + + if ((cplcf->conf->access || cplcf->conf->access6) + && ngx_http_cache_purge_access(cplcf->conf->access, + cplcf->conf->access6, + r->connection->sockaddr) != NGX_OK) { + return NGX_HTTP_FORBIDDEN; + } + + if (cplcf->handler == NULL) { + return NGX_HTTP_NOT_FOUND; + } + + return cplcf->handler(r); +} + +ngx_int_t +ngx_http_cache_purge_access(ngx_array_t *access, ngx_array_t *access6, + struct sockaddr *s) { + in_addr_t inaddr; + ngx_in_cidr_t *a; + ngx_uint_t i; +# if (NGX_HAVE_INET6) + struct in6_addr *inaddr6; + ngx_in6_cidr_t *a6; + u_char *p; + ngx_uint_t n; +# endif /* NGX_HAVE_INET6 */ + + switch (s->sa_family) { + case AF_INET: + if (access == NULL) { + return NGX_DECLINED; + } + + inaddr = ((struct sockaddr_in *) s)->sin_addr.s_addr; + +# if (NGX_HAVE_INET6) +ipv4: +# endif /* NGX_HAVE_INET6 */ + + a = access->elts; + for (i = 0; i < access->nelts; i++) { + if ((inaddr & a[i].mask) == a[i].addr) { + return NGX_OK; + } + } + + return NGX_DECLINED; + +# if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) s)->sin6_addr; + p = inaddr6->s6_addr; + + if (access && IN6_IS_ADDR_V4MAPPED(inaddr6)) { + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + inaddr = htonl(inaddr); + + goto ipv4; + } + + if (access6 == NULL) { + return NGX_DECLINED; + } + + a6 = access6->elts; + for (i = 0; i < access6->nelts; i++) { + for (n = 0; n < 16; n++) { + if ((p[n] & a6[i].mask.s6_addr[n]) != a6[i].addr.s6_addr[n]) { + goto next; + } + } + + return NGX_OK; + +next: + continue; + } + + return NGX_DECLINED; +# endif /* NGX_HAVE_INET6 */ + } + + return NGX_DECLINED; +} + +ngx_int_t +ngx_http_cache_purge_send_response(ngx_http_request_t *r) { + ngx_chain_t out; + ngx_buf_t *b; + ngx_str_t *key; + ngx_int_t rc; + size_t len; + + size_t body_len; + size_t resp_tmpl_len; + u_char *buf; + u_char *buf_keydata; + u_char *p; + const char *resp_ct; + size_t resp_ct_size; + const char *resp_body; + size_t resp_body_size; + + ngx_http_cache_purge_loc_conf_t *cplcf; + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + + key = r->cache->keys.elts; + + buf_keydata = ngx_pcalloc(r->pool, key[0].len+1); + if (buf_keydata == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = ngx_cpymem(buf_keydata, key[0].data, key[0].len); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + switch(cplcf->resptype) { + + case NGX_REPONSE_TYPE_JSON: + resp_ct = ngx_http_cache_purge_content_type_json; + resp_ct_size = ngx_http_cache_purge_content_type_json_size; + resp_body = ngx_http_cache_purge_body_templ_json; + resp_body_size = ngx_http_cache_purge_body_templ_json_size; + break; + + case NGX_REPONSE_TYPE_XML: + resp_ct = ngx_http_cache_purge_content_type_xml; + resp_ct_size = ngx_http_cache_purge_content_type_xml_size; + resp_body = ngx_http_cache_purge_body_templ_xml; + resp_body_size = ngx_http_cache_purge_body_templ_xml_size; + break; + + case NGX_REPONSE_TYPE_TEXT: + resp_ct = ngx_http_cache_purge_content_type_text; + resp_ct_size = ngx_http_cache_purge_content_type_text_size; + resp_body = ngx_http_cache_purge_body_templ_text; + resp_body_size = ngx_http_cache_purge_body_templ_text_size; + break; + + default: + case NGX_REPONSE_TYPE_HTML: + resp_ct = ngx_http_cache_purge_content_type_html; + resp_ct_size = ngx_http_cache_purge_content_type_html_size; + resp_body = ngx_http_cache_purge_body_templ_html; + resp_body_size = ngx_http_cache_purge_body_templ_html_size; + break; + } + + body_len = resp_body_size - 2 - 1; + r->headers_out.content_type.len = resp_ct_size - 1; + r->headers_out.content_type.data = (u_char *) resp_ct; + + resp_tmpl_len = body_len + key[0].len ; + + buf = ngx_pcalloc(r->pool, resp_tmpl_len); + if (buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = ngx_snprintf(buf, resp_tmpl_len, resp_body , buf_keydata); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + len = body_len + key[0].len; + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = len; + + if (r->method == NGX_HTTP_HEAD) { + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + + out.buf = b; + out.next = NULL; + + b->last = ngx_cpymem(b->last, buf, resp_tmpl_len); + b->last_buf = 1; + + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + return ngx_http_output_filter(r, &out); +} + +# if (nginx_version >= 1007009) + +/* + * Based on: ngx_http_upstream.c/ngx_http_upstream_cache_get + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ +ngx_int_t +ngx_http_cache_purge_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_http_file_cache_t **cache) { + ngx_str_t *name, val; + ngx_uint_t i; + ngx_http_file_cache_t **caches; + + if (u->conf->cache_zone) { + *cache = u->conf->cache_zone->data; + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 + || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) { + return NGX_DECLINED; + } + + caches = u->caches->elts; + + for (i = 0; i < u->caches->nelts; i++) { + name = &caches[i]->shm_zone->shm.name; + + if (name->len == val.len + && ngx_strncmp(name->data, val.data, val.len) == 0) { + *cache = caches[i]; + return NGX_OK; + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "cache \"%V\" not found", &val); + + return NGX_ERROR; +} + +# endif /* nginx_version >= 1007009 */ + +ngx_int_t +ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, + ngx_http_complex_value_t *cache_key) { + ngx_http_cache_t *c; + ngx_str_t *key; + ngx_int_t rc; + + rc = ngx_http_discard_request_body(r); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); + if (c == NULL) { + return NGX_ERROR; + } + + rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t)); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + key = ngx_array_push(&c->keys); + if (key == NULL) { + return NGX_ERROR; + } + + rc = ngx_http_complex_value(r, cache_key, key); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + r->cache = c; + c->body_start = ngx_pagesize; + c->file_cache = cache; + c->file.log = r->connection->log; + + ngx_http_file_cache_create_key(r); + + return NGX_OK; +} + +void +ngx_http_cache_purge_handler(ngx_http_request_t *r) { + ngx_http_cache_purge_loc_conf_t *cplcf; + ngx_int_t rc; + +# if (NGX_HAVE_FILE_AIO) + if (r->aio) { + return; + } +# endif + + cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); + rc = NGX_OK; + if (!cplcf->conf->purge_all && !ngx_http_cache_purge_is_partial(r)) { + rc = ngx_http_file_cache_purge(r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache purge: %i, \"%s\"", + rc, r->cache->file.name.data); + } + + switch (rc) { + case NGX_OK: + r->write_event_handler = ngx_http_request_empty_handler; + ngx_http_finalize_request(r, ngx_http_cache_purge_send_response(r)); + return; + case NGX_DECLINED: + ngx_http_finalize_request(r, NGX_HTTP_PRECONDITION_FAILED); + return; +# if (NGX_HAVE_FILE_AIO) + case NGX_AGAIN: + r->write_event_handler = ngx_http_cache_purge_handler; + return; +# endif + default: + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } +} + +ngx_int_t +ngx_http_file_cache_purge(ngx_http_request_t *r) { + ngx_http_file_cache_t *cache; + ngx_http_cache_t *c; + + switch (ngx_http_file_cache_open(r)) { + case NGX_OK: + case NGX_HTTP_CACHE_STALE: +# if (nginx_version >= 8001) \ + || ((nginx_version < 8000) && (nginx_version >= 7060)) + case NGX_HTTP_CACHE_UPDATING: +# endif + break; + case NGX_DECLINED: + return NGX_DECLINED; +# if (NGX_HAVE_FILE_AIO) + case NGX_AGAIN: + return NGX_AGAIN; +# endif + default: + return NGX_ERROR; + } + + c = r->cache; + cache = c->file_cache; + + /* + * delete file from disk but *keep* in-memory node, + * because other requests might still point to it. + */ + + ngx_shmtx_lock(&cache->shpool->mutex); + + if (!c->node->exists) { + /* race between concurrent purges, backoff */ + ngx_shmtx_unlock(&cache->shpool->mutex); + return NGX_DECLINED; + } + +# if (nginx_version >= 1000001) + cache->sh->size -= c->node->fs_size; + c->node->fs_size = 0; +# else + cache->sh->size -= (c->node->length + cache->bsize - 1) / cache->bsize; + c->node->length = 0; +# endif + + c->node->exists = 0; +# if (nginx_version >= 8001) \ + || ((nginx_version < 8000) && (nginx_version >= 7060)) + c->node->updating = 0; +# endif + + ngx_shmtx_unlock(&cache->shpool->mutex); + + if (ngx_delete_file(c->file.name.data) == NGX_FILE_ERROR) { + /* entry in error log is enough, don't notice client */ + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", c->file.name.data); + } + + /* file deleted from cache */ + return NGX_OK; +} + + +void +ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "purge_all http in %s", + cache->path->name.data); + + /* Walk the tree and remove all the files */ + ngx_tree_ctx_t tree; + tree.init_handler = NULL; + tree.file_handler = ngx_http_purge_file_cache_delete_file; + tree.pre_tree_handler = ngx_http_purge_file_cache_noop; + tree.post_tree_handler = ngx_http_purge_file_cache_noop; + tree.spec_handler = ngx_http_purge_file_cache_noop; + tree.data = NULL; + tree.alloc = 0; + tree.log = ngx_cycle->log; + + ngx_walk_tree(&tree, &cache->path->name); +} + +void +ngx_http_cache_purge_partial(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "purge_partial http in %s", + cache->path->name.data); + + u_char *key_partial; + ngx_str_t *key; + ngx_http_cache_t *c; + ngx_uint_t len; + + c = r->cache; + key = c->keys.elts; + len = key[0].len; + + /* Only check the first key */ + key_partial = ngx_pcalloc(r->pool, sizeof(u_char) * len); + ngx_memcpy(key_partial, key[0].data, sizeof(u_char) * (len - 1)); + + /* Walk the tree and remove all the files matching key_partial */ + ngx_tree_ctx_t tree; + tree.init_handler = NULL; + tree.file_handler = ngx_http_purge_file_cache_delete_partial_file; + tree.pre_tree_handler = ngx_http_purge_file_cache_noop; + tree.post_tree_handler = ngx_http_purge_file_cache_noop; + tree.spec_handler = ngx_http_purge_file_cache_noop; + tree.data = key_partial; + tree.alloc = 0; + tree.log = ngx_cycle->log; + + ngx_walk_tree(&tree, &cache->path->name); +} + +ngx_int_t +ngx_http_cache_purge_is_partial(ngx_http_request_t *r) { + ngx_str_t *key; + ngx_http_cache_t *c; + + c = r->cache; + key = c->keys.elts; + + /* Only check the first key */ + return c->keys.nelts > 0 // number of array elements + && key[0].len > 0 // char length of the key + && key[0].data[key[0].len - 1] == '*'; // is the last char an asterix char? +} + +char * +ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) { + ngx_cidr_t cidr; + ngx_in_cidr_t *access; +# if (NGX_HAVE_INET6) + ngx_in6_cidr_t *access6; +# endif /* NGX_HAVE_INET6 */ + ngx_str_t *value; + ngx_int_t rc; + ngx_uint_t i; + ngx_uint_t from_position; + + from_position = 2; + + /* xxx_cache_purge on|off| [purge_all] [from all| [.. ]] */ + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + cpcf->enable = 0; + return NGX_CONF_OK; + + } else if (ngx_strcmp(value[1].data, "on") == 0) { + ngx_str_set(&cpcf->method, "PURGE"); + + } else { + cpcf->method = value[1]; + } + + if (cf->args->nelts < 4) { + cpcf->enable = 1; + return NGX_CONF_OK; + } + + /* We will purge all the keys */ + if (ngx_strcmp(value[from_position].data, "purge_all") == 0) { + cpcf->purge_all = 1; + from_position++; + } + + + /* sanity check */ + if (ngx_strcmp(value[from_position].data, "from") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\", expected" + " \"from\" keyword", &value[from_position]); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[from_position + 1].data, "all") == 0) { + cpcf->enable = 1; + return NGX_CONF_OK; + } + + for (i = (from_position + 1); i < cf->args->nelts; i++) { + rc = ngx_ptocidr(&value[i], &cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", + &value[i]); + } + + switch (cidr.family) { + case AF_INET: + if (cpcf->access == NULL) { + cpcf->access = ngx_array_create(cf->pool, cf->args->nelts - (from_position + 1), + sizeof(ngx_in_cidr_t)); + if (cpcf->access == NULL) { + return NGX_CONF_ERROR; + } + } + + access = ngx_array_push(cpcf->access); + if (access == NULL) { + return NGX_CONF_ERROR; + } + + access->mask = cidr.u.in.mask; + access->addr = cidr.u.in.addr; + + break; + +# if (NGX_HAVE_INET6) + case AF_INET6: + if (cpcf->access6 == NULL) { + cpcf->access6 = ngx_array_create(cf->pool, cf->args->nelts - (from_position + 1), + sizeof(ngx_in6_cidr_t)); + if (cpcf->access6 == NULL) { + return NGX_CONF_ERROR; + } + } + + access6 = ngx_array_push(cpcf->access6); + if (access6 == NULL) { + return NGX_CONF_ERROR; + } + + access6->mask = cidr.u.in6.mask; + access6->addr = cidr.u.in6.addr; + + break; +# endif /* NGX_HAVE_INET6 */ + } + } + + cpcf->enable = 1; + + return NGX_CONF_OK; +} + +void +ngx_http_cache_purge_merge_conf(ngx_http_cache_purge_conf_t *conf, + ngx_http_cache_purge_conf_t *prev) { + if (conf->enable == NGX_CONF_UNSET) { + if (prev->enable == 1) { + conf->enable = prev->enable; + conf->method = prev->method; + conf->purge_all = prev->purge_all; + conf->access = prev->access; + conf->access6 = prev->access6; + } else { + conf->enable = 0; + } + } +} + +void * +ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) { + ngx_http_cache_purge_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_purge_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->*.method = { 0, NULL } + * conf->*.access = NULL + * conf->*.access6 = NULL + * conf->handler = NULL + * conf->original_handler = NULL + */ + +# if (NGX_HTTP_FASTCGI) + conf->fastcgi.enable = NGX_CONF_UNSET; +# endif /* NGX_HTTP_FASTCGI */ +# if (NGX_HTTP_PROXY) + conf->proxy.enable = NGX_CONF_UNSET; +# endif /* NGX_HTTP_PROXY */ +# if (NGX_HTTP_SCGI) + conf->scgi.enable = NGX_CONF_UNSET; +# endif /* NGX_HTTP_SCGI */ +# if (NGX_HTTP_UWSGI) + conf->uwsgi.enable = NGX_CONF_UNSET; +# endif /* NGX_HTTP_UWSGI */ + + conf->resptype = NGX_CONF_UNSET_UINT; + + conf->conf = NGX_CONF_UNSET_PTR; + + return conf; +} + +char * +ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { + ngx_http_cache_purge_loc_conf_t *prev = parent; + ngx_http_cache_purge_loc_conf_t *conf = child; + ngx_http_core_loc_conf_t *clcf; +# if (NGX_HTTP_FASTCGI) + ngx_http_fastcgi_loc_conf_t *flcf; +# endif /* NGX_HTTP_FASTCGI */ +# if (NGX_HTTP_PROXY) + ngx_http_proxy_loc_conf_t *plcf; +# endif /* NGX_HTTP_PROXY */ +# if (NGX_HTTP_SCGI) + ngx_http_scgi_loc_conf_t *slcf; +# endif /* NGX_HTTP_SCGI */ +# if (NGX_HTTP_UWSGI) + ngx_http_uwsgi_loc_conf_t *ulcf; +# endif /* NGX_HTTP_UWSGI */ + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + ngx_conf_merge_uint_value(conf->resptype, prev->resptype, NGX_REPONSE_TYPE_HTML); + +# if (NGX_HTTP_FASTCGI) + ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi); + + if (conf->fastcgi.enable && clcf->handler != NULL) { + flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); + + if (flcf->upstream.upstream || flcf->fastcgi_lengths) { + conf->conf = &conf->fastcgi; + conf->handler = flcf->upstream.cache + ? ngx_http_fastcgi_cache_purge_handler : NULL; + conf->original_handler = clcf->handler; + + clcf->handler = ngx_http_cache_purge_access_handler; + + return NGX_CONF_OK; + } + } +# endif /* NGX_HTTP_FASTCGI */ + +# if (NGX_HTTP_PROXY) + ngx_http_cache_purge_merge_conf(&conf->proxy, &prev->proxy); + + if (conf->proxy.enable && clcf->handler != NULL) { + plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); + + if (plcf->upstream.upstream || plcf->proxy_lengths) { + conf->conf = &conf->proxy; + conf->handler = plcf->upstream.cache + ? ngx_http_proxy_cache_purge_handler : NULL; + conf->original_handler = clcf->handler; + + clcf->handler = ngx_http_cache_purge_access_handler; + + return NGX_CONF_OK; + } + } +# endif /* NGX_HTTP_PROXY */ + +# if (NGX_HTTP_SCGI) + ngx_http_cache_purge_merge_conf(&conf->scgi, &prev->scgi); + + if (conf->scgi.enable && clcf->handler != NULL) { + slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); + + if (slcf->upstream.upstream || slcf->scgi_lengths) { + conf->conf = &conf->scgi; + conf->handler = slcf->upstream.cache + ? ngx_http_scgi_cache_purge_handler : NULL; + conf->original_handler = clcf->handler; + clcf->handler = ngx_http_cache_purge_access_handler; + + return NGX_CONF_OK; + } + } +# endif /* NGX_HTTP_SCGI */ + +# if (NGX_HTTP_UWSGI) + ngx_http_cache_purge_merge_conf(&conf->uwsgi, &prev->uwsgi); + + if (conf->uwsgi.enable && clcf->handler != NULL) { + ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); + + if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { + conf->conf = &conf->uwsgi; + conf->handler = ulcf->upstream.cache + ? ngx_http_uwsgi_cache_purge_handler : NULL; + conf->original_handler = clcf->handler; + + clcf->handler = ngx_http_cache_purge_access_handler; + + return NGX_CONF_OK; + } + } +# endif /* NGX_HTTP_UWSGI */ + + ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); + + if (conf->handler == NULL) { + conf->handler = prev->handler; + } + + if (conf->original_handler == NULL) { + conf->original_handler = prev->original_handler; + } + + return NGX_CONF_OK; +} + +#else /* !NGX_HTTP_CACHE */ + +static ngx_http_module_t ngx_http_cache_purge_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL, /* merge location configuration */ +}; + +ngx_module_t ngx_http_cache_purge_module = { + NGX_MODULE_V1, + &ngx_http_cache_purge_module_ctx, /* module context */ + NULL, /* 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 +}; + +#endif /* NGX_HTTP_CACHE */ diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1.t new file mode 100644 index 0000000..fefe9b8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1.t @@ -0,0 +1,136 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location ~ /purge(/.*) { + proxy_cache_purge test_cache $1$is_args$args; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1_vars.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1_vars.t new file mode 100644 index 0000000..b9da04b --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy1_vars.t @@ -0,0 +1,138 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location ~ /purge(/.*) { + proxy_cache_purge $cache $1$is_args$args; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2.t new file mode 100644 index 0000000..4c7e19f --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2.t @@ -0,0 +1,349 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 6 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + proxy_cache_purge on; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_allowed = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_forbidden = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 7: purge from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 8: purge from empty cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 9: get from source (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 10: get from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 11: purge from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 12: get from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 13: no cache (PURGE allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 14: no cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 15: multiple cache purge directives +--- http_config eval: $::http_config +--- config + fastcgi_cache_purge on; + proxy_cache_purge on; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2_vars.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2_vars.t new file mode 100644 index 0000000..08e3e1e --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy2_vars.t @@ -0,0 +1,353 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 6 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + proxy_cache_purge on; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_allowed = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_forbidden = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 7: purge from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 8: purge from empty cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 9: get from source (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 10: get from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 11: purge from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 12: get from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 13: no cache (PURGE allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 14: no cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 15: multiple cache purge directives +--- http_config eval: $::http_config +--- config + fastcgi_cache_purge on; + proxy_cache_purge on; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy3.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy3.t new file mode 100644 index 0000000..c8d71d9 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy3.t @@ -0,0 +1,140 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => 32; + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + proxy_cache_purge PURGE purge_all from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + } + + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare passwd +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 2: prepare shadow +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/shadow +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + + +=== TEST 3: get from cache passwd +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 4: get from cache shadow +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/shadow +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 5: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/any +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 6: get from empty cache passwd +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 7: get from empty cache shadow +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/shadow +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy4.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy4.t new file mode 100644 index 0000000..e4d2f30 --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/proxy4.t @@ -0,0 +1,168 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => 41; + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + } + + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare passwd +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 2: prepare passwd2 +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd2 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 3: prepare shadow +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/shadow +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 4: get from cache passwd +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 5: get from cache passwd2 +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd2 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 6: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/pass* +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 7: get from empty cache passwd +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 8: get from empty cache passwd2 +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd2 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ + + +=== TEST 9: get from cache shadow +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/shadow +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ diff --git a/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/resptype1.t b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/resptype1.t new file mode 100644 index 0000000..816c3ff --- /dev/null +++ b/modules_deb/libnginx-mod-http-cache-purge-2.5.3/t/resptype1.t @@ -0,0 +1,245 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + + cache_purge_response_type json; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache test_cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location ~ /purge(/.*) { + proxy_cache_purge test_cache $1$is_args$args; + cache_purge_response_type html; + } + + location ~ /purge_json(/.*) { + proxy_cache_purge test_cache $1$is_args$args; + } + + location ~ /purge_xml(/.*) { + proxy_cache_purge test_cache $1$is_args$args; + cache_purge_response_type xml; + } + + location ~ /purge_text(/.*) { + proxy_cache_purge test_cache $1$is_args$args; + cache_purge_response_type text; + } + + + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 412 +--- response_headers +Content-Type: text/html +--- response_body_like: 412 Precondition Failed +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 + +=== TEST 7-prepare: prepare purge +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd?t=7 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + +=== TEST 7: get a JSON response after purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge_json/proxy/passwd?t=7 +--- error_code: 200 +--- response_headers +Content-Type: application/json +--- response_body_like: {\"Key\": \"\/proxy\/passwd\?t=7\" +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + +=== TEST 8-prepare: prepare purge +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd?t=8 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + +=== TEST 8: get a XML response after purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge_xml/proxy/passwd?t=8 +--- error_code: 200 +--- response_headers +Content-Type: text/xml +--- response_body_like: \<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><\!\[CDATA\[\/proxy\/passwd\?t=8\]\]><\/Key> +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + +=== TEST 9-prepare: prepare purge +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd?t=9 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + +=== TEST 9: get a TEXT response after purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge_text/proxy/passwd?t=9 +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: Key +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 + + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/.gitattributes b/modules_deb/libnginx-mod-http-echo-0.63/.gitattributes new file mode 100644 index 0000000..6fe6f35 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/.gitattributes @@ -0,0 +1 @@ +*.t linguist-language=Text diff --git a/modules_deb/libnginx-mod-http-echo-0.63/.gitignore b/modules_deb/libnginx-mod-http-echo-0.63/.gitignore new file mode 100644 index 0000000..a9948e4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/.gitignore @@ -0,0 +1,65 @@ +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*.mobi +genmobi.sh +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[789] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +reindex +src/location.h +src/filter.c +src/subrequest.h +src/sleep.h +src/util.c +src/echo.c +src/info.c +src/util.h +src/var.h +src/filter.h +src/sleep.c +src/var.c +src/timer.c +src/module.h +src/echo.h +src/info.h +src/foreach.c +src/location.c +src/timer.h +src/module.c +src/subrequest.c +src/handler.h +src/foreach.h +src/handler.c +nginx +*.html +ctags +t/servroot +all +buildroot/ +go +Changes +build1[0-9] +analyze +Makefile +*.plist diff --git a/modules_deb/libnginx-mod-http-echo-0.63/.travis.yml b/modules_deb/libnginx-mod-http-echo-0.63/.travis.yml new file mode 100644 index 0000000..7dda358 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/.travis.yml @@ -0,0 +1,48 @@ +sudo: required +dist: bionic + +os: linux + +language: c + +compiler: + - gcc + +env: + global: + - LUAJIT_PREFIX=/opt/luajit21 + - LUAJIT_LIB=$LUAJIT_PREFIX/lib + - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 + - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH + matrix: + - NGINX_VERSION=1.17.8 + - NGINX_VERSION=1.19.9 + +before_install: + - sudo apt-get install -qq -y cpanminus libgd-dev ca-certificates + - sudo cpanm -v --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1) + +install: + - wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && tar -xzf nginx-${NGINX_VERSION}.tar.gz + - git clone https://github.com/simpl/ngx_devel_kit.git + - git clone https://github.com/openresty/set-misc-nginx-module.git + - git clone https://github.com/openresty/xss-nginx-module.git + - git clone https://github.com/openresty/rds-json-nginx-module.git + - git clone https://github.com/openresty/headers-more-nginx-module.git + - git clone https://github.com/openresty/lua-nginx-module.git + - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + - git clone https://github.com/openresty/nginx-eval-module.git + - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 + +script: + - cd luajit2/ + - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1) + - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) + - cd .. + - cd nginx-${NGINX_VERSION}/ + - ./configure --without-http_ssi_module --with-debug --with-select_module --with-poll_module --with-http_stub_status_module --with-http_image_filter_module --add-module=../ngx_devel_kit --add-module=../set-misc-nginx-module --add-module=../nginx-eval-module --add-module=../xss-nginx-module --add-module=../rds-json-nginx-module --add-module=../headers-more-nginx-module --add-module=../lua-nginx-module --add-module=.. > build.log 2>&1 || (cat build.log && exit 1) + - make -j2 > build.log 2>&1 || (cat build.log && exit 1) + - export PATH=$PATH:`pwd`/objs + - cd .. + - prove -I. -r t diff --git a/modules_deb/libnginx-mod-http-echo-0.63/LICENSE b/modules_deb/libnginx-mod-http-echo-0.63/LICENSE new file mode 100644 index 0000000..6feffbf --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/LICENSE @@ -0,0 +1,25 @@ +Copyright (C) 2009-2014, Yichun "agentzh" Zhang . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-echo-0.63/README.markdown b/modules_deb/libnginx-mod-http-echo-0.63/README.markdown new file mode 100644 index 0000000..a6b25e3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/README.markdown @@ -0,0 +1,1851 @@ +Name +==== + +**ngx_echo** - Brings "echo", "sleep", "time", "exec" and more shell-style goodies to Nginx config file. + +*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Version](#version) +* [Synopsis](#synopsis) +* [Description](#description) +* [Content Handler Directives](#content-handler-directives) + * [echo](#echo) + * [echo_duplicate](#echo_duplicate) + * [echo_flush](#echo_flush) + * [echo_sleep](#echo_sleep) + * [echo_blocking_sleep](#echo_blocking_sleep) + * [echo_reset_timer](#echo_reset_timer) + * [echo_read_request_body](#echo_read_request_body) + * [echo_location_async](#echo_location_async) + * [echo_location](#echo_location) + * [echo_subrequest_async](#echo_subrequest_async) + * [echo_subrequest](#echo_subrequest) + * [echo_foreach_split](#echo_foreach_split) + * [echo_end](#echo_end) + * [echo_request_body](#echo_request_body) + * [echo_exec](#echo_exec) + * [echo_status](#echo_status) +* [Filter Directives](#filter-directives) + * [echo_before_body](#echo_before_body) + * [echo_after_body](#echo_after_body) +* [Variables](#variables) + * [$echo_it](#echo_it) + * [$echo_timer_elapsed](#echo_timer_elapsed) + * [$echo_request_body](#echo_request_body) + * [$echo_request_method](#echo_request_method) + * [$echo_client_request_method](#echo_client_request_method) + * [$echo_client_request_headers](#echo_client_request_headers) + * [$echo_cacheable_request_uri](#echo_cacheable_request_uri) + * [$echo_request_uri](#echo_request_uri) + * [$echo_incr](#echo_incr) + * [$echo_response_status](#echo_response_status) +* [Installation](#installation) +* [Compatibility](#compatibility) +* [Modules that use this module for testing](#modules-that-use-this-module-for-testing) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Report Bugs](#report-bugs) +* [Source Repository](#source-repository) +* [Changes](#changes) +* [Test Suite](#test-suite) +* [TODO](#todo) +* [Getting involved](#getting-involved) +* [Author](#author) +* [Copyright & License](#copyright--license) +* [See Also](#see-also) + +Status +====== + +This module is production ready. + +Version +======= + +This document describes ngx_echo [v0.62](https://github.com/openresty/echo-nginx-module/tags) released on 2 July, 2020. + +Synopsis +======== + +```nginx + + location /hello { + echo "hello, world!"; + } +``` + +```nginx + + location /hello { + echo -n "hello, "; + echo "world!"; + } +``` + +```nginx + + location /timed_hello { + echo_reset_timer; + echo hello world; + echo "'hello world' takes about $echo_timer_elapsed sec."; + echo hiya igor; + echo "'hiya igor' takes about $echo_timer_elapsed sec."; + } +``` + +```nginx + + location /echo_with_sleep { + echo hello; + echo_flush; # ensure the client can see previous output immediately + echo_sleep 2.5; # in sec + echo world; + } +``` + +```nginx + + # in the following example, accessing /echo yields + # hello + # world + # blah + # hiya + # igor + location /echo { + echo_before_body hello; + echo_before_body world; + proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; + echo_after_body hiya; + echo_after_body igor; + } + location /echo/more { + echo blah; + } +``` + +```nginx + + # the output of /main might be + # hello + # world + # took 0.000 sec for total. + # and the whole request would take about 2 sec to complete. + location /main { + echo_reset_timer; + + # subrequests in parallel + echo_location_async /sub1; + echo_location_async /sub2; + + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 2; + echo hello; + } + location /sub2 { + echo_sleep 1; + echo world; + } +``` + +```nginx + + # the output of /main might be + # hello + # world + # took 3.003 sec for total. + # and the whole request would take about 3 sec to complete. + location /main { + echo_reset_timer; + + # subrequests in series (chained by CPS) + echo_location /sub1; + echo_location /sub2; + + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 2; + echo hello; + } + location /sub2 { + echo_sleep 1; + echo world; + } +``` + +```nginx + + # Accessing /dup gives + # ------ END ------ + location /dup { + echo_duplicate 3 "--"; + echo_duplicate 1 " END "; + echo_duplicate 3 "--"; + echo; + } +``` + +```nginx + + # /bighello will generate 1000,000,000 hello's. + location /bighello { + echo_duplicate 1000_000_000 'hello'; + } +``` + +```nginx + + # echo back the client request + location /echoback { + echo_duplicate 1 $echo_client_request_headers; + echo "\r"; + + echo_read_request_body; + + echo_request_body; + } +``` + +```nginx + + # GET /multi will yields + # querystring: foo=Foo + # method: POST + # body: hi + # content length: 2 + # /// + # querystring: bar=Bar + # method: PUT + # body: hello + # content length: 5 + # /// + location /multi { + echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi'; + echo_subrequest_async PUT '/sub' -q 'bar=Bar' -b 'hello'; + } + location /sub { + echo "querystring: $query_string"; + echo "method: $echo_request_method"; + echo "body: $echo_request_body"; + echo "content length: $http_content_length"; + echo '///'; + } +``` + +```nginx + + # GET /merge?/foo.js&/bar/blah.js&/yui/baz.js will merge the .js resources together + location /merge { + default_type 'text/javascript'; + echo_foreach_split '&' $query_string; + echo "/* JS File $echo_it */"; + echo_location_async $echo_it; + echo; + echo_end; + } +``` + +```nginx + + # accessing /if?val=abc yields the "hit" output + # while /if?val=bcd yields "miss": + location ^~ /if { + set $res miss; + if ($arg_val ~* '^a') { + set $res hit; + echo $res; + } + echo $res; + } +``` + +[Back to TOC](#table-of-contents) + +Description +=========== + +This module wraps lots of Nginx internal APIs for streaming input and output, parallel/sequential subrequests, timers and sleeping, as well as various meta data accessing. + +Basically it provides various utilities that help testing and debugging of other modules by trivially emulating different kinds of faked subrequest locations. + +People will also find it useful in real-world applications that need to + +1. serve static contents directly from memory (loading from the Nginx config file). +1. wrap the upstream response with custom header and footer (kinda like the [addition module](http://nginx.org/en/docs/http/ngx_http_addition_module.html) but with contents read directly from the config file and Nginx variables). +1. merge contents of various "Nginx locations" (i.e., subrequests) together in a single main request (using [echo_location](#echo_location) and its friends). + +This is a special dual-role module that can *lazily* serve as a content handler or register itself as an output filter only upon demand. By default, this module does not do anything at all. + +Technically, this module has also demonstrated the following techniques that might be helpful for module writers: + +1. Issue parallel subrequests directly from content handler. +1. Issue chained subrequests directly from content handler, by passing continuation along the subrequest chain. +1. Issue subrequests with all HTTP 1.1 methods and even an optional faked HTTP request body. +1. Interact with the Nginx event model directly from content handler using custom events and timers, and resume the content handler back if necessary. +1. Dual-role module that can (lazily) serve as a content handler or an output filter or both. +1. Nginx config file variable creation and interpolation. +1. Streaming output control using output_chain, flush and its friends. +1. Read client request body from the content handler, and returns back (asynchronously) to the content handler after completion. +1. Use Perl-based declarative [test suite](#test-suite) to drive the development of Nginx C modules. + +[Back to TOC](#table-of-contents) + +Content Handler Directives +========================== + +Use of the following directives register this module to the current Nginx location as a content handler. If you want to use another module, like the [standard proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), as the content handler, use the [filter directives](#filter-directives) provided by this module. + +All the content handler directives can be mixed together in a single Nginx location and they're supposed to run sequentially just as in the Bash scripting language. + +Every content handler directive supports variable interpolation in its arguments (if any). + +The MIME type set by the [standard default_type directive](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) is respected by this module, as in: + +```nginx + + location /hello { + default_type text/plain; + echo hello; + } +``` + +Then on the client side: + +```bash + + $ curl -I 'http://localhost/echo' + HTTP/1.1 200 OK + Server: nginx/0.8.20 + Date: Sat, 17 Oct 2009 03:40:19 GMT + Content-Type: text/plain + Connection: keep-alive +``` + +Since the [v0.22](#v022) release, all of the directives are allowed in the [rewrite module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [if](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if) directive block, for instance: + +```nginx + + location ^~ /if { + set $res miss; + if ($arg_val ~* '^a') { + set $res hit; + echo $res; + } + echo $res; + } +``` + +[Back to TOC](#table-of-contents) + +echo +---- +**syntax:** *echo \[options\] <string>...* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Sends arguments joined by spaces, along with a trailing newline, out to the client. + +Note that the data might be buffered by Nginx's underlying buffer. To force the output data flushed immediately, use the [echo_flush](#echo_flush) command just after `echo`, as in + +```nginx + + echo hello world; + echo_flush; +``` + +When no argument is specified, *echo* emits the trailing newline alone, just like the *echo* command in shell. + +Variables may appear in the arguments. An example is + +```nginx + + echo The current request uri is $request_uri; +``` + +where [$request_uri](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri) is a variable exposed by the [ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html). + +This command can be used multiple times in a single location configuration, as in + +```nginx + + location /echo { + echo hello; + echo world; + } +``` + +The output on the client side looks like this + +```bash + + $ curl 'http://localhost/echo' + hello + world +``` + +Special characters like newlines (`\n`) and tabs (`\t`) can be escaped using C-style escaping sequences. But a notable exception is the dollar sign (`$`). As of Nginx 0.8.20, there's still no clean way to escape this character. (A work-around might be to use a `$echo_dollor` variable that is always evaluated to the constant `$` character. This feature will possibly be introduced in a future version of this module.) + +As of the echo [v0.28](#v028) release, one can suppress the trailing newline character in the output by using the `-n` option, as in + +```nginx + + location /echo { + echo -n "hello, "; + echo "world"; + } +``` + +Accessing `/echo` gives + +```bash + + $ curl 'http://localhost/echo' + hello, world +``` + +Leading `-n` in variable values won't take effect and will be emitted literally, as in + +```nginx + + location /echo { + set $opt -n; + echo $opt "hello,"; + echo "world"; + } +``` + +This gives the following output + +```bash + + $ curl 'http://localhost/echo' + -n hello, + world +``` + +One can output leading `-n` literals and other options using the special `--` option like this + +```nginx + + location /echo { + echo -- -n is an option; + } +``` + +which yields + +```bash + + $ curl 'http://localhost/echo' + -n is an option +``` + +Use this form when you want to output anything leading with a dash (`-`). + +[Back to TOC](#table-of-contents) + +echo_duplicate +-------------- +**syntax:** *echo_duplicate <count> <string>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Outputs duplication of a string indicated by the second argument, using the count specified in the first argument. + +For instance, + +```nginx + + location /dup { + echo_duplicate 3 "abc"; + } +``` + +will lead to the output of `"abcabcabc"`. + +Underscores are allowed in the count number, just like in Perl. For example, to emit 1000,000,000 instances of `"hello, world"`: + +```nginx + + location /many_hellos { + echo_duplicate 1000_000_000 "hello, world"; + } +``` + +The `count` argument could be zero, but not negative. The second `string` argument could be an empty string ("") likewise. + +Unlike the [echo](#echo) directive, no trailing newline is appended to the result. So it's possible to "abuse" this directive as a no-trailing-newline version of [echo](#echo) by using "count" 1, as in + +```nginx + + location /echo_art { + echo_duplicate 2 '---'; + echo_duplicate 1 ' END '; # we don't want a trailing newline here + echo_duplicate 2 '---'; + echo; # we want a trailing newline here... + } +``` + +You get + +```bash + ------ END ------ +``` + +But use of the `-n` option in [echo](#echo) is more appropriate for this purpose. + +This directive was first introduced in [version 0.11](#v011). + +[Back to TOC](#table-of-contents) + +echo_flush +---------- +**syntax:** *echo_flush* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Forces the data potentially buffered by underlying Nginx output filters to send immediately to the client side via socket. + +Note that techically the command just emits a ngx_buf_t object with `flush` slot set to 1, so certain weird third-party output filter module could still block it before it reaches Nginx's (last) write filter. + +This directive does not take any argument. + +Consider the following example: + +```nginx + + location /flush { + echo hello; + + echo_flush; + + echo_sleep 1; + echo world; + } +``` + +Then on the client side, using curl to access `/flush`, you'll see the "hello" line immediately, but only after 1 second, the last "world" line. Without calling `echo_flush` in the example above, you'll most likely see no output until 1 second is elapsed due to the internal buffering of Nginx. + +This directive will fail to flush the output buffer in case of subrequests get involved. Consider the following example: + +```nginx + + location /main { + echo_location_async /sub; + echo hello; + echo_flush; + } + location /sub { + echo_sleep 1; + } +``` + +Then the client won't see "hello" appear even if `echo_flush` has been executed before the subrequest to `/sub` has actually started executing. The outputs of `/main` that are sent *after* [echo_location_async](#echo_location_async) will be postponed and buffered firmly. + +This does *not* apply to outputs sent before the subrequest initiated. For a modified version of the example given above: + +```nginx + + location /main { + echo hello; + echo_flush; + echo_location_async /sub; + } + location /sub { + echo_sleep 1; + } +``` + +The client will immediately see "hello" before `/sub` enters sleeping. + +See also [echo](#echo), [echo_sleep](#echo_sleep), and [echo_location_async](#echo_location_async). + +[Back to TOC](#table-of-contents) + +echo_sleep +---------- +**syntax:** *echo_sleep <seconds>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Sleeps for the time period specified by the argument, which is in seconds. + +This operation is non-blocking on server side, so unlike the [echo_blocking_sleep](#echo_blocking_sleep) directive, it won't block the whole Nginx worker process. + +The period might takes three digits after the decimal point and must be greater than 0.001. + +An example is + +```nginx + + location /echo_after_sleep { + echo_sleep 1.234; + echo resumed!; + } +``` + +Behind the scene, it sets up a per-request "sleep" ngx_event_t object, and adds a timer using that custom event to the Nginx event model and just waits for a timeout on that event. Because the "sleep" event is per-request, this directive can work in parallel subrequests. + +[Back to TOC](#table-of-contents) + +echo_blocking_sleep +------------------- +**syntax:** *echo_blocking_sleep <seconds>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +This is a blocking version of the [echo_sleep](#echo_sleep) directive. + +See the documentation of [echo_sleep](#echo_sleep) for more detail. + +Behind the curtain, it calls the ngx_msleep macro provided by the Nginx core which maps to usleep on POSIX-compliant systems. + +Note that this directive will block the current Nginx worker process completely while being executed, so never use it in production environment. + +[Back to TOC](#table-of-contents) + +echo_reset_timer +---------------- +**syntax:** *echo_reset_timer* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Reset the timer begin time to *now*, i.e., the time when this command is executed during request. + +The timer begin time is default to the starting time of the current request and can be overridden by this directive, potentially multiple times in a single location. For example: + +```nginx + + location /timed_sleep { + echo_sleep 0.03; + echo "$echo_timer_elapsed sec elapsed."; + + echo_reset_timer; + + echo_sleep 0.02; + echo "$echo_timer_elapsed sec elapsed."; + } +``` + +The output on the client side might be + +```bash + + $ curl 'http://localhost/timed_sleep' + 0.032 sec elapsed. + 0.020 sec elapsed. +``` + +The actual figures you get on your side may vary a bit due to your system's current activities. + +Invocation of this directive will force the underlying Nginx timer to get updated to the current system time (regardless the timer resolution specified elsewhere in the config file). Furthermore, references of the [$echo_timer_elapsed](#echo_timer_elapsed) variable will also trigger timer update forcibly. + +See also [echo_sleep](#echo_sleep) and [$echo_timer_elapsed](#echo_timer_elapsed). + +[Back to TOC](#table-of-contents) + +echo_read_request_body +---------------------- +**syntax:** *echo_read_request_body* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Explicitly reads request body so that the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable will always have non-empty values (unless the body is so big that it has been saved by Nginx to a local temporary file). + +Note that this might not be the original client request body because the current request might be a subrequest with a "artificial" body specified by its parent. + +This directive does not generate any output itself, just like [echo_sleep](#echo_sleep). + +Here's an example for echo'ing back the original HTTP client request (both headers and body are included): + +```nginx + + location /echoback { + echo_duplicate 1 $echo_client_request_headers; + echo "\r"; + echo_read_request_body; + echo $request_body; + } +``` + +The content of `/echoback` looks like this on my side (I was using Perl's LWP utility to access this location on the server): + +```bash + + $ (echo hello; echo world) | lwp-request -m POST 'http://localhost/echoback' + POST /echoback HTTP/1.1 + TE: deflate,gzip;q=0.3 + Connection: TE, close + Host: localhost + User-Agent: lwp-request/5.818 libwww-perl/5.820 + Content-Length: 12 + Content-Type: application/x-www-form-urlencoded + + hello + world +``` + +Because `/echoback` is the main request, [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) holds the original client request body. + +Before Nginx 0.7.56, it makes no sense to use this directive because [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) was first introduced in Nginx 0.7.58. + +This directive itself was first introduced in the echo module's [v0.14 release](#v014). + +[Back to TOC](#table-of-contents) + +echo_location_async +------------------- +**syntax:** *echo_location_async <location> [<url_args>]* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Issue GET subrequest to the location specified (first argument) with optional url arguments specified in the second argument. + +As of Nginx 0.8.20, the `location` argument does *not* support named location, due to a limitation in the `ngx_http_subrequest` function. The same is true for its brother, the [echo_location](#echo_location) directive. + +A very simple example is + +```nginx + + location /main { + echo_location_async /sub; + echo world; + } + location /sub { + echo hello; + } +``` + +Accessing `/main` gets + +```bash + + hello + world +``` + +Calling multiple locations in parallel is also possible: + +```nginx + + location /main { + echo_reset_timer; + echo_location_async /sub1; + echo_location_async /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 2; # sleeps 2 sec + echo hello; + } + location /sub2 { + echo_sleep 1; # sleeps 1 sec + echo world; + } +``` + +Accessing `/main` yields + +```bash + + $ time curl 'http://localhost/main' + hello + world + took 0.000 sec for total. + + real 0m2.006s + user 0m0.000s + sys 0m0.004s +``` + +You can see that the main handler `/main` does *not* wait the subrequests `/sub1` and `/sub2` to complete and quickly goes on, hence the "0.000 sec" timing result. The whole request, however takes approximately 2 sec in total to complete because `/sub1` and `/sub2` run in parallel (or "concurrently" to be more accurate). + +If you use [echo_blocking_sleep](#echo_blocking_sleep) in the previous example instead, then you'll get the same output, but with 3 sec total response time, because "blocking sleep" blocks the whole Nginx worker process. + +Locations can also take an optional querystring argument, for instance + +```nginx + + location /main { + echo_location_async /sub 'foo=Foo&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +``` + +Accessing `/main` yields + +```bash + + $ curl 'http://localhost/main' + Foo Bar +``` + +Querystrings is *not* allowed to be concatenated onto the `location` argument with "?" directly, for example, `/sub?foo=Foo&bar=Bar` is an invalid location, and shouldn't be fed as the first argument to this directive. + +Technically speaking, this directive is an example that Nginx content handler issues one or more subrequests directly. AFAIK, the [fancyindex module](https://connectical.com/projects/ngx-fancyindex/wiki) also does such kind of things ;) + +Nginx named locations like `@foo` is *not* supported here. + +This directive is logically equivalent to the GET version of [echo_subrequest_async](#echo_subrequest_async). For example, + +```nginx + + echo_location_async /foo 'bar=Bar'; +``` + +is logically equivalent to + +```nginx + + echo_subrequest_async GET /foo -q 'bar=Bar'; +``` + +But calling this directive is slightly faster than calling [echo_subrequest_async](#echo_subrequest_async) using `GET` because we don't have to parse the HTTP method names like `GET` and options like `-q`. + +This directive is first introduced in [version 0.09](#v009) of this module and requires at least Nginx 0.7.46. + +[Back to TOC](#table-of-contents) + +echo_location +------------- +**syntax:** *echo_location <location> [<url_args>]* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Just like the [echo_location_async](#echo_location_async) directive, but `echo_location` issues subrequests *in series* rather than in parallel. That is, the content handler directives following this directive won't be executed until the subrequest issued by this directive completes. + +The final response body is almost always equivalent to the case when [echo_location_async](#echo_location_async) is used instead, only if timing variables is used in the outputs. + +Consider the following example: + +```nginx + + location /main { + echo_reset_timer; + echo_location /sub1; + echo_location /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 2; + echo hello; + } + location /sub2 { + echo_sleep 1; + echo world; + } +``` + +The location `/main` above will take for total 3 sec to complete (compared to 2 sec if [echo_location_async](#echo_location_async) is used instead here). Here's the result in action on my machine: + +```bash + + $ curl 'http://localhost/main' + hello + world + took 3.003 sec for total. + + real 0m3.027s + user 0m0.020s + sys 0m0.004s +``` + +This directive is logically equivalent to the GET version of [echo_subrequest](#echo_subrequest). For example, + +```nginx + + echo_location /foo 'bar=Bar'; +``` + +is logically equivalent to + +```nginx + + echo_subrequest GET /foo -q 'bar=Bar'; +``` + +But calling this directive is slightly faster than calling [echo_subrequest](#echo_subrequest) using `GET` because we don't have to parse the HTTP method names like `GET` and options like `-q`. + +Behind the scene, it creates an `ngx_http_post_subrequest_t` object as a *continuation* and passes it into the `ngx_http_subrequest` function call. Nginx will later reopen this "continuation" in the subrequest's `ngx_http_finalize_request` function call. We resumes the execution of the parent-request's content handler and starts to run the next directive (command) if any. + +Nginx named locations like `@foo` is *not* supported here. + +This directive was first introduced in the [release v0.12](#v012). + +See also [echo_location_async](#echo_location_async) for more details about the meaning of the arguments. + +[Back to TOC](#table-of-contents) + +echo_subrequest_async +--------------------- +**syntax:** *echo_subrequest_async <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Initiate an asynchronous subrequest using HTTP method, an optional url arguments (or querystring) and an optional request body which can be defined as a string or as a path to a file which contains the body. + +This directive is very much like a generalized version of the [echo_location_async](#echo_location_async) directive. + +Here's a small example demonstrating its usage: + +```nginx + + location /multi { + # body defined as string + echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi'; + # body defined as path to a file, relative to nginx prefix path if not absolute + echo_subrequest_async PUT '/sub' -q 'bar=Bar' -f '/tmp/hello.txt'; + } + location /sub { + echo "querystring: $query_string"; + echo "method: $echo_request_method"; + echo "body: $echo_request_body"; + echo "content length: $http_content_length"; + echo '///'; + } +``` + +Then on the client side: + +```bash + + $ echo -n hello > /tmp/hello.txt + $ curl 'http://localhost/multi' + querystring: foo=Foo + method: POST + body: hi + content length: 2 + /// + querystring: bar=Bar + method: PUT + body: hello + content length: 5 + /// +``` + +Here's more funny example using the standard [proxy module](#httpproxymodule) to handle the subrequest: + +```nginx + + location /main { + echo_subrequest_async POST /sub -b 'hello, world'; + } + location /sub { + proxy_pass $scheme://127.0.0.1:$server_port/proxied; + } + location /proxied { + echo "method: $echo_request_method."; + + # we need to read body explicitly here...or $echo_request_body + # will evaluate to empty ("") + echo_read_request_body; + + echo "body: $echo_request_body."; + } +``` + +Then on the client side, we can see that + +```bash + + $ curl 'http://localhost/main' + method: POST. + body: hello, world. +``` + +Nginx named locations like `@foo` is *not* supported here. + +This directive takes several options: + + + -q Specify the URL arguments (or URL querystring) for the subrequest. + + -f Specify the path for the file whose content will be serve as the + subrequest's request body. + + -b Specify the request body data + + +This directive was first introduced in the [release v0.15](#v015). + +The `-f` option to define a file path for the body was introduced in the [release v0.35](#v035). + +See also the [echo_subrequest](#echo_subrequest) and [echo_location_async](#echo_location_async) directives. + +[Back to TOC](#table-of-contents) + +echo_subrequest +--------------- +**syntax:** *echo_subrequest <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +This is the synchronous version of the [echo_subrequest_async](#echo_subrequest_async) directive. And just like [echo_location](#echo_location), it does not block the Nginx worker process (while [echo_blocking_sleep](#echo_blocking_sleep) does), rather, it uses continuation to pass control along the subrequest chain. + +See [echo_subrequest_async](#echo_subrequest_async) for more details. + +Nginx named locations like `@foo` is *not* supported here. + +This directive was first introduced in the [release v0.15](#v015). + +[Back to TOC](#table-of-contents) + +echo_foreach_split +------------------ +**syntax:** *echo_foreach_split <delimiter> <string>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Split the second argument `string` using the delimiter specified in the first argument, and then iterate through the resulting items. For instance: + +```nginx + + location /loop { + echo_foreach_split ',' $arg_list; + echo "item: $echo_it"; + echo_end; + } +``` + +Accessing /main yields + +```bash + + $ curl 'http://localhost/loop?list=cat,dog,mouse' + item: cat + item: dog + item: mouse +``` + +As seen in the previous example, this directive should always be accompanied by an [echo_end](#echo_end) directive. + +Parallel `echo_foreach_split` loops are allowed, but nested ones are currently forbidden. + +The `delimiter` argument could contain *multiple* arbitrary characters, like + +```nginx + + # this outputs "cat\ndog\nmouse\n" + echo_foreach_split -- '-a-' 'cat-a-dog-a-mouse'; + echo $echo_it; + echo_end; +``` + +Logically speaking, this looping structure is just the `foreach` loop combined with a `split` function call in Perl (using the previous example): + +```perl + + foreach (split ',', $arg_list) { + print "item $_\n"; + } +``` + +People will also find it useful in merging multiple `.js` or `.css` resources into a whole. Here's an example: + +```nginx + + location /merge { + default_type 'text/javascript'; + + echo_foreach_split '&' $query_string; + echo "/* JS File $echo_it */"; + echo_location_async $echo_it; + echo; + echo_end; + } +``` + +Then accessing /merge to merge the `.js` resources specified in the query string: + +```bash + + $ curl 'http://localhost/merge?/foo/bar.js&/yui/blah.js&/baz.js' +``` + +One can also use third-party Nginx cache module to cache the merged response generated by the `/merge` location in the previous example. + +This directive was first introduced in the [release v0.17](#v017). + +[Back to TOC](#table-of-contents) + +echo_end +-------- +**syntax:** *echo_end* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +This directive is used to terminate the body of looping and conditional control structures like [echo_foreach_split](#echo_foreach_split). + +This directive was first introduced in the [release v0.17](#v017). + +[Back to TOC](#table-of-contents) + +echo_request_body +----------------- +**syntax:** *echo_request_body* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Outputs the contents of the request body previous read. + +Behind the scene, it's implemented roughly like this: + +```C + + if (r->request_body && r->request_body->bufs) { + return ngx_http_output_filter(r, r->request_body->bufs); + } +``` + +Unlike the [$echo_request_body](#echo_request_body) and $request_body variables, this directive will show the whole request body even if some parts or all parts of it are saved in temporary files on the disk. + +It is a "no-op" if no request body has been read yet. + +This directive was first introduced in the [release v0.18](#v018). + +See also [echo_read_request_body](#echo_read_request_body) and the [chunkin module](http://github.com/agentzh/chunkin-nginx-module). + +[Back to TOC](#table-of-contents) + +echo_exec +--------- +**syntax:** *echo_exec <location> [<query_string>]* + +**syntax:** *echo_exec <named_location>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *content* + +Does an internal redirect to the location specified. An optional query string can be specified for normal locations, as in + +```nginx + + location /foo { + echo_exec /bar weight=5; + } + location /bar { + echo $arg_weight; + } +``` + +Or equivalently + +```nginx + + location /foo { + echo_exec /bar?weight=5; + } + location /bar { + echo $arg_weight; + } +``` + +Named locations are also supported. Here's an example: + +```nginx + + location /foo { + echo_exec @bar; + } + location @bar { + # you'll get /foo rather than @bar + # due to a potential bug in nginx. + echo $echo_request_uri; + } +``` + +But query string (if any) will always be ignored for named location redirects due to a limitation in the `ngx_http_named_location` function. + +Never try to echo things before the `echo_exec` directive or you won't see the proper response of the location you want to redirect to. Because any echoing will cause the original location handler to send HTTP headers before the redirection happens. + +Technically speaking, this directive exposes the Nginx internal API functions `ngx_http_internal_redirect` and `ngx_http_named_location`. + +This directive was first introduced in the [v0.21 release](#v021). + +[Back to TOC](#table-of-contents) + +echo_status +----------- +**syntax:** *echo_status <status-num>* + +**default:** *echo_status 200* + +**context:** *location, location if* + +**phase:** *content* + +Specify the default response status code. Default to `200`. This directive is declarative and the relative order with other echo-like directives is not important. + +Here is an example, + +```nginx + + location = /bad { + echo_status 404; + echo "Something is missing..."; + } +``` + +then we get a response like this: + + + HTTP/1.1 404 Not Found + Server: nginx/1.2.1 + Date: Sun, 24 Jun 2012 03:58:18 GMT + Content-Type: text/plain + Transfer-Encoding: chunked + Connection: keep-alive + + Something is missing... + + +This directive was first introduced in the `v0.40` release. + +[Back to TOC](#table-of-contents) + +Filter Directives +================= + +Use of the following directives trigger the filter registration of this module. By default, no filter will be registered by this module. + +Every filter directive supports variable interpolation in its arguments (if any). + +[Back to TOC](#table-of-contents) + +echo_before_body +---------------- +**syntax:** *echo_before_body \[options\] \[argument\]...* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *output filter* + +It's the filter version of the [echo](#echo) directive, and prepends its output to the beginning of the original outputs generated by the underlying content handler. + +An example is + +```nginx + + location /echo { + echo_before_body hello; + proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; + } + location /echo/more { + echo world + } +``` + +Accessing `/echo` from the client side yields + +```bash + + hello + world +``` + +In the previous sample, we borrow the [standard proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) to serve as the underlying content handler that generates the "main contents". + +Multiple instances of this filter directive are also allowed, as in: + +```nginx + + location /echo { + echo_before_body hello; + echo_before_body world; + echo !; + } +``` + +On the client side, the output is like + +```bash + + $ curl 'http://localhost/echo' + hello + world + ! +``` + +In this example, we also use the [content handler directives](#content-handler-directives) provided by this module as the underlying content handler. + +This directive also supports the `-n` and `--` options like the [echo](#echo) directive. + +This directive can be mixed with its brother directive [echo_after_body](#echo_after_body). + +[Back to TOC](#table-of-contents) + +echo_after_body +--------------- +**syntax:** *echo_after_body \[argument\]...* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *output filter* + +It's very much like the [echo_before_body](#echo_before_body) directive, but *appends* its output to the end of the original outputs generated by the underlying content handler. + +Here's a simple example: + +```nginx + + location /echo { + echo_after_body hello; + proxy_pass http://127.0.0.1:$server_port$request_uri/more; + } + location /echo/more { + echo world + } +``` + +Accessing `/echo` from the client side yields + + + world + hello + + +Multiple instances are allowed, as in: + +```nginx + + location /echo { + echo_after_body hello; + echo_after_body world; + echo i; + echo say; + } +``` + +The output on the client side while accessing the `/echo` location looks like + + + i + say + hello + world + + +This directive also supports the `-n` and `--` options like the [echo](#echo) directive. + +This directive can be mixed with its brother directive [echo_before_body](#echo_before_body). + +[Back to TOC](#table-of-contents) + +Variables +========= + +[Back to TOC](#table-of-contents) + +$echo_it +-------- + +This is a "topic variable" used by [echo_foreach_split](#echo_foreach_split), just like the `$_` variable in Perl. + +[Back to TOC](#table-of-contents) + +$echo_timer_elapsed +------------------- + +This variable holds the seconds elapsed since the start of the current request (might be a subrequest though) or the last invocation of the [echo_reset_timer](#echo_reset_timer) command. + +The timing result takes three digits after the decimal point. + +References of this variable will force the underlying Nginx timer to update to the current system time, regardless the timer resolution settings elsewhere in the config file, just like the [echo_reset_timer](#echo_reset_timer) directive. + +[Back to TOC](#table-of-contents) + +$echo_request_body +------------------ + +Evaluates to the current (sub)request's request body previously read if no part of the body has been saved to a temporary file. To always show the request body even if it's very large, use the [echo_request_body](#echo_request_body) directive. + +[Back to TOC](#table-of-contents) + +$echo_request_method +-------------------- + +Evaluates to the HTTP request method of the current request (it can be a subrequest). + +Behind the scene, it just takes the string data stored in `r->method_name`. + +Compare it to the [$echo_client_request_method](#echo_client_request_method) variable. + +At least for Nginx 0.8.20 and older, the [$request_method](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_method) variable provided by the [http core module](http://nginx.org/en/docs/http/ngx_http_core_module.html) is actually doing what our [$echo_client_request_method](#echo_client_request_method) is doing. + +This variable was first introduced in our [v0.15 release](#v015). + +[Back to TOC](#table-of-contents) + +$echo_client_request_method +--------------------------- + +Always evaluates to the main request's HTTP method even if the current request is a subrequest. + +Behind the scene, it just takes the string data stored in `r->main->method_name`. + +Compare it to the [$echo_request_method](#echo_request_method) variable. + +This variable was first introduced in our [v0.15 release](#v015). + +[Back to TOC](#table-of-contents) + +$echo_client_request_headers +---------------------------- + +Evaluates to the original client request's headers. + +Just as the name suggests, it will always take the main request (or the client request) even if it's currently executed in a subrequest. + +A simple example is below: + +```nginx + + location /echoback { + echo "headers are:" + echo $echo_client_request_headers; + } +``` + +Accessing `/echoback` yields + +```bash + + $ curl 'http://localhost/echoback' + headers are + GET /echoback HTTP/1.1 + User-Agent: curl/7.18.2 (i486-pc-linux-gnu) libcurl/7.18.2 OpenSSL/0.9.8g + Host: localhost:1984 + Accept: */* +``` + +Behind the scene, it recovers `r->main->header_in` (or the large header buffers, if any) on the C level and does not construct the headers itself by traversing parsed results in the request object. + +This varible is always evaluated to an empty value in HTTP/2 requests for now due to the current implementation. + +This variable was first introduced in [version 0.15](#v015). + +[Back to TOC](#table-of-contents) + +$echo_cacheable_request_uri +--------------------------- + +Evaluates to the parsed form of the URI (usually led by `/`) of the current (sub-)request. Unlike the [$echo_request_uri](#echo_request_uri) variable, it is cacheable. + +See [$echo_request_uri](#echo_request_uri) for more details. + +This variable was first introduced in [version 0.17](#v017). + +[Back to TOC](#table-of-contents) + +$echo_request_uri +----------------- + +Evaluates to the parsed form of the URI (usually led by `/`) of the current (sub-)request. Unlike the [$echo_cacheable_request_uri](#echo_cacheable_request_uri) variable, it is *not* cacheable. + +This is quite different from the [$request_uri](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri) variable exported by the [ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html), because `$request_uri` is the *unparsed* form of the current request's URI. + +This variable was first introduced in [version 0.17](#v017). + +[Back to TOC](#table-of-contents) + +$echo_incr +---------- + +It is a counter that always generate the current counting number, starting from 1. The counter is always associated with the main request even if it is accessed within a subrequest. + +Consider the following example + +```Nginx + + location /main { + echo "main pre: $echo_incr"; + echo_location_async /sub; + echo_location_async /sub; + echo "main post: $echo_incr"; + } + location /sub { + echo "sub: $echo_incr"; + } +``` + +Accessing `/main` yields + + main pre: 1 + sub: 3 + sub: 4 + main post: 2 + +This directive was first introduced in the [v0.18 release](#v018). + +[Back to TOC](#table-of-contents) + +$echo_response_status +--------------------- + +Evaluates to the status code of the current (sub)request, null if not any. + +Behind the scene, it's just the textual representation of `r->headers_out->status`. + +This directive was first introduced in the [v0.23 release](#v023). + +[Back to TOC](#table-of-contents) + +Installation +============ + +You're recommended to install this module (as well as the Nginx core and many other goodies) via the [OpenResty bundle](http://openresty.org). See [the detailed instructions](http://openresty.org/#Installation) for downloading and installing OpenResty into your system. This is the easiest and most safe way to set things up. + +Alternatively, you can install this module manually with the Nginx source: + +Grab the nginx source code from [nginx.org](http://nginx.org/), for example, +the version 1.11.2 (see [nginx compatibility](#compatibility)), and then build the source with this module: + +```bash + + $ wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' + $ tar -xzvf nginx-1.11.2.tar.gz + $ cd nginx-1.11.2/ + + # Here we assume you would install you nginx under /opt/nginx/. + $ ./configure --prefix=/opt/nginx \ + --add-module=/path/to/echo-nginx-module + + $ make -j2 + $ make install +``` + +Download the latest version of the release tarball of this module from [echo-nginx-module file list](https://github.com/openresty/echo-nginx-module/tags). + +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ngx_http_echo_module.so; +``` + +Also, this module is included and enabled by default in the [OpenResty bundle](http://openresty.org). + +[Back to TOC](#table-of-contents) + +Compatibility +============= + +The following versions of Nginx should work with this module: + +* **1.16.x** +* **1.15.x** (last tested: 1.15.8) +* **1.14.x** +* **1.13.x** (last tested: 1.13.6) +* **1.12.x** +* **1.11.x** (last tested: 1.11.2) +* **1.10.x** +* **1.9.x** (last tested: 1.9.15) +* **1.8.x** +* **1.7.x** (last tested: 1.7.10) +* **1.6.x** +* **1.5.x** (last tested: 1.5.12) +* **1.4.x** (last tested: 1.4.4) +* **1.3.x** (last tested: 1.3.7) +* **1.2.x** (last tested: 1.2.9) +* **1.1.x** (last tested: 1.1.5) +* **1.0.x** (last tested: 1.0.11) +* **0.9.x** (last tested: 0.9.4) +* **0.8.x** (last tested: 0.8.54) +* **0.7.x >= 0.7.21** (last tested: 0.7.68) + +In particular, + +* the directive [echo_location_async](#echo_location_async) and its brother [echo_subrequest_async](#echo_subrequest_async) do *not* work with **0.7.x < 0.7.46**. +* the [echo_after_body](#echo_after_body) directive does *not* work at all with nginx **< 0.8.7**. +* the [echo_sleep](#echo_sleep) directive cannot be used after [echo_location](#echo_location) or [echo_subrequest](#echo_subrequest) for nginx **< 0.8.11**. + +Earlier versions of Nginx like 0.6.x and 0.5.x will *not* work at all. + +If you find that any particular version of Nginx above 0.7.21 does not work with this module, please consider [reporting a bug](#report-bugs). + +[Back to TOC](#table-of-contents) + +Modules that use this module for testing +======================================== + +The following modules take advantage of this `echo` module in their test suite: + +* The [memc](http://github.com/openresty/memc-nginx-module) module that supports almost the whole memcached TCP protocol. +* The [chunkin](http://github.com/agentzh/chunkin-nginx-module) module that adds HTTP 1.1 chunked input support to Nginx. +* The [headers_more](http://github.com/openresty/headers-more-nginx-module) module that allows you to add, set, and clear input and output headers under the conditions that you specify. +* The `echo` module itself. + +Please mail me other modules that use `echo` in any form and I'll add them to the list above :) + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Report Bugs +=========== + +Although a lot of effort has been put into testing and code tuning, there must be some serious bugs lurking somewhere in this module. So whenever you are bitten by any quirks, please don't hesitate to + +1. create a ticket on the [issue tracking interface](https://github.com/openresty/echo-nginx-module/issues) provided by GitHub, +1. or send a bug report, questions, or even patches to the [OpenResty Community](#community). + +[Back to TOC](#table-of-contents) + +Source Repository +================= + +Available on github at [openresty/echo-nginx-module](https://github.com/openresty/echo-nginx-module). + +[Back to TOC](#table-of-contents) + +Changes +======= + +The changes of every release of this module can be obtained from the OpenResty bundle's change logs: + + + +[Back to TOC](#table-of-contents) + +Test Suite +========== + +This module comes with a Perl-driven test suite. The [test cases](https://github.com/openresty/echo-nginx-module/tree/master/t/) are +[declarative](https://github.com/openresty/echo-nginx-module/blob/master/t/echo.t) too. Thanks to the [Test::Nginx](http://search.cpan.org/perldoc?Test::Nginx) module in the Perl world. + +To run it on your side: + +```bash + + $ PATH=/path/to/your/nginx-with-echo-module:$PATH prove -r t +``` + +You need to terminate any Nginx processes before running the test suite if you have changed the Nginx server binary. + +Because a single nginx server (by default, `localhost:1984`) is used across all the test scripts (`.t` files), it's meaningless to run the test suite in parallel by specifying `-jN` when invoking the `prove` utility. + +Some parts of the test suite requires standard modules [proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) and [SSI](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) to be enabled as well when building Nginx. + +[Back to TOC](#table-of-contents) + +TODO +==== + +* Fix the [echo_after_body](#echo_after_body) directive in subrequests. +* Add directives *echo_read_client_request_body* and *echo_request_headers*. +* Add new directive *echo_log* to use Nginx's logging facility directly from the config file and specific loglevel can be specified, as in + +```nginx + + echo_log debug "I am being called."; +``` + +* Add support for options `-h` and `-t` to [echo_subrequest_async](#echo_subrequest_async) and [echo_subrequest](#echo_subrequest). For example + +```nginx + + echo_subrequest POST /sub -q 'foo=Foo&bar=Bar' -b 'hello' -t 'text/plan' -h 'X-My-Header: blah blah' +``` + +* Add options to control whether a subrequest should inherit cached variables from its parent request (i.e. the current request that is calling the subrequest in question). Currently none of the subrequests issued by this module inherit the cached variables from the parent request. +* Add new variable *$echo_active_subrequests* to show `r->main->count - 1`. +* Add the *echo_file* and *echo_cached_file* directives. +* Add new varaible *$echo_request_headers* to accompany the existing [$echo_client_request_headers](#echo_client_request_headers) variable. +* Add new directive *echo_foreach*, as in + +```nginx + + echo_foreach 'cat' 'dog' 'mouse'; + echo_location_async "/animals/$echo_it"; + echo_end; +``` + +* Add new directive *echo_foreach_range*, as in + +```nginx + + echo_foreach_range '[1..100]' '[a-zA-z0-9]'; + echo_location_async "/item/$echo_it"; + echo_end; +``` + +* Add new directive *echo_repeat*, as in + +```nginx + + echo_repeat 10 $i { + echo "Page $i"; + echo_location "/path/to/page/$i"; + } +``` + +This is just another way of saying + +```nginx + + echo_foreach_range $i [1..10]; + echo "Page $i"; + echo_location "/path/to/page/$i"; + echo_end; +``` + +Thanks Marcus Clyne for providing this idea. + +* Add new variable $echo_random which always returns a random non-negative integer with the lower/upper limit specified by the new directives `echo_random_min` and `echo_random_max`. For example, + +```nginx + + echo_random_min 10 + echo_random_max 200 + echo "random number: $echo_random"; +``` + +Thanks Marcus Clyne for providing this idea. + +[Back to TOC](#table-of-contents) + +Getting involved +================ + +You'll be very welcomed to submit patches to the [author](#author) or just ask for a commit bit to the [source repository](#source-repository) on GitHub. + +[Back to TOC](#table-of-contents) + +Author +====== + +Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, OpenResty Inc. + +This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. + +[Back to TOC](#table-of-contents) + +Copyright & License +=================== + +Copyright (c) 2009-2018, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. + +This module is licensed under the terms of the BSD license. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== + +* The original [blog post](http://agentzh.blogspot.com/2009/10/hacking-on-nginx-echo-module.html) about this module's initial development. +* The standard [addition filter module](http://nginx.org/en/docs/http/ngx_http_addition_module.html). +* The standard [proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html). +* The [OpenResty](http://openresty.org) bundle. + +[Back to TOC](#table-of-contents) + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/config b/modules_deb/libnginx-mod-http-echo-0.63/config new file mode 100644 index 0000000..4bf0f00 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/config @@ -0,0 +1,63 @@ +ngx_addon_name=ngx_http_echo_module + +ECHO_SRCS=" \ + $ngx_addon_dir/src/ngx_http_echo_module.c \ + $ngx_addon_dir/src/ngx_http_echo_util.c \ + $ngx_addon_dir/src/ngx_http_echo_timer.c \ + $ngx_addon_dir/src/ngx_http_echo_var.c \ + $ngx_addon_dir/src/ngx_http_echo_handler.c \ + $ngx_addon_dir/src/ngx_http_echo_filter.c \ + $ngx_addon_dir/src/ngx_http_echo_sleep.c \ + $ngx_addon_dir/src/ngx_http_echo_location.c \ + $ngx_addon_dir/src/ngx_http_echo_echo.c \ + $ngx_addon_dir/src/ngx_http_echo_request_info.c \ + $ngx_addon_dir/src/ngx_http_echo_subrequest.c \ + $ngx_addon_dir/src/ngx_http_echo_foreach.c \ + " + +ECHO_DEPS=" \ + $ngx_addon_dir/src/ddebug.h \ + $ngx_addon_dir/src/ngx_http_echo_module.h \ + $ngx_addon_dir/src/ngx_http_echo_handler.h \ + $ngx_addon_dir/src/ngx_http_echo_util.h \ + $ngx_addon_dir/src/ngx_http_echo_sleep.h \ + $ngx_addon_dir/src/ngx_http_echo_filter.h \ + $ngx_addon_dir/src/ngx_http_echo_var.h \ + $ngx_addon_dir/src/ngx_http_echo_location.h \ + $ngx_addon_dir/src/ngx_http_echo_echo.h \ + $ngx_addon_dir/src/ngx_http_echo_request_info.h \ + $ngx_addon_dir/src/ngx_http_echo_subrequest.h \ + $ngx_addon_dir/src/ngx_http_echo_foreach.h \ + " + +# nginx 1.17.0+ unconditionally enables the postpone filter +if [ ! -z "$HTTP_POSTPONE" ]; then + # nginx won't have HTTP_POSTPONE_FILTER_MODULE & HTTP_POSTPONE_FILTER_SRCS + # defined since 1.9.11 + if [ -z "$HTTP_POSTPONE_FILTER_MODULE" ]; then + HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module + HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c + fi + + # This module depends upon the postpone filter being activated + if [ "$HTTP_POSTPONE" != YES ]; then + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS" + HTTP_POSTPONE=YES + fi +fi + +if [ -n "$ngx_module_link" ]; then + ngx_module_type=HTTP_AUX_FILTER + ngx_module_name=$ngx_addon_name + ngx_module_incs= + ngx_module_deps="$ECHO_DEPS" + ngx_module_srcs="$ECHO_SRCS" + ngx_module_libs= + + . auto/module +else + HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ECHO_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ECHO_DEPS" +fi diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/changelog b/modules_deb/libnginx-mod-http-echo-0.63/debian/changelog new file mode 100644 index 0000000..1e6c923 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/changelog @@ -0,0 +1,53 @@ +libnginx-mod-http-echo (1:0.63-7) unstable; urgency=medium + + * d/control: update my email to janmojzis@debian.org + * d/copyright: update my email to janmojzis@debian.org + * d/control: bump Standards-Version: 4.7.2, no changes + * d/copyright: bump debian/* copyright year + * d/watch: use more generic template + + -- Jan Mojžíš Fri, 11 Apr 2025 14:26:58 +0200 + +libnginx-mod-http-echo (1:0.63-6) unstable; urgency=medium + + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + + -- Jan Mojžíš Sat, 07 Oct 2023 15:31:26 +0200 + +libnginx-mod-http-echo (1:0.63-5) unstable; urgency=medium + + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Tue, 27 Jun 2023 23:16:36 +0200 + +libnginx-mod-http-echo (1:0.63-4) unstable; urgency=medium + + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/gbb.conf: added + * d/copyright: bump my copyright year + * d/copyright: reformat text to be compatible with 'cme update dpkg-copyright' + * d/fix.scanned.copyright: added, fixes upstream author name parsing + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 15:03:42 +0100 + +libnginx-mod-http-echo (1:0.63-3) unstable; urgency=medium + + * No source change upload to unstable. + + -- Jan Mojžíš Fri, 09 Dec 2022 14:36:45 +0100 + +libnginx-mod-http-echo (1:0.63-2) experimental; urgency=medium + + * d/control: added Multi-Arch: foreign + * d/copyright: update, add Igor Sysoev + + -- Jan Mojžíš Mon, 05 Dec 2022 21:14:02 +0100 + +libnginx-mod-http-echo (1:0.63-1) experimental; urgency=medium + + * Initial release. (Closes: 1024153) + + -- Jan Mojžíš Wed, 30 Nov 2022 14:46:48 +0100 diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/control b/modules_deb/libnginx-mod-http-echo-0.63/debian/control new file mode 100644 index 0000000..e7cfde3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/control @@ -0,0 +1,36 @@ +Source: libnginx-mod-http-echo +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jan Mojžíš , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, +Standards-Version: 4.7.2 +Homepage: https://github.com/agentzh/echo-nginx-module +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-echo.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-echo +Rules-Requires-Root: no + +Package: libnginx-mod-http-echo +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: Bring echo and more shell style goodies to Nginx + Echo module wraps lots of Nginx internal APIs for streaming input and output, + parallel/sequential subrequests, timers and sleeping, as well as various meta + data accessing. + . + Basically it provides various utilities that help testing and debugging of + other modules by trivially emulating different kinds of faked subrequest + locations. + . + People will also find it useful in real-world applications that need to: + . + 1. Serve static contents directly from memory. + 2. Wrap the upstream response with custom header and footer (kinda like the + addition module but with contents read directly from the config file and + Nginx variables). + 3. Merge contents of various "Nginx locations" (i.e., subrequests) together in + a single main request (using echo_location and its friends). diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/copyright b/modules_deb/libnginx-mod-http-echo-0.63/debian/copyright new file mode 100644 index 0000000..061d047 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/copyright @@ -0,0 +1,71 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: echo-nginx-module +Upstream-Contact: Yichun "agentzh" Zhang +Source: https://github.com/agentzh/echo-nginx-module + +Files: * +Copyright: 2009-2018, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. + 2009-2014, Yichun "agentzh" Zhang . +License: BSD-2-clause + +Files: README.markdown +Copyright: 2009-2018, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +License: BSD-2-clause + +Files: config +Copyright: 2009-2018, Yichun "agentzh" Zhang . +License: BSD-2-clause + +Files: debian/* +Copyright: 2022, Miao Wang + 2022-2025, Jan Mojzis +License: BSD-2-clause + +Files: src/* +Copyright: 2009-2018, Yichun "agentzh" Zhang . +License: BSD-2-clause + +Files: src/ngx_http_echo_handler.c + src/ngx_http_echo_module.c + src/ngx_http_echo_module.h + src/ngx_http_echo_request_info.c + src/ngx_http_echo_sleep.c + src/ngx_http_echo_subrequest.c + src/ngx_http_echo_util.c + src/ngx_http_echo_util.h +Copyright: Yichun Zhang (agentzh) +License: BSD-2-clause + +Files: t/* +Copyright: 2009-2018, Yichun "agentzh" Zhang . +License: BSD-2-clause + +Files: util/* +Copyright: 2009-2018, Yichun "agentzh" Zhang . +License: BSD-2-clause + +License: BSD-2-clause + All rights reserved. + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/fix.scanned.copyright b/modules_deb/libnginx-mod-http-echo-0.63/debian/fix.scanned.copyright new file mode 100644 index 0000000..b25e244 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/fix.scanned.copyright @@ -0,0 +1,2 @@ +# fixes upstream author name parsing +! copyright Files:~/.*/ Copyright=~"s/(Zhang)\s\(.*x\{6625\}\)/$1\ (章亦春)/" diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/gbp.conf b/modules_deb/libnginx-mod-http-echo-0.63/debian/gbp.conf new file mode 100644 index 0000000..d9f01a6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/gbp.conf @@ -0,0 +1,9 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = False +sign-tags = True + +[import-orig] +merge-mode = replace diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/rules b/modules_deb/libnginx-mod-http-echo-0.63/debian/rules new file mode 100755 index 0000000..d8309f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/source/format b/modules_deb/libnginx-mod-http-echo-0.63/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/control b/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/control new file mode 100644 index 0000000..b95c6ff --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/control @@ -0,0 +1,13 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, + +Tests: helloworld +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/generic b/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/helloworld b/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/helloworld new file mode 100644 index 0000000..c66b2dc --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/tests/helloworld @@ -0,0 +1,32 @@ +#!/bin/sh +set -e + +cat < "/etc/nginx/sites-enabled/default" +server { + listen 80 default_server; + + location /helloworld { + echo "hello world"; + } +} +EOF + +exp="hello world +response_code: 200" + +nginx -t +invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; } + +out=`curl --fail -w "response_code: %{http_code}\n" http://127.0.0.1/helloworld` + +if [ x"${out}" != x"${exp}" ]; then + echo "output:" + echo "=====================" + echo "${out}" + echo "=====================" + echo "expected output:" + echo "=====================" + echo "${exp}" + echo "=====================" + exit 1 +fi diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/upstream/metadata b/modules_deb/libnginx-mod-http-echo-0.63/debian/upstream/metadata new file mode 100644 index 0000000..81ba6ec --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/agentzh/echo-nginx-module/issues +Bug-Submit: https://github.com/agentzh/echo-nginx-module/issues/new +Repository-Browse: https://github.com/agentzh/echo-nginx-module \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-echo-0.63/debian/watch b/modules_deb/libnginx-mod-http-echo-0.63/debian/watch new file mode 100644 index 0000000..55febdb --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/agentzh/echo-nginx-module/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ddebug.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ddebug.h new file mode 100644 index 0000000..a92d7a7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ddebug.h @@ -0,0 +1,114 @@ +#ifndef DDEBUG_H +#define DDEBUG_H + +#include +#include +#include + +#if defined(DDEBUG) && (DDEBUG) + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) fprintf(stderr, "echo *** %s: ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) + +# else + +#include +#include + +#include + +static ngx_inline void +dd(const char * fmt, ...) { +} + +# endif + +# if DDEBUG > 1 + +# define dd_enter() dd_enter_helper(r, __func__) + +static ngx_inline void +dd_enter_helper(ngx_http_request_t *r, const char *func) { + ngx_http_posted_request_t *pr; + + fprintf(stderr, ">enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", + func, + (int) r->method_name.len, r->method_name.data, + (int) r->uri.len, r->uri.data, + (int) r->args.len, r->args.data, + 0/*(int) r->main->count*/, r->main, + r, r->connection->data, r->parent); + + if (r->posted_requests) { + fprintf(stderr, " posted:"); + + for (pr = r->posted_requests; pr; pr = pr->next) { + fprintf(stderr, "%p,", pr); + } + } + + fprintf(stderr, "\n"); +} + +# else + +# define dd_enter() + +# endif + +#else + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) + +# define dd_enter() + +# else + +#include + +static ngx_inline void +dd(const char * fmt, ...) { +} + +static ngx_inline void +dd_enter() { +} + +# endif + +#endif + +#if defined(DDEBUG) && (DDEBUG) + +#define dd_check_read_event_handler(r) \ + dd("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#define dd_check_write_event_handler(r) \ + dd("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + +#define dd_check_read_event_handler(r) +#define dd_check_write_event_handler(r) + +#endif + +#endif /* DDEBUG_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.c new file mode 100644 index 0000000..f5789f5 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.c @@ -0,0 +1,342 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_echo_echo.h" +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_filter.h" + +#include + +static ngx_buf_t ngx_http_echo_space_buf; + +static ngx_buf_t ngx_http_echo_newline_buf; + + +ngx_int_t +ngx_http_echo_echo_init(ngx_conf_t *cf) +{ + static u_char space_str[] = " "; + static u_char newline_str[] = "\n"; + + dd("global init..."); + + ngx_memzero(&ngx_http_echo_space_buf, sizeof(ngx_buf_t)); + + ngx_http_echo_space_buf.memory = 1; + + ngx_http_echo_space_buf.start = + ngx_http_echo_space_buf.pos = + space_str; + + ngx_http_echo_space_buf.end = + ngx_http_echo_space_buf.last = + space_str + sizeof(space_str) - 1; + + ngx_memzero(&ngx_http_echo_newline_buf, sizeof(ngx_buf_t)); + + ngx_http_echo_newline_buf.memory = 1; + + ngx_http_echo_newline_buf.start = + ngx_http_echo_newline_buf.pos = + newline_str; + + ngx_http_echo_newline_buf.end = + ngx_http_echo_newline_buf.last = + newline_str + sizeof(newline_str) - 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_echo_sync(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ + ngx_buf_t *buf; + ngx_chain_t *cl = NULL; /* the head of the chain link */ + + buf = ngx_calloc_buf(r->pool); + if (buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + buf->sync = 1; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cl->buf = buf; + cl->next = NULL; + + return ngx_http_echo_send_chain_link(r, ctx, cl); +} + + +ngx_int_t +ngx_http_echo_exec_echo(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args, + ngx_flag_t in_filter, ngx_array_t *opts) +{ + ngx_uint_t i; + + ngx_buf_t *space_buf; + ngx_buf_t *newline_buf; + ngx_buf_t *buf; + + ngx_str_t *computed_arg; + ngx_str_t *computed_arg_elts; + ngx_str_t *opt; + + ngx_chain_t *cl = NULL; /* the head of the chain link */ + ngx_chain_t **ll = &cl; /* always point to the address of the last link */ + + dd_enter(); + + if (computed_args == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + computed_arg_elts = computed_args->elts; + for (i = 0; i < computed_args->nelts; i++) { + computed_arg = &computed_arg_elts[i]; + + if (computed_arg->len == 0) { + buf = NULL; + + } else { + buf = ngx_calloc_buf(r->pool); + if (buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + buf->start = buf->pos = computed_arg->data; + buf->last = buf->end = computed_arg->data + + computed_arg->len; + + buf->memory = 1; + } + + if (cl == NULL) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + cl->buf = buf; + cl->next = NULL; + ll = &cl->next; + + } else { + /* append a space first */ + *ll = ngx_alloc_chain_link(r->pool); + + if (*ll == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + space_buf = ngx_calloc_buf(r->pool); + + if (space_buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* nginx clears buf flags at the end of each request handling, + * so we have to make a clone here. */ + *space_buf = ngx_http_echo_space_buf; + + (*ll)->buf = space_buf; + (*ll)->next = NULL; + + ll = &(*ll)->next; + + /* then append the buf only if it's non-empty */ + if (buf) { + *ll = ngx_alloc_chain_link(r->pool); + if (*ll == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + (*ll)->buf = buf; + (*ll)->next = NULL; + + ll = &(*ll)->next; + } + } + } /* end for */ + + if (cl && cl->buf == NULL) { + cl = cl->next; + } + + if (opts && opts->nelts > 0) { + opt = opts->elts; + /* FIXME handle other unrecognized options here */ + if (opt[0].len == 1 && opt[0].data[0] == 'n') { + goto done; + } + } + + /* append the newline character */ + + newline_buf = ngx_calloc_buf(r->pool); + + if (newline_buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + *newline_buf = ngx_http_echo_newline_buf; + + if (cl == NULL) { + cl = ngx_alloc_chain_link(r->pool); + + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cl->buf = newline_buf; + cl->next = NULL; + /* ll = &cl->next; */ + + } else { + *ll = ngx_alloc_chain_link(r->pool); + + if (*ll == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + (*ll)->buf = newline_buf; + (*ll)->next = NULL; + /* ll = &(*ll)->next; */ + } + +done: + + if (cl == NULL || cl->buf == NULL) { + return NGX_OK; + } + + if (in_filter) { + return ngx_http_echo_next_body_filter(r, cl); + } + + return ngx_http_echo_send_chain_link(r, ctx, cl); +} + + +ngx_int_t +ngx_http_echo_exec_echo_flush(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) +{ + return ngx_http_send_special(r, NGX_HTTP_FLUSH); +} + + +ngx_int_t +ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ + ngx_buf_t *b; + ngx_chain_t *out, *cl, **ll; + + if (r->request_body == NULL || r->request_body->bufs == NULL) { + return NGX_OK; + } + + out = NULL; + ll = &out; + + for (cl = r->request_body->bufs; cl; cl = cl->next) { + if (ngx_buf_special(cl->buf)) { + /* we do not want to create zero-size bufs */ + continue; + } + + *ll = ngx_alloc_chain_link(r->pool); + if (*ll == NULL) { + return NGX_ERROR; + } + + b = ngx_alloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + (*ll)->buf = b; + (*ll)->next = NULL; + + ngx_memcpy(b, cl->buf, sizeof(ngx_buf_t)); + b->tag = (ngx_buf_tag_t) &ngx_http_echo_exec_echo_request_body; + b->last_buf = 0; + b->last_in_chain = 0; + + ll = &(*ll)->next; + } + + if (out == NULL) { + return NGX_OK; + } + + return ngx_http_echo_send_chain_link(r, ctx, out); +} + + +ngx_int_t +ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_str_t *computed_arg; + ngx_str_t *computed_arg_elts; + ssize_t i, count; + ngx_str_t *str; + u_char *p; + ngx_int_t rc; + ngx_buf_t *buf; + ngx_chain_t *cl; + + dd_enter(); + + computed_arg_elts = computed_args->elts; + + computed_arg = &computed_arg_elts[0]; + + count = ngx_http_echo_atosz(computed_arg->data, computed_arg->len); + + if (count == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid size specified: \"%V\"", computed_arg); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + str = &computed_arg_elts[1]; + + if (count == 0 || str->len == 0) { + rc = ngx_http_echo_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + return NGX_OK; + } + + buf = ngx_create_temp_buf(r->pool, count * str->len); + if (buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = buf->pos; + for (i = 0; i < count; i++) { + p = ngx_copy(p, str->data, str->len); + } + buf->last = p; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + cl->next = NULL; + cl->buf = buf; + + return ngx_http_echo_send_chain_link(r, ctx, cl); +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.h new file mode 100644 index 0000000..896f1ed --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_echo.h @@ -0,0 +1,25 @@ +#ifndef ECHO_ECHO_H +#define ECHO_ECHO_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_echo_init(ngx_conf_t *cf); + +ngx_int_t ngx_http_echo_exec_echo_sync(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); + +ngx_int_t ngx_http_echo_exec_echo(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args, + ngx_flag_t in_filter, ngx_array_t *opts); + +ngx_int_t ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); + +ngx_int_t ngx_http_echo_exec_echo_flush(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); + +ngx_int_t ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +#endif /* ECHO_ECHO_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.c new file mode 100644 index 0000000..689b52e --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.c @@ -0,0 +1,282 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_echo_filter.h" +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_echo.h" + +#include + + + +ngx_http_output_header_filter_pt ngx_http_echo_next_header_filter; + +ngx_http_output_body_filter_pt ngx_http_echo_next_body_filter; + +static ngx_int_t ngx_http_echo_header_filter(ngx_http_request_t *r); + +static ngx_int_t ngx_http_echo_body_filter(ngx_http_request_t *r, + ngx_chain_t *in); + +/* filter handlers */ +static ngx_int_t ngx_http_echo_exec_filter_cmds(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *cmds, ngx_uint_t *iterator); + + +static volatile ngx_cycle_t *ngx_http_echo_prev_cycle = NULL; + + +ngx_int_t +ngx_http_echo_filter_init(ngx_conf_t *cf) +{ + int multi_http_blocks; + ngx_http_echo_main_conf_t *emcf; + + emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module); + + if (ngx_http_echo_prev_cycle != ngx_cycle) { + ngx_http_echo_prev_cycle = ngx_cycle; + multi_http_blocks = 0; + + } else { + multi_http_blocks = 1; + } + + if (multi_http_blocks || emcf->requires_filter) { + dd("top header filter: %ld", + (unsigned long) ngx_http_top_header_filter); + + ngx_http_echo_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_echo_header_filter; + + dd("top body filter: %ld", (unsigned long) ngx_http_top_body_filter); + + ngx_http_echo_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_echo_body_filter; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_echo_header_filter(ngx_http_request_t *r) +{ + ngx_http_echo_loc_conf_t *conf; + ngx_http_echo_ctx_t *ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo header filter, uri \"%V?%V\"", &r->uri, &r->args); + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + /* XXX we should add option to insert contents for responses + * of non-200 status code here... */ + /* + if (r->headers_out.status != NGX_HTTP_OK) { + if (ctx != NULL) { + ctx->skip_filter = 1; + } + return ngx_http_echo_next_header_filter(r); + } + */ + + conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); + if (conf->before_body_cmds == NULL && conf->after_body_cmds == NULL) { + if (ctx != NULL) { + ctx->skip_filter = 1; + } + return ngx_http_echo_next_header_filter(r); + } + + if (ctx == NULL) { + ctx = ngx_http_echo_create_ctx(r); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_echo_module); + } + + /* enable streaming here (use chunked encoding) */ + ngx_http_clear_content_length(r); + ngx_http_clear_accept_ranges(r); + + return ngx_http_echo_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_echo_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_http_echo_ctx_t *ctx; + ngx_int_t rc; + ngx_http_echo_loc_conf_t *conf; + unsigned last; + ngx_chain_t *cl; + ngx_buf_t *b; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo body filter, uri \"%V?%V\"", &r->uri, &r->args); + + if (in == NULL || r->header_only) { + return ngx_http_echo_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + if (ctx == NULL || ctx->skip_filter) { + return ngx_http_echo_next_body_filter(r, in); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); + + if (!ctx->before_body_sent) { + ctx->before_body_sent = 1; + + if (conf->before_body_cmds != NULL) { + rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->before_body_cmds, + &ctx->next_before_body_cmd); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + } + + if (conf->after_body_cmds == NULL) { + ctx->skip_filter = 1; + return ngx_http_echo_next_body_filter(r, in); + } + + last = 0; + + for (cl = in; cl; cl = cl->next) { + dd("cl %p, special %d", cl, ngx_buf_special(cl->buf)); + + if (cl->buf->last_buf || cl->buf->last_in_chain) { + cl->buf->last_buf = 0; + cl->buf->last_in_chain = 0; + cl->buf->sync = 1; + last = 1; + } + } + + dd("in %p, last %d", in, (int) last); + + if (in) { + rc = ngx_http_echo_next_body_filter(r, in); + +#if 0 + if (rc == NGX_AGAIN) { + return NGX_ERROR; + } +#endif + + dd("next filter returns %d, last %d", (int) rc, (int) last); + + if (rc == NGX_ERROR || rc > NGX_OK || !last) { + return rc; + } + } + + dd("exec filter cmds for after body cmds"); + + rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->after_body_cmds, + &ctx->next_after_body_cmd); + if (rc == NGX_ERROR || rc > NGX_OK) { + dd("FAILED: exec filter cmds for after body cmds"); + return NGX_ERROR; + } + + ctx->skip_filter = 1; + + dd("after body cmds executed...terminating..."); + + /* XXX we can NOT use + * ngx_http_send_special(r, NGX_HTTP_LAST) here + * because we should bypass the upstream filters. */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + if (r == r->main && !r->post_action) { + b->last_buf = 1; + + } else { + b->sync = 1; + b->last_in_chain = 1; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->next = NULL; + cl->buf = b; + + return ngx_http_echo_next_body_filter(r, cl); +} + + +static ngx_int_t +ngx_http_echo_exec_filter_cmds(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *cmds, ngx_uint_t *iterator) +{ + ngx_int_t rc; + ngx_array_t *opts = NULL; + ngx_array_t *computed_args = NULL; + ngx_http_echo_cmd_t *cmd; + ngx_http_echo_cmd_t *cmd_elts; + + for (cmd_elts = cmds->elts; *iterator < cmds->nelts; (*iterator)++) { + cmd = &cmd_elts[*iterator]; + + /* evaluate arguments for the current cmd (if any) */ + if (cmd->args) { + computed_args = ngx_array_create(r->pool, cmd->args->nelts, + sizeof(ngx_str_t)); + if (computed_args == NULL) { + return NGX_ERROR; + } + + opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t)); + if (opts == NULL) { + return NGX_ERROR; + } + + rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts); + + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "Failed to evaluate arguments for " + "the directive."); + return rc; + } + } + + /* do command dispatch based on the opcode */ + switch (cmd->opcode) { + case echo_opcode_echo_before_body: + case echo_opcode_echo_after_body: + dd("exec echo_before_body or echo_after_body..."); + + rc = ngx_http_echo_exec_echo(r, ctx, computed_args, + 1 /* in filter */, opts); + + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + + break; + default: + break; + } + } + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.h new file mode 100644 index 0000000..ea5115d --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_filter.h @@ -0,0 +1,15 @@ +#ifndef ECHO_FILTER_H +#define ECHO_FILTER_H + +#include "ngx_http_echo_module.h" + + +extern ngx_http_output_header_filter_pt ngx_http_echo_next_header_filter; + +extern ngx_http_output_body_filter_pt ngx_http_echo_next_body_filter; + + +ngx_int_t ngx_http_echo_filter_init (ngx_conf_t *cf); + +#endif /* ECHO_FILTER_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.c new file mode 100644 index 0000000..a4a2b54 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.c @@ -0,0 +1,183 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_echo_foreach.h" +#include "ngx_http_echo_util.h" + +#include + + +ngx_int_t +ngx_http_echo_it_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_echo_ctx_t *ctx; + ngx_uint_t i; + ngx_array_t *choices; + ngx_str_t *choice_elts, *choice; + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + if (ctx && ctx->foreach != NULL) { + + choices = ctx->foreach->choices; + i = ctx->foreach->next_choice; + + if (i < choices->nelts) { + choice_elts = choices->elts; + choice = &choice_elts[i]; + + v->len = choice->len; + v->data = choice->data; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + return NGX_OK; + } + } + + v->not_found = 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_http_echo_loc_conf_t *elcf; + ngx_str_t *delimiter, *compound; + u_char *pos, *last, *end; + ngx_str_t *choice; + ngx_str_t *computed_arg_elts; + ngx_array_t *cmds; + ngx_http_echo_cmd_t *cmd; + ngx_http_echo_cmd_t *cmd_elts; + + if (ctx->foreach != NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "Nested echo_foreach not supported yet."); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (computed_args->nelts < 2) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "echo_foreach should take at least two arguments. " + "(if your delimiter starts with \"-\", preceding it " + "with a \"--\".)"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + computed_arg_elts = computed_args->elts; + + compound = &computed_arg_elts[1]; + + dd("HEY coumpound len: %u", (int) compound->len); + + ctx->foreach = ngx_palloc(r->pool, sizeof(ngx_http_echo_foreach_ctx_t)); + + if (ctx->foreach == NULL) { + return NGX_ERROR; + } + + ctx->foreach->cmd_index = ctx->next_handler_cmd; + + ctx->foreach->next_choice = 0; + + ctx->foreach->choices = ngx_array_create(r->pool, 10, sizeof(ngx_str_t)); + if (ctx->foreach->choices == NULL) { + return NGX_ERROR; + } + + delimiter = &computed_arg_elts[0]; + + pos = compound->data; + end = compound->data + compound->len; + + while ((last = ngx_http_echo_strlstrn(pos, end, delimiter->data, + delimiter->len - 1)) != NULL) + { + dd("entered the loop"); + + if (last == pos) { + dd("!!! len == 0"); + pos = last + delimiter->len; + continue; + } + + choice = ngx_array_push(ctx->foreach->choices); + if (choice == NULL) { + return NGX_ERROR; + } + + choice->data = pos; + choice->len = last - pos; + pos = last + delimiter->len; + } + + if (pos < end) { + choice = ngx_array_push(ctx->foreach->choices); + if (choice == NULL) { + return NGX_ERROR; + } + + choice->data = pos; + choice->len = end - pos; + } + + if (ctx->foreach->choices->nelts == 0) { + /* skip the foreach body entirely */ + elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); + cmds = elcf->handler_cmds; + cmd_elts = cmds->elts; + for (/* void */; ctx->next_handler_cmd < cmds->nelts; + ctx->next_handler_cmd++) + { + cmd = &cmd_elts[ctx->next_handler_cmd + 1]; + if (cmd->opcode == echo_opcode_echo_end) { + return NGX_OK; + } + } + + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_echo_end(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ + if (ctx->foreach == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "Found a echo_end that has no corresponding echo_foreach " + "before it."); + return NGX_ERROR; + } + + ctx->foreach->next_choice++; + + if (ctx->foreach->next_choice >= ctx->foreach->choices->nelts) { + /* TODO We need to explicitly free the foreach ctx from + * the pool */ + ctx->foreach = NULL; + + return NGX_OK; + } + + dd("echo_end: ++ next_choice (total: %u): %u", + (unsigned) ctx->foreach->choices->nelts, + (unsigned) ctx->foreach->next_choice); + + /* the main handler dispatcher loop will increment + * ctx->next_handler_cmd for us anyway. */ + ctx->next_handler_cmd = ctx->foreach->cmd_index; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.h new file mode 100644 index 0000000..49592f4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_foreach.h @@ -0,0 +1,16 @@ +#ifndef ECHO_FOREACH_H +#define ECHO_FOREACH_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +ngx_int_t ngx_http_echo_exec_echo_end(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); + +ngx_int_t ngx_http_echo_it_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +#endif /* ECHO_FOREACH_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.c new file mode 100644 index 0000000..120c8b0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.c @@ -0,0 +1,433 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_echo_filter.h" +#include "ngx_http_echo_handler.h" +#include "ngx_http_echo_echo.h" +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_sleep.h" +#include "ngx_http_echo_var.h" +#include "ngx_http_echo_timer.h" +#include "ngx_http_echo_location.h" +#include "ngx_http_echo_subrequest.h" +#include "ngx_http_echo_request_info.h" +#include "ngx_http_echo_foreach.h" + +#include +#include + + +void +ngx_http_echo_wev_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_echo_ctx_t *ctx; + + dd("wev handler"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + if (ctx == NULL) { + ngx_http_finalize_request(r, NGX_ERROR); + return; + } + + dd("waiting: %d, done: %d", (int) ctx->waiting, (int) ctx->done); + + if (ctx->waiting && ! ctx->done) { + + if (r == r->connection->data && r->postponed) { + + if (r->postponed->request) { + r->connection->data = r->postponed->request; + +#if defined(nginx_version) && nginx_version >= 8012 + ngx_http_post_request(r->postponed->request, NULL); +#else + ngx_http_post_request(r->postponed->request); +#endif + + } else { + ngx_http_echo_flush_postponed_outputs(r); + } + } + + return; + } + + ctx->done = 0; + + ctx->next_handler_cmd++; + + rc = ngx_http_echo_run_cmds(r); + + dd("rc: %d", (int) rc); + + if (rc == NGX_ERROR || rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == NGX_AGAIN) { + dd("mark busy %d for %.*s", (int) ctx->next_handler_cmd, + (int) r->uri.len, + r->uri.data); + + ctx->waiting = 1; + ctx->done = 0; + + } else { + dd("mark ready %d", (int) ctx->next_handler_cmd); + ctx->waiting = 0; + ctx->done = 1; + + dd("finalizing with rc %d", (int) rc); + + dd("finalize request %.*s with %d", (int) r->uri.len, r->uri.data, + (int) rc); + + ngx_http_finalize_request(r, rc); + } +} + + +ngx_int_t +ngx_http_echo_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_echo_ctx_t *ctx; + + dd("subrequest in memory: %d", (int) r->subrequest_in_memory); + + rc = ngx_http_echo_run_cmds(r); + + dd("run cmds returned %d", (int) rc); + + if (rc == NGX_ERROR + || rc == NGX_OK + || rc == NGX_DONE + || rc == NGX_DECLINED) + { + return rc; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + if (ctx && r->header_sent) { + return NGX_ERROR; + } + + return rc; + } + + /* rc == NGX_AGAIN */ + +#if defined(nginx_version) && nginx_version >= 8011 + r->main->count++; +#endif + + dd("%d", r->connection->destroyed); + dd("%d", r->done); + + if (ctx) { + dd("mark busy %d for %.*s", (int) ctx->next_handler_cmd, + (int) r->uri.len, + r->uri.data); + + ctx->waiting = 1; + ctx->done = 0; + } + + return NGX_DONE; +} + + +ngx_int_t +ngx_http_echo_run_cmds(ngx_http_request_t *r) +{ + ngx_http_echo_loc_conf_t *elcf; + ngx_http_echo_ctx_t *ctx; + ngx_int_t rc; + ngx_array_t *cmds; + ngx_array_t *computed_args = NULL; + ngx_http_echo_cmd_t *cmd; + ngx_http_echo_cmd_t *cmd_elts; + ngx_array_t *opts = NULL; + + elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); + cmds = elcf->handler_cmds; + if (cmds == NULL) { + return NGX_DECLINED; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + if (ctx == NULL) { + ctx = ngx_http_echo_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_echo_module); + } + + dd("exec handler: %.*s: %i", (int) r->uri.len, r->uri.data, + (int) ctx->next_handler_cmd); + + cmd_elts = cmds->elts; + + for (; ctx->next_handler_cmd < cmds->nelts; ctx->next_handler_cmd++) { + + cmd = &cmd_elts[ctx->next_handler_cmd]; + + /* evaluate arguments for the current cmd (if any) */ + if (cmd->args) { + computed_args = ngx_array_create(r->pool, cmd->args->nelts, + sizeof(ngx_str_t)); + + if (computed_args == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t)); + + if (opts == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "Failed to evaluate arguments for " + "the directive."); + return rc; + } + } + + if (computed_args == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* do command dispatch based on the opcode */ + + switch (cmd->opcode) { + + case echo_opcode_echo_sync: + rc = ngx_http_echo_exec_echo_sync(r, ctx); + break; + + case echo_opcode_echo: + /* XXX moved the following code to a separate + * function */ + dd("found echo opcode"); + rc = ngx_http_echo_exec_echo(r, ctx, computed_args, + 0 /* in filter */, opts); + break; + + case echo_opcode_echo_request_body: + rc = ngx_http_echo_exec_echo_request_body(r, ctx); + break; + + case echo_opcode_echo_location_async: + if (!r->request_body) { + /* we require reading the request body before doing + * subrequests */ + + ctx->next_handler_cmd--; /* re-run the current cmd */ + goto read_request_body; + } + + dd("found opcode echo location async..."); + rc = ngx_http_echo_exec_echo_location_async(r, ctx, + computed_args); + break; + + case echo_opcode_echo_location: + if (!r->request_body) { + /* we require reading the request body before doing + * subrequests */ + + ctx->next_handler_cmd--; /* re-run the current cmd */ + goto read_request_body; + } + + return ngx_http_echo_exec_echo_location(r, ctx, computed_args); + + case echo_opcode_echo_subrequest_async: + if (!r->request_body) { + /* we require reading the request body before doing + * subrequests */ + + ctx->next_handler_cmd--; /* re-run the current cmd */ + goto read_request_body; + } + + dd("found opcode echo subrequest async..."); + rc = ngx_http_echo_exec_echo_subrequest_async(r, ctx, + computed_args); + break; + + case echo_opcode_echo_subrequest: + if (!r->request_body) { + /* we require reading the request body before doing + * subrequests */ + + ctx->next_handler_cmd--; /* re-run the current cmd */ + goto read_request_body; + } + + return ngx_http_echo_exec_echo_subrequest(r, ctx, computed_args); + + case echo_opcode_echo_sleep: + return ngx_http_echo_exec_echo_sleep(r, ctx, computed_args); + + case echo_opcode_echo_flush: + rc = ngx_http_echo_exec_echo_flush(r, ctx); + break; + + case echo_opcode_echo_blocking_sleep: + rc = ngx_http_echo_exec_echo_blocking_sleep(r, ctx, + computed_args); + break; + + case echo_opcode_echo_reset_timer: + rc = ngx_http_echo_exec_echo_reset_timer(r, ctx); + break; + + case echo_opcode_echo_duplicate: + rc = ngx_http_echo_exec_echo_duplicate(r, ctx, computed_args); + break; + + case echo_opcode_echo_read_request_body: + +read_request_body: + + ctx->wait_read_request_body = 0; + + rc = ngx_http_echo_exec_echo_read_request_body(r, ctx); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { +#if (nginx_version >= 8011 && nginx_version < 1002006) \ + || (nginx_version >= 1003000 && nginx_version < 1003009) + r->main->count--; +#endif + return rc; + } + +#if nginx_version >= 8011 + r->main->count--; +#endif + dd("read request body: %d", (int) rc); + + if (rc == NGX_OK) { + continue; + } + + /* rc == NGX_AGAIN */ + ctx->wait_read_request_body = 1; + return NGX_AGAIN; + + case echo_opcode_echo_foreach_split: + rc = ngx_http_echo_exec_echo_foreach_split(r, ctx, computed_args); + break; + + case echo_opcode_echo_end: + rc = ngx_http_echo_exec_echo_end(r, ctx); + break; + + case echo_opcode_echo_exec: + dd("echo_exec"); + return ngx_http_echo_exec_exec(r, ctx, computed_args); + + default: + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown opcode: %d", cmd->opcode); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + } + + rc = ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */); + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + if (!r->request_body) { + if (ngx_http_discard_request_body(r) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_post_subrequest(ngx_http_request_t *r, + void *data, ngx_int_t rc) +{ + ngx_http_echo_ctx_t *ctx = data; + ngx_http_request_t *pr; + ngx_http_echo_ctx_t *pr_ctx; + + dd("echo post_subrequest: %.*s", (int) r->uri.len, r->uri.data); + + if (ctx->run_post_subrequest) { + dd("already run post_subrequest: %p: %.*s", ctx, + (int) r->uri.len, r->uri.data); + + return rc; + } + + dd("setting run_post_subrequest to 1 for %p for %.*s", ctx, + (int) r->uri.len, r->uri.data); + + ctx->run_post_subrequest = 1; + + pr = r->parent; + + pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_echo_module); + if (pr_ctx == NULL) { + return NGX_ERROR; + } + + dd("mark ready %d", (int) pr_ctx->next_handler_cmd); + + pr_ctx->waiting = 0; + pr_ctx->done = 1; + + pr->write_event_handler = ngx_http_echo_wev_handler; + + /* work-around issues in nginx's event module */ + + if (r != r->connection->data + && r->postponed + && (r->main->posted_requests == NULL + || r->main->posted_requests->request != pr)) + { +#if defined(nginx_version) && nginx_version >= 8012 + ngx_http_post_request(pr, NULL); +#else + ngx_http_post_request(pr); +#endif + } + + return rc; +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.h new file mode 100644 index 0000000..afc0666 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_handler.h @@ -0,0 +1,18 @@ +#ifndef ECHO_HANDLER_H +#define ECHO_HANDLER_H + +#include "ngx_http_echo_module.h" + + +void ngx_http_echo_wev_handler(ngx_http_request_t *r); + +ngx_int_t ngx_http_echo_handler(ngx_http_request_t *r); + +ngx_int_t ngx_http_echo_run_cmds(ngx_http_request_t *r); + +ngx_int_t ngx_http_echo_post_subrequest(ngx_http_request_t *r, + void *data, ngx_int_t rc); + + +#endif /* ECHO_HANDLER_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.c new file mode 100644 index 0000000..820e504 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.c @@ -0,0 +1,182 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_location.h" +#include "ngx_http_echo_handler.h" + +#include + + +static ngx_int_t ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr); + + +ngx_int_t +ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_int_t rc; + ngx_http_request_t *sr; /* subrequest object */ + ngx_str_t *computed_arg_elts; + ngx_str_t location; + ngx_str_t *url_args; + ngx_str_t args; + ngx_uint_t flags = 0; + + dd_enter(); + + computed_arg_elts = computed_args->elts; + + location = computed_arg_elts[0]; + + if (location.len == 0) { + return NGX_ERROR; + } + + if (computed_args->nelts > 1) { + url_args = &computed_arg_elts[1]; + } else { + url_args = NULL; + } + + args.data = NULL; + args.len = 0; + + if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo_location_async sees unsafe uri: \"%V\"", + &location); + return NGX_ERROR; + } + + if (args.len > 0 && url_args == NULL) { + url_args = &args; + } + + rc = ngx_http_echo_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + rc = ngx_http_echo_adjust_subrequest(sr); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_echo_location(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_int_t rc; + ngx_http_request_t *sr; /* subrequest object */ + ngx_str_t *computed_arg_elts; + ngx_str_t location; + ngx_str_t *url_args; + ngx_http_post_subrequest_t *psr; + ngx_str_t args; + ngx_uint_t flags = 0; + ngx_http_echo_ctx_t *sr_ctx; + + if (computed_args == NULL) { + return NGX_ERROR; + } + + computed_arg_elts = computed_args->elts; + + location = computed_arg_elts[0]; + + if (location.len == 0) { + return NGX_ERROR; + } + + if (computed_args->nelts > 1) { + url_args = &computed_arg_elts[1]; + + } else { + url_args = NULL; + } + + args.data = NULL; + args.len = 0; + + if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo_location sees unsafe uri: \"%V\"", + &location); + return NGX_ERROR; + } + + if (args.len > 0 && url_args == NULL) { + url_args = &args; + } + + rc = ngx_http_echo_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + sr_ctx = ngx_http_echo_create_ctx(r); + + psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); + if (psr == NULL) { + return NGX_ERROR; + } + + psr->handler = ngx_http_echo_post_subrequest; + psr->data = sr_ctx; + + rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + rc = ngx_http_echo_adjust_subrequest(sr); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr) +{ + ngx_http_core_main_conf_t *cmcf; + ngx_http_request_t *r; + + /* we do not inherit the parent request's variables */ + cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); + + r = sr->parent; + + sr->header_in = r->header_in; + + /* XXX work-around a bug in ngx_http_subrequest */ + if (r->headers_in.headers.last == &r->headers_in.headers.part) { + sr->headers_in.headers.last = &sr->headers_in.headers.part; + } + + sr->variables = ngx_pcalloc(sr->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t)); + + if (sr->variables == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.h new file mode 100644 index 0000000..6bc0e03 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_location.h @@ -0,0 +1,13 @@ +#ifndef ECHO_LOCATION_H +#define ECHO_LOCATION_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +#endif /* ECHO_LOCATION_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.c new file mode 100644 index 0000000..8d736d7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.c @@ -0,0 +1,682 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_echo_handler.h" +#include "ngx_http_echo_filter.h" +#include "ngx_http_echo_echo.h" +#include "ngx_http_echo_request_info.h" +#include "ngx_http_echo_var.h" +#include "ngx_http_echo_util.h" + + +#include +#include +#include + + +/* config init handler */ +static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static void *ngx_http_echo_create_main_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_echo_post_config(ngx_conf_t *cf); + +/* config directive handlers */ +static char *ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_echo_echo_request_body(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_reset_timer(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_before_body(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_after_body(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_location_async(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_location(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_subrequest(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_duplicate(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_read_request_body(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_foreach_split(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_end(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_abort_parent(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_echo_exec(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_echo_helper(ngx_http_echo_opcode_t opcode, + ngx_http_echo_cmd_category_t cat, + ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_http_module_t ngx_http_echo_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_echo_post_config, /* postconfiguration */ + + ngx_http_echo_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_echo_create_loc_conf, /* create location configuration */ + ngx_http_echo_merge_loc_conf /* merge location configuration */ +}; + + +static ngx_command_t ngx_http_echo_commands[] = { + + { ngx_string("echo"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY, + ngx_http_echo_echo, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_request_body"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, + ngx_http_echo_echo_request_body, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_sleep"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_http_echo_echo_sleep, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_flush"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, + ngx_http_echo_echo_flush, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_blocking_sleep"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_http_echo_echo_blocking_sleep, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_reset_timer"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, + ngx_http_echo_echo_reset_timer, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_before_body"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY, + ngx_http_echo_echo_before_body, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, before_body_cmds), + NULL }, + + { ngx_string("echo_after_body"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY, + ngx_http_echo_echo_after_body, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, after_body_cmds), + NULL }, + + { ngx_string("echo_location_async"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ngx_http_echo_echo_location_async, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_location"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ngx_http_echo_echo_location, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_subrequest_async"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, + ngx_http_echo_echo_subrequest_async, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_subrequest"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, + ngx_http_echo_echo_subrequest, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_duplicate"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, + ngx_http_echo_echo_duplicate, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_read_request_body"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, + ngx_http_echo_echo_read_request_body, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_foreach_split"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, + ngx_http_echo_echo_foreach_split, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_end"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, + ngx_http_echo_echo_end, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_abort_parent"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, + ngx_http_echo_echo_abort_parent, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_exec"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ngx_http_echo_echo_exec, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, handler_cmds), + NULL }, + + { ngx_string("echo_status"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_echo_loc_conf_t, status), + NULL }, + + ngx_null_command +}; + + +ngx_module_t ngx_http_echo_module = { + NGX_MODULE_V1, + &ngx_http_echo_module_ctx, /* module context */ + ngx_http_echo_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 void * +ngx_http_echo_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_echo_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc + * conf->handler_cmds = NULL + * conf->before_body_cmds = NULL + * conf->after_body_cmds = NULL + * conf->seen_leading_output = 0 + * conf->seen_trailing_output = 0 + */ + + conf->status = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_echo_loc_conf_t *prev = parent; + ngx_http_echo_loc_conf_t *conf = child; + + if (conf->handler_cmds == NULL) { + conf->handler_cmds = prev->handler_cmds; + conf->seen_leading_output = prev->seen_leading_output; + } + + if (conf->before_body_cmds == NULL) { + conf->before_body_cmds = prev->before_body_cmds; + } + + if (conf->after_body_cmds == NULL) { + conf->after_body_cmds = prev->after_body_cmds; + } + + ngx_conf_merge_value(conf->status, prev->status, 200); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_echo_helper(ngx_http_echo_opcode_t opcode, + ngx_http_echo_cmd_category_t cat, + ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *raw_args; + ngx_uint_t i, n; + ngx_array_t **args_ptr; + ngx_array_t **cmds_ptr; + ngx_http_echo_cmd_t *echo_cmd; + ngx_http_core_loc_conf_t *clcf; + ngx_http_script_compile_t sc; + ngx_http_echo_main_conf_t *emcf; + ngx_http_echo_arg_template_t *arg; + + emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module); + + /* cmds_ptr points to ngx_http_echo_loc_conf_t's + * handler_cmds, before_body_cmds, or after_body_cmds + * array, depending on the actual offset */ + cmds_ptr = (ngx_array_t **) (((u_char *) conf) + cmd->offset); + + if (*cmds_ptr == NULL) { + *cmds_ptr = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_echo_cmd_t)); + + if (*cmds_ptr == NULL) { + return NGX_CONF_ERROR; + } + + if (cat == echo_handler_cmd) { + dd("registering the content handler"); + /* register the content handler */ + clcf = ngx_http_conf_get_module_loc_conf(cf, + ngx_http_core_module); + + dd("registering the content handler (2)"); + clcf->handler = ngx_http_echo_handler; + + } else { + dd("filter used = 1"); + emcf->requires_filter = 1; + } + } + + echo_cmd = ngx_array_push(*cmds_ptr); + + if (echo_cmd == NULL) { + return NGX_CONF_ERROR; + } + + echo_cmd->opcode = opcode; + + args_ptr = &echo_cmd->args; + *args_ptr = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_echo_arg_template_t)); + + if (*args_ptr == NULL) { + return NGX_CONF_ERROR; + } + + raw_args = cf->args->elts; + + /* we skip the first arg and start from the second */ + + for (i = 1 ; i < cf->args->nelts; i++) { + arg = ngx_array_push(*args_ptr); + + if (arg == NULL) { + return NGX_CONF_ERROR; + } + + arg->raw_value = raw_args[i]; + + dd("found raw arg %s", raw_args[i].data); + + arg->lengths = NULL; + arg->values = NULL; + + n = ngx_http_script_variables_count(&arg->raw_value); + + if (n > 0) { + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &arg->raw_value; + sc.lengths = &arg->lengths; + sc.values = &arg->values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } /* end for */ + + return NGX_CONF_OK; +} + + +static char * +ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + } + + dd("in echo_echo..."); + return ngx_http_echo_helper(echo_opcode_echo, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_request_body(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + } + + dd("in echo_echo_request_body..."); + return ngx_http_echo_helper(echo_opcode_echo_request_body, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + dd("in echo_sleep..."); + return ngx_http_echo_helper(echo_opcode_echo_sleep, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + } + + dd("in echo_flush..."); + return ngx_http_echo_helper(echo_opcode_echo_flush, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + dd("in echo_blocking_sleep..."); + return ngx_http_echo_helper(echo_opcode_echo_blocking_sleep, + echo_handler_cmd, cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_reset_timer(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_reset_timer, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_before_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + dd("processing echo_before_body directive..."); + return ngx_http_echo_helper(echo_opcode_echo_before_body, echo_filter_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_after_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_after_body, echo_filter_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_location_async(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + char *ret; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + + ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, + cf, cmd, conf); + + if (ret != NGX_CONF_OK) { + return ret; + } + } + + return ngx_http_echo_helper(echo_opcode_echo_location_async, + echo_handler_cmd, cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_location(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + char *ret; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + + ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, + cf, cmd, conf); + + if (ret != NGX_CONF_OK) { + return ret; + } + } + + return ngx_http_echo_helper(echo_opcode_echo_location, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *ret; + ngx_http_echo_loc_conf_t *elcf = conf; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + + ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, + cf, cmd, conf); + + if (ret != NGX_CONF_OK) { + return ret; + } + } + + return ngx_http_echo_helper(echo_opcode_echo_subrequest_async, + echo_handler_cmd, cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_subrequest(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + char *ret; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + + ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, + cf, cmd, conf); + + if (ret != NGX_CONF_OK) { + return ret; + } + } + + return ngx_http_echo_helper(echo_opcode_echo_subrequest, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_duplicate(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_echo_loc_conf_t *elcf = conf; + + if (!elcf->seen_leading_output) { + elcf->seen_leading_output = 1; + } + + return ngx_http_echo_helper(echo_opcode_echo_duplicate, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_read_request_body(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_read_request_body, + echo_handler_cmd, cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_foreach_split(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_foreach_split, + echo_handler_cmd, cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_end(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_end, echo_handler_cmd, cf, + cmd, conf); +} + + +static char * +ngx_http_echo_echo_abort_parent(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_abort_parent, echo_handler_cmd, + cf, cmd, conf); +} + + +static char * +ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return ngx_http_echo_helper(echo_opcode_echo_exec, echo_handler_cmd, + cf, cmd, conf); +} + + +static void * +ngx_http_echo_create_main_conf(ngx_conf_t *cf) +{ +#if nginx_version >= 1011011 + ngx_pool_cleanup_t *cln; +#endif + ngx_http_echo_main_conf_t *emcf; + + emcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_main_conf_t)); + if (emcf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * hmcf->requires_filter = 0; + */ + +#if nginx_version >= 1011011 + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->data = emcf; + cln->handler = ngx_http_echo_request_headers_cleanup; +#endif + + return emcf; +} + + +static ngx_int_t +ngx_http_echo_post_config(ngx_conf_t *cf) +{ + ngx_int_t rc; + + rc = ngx_http_echo_filter_init(cf); + if (rc != NGX_OK) { + return rc; + } + + rc = ngx_http_echo_echo_init(cf); + if (rc != NGX_OK) { + return rc; + } + + ngx_http_echo_content_length_hash = + ngx_http_echo_hash_literal("content-length"); + + return ngx_http_echo_add_variables(cf); +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.h new file mode 100644 index 0000000..ce0a305 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_module.h @@ -0,0 +1,151 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef NGX_HTTP_ECHO_MODULE_H +#define NGX_HTTP_ECHO_MODULE_H + + +#include +#include +#include + + +extern ngx_module_t ngx_http_echo_module; + + +/* config directive's opcode */ +typedef enum { + echo_opcode_echo_sync, + echo_opcode_echo, + echo_opcode_echo_request_body, + echo_opcode_echo_sleep, + echo_opcode_echo_flush, + echo_opcode_echo_blocking_sleep, + echo_opcode_echo_reset_timer, + echo_opcode_echo_before_body, + echo_opcode_echo_after_body, + echo_opcode_echo_location_async, + echo_opcode_echo_location, + echo_opcode_echo_subrequest_async, + echo_opcode_echo_subrequest, + echo_opcode_echo_duplicate, + echo_opcode_echo_read_request_body, + echo_opcode_echo_foreach_split, + echo_opcode_echo_end, + echo_opcode_echo_abort_parent, + echo_opcode_echo_exec +} ngx_http_echo_opcode_t; + + +/* all the various config directives (or commands) are + * divided into two categories: "handler commands", + * and "filter commands". For instance, the "echo" + * directive is a handler command while + * "echo_before_body" is a filter one. */ +typedef enum { + echo_handler_cmd, + echo_filter_cmd + +} ngx_http_echo_cmd_category_t; + + +/* compiled form of a config directive argument's value */ +typedef struct { + /* holds the raw string of the argument value */ + ngx_str_t raw_value; + + /* fields "lengths" and "values" are set by + * the function ngx_http_script_compile, + * iff the argument value indeed contains + * nginx variables like "$foo" */ + ngx_array_t *lengths; + ngx_array_t *values; + +} ngx_http_echo_arg_template_t; + + +/* represent a config directive (or command) like "echo". */ +typedef struct { + ngx_http_echo_opcode_t opcode; + + /* each argument is of type echo_arg_template_t: */ + ngx_array_t *args; +} ngx_http_echo_cmd_t; + + +/* location config struct */ +typedef struct { + /* elements of the following arrays are of type + * ngx_http_echo_cmd_t */ + ngx_array_t *handler_cmds; + ngx_array_t *before_body_cmds; + ngx_array_t *after_body_cmds; + + unsigned seen_leading_output; + + ngx_int_t status; +} ngx_http_echo_loc_conf_t; + + +typedef struct { + ngx_int_t requires_filter; +#if nginx_version >= 1011011 + ngx_buf_t **busy_buf_ptrs; + ngx_int_t busy_buf_ptr_count; +#endif +} ngx_http_echo_main_conf_t; + + +typedef struct { + ngx_array_t *choices; /* items after splitting */ + ngx_uint_t next_choice; /* current item index */ + ngx_uint_t cmd_index; /* cmd index for the echo_foreach direcitve */ +} ngx_http_echo_foreach_ctx_t; + + +/* context struct in the request handling cycle, holding + * the current states of the command evaluator */ +typedef struct { + /* index of the next handler command in + * ngx_http_echo_loc_conf_t's "handler_cmds" array. */ + ngx_uint_t next_handler_cmd; + + /* index of the next before-body filter command in + * ngx_http_echo_loc_conf_t's "before_body_cmds" array. */ + ngx_uint_t next_before_body_cmd; + + /* index of the next after-body filter command in + * ngx_http_echo_loc_conf_t's "after_body_cmds" array. */ + ngx_uint_t next_after_body_cmd; + + ngx_http_echo_foreach_ctx_t *foreach; + + ngx_time_t timer_begin; + + ngx_event_t sleep; + + ngx_uint_t counter; + + unsigned before_body_sent:1; + unsigned skip_filter:1; + + unsigned wait_read_request_body:1; + + unsigned waiting:1; + unsigned done:1; + + unsigned run_post_subrequest:1; + unsigned header_sent:1; /* r->header_sent is not sufficient + * because special header filters like + * ngx_http_image_filter_module's may + * intercept the whole header filter chain + * leaving r->header_sent unset. So we + * should always test both flags. */ + +} ngx_http_echo_ctx_t; + + +#endif /* NGX_HTTP_ECHO_MODULE_H */ diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.c new file mode 100644 index 0000000..7dd3683 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.c @@ -0,0 +1,522 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_echo_request_info.h" +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_handler.h" + +#include + + +static void ngx_http_echo_post_read_request_body(ngx_http_request_t *r); +#if nginx_version >= 1011011 +void ngx_http_echo_request_headers_cleanup(void *data); +#endif + + +ngx_int_t +ngx_http_echo_exec_echo_read_request_body(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ + return ngx_http_read_client_request_body(r, + ngx_http_echo_post_read_request_body); +} + + +static void +ngx_http_echo_post_read_request_body(ngx_http_request_t *r) +{ + ngx_http_echo_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + dd("wait read request body %d", (int) ctx->wait_read_request_body); + + if (ctx->wait_read_request_body) { + ctx->waiting = 0; + ctx->done = 1; + + r->write_event_handler = ngx_http_echo_wev_handler; + + ngx_http_echo_wev_handler(r); + } +} + + +/* this function's implementation is borrowed from nginx 0.8.20 + * and modified a bit to work with subrequests. + * Copyrighted (C) by Igor Sysoev */ +ngx_int_t +ngx_http_echo_request_method_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->method_name.data) { + v->len = r->method_name.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->method_name.data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +/* this function's implementation is borrowed from nginx 0.8.20 + * and modified a bit to work with subrequests. + * Copyrighted (C) by Igor Sysoev */ +ngx_int_t +ngx_http_echo_client_request_method_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->main->method_name.data) { + v->len = r->main->method_name.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->main->method_name.data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +/* this function's implementation is borrowed from nginx 0.8.20 + * and modified a bit to work with subrequests. + * Copyrighted (C) by Igor Sysoev */ +ngx_int_t +ngx_http_echo_request_body_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_chain_t *in; + + if (r->request_body == NULL + || r->request_body->bufs == NULL + || r->request_body->temp_file) + { + v->not_found = 1; + + return NGX_OK; + } + + in = r->request_body->bufs; + + len = 0; + for (cl = in; cl; cl = cl->next) { + b = cl->buf; + + if (!ngx_buf_in_memory(b)) { + if (b->in_file) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "variable echo_request_body sees in-file only " + "buffers and discard the whole body data"); + + v->not_found = 1; + + return NGX_OK; + } + + } else { + len += b->last - b->pos; + } + } + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + for (cl = in; cl; cl = cl->next) { + b = cl->buf; + + if (ngx_buf_in_memory(b)) { + p = ngx_copy(p, b->pos, b->last - b->pos); + } + } + + if (p - v->data != (ssize_t) len) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "variable echo_request_body: buffer error"); + + v->not_found = 1; + + return NGX_OK; + } + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + int line_break_len; + size_t size; + u_char *p, *last, *pos; + ngx_int_t i, j; + ngx_buf_t *b, *first = NULL; + unsigned found; +#if nginx_version >= 1011011 + ngx_buf_t **bb; + ngx_chain_t *cl; + ngx_http_echo_main_conf_t *emcf; +#endif + ngx_connection_t *c; + ngx_http_request_t *mr; + ngx_http_connection_t *hc; + + mr = r->main; + hc = r->main->http_connection; + c = mr->connection; + +#if (NGX_HTTP_V2) + /* TODO */ + if (mr->stream) { + v->not_found = 1; + return NGX_OK; + } +#endif + +#if nginx_version >= 1011011 + emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module); +#endif + + size = 0; + b = c->buffer; + + if (mr->request_line.data[mr->request_line.len] == CR) { + line_break_len = 2; + + } else { + line_break_len = 1; + } + + if (mr->request_line.data >= b->start + && mr->request_line.data + mr->request_line.len + line_break_len + <= b->pos) + { + first = b; + size += b->pos - mr->request_line.data; + } + + if (hc->nbusy) { + b = NULL; + +#if nginx_version >= 1011011 + if (hc->nbusy > emcf->busy_buf_ptr_count) { + if (emcf->busy_buf_ptrs) { + ngx_free(emcf->busy_buf_ptrs); + } + + emcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), + r->connection->log); + + if (emcf->busy_buf_ptrs == NULL) { + return NGX_ERROR; + } + + emcf->busy_buf_ptr_count = hc->nbusy; + } + + bb = emcf->busy_buf_ptrs; + for (cl = hc->busy; cl; cl = cl->next) { + *bb++ = cl->buf; + } + + bb = emcf->busy_buf_ptrs; + for (i = hc->nbusy; i > 0; i--) { + b = bb[i - 1]; +#else + for (i = 0; i < hc->nbusy; i++) { + b = hc->busy[i]; +#endif + + if (first == NULL) { + if (mr->request_line.data >= b->pos + || mr->request_line.data + mr->request_line.len + + line_break_len <= b->start) + { + continue; + } + + dd("found first at %d", (int) i); + first = b; + } + + size += b->pos - b->start; + } + } + + + size++; /* plus the null terminator, as required by the later + ngx_strstr() call */ + + v->data = ngx_palloc(r->pool, size); + if (v->data == NULL) { + return NGX_ERROR; + } + + last = v->data; + + b = c->buffer; + found = 0; + + if (first == b) { + found = 1; + pos = b->pos; + + last = ngx_copy(v->data, mr->request_line.data, + pos - mr->request_line.data); + + if (b != mr->header_in) { + /* skip truncated header entries (if any) */ + while (last > v->data && last[-1] != LF) { + last--; + } + } + + i = 0; + for (p = v->data; p != last; p++) { + if (*p == '\0') { + i++; + if (p + 1 != last && *(p + 1) == LF) { + *p = CR; + + } else if (i % 2 == 1) { + *p = ':'; + + } else { + *p = LF; + } + } + } + } + + if (hc->nbusy) { + +#if nginx_version >= 1011011 + bb = emcf->busy_buf_ptrs; + for (i = hc->nbusy; i > 0; i--) { + b = bb[i - 1]; +#else + for (i = 0; i < hc->nbusy; i++) { + b = hc->busy[i]; +#endif + + if (!found) { + if (b != first) { + continue; + } + + dd("found first"); + found = 1; + } + + p = last; + + pos = b->pos; + + if (b == first) { + dd("request line: %.*s", (int) mr->request_line.len, + mr->request_line.data); + + last = ngx_copy(last, + mr->request_line.data, + pos - mr->request_line.data); + + } else { + last = ngx_copy(last, b->start, pos - b->start); + } + +#if 1 + /* skip truncated header entries (if any) */ + while (last > p && last[-1] != LF) { + last--; + } +#endif + + j = 0; + for (; p != last; p++) { + if (*p == '\0') { + j++; + if (p + 1 == last) { + /* XXX this should not happen */ + dd("found string end!!"); + + } else if (*(p + 1) == LF) { + *p = CR; + + } else if (j % 2 == 1) { + *p = ':'; + + } else { + *p = LF; + } + } + } + + if (b == mr->header_in) { + break; + } + } + } + + *last++ = '\0'; + + if (last - v->data > (ssize_t) size) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "buffer error when evaluating " + "$echo_client__request_headers: \"%V\"", + (ngx_int_t) (last - v->data - size)); + + return NGX_ERROR; + } + + /* strip the leading part (if any) of the request body in our header. + * the first part of the request body could slip in because nginx core's + * ngx_http_request_body_length_filter and etc can move r->header_in->pos + * in case that some of the body data has been preread into r->header_in. + */ + + if ((p = (u_char *) ngx_strstr(v->data, CRLF CRLF)) != NULL) { + last = p + sizeof(CRLF CRLF) - 1; + + } else if ((p = (u_char *) ngx_strstr(v->data, CRLF "\n")) != NULL) { + last = p + sizeof(CRLF "\n") - 1; + + } else if ((p = (u_char *) ngx_strstr(v->data, "\n" CRLF)) != NULL) { + last = p + sizeof("\n" CRLF) - 1; + + } else { + for (p = last - 1; p - v->data >= 2; p--) { + if (p[0] == LF && p[-1] == CR) { + p[-1] = LF; + last = p + 1; + break; + } + + if (p[0] == LF && p[-1] == LF) { + last = p + 1; + break; + } + } + } + + v->len = last - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_cacheable_request_uri_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->uri.len) { + v->len = r->uri.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->uri.data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_request_uri_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->uri.len) { + v->len = r->uri.len; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + v->data = r->uri.data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_response_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + if (r->headers_out.status) { + dd("headers out status: %d", (int) r->headers_out.status); + + p = ngx_palloc(r->pool, NGX_INT_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%ui", r->headers_out.status) - p; + v->data = p; + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +#if nginx_version >= 1011011 +void +ngx_http_echo_request_headers_cleanup(void *data) +{ + ngx_http_echo_main_conf_t *emcf; + + emcf = (ngx_http_echo_main_conf_t *) data; + + if (emcf->busy_buf_ptrs) { + ngx_free(emcf->busy_buf_ptrs); + emcf->busy_buf_ptrs = NULL; + } +} +#endif + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.h new file mode 100644 index 0000000..aa5730b --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_request_info.h @@ -0,0 +1,36 @@ +#ifndef ECHO_REQUEST_INFO_H +#define ECHO_REQUEST_INFO_H + + +#include "ngx_http_echo_module.h" + + +ngx_int_t ngx_http_echo_exec_echo_read_request_body( + ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx); + +ngx_int_t ngx_http_echo_request_method_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_client_request_method_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_request_body_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_cacheable_request_uri_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_request_uri_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_response_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +#if nginx_version >= 1011011 +void ngx_http_echo_request_headers_cleanup(void *data); +#endif + +#endif /* ECHO_REQUEST_INFO_H */ diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.c new file mode 100644 index 0000000..c96fa5a --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.c @@ -0,0 +1,208 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_echo_sleep.h" +#include "ngx_http_echo_handler.h" + +#include +#include + + +/* event handler for echo_sleep */ + +static void ngx_http_echo_post_sleep(ngx_http_request_t *r); +static void ngx_http_echo_sleep_cleanup(void *data); + + +ngx_int_t +ngx_http_echo_exec_echo_sleep(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_str_t *computed_arg; + ngx_str_t *computed_arg_elts; + ngx_int_t delay; /* in msec */ + ngx_http_cleanup_t *cln; + + computed_arg_elts = computed_args->elts; + computed_arg = &computed_arg_elts[0]; + + delay = ngx_atofp(computed_arg->data, computed_arg->len, 3); + + if (delay == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid sleep duration \"%V\"", &computed_arg_elts[0]); + + return NGX_HTTP_BAD_REQUEST; + } + + dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, + (int) r->uri.len, r->uri.data); + + ngx_add_timer(&ctx->sleep, (ngx_msec_t) delay); + + /* we don't check broken downstream connections + * ourselves so even if the client shuts down + * the connection prematurely, nginx will still + * go on waiting for our timers to get properly + * expired. However, we'd still register a + * cleanup handler for completeness. */ + + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_http_echo_sleep_cleanup; + cln->data = r; + + return NGX_AGAIN; +} + + +static void +ngx_http_echo_post_sleep(ngx_http_request_t *r) +{ + ngx_http_echo_ctx_t *ctx; + /* ngx_int_t rc; */ + + dd("post sleep, r:%.*s", (int) r->uri.len, r->uri.data); + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + + if (ctx == NULL) { + return; + } + + ctx->waiting = 0; + ctx->done = 1; + + dd("sleep: after get module ctx"); + + dd("timed out? %d", ctx->sleep.timedout); + dd("timer set? %d", ctx->sleep.timer_set); + + if (!ctx->sleep.timedout) { + dd("HERE reached!"); + return; + } + + ctx->sleep.timedout = 0; + + if (ctx->sleep.timer_set) { + dd("deleting timer for echo_sleep"); + + ngx_del_timer(&ctx->sleep); + } + + /* r->write_event_handler = ngx_http_request_empty_handler; */ + + ngx_http_echo_wev_handler(r); +} + + +void +ngx_http_echo_sleep_event_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + + r = ev->data; + c = r->connection; + + if (c->destroyed) { + return; + } + + if (c->error) { + ngx_http_finalize_request(r, NGX_ERROR); + return; + } + + ctx = c->log->data; + ctx->current_request = r; + + /* XXX when r->done == 1 we should do cleaning immediately + * and delete our timer and then quit. */ + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "echo sleep event handler: \"%V?%V\"", &r->uri, &r->args); + + /* + if (r->done) { + return; + } + */ + + ngx_http_echo_post_sleep(r); + +#if defined(nginx_version) + + dd("before run posted requests"); + + ngx_http_run_posted_requests(c); + + dd("after run posted requests"); + +#endif +} + + +ngx_int_t +ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_str_t *computed_arg; + ngx_str_t *computed_arg_elts; + ngx_int_t delay; /* in msec */ + + computed_arg_elts = computed_args->elts; + computed_arg = &computed_arg_elts[0]; + + delay = ngx_atofp(computed_arg->data, computed_arg->len, 3); + + if (delay == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid sleep duration \"%V\"", &computed_arg_elts[0]); + return NGX_HTTP_BAD_REQUEST; + } + + dd("blocking delay: %lu ms", (unsigned long) delay); + + ngx_msleep((ngx_msec_t) delay); + + return NGX_OK; +} + + +static void +ngx_http_echo_sleep_cleanup(void *data) +{ + ngx_http_request_t *r = data; + ngx_http_echo_ctx_t *ctx; + + dd("echo sleep cleanup"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + if (ctx == NULL) { + return; + } + + if (ctx->sleep.timer_set) { + dd("cleanup: deleting timer for echo_sleep"); + + ngx_del_timer(&ctx->sleep); + return; + } + + dd("cleanup: timer not set"); +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.h new file mode 100644 index 0000000..8bb70c3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_sleep.h @@ -0,0 +1,16 @@ +#ifndef ECHO_SLEEP_H +#define ECHO_SLEEP_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_exec_echo_sleep( + ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, + ngx_array_t *computed_args); + +ngx_int_t ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +void ngx_http_echo_sleep_event_handler(ngx_event_t *ev); + +#endif /* ECHO_SLEEP_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.c new file mode 100644 index 0000000..0980d58 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.c @@ -0,0 +1,791 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_subrequest.h" +#include "ngx_http_echo_handler.h" +#include + + +#define ngx_http_echo_method_name(m) { sizeof(m) - 1, (u_char *) m " " } + + +ngx_str_t ngx_http_echo_content_length_header_key = + ngx_string("Content-Length"); + +ngx_str_t ngx_http_echo_get_method = ngx_http_echo_method_name("GET"); +ngx_str_t ngx_http_echo_put_method = ngx_http_echo_method_name("PUT"); +ngx_str_t ngx_http_echo_post_method = ngx_http_echo_method_name("POST"); +ngx_str_t ngx_http_echo_head_method = ngx_http_echo_method_name("HEAD"); +ngx_str_t ngx_http_echo_copy_method = ngx_http_echo_method_name("COPY"); +ngx_str_t ngx_http_echo_move_method = ngx_http_echo_method_name("MOVE"); +ngx_str_t ngx_http_echo_lock_method = ngx_http_echo_method_name("LOCK"); +ngx_str_t ngx_http_echo_mkcol_method = ngx_http_echo_method_name("MKCOL"); +ngx_str_t ngx_http_echo_trace_method = ngx_http_echo_method_name("TRACE"); +ngx_str_t ngx_http_echo_delete_method = ngx_http_echo_method_name("DELETE"); +ngx_str_t ngx_http_echo_unlock_method = ngx_http_echo_method_name("UNLOCK"); +ngx_str_t ngx_http_echo_options_method = ngx_http_echo_method_name("OPTIONS"); +ngx_str_t ngx_http_echo_propfind_method = + ngx_http_echo_method_name("PROPFIND"); +ngx_str_t ngx_http_echo_proppatch_method = + ngx_http_echo_method_name("PROPPATCH"); + + +typedef struct ngx_http_echo_subrequest_s { + ngx_uint_t method; + ngx_str_t *method_name; + ngx_str_t *location; + ngx_str_t *query_string; + ssize_t content_length_n; + ngx_http_request_body_t *request_body; +} ngx_http_echo_subrequest_t; + + +static ngx_int_t ngx_http_echo_parse_method_name(ngx_str_t **method_name_ptr); +static ngx_int_t ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr, + ngx_http_echo_subrequest_t *parsed_sr); +static ngx_int_t ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r, + ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr); +static ngx_int_t ngx_http_echo_set_content_length_header(ngx_http_request_t *r, + off_t len); + + +ngx_int_t +ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_int_t rc; + ngx_http_echo_subrequest_t *parsed_sr; + ngx_http_request_t *sr; /* subrequest object */ + ngx_str_t args; + ngx_uint_t flags = 0; + + dd_enter(); + + rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); + if (rc != NGX_OK) { + return rc; + } + + dd("location: %.*s", + (int) parsed_sr->location->len, + parsed_sr->location->data); + + args.data = NULL; + args.len = 0; + + if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) + != NGX_OK) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo_subrequest_async sees unsafe uri: \"%V\"", + parsed_sr->location); + return NGX_ERROR; + } + + if (args.len > 0 && parsed_sr->query_string == NULL) { + parsed_sr->query_string = &args; + } + + rc = ngx_http_echo_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, + &sr, NULL, 0); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); + + if (rc != NGX_OK) { + return rc; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_int_t rc; + ngx_http_request_t *sr; /* subrequest object */ + ngx_http_post_subrequest_t *psr; + ngx_http_echo_subrequest_t *parsed_sr; + ngx_str_t args; + ngx_uint_t flags = 0; + ngx_http_echo_ctx_t *sr_ctx; + + dd_enter(); + + rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); + if (rc != NGX_OK) { + return rc; + } + + args.data = NULL; + args.len = 0; + + if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) + != NGX_OK) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo_subrequest sees unsafe uri: \"%V\"", + parsed_sr->location); + return NGX_ERROR; + } + + if (args.len > 0 && parsed_sr->query_string == NULL) { + parsed_sr->query_string = &args; + } + + rc = ngx_http_echo_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + sr_ctx = ngx_http_echo_create_ctx(r); + + /* set by ngx_http_echo_create_ctx + * sr_ctx->run_post_subrequest = 0 + */ + + dd("creating sr ctx for %.*s: %p", (int) parsed_sr->location->len, + parsed_sr->location->data, sr_ctx); + + psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); + + if (psr == NULL) { + return NGX_ERROR; + } + + psr->handler = ngx_http_echo_post_subrequest; + psr->data = sr_ctx; + + rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, + &sr, psr, 0); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + sr_ctx->sleep.data = sr; + + ngx_http_set_ctx(sr, sr_ctx, ngx_http_echo_module); + + rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r, + ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr) +{ + ngx_str_t *computed_arg_elts, *arg; + ngx_str_t **to_write = NULL; + ngx_str_t *method_name; + ngx_str_t *body_str = NULL; + ngx_str_t *body_file = NULL; + ngx_uint_t i; + ngx_flag_t expecting_opt; + ngx_http_request_body_t *rb = NULL; + ngx_buf_t *b; + ngx_http_echo_subrequest_t *parsed_sr; + ngx_open_file_info_t of; + ngx_http_core_loc_conf_t *clcf; + size_t len; + + *parsed_sr_ptr = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_subrequest_t)); + if (*parsed_sr_ptr == NULL) { + return NGX_ERROR; + } + + parsed_sr = *parsed_sr_ptr; + computed_arg_elts = computed_args->elts; + method_name = &computed_arg_elts[0]; + parsed_sr->location = &computed_arg_elts[1]; + + if (parsed_sr->location->len == 0) { + return NGX_ERROR; + } + + expecting_opt = 1; + + for (i = 2; i < computed_args->nelts; i++) { + arg = &computed_arg_elts[i]; + + if (!expecting_opt) { + if (to_write == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "echo_subrequest_async: to_write should NOT be NULL"); + return NGX_ERROR; + } + + *to_write = arg; + to_write = NULL; + + expecting_opt = 1; + + continue; + } + + if (arg->len == 2) { + if (ngx_strncmp("-q", arg->data, arg->len) == 0) { + to_write = &parsed_sr->query_string; + expecting_opt = 0; + continue; + } + + if (ngx_strncmp("-b", arg->data, arg->len) == 0) { + to_write = &body_str; + expecting_opt = 0; + continue; + } + + if (ngx_strncmp("-f", arg->data, arg->len) == 0) { + dd("found option -f"); + to_write = &body_file; + expecting_opt = 0; + continue; + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown option for echo_subrequest*: %V", arg); + + return NGX_ERROR; + } + + if (body_str != NULL && body_str->len) { + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + + if (rb == NULL) { + return NGX_ERROR; + } + + parsed_sr->content_length_n = body_str->len; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->temporary = 1; + /* b->memory = 1; */ + b->start = b->pos = body_str->data; + b->end = b->last = body_str->data + body_str->len; + + rb->bufs = ngx_alloc_chain_link(r->pool); + if (rb->bufs == NULL) { + return NGX_ERROR; + } + + rb->bufs->buf = b; + rb->bufs->next = NULL; + + rb->buf = b; + + } else if (body_file != NULL && body_file->len) { + + dd("body_file defined %.*s", (int) body_file->len, body_file->data); + + body_file->data = ngx_http_echo_rebase_path(r->pool, body_file->data, + body_file->len, &len); + + if (body_file->data == NULL) { + return NGX_ERROR; + } + + body_file->len = len; + + dd("after rebase, the path becomes %.*s", (int) body_file->len, + body_file->data); + + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (rb == NULL) { + return NGX_ERROR; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + +#if defined(nginx_version) && nginx_version >= 8018 + of.read_ahead = clcf->read_ahead; +#endif + + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + if (ngx_open_cached_file(clcf->open_file_cache, body_file, &of, r->pool) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, + "%s \"%V\" failed", + of.failed, body_file); + + return NGX_ERROR; + } + + dd("file content size: %d", (int) of.size); + + parsed_sr->content_length_n = (ssize_t) of.size; + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_ERROR; + } + + b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); + if (b->file == NULL) { + return NGX_ERROR; + } + + b->file_pos = 0; + b->file_last = of.size; + + b->in_file = b->file_last ? 1: 0; + +#if 0 + b->last_buf = (r == r->main) ? 1: 0; + b->last_in_chain = 1; +#endif + + b->file->fd = of.fd; + b->file->name = *body_file; + b->file->log = r->connection->log; + b->file->directio = of.is_directio; + + rb->bufs = ngx_alloc_chain_link(r->pool); + if (rb->bufs == NULL) { + return NGX_ERROR; + } + + rb->bufs->buf = b; + rb->bufs->next = NULL; + rb->buf = b; + } + + parsed_sr->request_body = rb; + + parsed_sr->method = ngx_http_echo_parse_method_name(&method_name); + parsed_sr->method_name = method_name; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr, + ngx_http_echo_subrequest_t *parsed_sr) +{ + ngx_http_core_main_conf_t *cmcf; + ngx_http_request_t *r; + ngx_http_request_body_t *body; + ngx_int_t rc; + + sr->method = parsed_sr->method; + sr->method_name = *(parsed_sr->method_name); + + if (sr->method == NGX_HTTP_HEAD) { + sr->header_only = 1; + } + + r = sr->parent; + + sr->header_in = r->header_in; + + /* XXX work-around a bug in ngx_http_subrequest */ + if (r->headers_in.headers.last == &r->headers_in.headers.part) { + sr->headers_in.headers.last = &sr->headers_in.headers.part; + } + + /* we do not inherit the parent request's variables */ + cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); + sr->variables = ngx_pcalloc(sr->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t)); + + if (sr->variables == NULL) { + return NGX_ERROR; + } + + body = parsed_sr->request_body; + if (body) { + sr->request_body = body; + + rc = ngx_http_echo_set_content_length_header(sr, body->buf ? + ngx_buf_size(body->buf) + : 0); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + + dd("subrequest body: %p", sr->request_body); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_echo_parse_method_name(ngx_str_t **method_name_ptr) +{ + const ngx_str_t *method_name = *method_name_ptr; + + switch (method_name->len) { + case 3: + if (ngx_http_echo_strcmp_const(method_name->data, "GET") == 0) { + *method_name_ptr = &ngx_http_echo_get_method; + return NGX_HTTP_GET; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "PUT") == 0) { + *method_name_ptr = &ngx_http_echo_put_method; + return NGX_HTTP_PUT; + } + + return NGX_HTTP_UNKNOWN; + + case 4: + if (ngx_http_echo_strcmp_const(method_name->data, "POST") == 0) { + *method_name_ptr = &ngx_http_echo_post_method; + return NGX_HTTP_POST; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "HEAD") == 0) { + *method_name_ptr = &ngx_http_echo_head_method; + return NGX_HTTP_HEAD; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "COPY") == 0) { + *method_name_ptr = &ngx_http_echo_copy_method; + return NGX_HTTP_COPY; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "MOVE") == 0) { + *method_name_ptr = &ngx_http_echo_move_method; + return NGX_HTTP_MOVE; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "LOCK") == 0) { + *method_name_ptr = &ngx_http_echo_lock_method; + return NGX_HTTP_LOCK; + } + + return NGX_HTTP_UNKNOWN; + + case 5: + if (ngx_http_echo_strcmp_const(method_name->data, "MKCOL") == 0) { + *method_name_ptr = &ngx_http_echo_mkcol_method; + return NGX_HTTP_MKCOL; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "TRACE") == 0) { + *method_name_ptr = &ngx_http_echo_trace_method; + return NGX_HTTP_TRACE; + } + + return NGX_HTTP_UNKNOWN; + + case 6: + if (ngx_http_echo_strcmp_const(method_name->data, "DELETE") == 0) { + *method_name_ptr = &ngx_http_echo_delete_method; + return NGX_HTTP_DELETE; + } + + if (ngx_http_echo_strcmp_const(method_name->data, "UNLOCK") == 0) { + *method_name_ptr = &ngx_http_echo_unlock_method; + return NGX_HTTP_UNLOCK; + } + + return NGX_HTTP_UNKNOWN; + + case 7: + if (ngx_http_echo_strcmp_const(method_name->data, "OPTIONS") == 0) { + *method_name_ptr = &ngx_http_echo_options_method; + return NGX_HTTP_OPTIONS; + } + + return NGX_HTTP_UNKNOWN; + + case 8: + if (ngx_http_echo_strcmp_const(method_name->data, "PROPFIND") == 0) { + *method_name_ptr = &ngx_http_echo_propfind_method; + return NGX_HTTP_PROPFIND; + } + + return NGX_HTTP_UNKNOWN; + + case 9: + if (ngx_http_echo_strcmp_const(method_name->data, "PROPPATCH") == 0) { + *method_name_ptr = &ngx_http_echo_proppatch_method; + return NGX_HTTP_PROPPATCH; + } + + return NGX_HTTP_UNKNOWN; + + default: + return NGX_HTTP_UNKNOWN; + } +} + + +/* XXX extermely evil and not working yet */ +ngx_int_t +ngx_http_echo_exec_abort_parent(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ +#if 0 + ngx_http_postponed_request_t *pr, *ppr; + ngx_http_request_t *saved_data = NULL; + ngx_chain_t *out = NULL; + /* ngx_int_t rc; */ + + dd("aborting parent..."); + + if (r == r->main || r->parent == NULL) { + return NGX_OK; + } + + if (r->parent->postponed) { + dd("Found parent->postponed..."); + + saved_data = r->connection->data; + ppr = NULL; + for (pr = r->parent->postponed; pr->next; pr = pr->next) { + if (pr->request == NULL) { + continue; + } + + if (pr->request == r) { + /* r->parent->postponed->next = pr; */ + dd("found the current subrequest"); + out = pr->out; + continue; + } + + /* r->connection->data = pr->request; */ + dd("finalizing the subrequest..."); + ngx_http_upstream_create(pr->request); + pr->request->upstream = NULL; + + if (ppr == NULL) { + r->parent->postponed = pr->next; + ppr = pr->next; + } else { + ppr->next = pr->next; + ppr = pr->next; + } + } + } + + r->parent->postponed->next = NULL; + + /* + r->connection->data = r->parent; + r->connection->buffered = 0; + + if (out != NULL) { + dd("trying to send more stuffs for the parent"); + ngx_http_output_filter(r->parent, out); + } + */ + + /* ngx_http_send_special(r->parent, NGX_HTTP_LAST); */ + + if (saved_data) { + r->connection->data = saved_data; + } + + dd("terminating the parent request"); + + return ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */); + + /* ngx_http_upstream_create(r); */ + + /* ngx_http_finalize_request(r->parent, NGX_ERROR); */ +#endif + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_exec(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) +{ + ngx_str_t *uri; + ngx_str_t *user_args; + ngx_str_t args; + ngx_uint_t flags = 0; + ngx_str_t *computed_arg; + + computed_arg = computed_args->elts; + + uri = &computed_arg[0]; + + if (uri->len == 0) { + return NGX_HTTP_BAD_REQUEST; + } + + if (computed_args->nelts > 1) { + user_args = &computed_arg[1]; + + } else { + user_args = NULL; + } + + args.data = NULL; + args.len = 0; + + if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "echo_exec sees unsafe uri: \"%V\"", + uri); + return NGX_ERROR; + } + + if (args.len > 0 && user_args == NULL) { + user_args = &args; + } + + r->write_event_handler = ngx_http_request_empty_handler; + + if (uri->data[0] == '@') { + + if (user_args && user_args->len > 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "querystring %V ignored when exec'ing named " + "location %V", user_args, uri); + } + +#if 1 + /* clear the modules contexts */ + ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); +#endif + + dd("named location: %.*s, c:%d", (int) uri->len, uri->data, + (int) r->main->count); + + return ngx_http_named_location(r, uri); + } + + return ngx_http_internal_redirect(r, uri, user_args); +} + + +static ngx_int_t +ngx_http_echo_set_content_length_header(ngx_http_request_t *r, off_t len) +{ + ngx_table_elt_t *h, *header; + u_char *p; + ngx_list_part_t *part; + ngx_http_request_t *pr; + ngx_uint_t i; + + r->headers_in.content_length_n = len; + + if (ngx_list_init(&r->headers_in.headers, r->pool, 20, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->key = ngx_http_echo_content_length_header_key; + h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); + if (h->lowcase_key == NULL) { + return NGX_ERROR; + } + + ngx_strlow(h->lowcase_key, h->key.data, h->key.len); + + r->headers_in.content_length = h; + + p = ngx_palloc(r->pool, NGX_OFF_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + h->value.data = p; + + h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data; + + h->hash = ngx_http_echo_content_length_hash; + + dd("r content length: %.*s", + (int) r->headers_in.content_length->value.len, + r->headers_in.content_length->value.data); + + pr = r->parent; + + if (pr == NULL) { + return NGX_OK; + } + + /* forward the parent request's all other request headers */ + + part = &pr->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].key.len == sizeof("Content-Length") - 1 + && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length", + sizeof("Content-Length") - 1) + == 0) + { + continue; + } + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = header[i]; + } + + /* XXX maybe we should set those built-in header slot in + * ngx_http_headers_in_t too? */ + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.h new file mode 100644 index 0000000..61c0a04 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_subrequest.h @@ -0,0 +1,19 @@ +#ifndef ECHO_SUBREQUEST_H +#define ECHO_SUBREQUEST_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +ngx_int_t ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +ngx_int_t ngx_http_echo_exec_abort_parent(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); + +ngx_int_t ngx_http_echo_exec_exec(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); + +#endif /* ECHO_SUBREQUEST_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.c new file mode 100644 index 0000000..e2777ee --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.c @@ -0,0 +1,95 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif + +#include "ddebug.h" + +#include "ngx_http_echo_timer.h" +#include "ngx_http_echo_util.h" + +#include +#include +#include + + +ngx_int_t +ngx_http_echo_timer_elapsed_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_echo_ctx_t *ctx; + ngx_msec_int_t ms; + u_char *p; + ngx_time_t *tp; + size_t size; + + ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); + if (ctx == NULL) { + ctx = ngx_http_echo_create_ctx(r); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_echo_module); + } + + if (ctx->timer_begin.sec == 0) { + ctx->timer_begin.sec = r->start_sec; + ctx->timer_begin.msec = (ngx_msec_t) r->start_msec; + } + + /* force the ngx timer to update */ + +#if (nginx_version >= 8035) || (nginx_version < 8000 && nginx_version >= 7066) + ngx_time_update(); +#else + ngx_time_update(0, 0); +#endif + + tp = ngx_timeofday(); + + dd("old sec msec: %ld %d\n", (long) ctx->timer_begin.sec, + (int) ctx->timer_begin.msec); + + dd("new sec msec: %ld %d\n", (long) tp->sec, (int) tp->msec); + + ms = (ngx_msec_int_t) + ((tp->sec - ctx->timer_begin.sec) * 1000 + + (tp->msec - ctx->timer_begin.msec)); + ms = (ms >= 0) ? ms : 0; + + size = sizeof("-9223372036854775808.000") - 1; + + p = ngx_palloc(r->pool, size); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_snprintf(p, size, "%T.%03M", ms / 1000, ms % 1000) - p; + v->data = p; + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_exec_echo_reset_timer(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ + dd("Exec timer..."); + + /* force the ngx timer to update */ + +#if (nginx_version >= 8035) || (nginx_version < 8000 && nginx_version >= 7066) + ngx_time_update(); +#else + ngx_time_update(0, 0); +#endif + + ctx->timer_begin = *ngx_timeofday(); + return NGX_OK; +} + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.h new file mode 100644 index 0000000..b6e7ff3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_timer.h @@ -0,0 +1,13 @@ +#ifndef ECHO_TIMER_H +#define ECHO_TIMER_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_timer_elapsed_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +ngx_int_t ngx_http_echo_exec_echo_reset_timer(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); + +#endif /* ECHO_TIMER_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.c new file mode 100644 index 0000000..fed0587 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.c @@ -0,0 +1,302 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_echo_util.h" +#include "ngx_http_echo_sleep.h" + + +ngx_uint_t ngx_http_echo_content_length_hash = 0; + + +ngx_http_echo_ctx_t * +ngx_http_echo_create_ctx(ngx_http_request_t *r) +{ + ngx_http_echo_ctx_t *ctx; + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ctx->sleep.handler = ngx_http_echo_sleep_event_handler; + ctx->sleep.data = r; + ctx->sleep.log = r->connection->log; + + return ctx; +} + + +ngx_int_t +ngx_http_echo_eval_cmd_args(ngx_http_request_t *r, + ngx_http_echo_cmd_t *cmd, ngx_array_t *computed_args, + ngx_array_t *opts) +{ + unsigned expecting_opts = 1; + ngx_uint_t i; + ngx_array_t *args = cmd->args; + ngx_str_t *arg, *raw, *opt; + ngx_http_echo_arg_template_t *value; + + value = args->elts; + + for (i = 0; i < args->nelts; i++) { + raw = &value[i].raw_value; + + if (value[i].lengths == NULL && raw->len > 0) { + if (expecting_opts) { + if (raw->len == 1 || raw->data[0] != '-') { + expecting_opts = 0; + + } else if (raw->data[1] == '-') { + expecting_opts = 0; + continue; + + } else { + opt = ngx_array_push(opts); + if (opt == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + opt->len = raw->len - 1; + opt->data = raw->data + 1; + + dd("pushing opt: %.*s", (int) opt->len, opt->data); + + continue; + } + } + + } else { + expecting_opts = 0; + } + + arg = ngx_array_push(computed_args); + if (arg == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (value[i].lengths == NULL) { /* does not contain vars */ + dd("Using raw value \"%.*s\"", (int) raw->len, raw->data); + *arg = *raw; + + } else { + if (ngx_http_script_run(r, arg, value[i].lengths->elts, + 0, value[i].values->elts) + == NULL) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + dd("pushed arg: %.*s", (int) arg->len, arg->data); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_echo_send_chain_link(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_chain_t *in) +{ + ngx_int_t rc; + + rc = ngx_http_echo_send_header_if_needed(r, ctx); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + if (in == NULL) { + +#if defined(nginx_version) && nginx_version <= 8004 + + /* earlier versions of nginx does not allow subrequests + to send last_buf themselves */ + if (r != r->main) { + return NGX_OK; + } + +#endif + + rc = ngx_http_send_special(r, NGX_HTTP_LAST); + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + return NGX_OK; + } + + /* FIXME we should udpate chains to recycle chain links and bufs */ + return ngx_http_output_filter(r, in); +} + + +ngx_int_t +ngx_http_echo_send_header_if_needed(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_http_echo_loc_conf_t *elcf; + + if (!r->header_sent && !ctx->header_sent) { + elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); + + r->headers_out.status = (ngx_uint_t) elcf->status; + + if (ngx_http_set_content_type(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_clear_content_length(r); + ngx_http_clear_accept_ranges(r); + + rc = ngx_http_send_header(r); + ctx->header_sent = 1; + return rc; + } + + return NGX_OK; +} + + +ssize_t +ngx_http_echo_atosz(u_char *line, size_t n) +{ + ssize_t value; + + if (n == 0) { + return NGX_ERROR; + } + + for (value = 0; n--; line++) { + if (*line == '_') { /* we ignore undercores */ + continue; + } + + if (*line < '0' || *line > '9') { + return NGX_ERROR; + } + + value = value * 10 + (*line - '0'); + } + + if (value < 0) { + return NGX_ERROR; + } + + return value; +} + + +/* Modified from the ngx_strlcasestrn function in ngx_string.h + * Copyright (C) by Igor Sysoev */ +u_char * +ngx_http_echo_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n) +{ + ngx_uint_t c1, c2; + + c2 = (ngx_uint_t) *s2++; + last -= n; + + do { + do { + if (s1 >= last) { + return NULL; + } + + c1 = (ngx_uint_t) *s1++; + + } while (c1 != c2); + + } while (ngx_strncmp(s1, s2, n) != 0); + + return --s1; +} + + +ngx_int_t +ngx_http_echo_post_request_at_head(ngx_http_request_t *r, + ngx_http_posted_request_t *pr) +{ + dd_enter(); + + if (pr == NULL) { + pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } + } + + pr->request = r; + pr->next = r->main->posted_requests; + r->main->posted_requests = pr; + + return NGX_OK; +} + + +u_char * +ngx_http_echo_rebase_path(ngx_pool_t *pool, u_char *src, size_t osize, + size_t *nsize) +{ + u_char *p, *dst; + + if (osize == 0) { + return NULL; + } + + if (src[0] == '/') { + /* being an absolute path already, just add a trailing '\0' */ + *nsize = osize; + + dst = ngx_palloc(pool, *nsize + 1); + if (dst == NULL) { + *nsize = 0; + return NULL; + } + + p = ngx_copy(dst, src, osize); + *p = '\0'; + + return dst; + } + + *nsize = ngx_cycle->prefix.len + osize; + + dst = ngx_palloc(pool, *nsize + 1); + if (dst == NULL) { + *nsize = 0; + return NULL; + } + + p = ngx_copy(dst, ngx_cycle->prefix.data, ngx_cycle->prefix.len); + p = ngx_copy(p, src, osize); + + *p = '\0'; + + return dst; +} + + +ngx_int_t +ngx_http_echo_flush_postponed_outputs(ngx_http_request_t *r) +{ + if (r == r->connection->data && r->postponed) { + /* notify the downstream postpone filter to flush the postponed + * outputs of the current request */ + return ngx_http_output_filter(r, NULL); + } + + /* do nothing */ + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.h new file mode 100644 index 0000000..d620d09 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_util.h @@ -0,0 +1,58 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef NGX_HTTP_ECHO_UTIL_H +#define NGX_HTTP_ECHO_UTIL_H + + +#include "ngx_http_echo_module.h" + + +#define ngx_http_echo_strcmp_const(a, b) \ + ngx_strncmp(a, b, sizeof(b) - 1) + + +#define ngx_http_echo_hash_literal(s) \ + ngx_http_echo_hash_str((u_char *) s, sizeof(s) - 1) + + +static ngx_inline ngx_uint_t +ngx_http_echo_hash_str(u_char *src, size_t n) +{ + ngx_uint_t key; + + key = 0; + + while (n--) { + key = ngx_hash(key, *src); + src++; + } + + return key; +} + + +extern ngx_uint_t ngx_http_echo_content_length_hash; + + +ngx_http_echo_ctx_t *ngx_http_echo_create_ctx(ngx_http_request_t *r); +ngx_int_t ngx_http_echo_eval_cmd_args(ngx_http_request_t *r, + ngx_http_echo_cmd_t *cmd, ngx_array_t *computed_args, + ngx_array_t *opts); +ngx_int_t ngx_http_echo_send_header_if_needed(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx); +ngx_int_t ngx_http_echo_send_chain_link(ngx_http_request_t *r, + ngx_http_echo_ctx_t *ctx, ngx_chain_t *cl); +ssize_t ngx_http_echo_atosz(u_char *line, size_t n); +u_char *ngx_http_echo_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n); +ngx_int_t ngx_http_echo_post_request_at_head(ngx_http_request_t *r, + ngx_http_posted_request_t *pr); +u_char *ngx_http_echo_rebase_path(ngx_pool_t *pool, u_char *src, size_t osize, + size_t *nsize); +ngx_int_t ngx_http_echo_flush_postponed_outputs(ngx_http_request_t *r); + + +#endif /* NGX_HTTP_ECHO_UTIL_H */ diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.c b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.c new file mode 100644 index 0000000..138a510 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.c @@ -0,0 +1,110 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_echo_var.h" +#include "ngx_http_echo_timer.h" +#include "ngx_http_echo_request_info.h" +#include "ngx_http_echo_foreach.h" + + +static ngx_int_t ngx_http_echo_incr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + + +static ngx_http_variable_t ngx_http_echo_variables[] = { + + { ngx_string("echo_timer_elapsed"), NULL, + ngx_http_echo_timer_elapsed_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_request_method"), NULL, + ngx_http_echo_request_method_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_cacheable_request_uri"), NULL, + ngx_http_echo_cacheable_request_uri_variable, 0, + 0, 0 }, + + { ngx_string("echo_request_uri"), NULL, + ngx_http_echo_request_uri_variable, 0, + 0, 0 }, + + { ngx_string("echo_client_request_method"), NULL, + ngx_http_echo_client_request_method_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_request_body"), NULL, + ngx_http_echo_request_body_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_client_request_headers"), NULL, + ngx_http_echo_client_request_headers_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_it"), NULL, + ngx_http_echo_it_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_incr"), NULL, + ngx_http_echo_incr_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("echo_response_status"), NULL, + ngx_http_echo_response_status_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +ngx_int_t +ngx_http_echo_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_echo_variables; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_echo_incr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_echo_ctx_t *ctx; + u_char *p; + + ctx = ngx_http_get_module_ctx(r->main, ngx_http_echo_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->counter++; + + p = ngx_palloc(r->pool, NGX_INT_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%ui", ctx->counter) - p; + v->data = p; + + v->valid = 1; + v->not_found = 0; + v->no_cacheable = 1; + + return NGX_OK; +} + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.h b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.h new file mode 100644 index 0000000..8b24e02 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/src/ngx_http_echo_var.h @@ -0,0 +1,9 @@ +#ifndef ECHO_VAR_H +#define ECHO_VAR_H + +#include "ngx_http_echo_module.h" + +ngx_int_t ngx_http_echo_add_variables(ngx_conf_t *cf); + +#endif /* ECHO_VAR_H */ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/abort-parent.t b/modules_deb/libnginx-mod-http-echo-0.63/t/abort-parent.t new file mode 100644 index 0000000..6137607 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/abort-parent.t @@ -0,0 +1,63 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::LWP skip_all => + 'not working at all'; + +plan tests => 2 * blocks(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /abort { + echo hello; + echo_flush; + echo_location_async '/foo'; + echo_location_async '/bar'; + echo_location_async '/baz'; + echo world; + echo_flush; + } + + location /proxy { + proxy_pass "http://127.0.0.1:$server_port/sleep?$query_string"; + } + + location /sleep { + echo_sleep $arg_sleep; + echo $arg_echo; + echo_flush; + } + + location /foo { + echo_location '/proxy?sleep=1&echo=foo'; + #echo_flush; + echo_abort_parent; + } + + location /bar { + proxy_pass 'http://127.0.0.1:$server_port/sleep_bar'; + } + + location /baz { + proxy_pass 'http://127.0.0.1:$server_port/sleep_baz'; + } + + location /sleep_bar { + echo_sleep 2; + echo bar; + } + + location /sleep_baz { + echo_sleep 3; + echo baz; + } +--- request + GET /abort +--- response_body +hello +bar + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/blocking-sleep.t b/modules_deb/libnginx-mod-http-echo-0.63/t/blocking-sleep.t new file mode 100644 index 0000000..0bdc6cc --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/blocking-sleep.t @@ -0,0 +1,156 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /echo { + echo_blocking_sleep 1; + } +--- request + GET /echo +--- response_body + + + +=== TEST 2: fractional delay +--- config + location /echo { + echo_blocking_sleep 0.01; + } +--- request + GET /echo +--- response_body + + + +=== TEST 3: leading echo +--- config + location /echo { + echo before...; + echo_blocking_sleep 0.01; + } +--- request + GET /echo +--- response_body +before... + + + +=== TEST 4: trailing echo +--- config + location /echo { + echo_blocking_sleep 0.01; + echo after...; + } +--- request + GET /echo +--- response_body +after... + + + +=== TEST 5: two echos around sleep +--- config + location /echo { + echo before...; + echo_blocking_sleep 0.01; + echo after...; + } +--- request + GET /echo +--- response_body +before... +after... + + + +=== TEST 6: interleaving sleep and echo +--- config + location /echo { + echo 1; + echo_blocking_sleep 0.01; + echo 2; + echo_blocking_sleep 0.01; + } +--- request + GET /echo +--- response_body +1 +2 + + + +=== TEST 7: interleaving sleep and echo with echo at the end... +--- config + location /echo { + echo 1; + echo_blocking_sleep 0.01; + echo 2; + echo_blocking_sleep 0.01; + echo 3; + } +--- request + GET /echo +--- response_body +1 +2 +3 + + + +=== TEST 8: flush before sleep +we didn't really test the actual effect of "echo_flush" here... +merely checks if it croaks if appears. +--- config + location /flush { + echo hi; + echo_flush; + echo_blocking_sleep 0.01; + echo trees; + } +--- request + GET /flush +--- response_body +hi +trees + + + +=== TEST 9: flush does not increment opcode pointer itself +--- config + location /flush { + echo hi; + echo_flush; + echo trees; + } +--- request + GET /flush +--- response_body +hi +trees + + + +=== TEST 10: blocking sleep by variable +--- config + location ~ ^/sleep/(.+) { + echo before...; + echo_blocking_sleep $1; + echo after...; + } +--- request + GET /sleep/0.01 +--- response_body +before... +after... + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/echo-after-body.t b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-after-body.t new file mode 100644 index 0000000..44c4c72 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-after-body.t @@ -0,0 +1,261 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks() + 1); + +no_long_string(); +log_level('warn'); + +#master_on(); +#workers(1); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- http_config + postpone_output 1; +--- config + location /echo { + echo_after_body hello; + echo world; + } +--- request + GET /echo +--- response_body +world +hello + + + +=== TEST 2: echo after proxy +--- config + location /echo { + echo_after_body hello; + proxy_pass http://127.0.0.1:$server_port$request_uri/more; + } + location /echo/more { + echo world; + } +--- request + GET /echo +--- response_body +world +hello + + + +=== TEST 3: with variables +--- config + location /echo { + echo_after_body $request_method; + echo world; + } +--- request + GET /echo +--- response_body +world +GET + + + +=== TEST 4: w/o args +--- config + location /echo { + echo_after_body; + echo world; + } +--- request + GET /echo +--- response_body eval +"world\n\n" + + + +=== TEST 5: order is not important +--- config + location /reversed { + echo world; + echo_after_body hello; + } +--- request + GET /reversed +--- response_body +world +hello + + + +=== TEST 6: multiple echo_after_body instances +--- config + location /echo { + echo_after_body hello; + echo_after_body world; + echo !; + } +--- request + GET /echo +--- response_body +! +hello +world + + + +=== TEST 7: multiple echo_after_body instances with multiple echo cmds +--- config + location /echo { + echo_after_body hello; + echo_after_body world; + echo i; + echo say; + } +--- request + GET /echo +--- response_body +i +say +hello +world + + + +=== TEST 8: echo-after-body & echo-before-body +--- config + location /mixed { + echo_before_body hello; + echo_after_body world; + echo_before_body hiya; + echo_after_body igor; + echo ////////; + } +--- request + GET /mixed +--- response_body +hello +hiya +//////// +world +igor + + + +=== TEST 9: echo around proxy +--- config + location /echo { + echo_before_body hello; + echo_before_body world; + #echo $scheme://$host:$server_port$request_uri/more; + proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; + echo_after_body hiya; + echo_after_body igor; + } + location /echo/more { + echo blah; + } +--- request + GET /echo +--- response_body +hello +world +blah +hiya +igor + + + +=== TEST 10: with $echo_response_status +--- config + location /status { + echo_after_body "status: $echo_response_status"; + return 404; + } +--- request + GET /status +--- response_body_like +.*404 Not Found.* +status: 404$ +--- error_code: 404 + + + +=== TEST 11: in subrequests +--- config + location /main { + echo_location_async /hello; + } + location /hello { + echo_after_body 'world!'; + echo 'hello'; + } +--- request + GET /main +--- response_body +hello +world! + + + +=== TEST 12: echo_after_body + gzip +--- config + gzip on; + gzip_min_length 1; + location /main { + echo_after_body 'world!'; + echo_duplicate 1024 'hello'; + } +--- request + GET /main +--- response_body_like +hello +--- SKIP + + + +=== TEST 13: echo_after_body + proxy output +--- config + #gzip on; + #gzip_min_length 1; + location /main { + echo_after_body 'world'; + proxy_pass http://127.0.0.1:$server_port/foo; + } + location /foo { + echo_duplicate 10 hello; + } +--- request + GET /main +--- response_body_like +^(?:hello){10}world$ + + + +=== TEST 14: in subrequests (we get last_in_chain set properly) +--- config + location /main { + echo_location_async /hello; + } + location /hello { + echo 'hello'; + echo_after_body 'world!'; + body_filter_by_lua ' + local eof = ngx.arg[2] + if eof then + print("lua: eof found in body") + end + '; + } +--- request + GET /main +--- response_body +hello +world! +--- log_level: notice +--- error_log +lua: eof found in body + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/echo-before-body.t b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-before-body.t new file mode 100644 index 0000000..1513184 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-before-body.t @@ -0,0 +1,278 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /echo { + echo_before_body hello; + echo world; + } +--- request + GET /echo +--- response_body +hello +world + + + +=== TEST 2: echo before proxy +--- config + location /echo { + echo_before_body hello; + proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; + } + location /echo/more { + echo world; + } +--- request + GET /echo +--- response_body +hello +world + + + +=== TEST 3: with variables +--- config + location /echo { + echo_before_body $request_method; + echo world; + } +--- request + GET /echo +--- response_body +GET +world + + + +=== TEST 4: w/o args +--- config + location /echo { + echo_before_body; + echo world; + } +--- request + GET /echo +--- response_body eval +"\nworld\n" + + + +=== TEST 5: order is not important +--- config + location /reversed { + echo world; + echo_before_body hello; + } +--- request + GET /reversed +--- response_body +hello +world + + + +=== TEST 6: multiple echo_before_body instances +--- config + location /echo { + echo_before_body hello; + echo_before_body world; + echo !; + } +--- request + GET /echo +--- response_body +hello +world +! + + + +=== TEST 7: multiple echo_before_body instances with multiple echo cmds +--- config + location /echo { + echo_before_body hello; + echo_before_body world; + echo i; + echo say; + } +--- request + GET /echo +--- response_body +hello +world +i +say + + + +=== TEST 8: with $echo_response_status +--- config + location /status { + echo_before_body "status: $echo_response_status"; + return 404; + } +--- request + GET /status +--- response_body_like +status: 404 +.*404 Not Found.*$ +--- error_code: 404 + + + +=== TEST 9: $echo_response_status in echo_before_body in subrequests +--- config + location /main { + echo_location '/status?val=403'; + echo_location '/status?val=500'; + } + location /status { + if ($arg_val = 500) { + echo_before_body "status: $echo_response_status"; + return 500; + break; + } + if ($arg_val = 403) { + echo_before_body "status: $echo_response_status"; + return 403; + break; + } + return 200; + } +--- request + GET /main +--- response_body_like +^status: 403.*?status: 500.*$ + + + +=== TEST 10: echo -n +--- config + location /echo { + echo_before_body -n hello; + echo_before_body -n world; + echo ==; + } +--- request + GET /echo +--- response_body +helloworld== + + + +=== TEST 11: echo a -n +--- config + location /echo { + echo_before_body a -n hello; + echo_before_body b -n world; + echo ==; + } +--- request + GET /echo +--- response_body +a -n hello +b -n world +== + + + +=== TEST 12: -n in a var +--- config + location /echo { + set $opt -n; + echo_before_body $opt hello; + echo_before_body $opt world; + echo ==; + } +--- request + GET /echo +--- response_body +-n hello +-n world +== + + + +=== TEST 13: -n only +--- config + location /echo { + echo_before_body -n; + echo_before_body -n; + echo ==; + } +--- request + GET /echo +--- response_body +== + + + +=== TEST 14: -n with an empty string +--- config + location /echo { + echo_before_body -n ""; + set $empty ""; + echo_before_body -n $empty; + echo ==; + } +--- request + GET /echo +--- response_body +== + + + +=== TEST 15: -- -n +--- config + location /echo { + echo_before_body -- -n hello; + echo_before_body -- -n world; + echo ==; + } +--- request + GET /echo +--- response_body +-n hello +-n world +== + + + +=== TEST 16: -n -n +--- config + location /echo { + echo_before_body -n -n hello; + echo_before_body -n -n world; + echo ==; + } +--- request + GET /echo +--- response_body +helloworld== + + + +=== TEST 17: -n -- -n +--- config + location /echo { + echo_before_body -n -- -n hello; + echo_before_body -n -- -n world; + echo ==; + } +--- request + GET /echo +--- response_body +-n hello-n world== + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/echo-duplicate.t b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-duplicate.t new file mode 100644 index 0000000..82b6725 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-duplicate.t @@ -0,0 +1,89 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /dup { + echo_duplicate 3 a; + } +--- request + GET /dup +--- response_body: aaa + + + +=== TEST 2: abc abc +--- config + location /dup { + echo_duplicate 2 abc; + } +--- request + GET /dup +--- response_body: abcabc + + + +=== TEST 3: big size with underscores +--- config + location /dup { + echo_duplicate 10_000 A; + } +--- request + GET /dup +--- response_body eval +'A' x 10_000 + + + +=== TEST 4: 0 duplicate 0 empty strings +--- config + location /dup { + echo_duplicate 0 ""; + } +--- request + GET /dup +--- response_body + + + +=== TEST 5: 0 duplicate non-empty strings +--- config + location /dup { + echo_duplicate 0 "abc"; + } +--- request + GET /dup +--- response_body + + + +=== TEST 6: duplication of empty strings +--- config + location /dup { + echo_duplicate 2 ""; + } +--- request + GET /dup +--- response_body + + + +=== TEST 7: sanity (HEAD) +--- config + location /dup { + echo_duplicate 3 a; + } +--- request + HEAD /dup +--- response_body + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/echo-timer.t b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-timer.t new file mode 100644 index 0000000..712524d --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/echo-timer.t @@ -0,0 +1,107 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +run_tests(); + +__DATA__ + +=== TEST 1: timer without explicit reset +--- config + location /timer { + echo_sleep 0.03; + echo "elapsed $echo_timer_elapsed sec."; + } +--- request + GET /timer +--- response_body_like +^elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ + + + +=== TEST 2: timer without explicit reset and sleep +--- config + location /timer { + echo "elapsed $echo_timer_elapsed sec."; + } +--- request + GET /timer +--- response_body_like +^elapsed 0\.00[0-5] sec\.$ + + + +=== TEST 3: timing accumulated sleeps +--- config + location /timer { + echo_sleep 0.03; + echo_sleep 0.02; + echo "elapsed $echo_timer_elapsed sec."; + } +--- request + GET /timer +--- response_body_like +^elapsed 0\.0(4[6-9]|5[0-6]) sec\.$ + + + +=== TEST 4: timer with explicit reset but without sleep +--- config + location /timer { + echo_reset_timer; + echo "elapsed $echo_timer_elapsed sec."; + } +--- request + GET /timer +--- response_body_like +^elapsed 0\.00[0-5] sec\.$ + + + +=== TEST 5: reset timer between sleeps +--- config + location /timer { + echo_sleep 0.02; + echo "elapsed $echo_timer_elapsed sec."; + echo_reset_timer; + echo_sleep 0.03; + echo "elapsed $echo_timer_elapsed sec."; + } +--- request + GET /timer +--- response_body_like +^elapsed 0\.0(1[6-9]|2[0-6]) sec\. +elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ + + + +=== TEST 6: reset timer between blocking sleeps +--- config + location /timer { + echo_blocking_sleep 0.02; + echo "elapsed $echo_timer_elapsed sec."; + echo_reset_timer; + echo_blocking_sleep 0.03; + echo "elapsed $echo_timer_elapsed sec."; + } +--- request + GET /timer +--- response_body_like +^elapsed 0\.0(1[6-9]|2[0-9]) sec\. +elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ + + + +=== TEST 7: timer without explicit reset +--- config + location = /timer { + return 200 "$echo_timer_elapsed"; + } +--- request + GET /timer +--- response_body_like chop +^0(\.0\d*)$ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/echo.t b/modules_deb/libnginx-mod-http-echo-0.63/t/echo.t new file mode 100644 index 0000000..b181259 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/echo.t @@ -0,0 +1,416 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks() + 6); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /echo { + echo hello; + } +--- request + GET /echo +--- response_body +hello + + + +=== TEST 2: multiple args +--- config + location /echo { + echo say hello world; + } +--- request + GET /echo +--- response_body +say hello world + + + +=== TEST 3: multiple directive instances +--- config + location /echo { + echo say that; + echo hello; + echo world !; + } +--- request + GET /echo +--- response_body +say that +hello +world ! + + + +=== TEST 4: echo without arguments +--- config + location /echo { + echo; + echo; + } +--- request + GET /echo +--- response_body eval +"\n\n" + + + +=== TEST 5: escaped newline +--- config + location /echo { + echo "hello\nworld"; + } +--- request + GET /echo +--- response_body +hello +world + + + +=== TEST 6: escaped tabs and \r and " wihtin "..." +--- config + location /echo { + echo "i say \"hello\tworld\"\r"; + } +--- request + GET /echo +--- response_body eval: "i say \"hello\tworld\"\r\n" + + + +=== TEST 7: escaped tabs and \r and " in single quotes +--- config + location /echo { + echo 'i say \"hello\tworld\"\r'; + } +--- request + GET /echo +--- response_body eval: "i say \"hello\tworld\"\r\n" + + + +=== TEST 8: escaped tabs and \r and " w/o any quotes +--- config + location /echo { + echo i say \"hello\tworld\"\r; + } +--- request + GET /echo +--- response_body eval: "i say \"hello\tworld\"\r\n" + + + +=== TEST 9: escaping $ +As of Nginx 0.8.20, there's still no way to escape the '$' character. +--- config + location /echo { + echo \$; + } +--- request + GET /echo +--- response_body +$ +--- SKIP + + + +=== TEST 10: XSS +--- config + location /blah { + echo_duplicate 1 "$arg_callback("; + echo_location_async "/data?$uri"; + echo_duplicate 1 ")"; + } + location /data { + echo_duplicate 1 '{"dog":"$query_string"}'; + } +--- request + GET /blah/9999999.json?callback=ding1111111 +--- response_body chomp +ding1111111({"dog":"/blah/9999999.json"}) + + + +=== TEST 11: XSS - filter version +--- config + location /blah { + echo_before_body "$arg_callback("; + + echo_duplicate 1 '{"dog":"$uri"}'; + + echo_after_body ")"; + } +--- request + GET /blah/9999999.json?callback=ding1111111 +--- response_body +ding1111111( +{"dog":"/blah/9999999.json"}) + + + +=== TEST 12: if +--- config +location /first { + echo "before"; + echo_location_async /second $request_uri; + echo "after"; +} + +location = /second { + if ($query_string ~ '([^?]+)') { + set $memcached_key $1; # needing this to be keyed on the request_path, not the entire uri + echo $memcached_key; + } +} +--- request + GET /first/9999999.json?callback=ding1111111 +--- response_body +before +/first/9999999.json +after + + + +=== TEST 13: echo -n +--- config + location /echo { + echo -n hello; + echo -n world; + } +--- request + GET /echo +--- response_body chop +helloworld + + + +=== TEST 14: echo a -n +--- config + location /echo { + echo a -n hello; + echo b -n world; + } +--- request + GET /echo +--- response_body +a -n hello +b -n world + + + +=== TEST 15: -n in a var +--- config + location /echo { + set $opt -n; + echo $opt hello; + echo $opt world; + } +--- request + GET /echo +--- response_body +-n hello +-n world + + + +=== TEST 16: -n only +--- config + location /echo { + echo -n; + echo -n; + } +--- request + GET /echo +--- response_body chop + + + +=== TEST 17: -n with an empty string +--- config + location /echo { + echo -n ""; + set $empty ""; + echo -n $empty; + } +--- request + GET /echo +--- response_body chop + + + +=== TEST 18: -- -n +--- config + location /echo { + echo -- -n hello; + echo -- -n world; + } +--- request + GET /echo +--- response_body +-n hello +-n world + + + +=== TEST 19: -n -n +--- config + location /echo { + echo -n -n hello; + echo -n -n world; + } +--- request + GET /echo +--- response_body chop +helloworld + + + +=== TEST 20: -n -- -n +--- config + location /echo { + echo -n -- -n hello; + echo -n -- -n world; + } +--- request + GET /echo +--- response_body chop +-n hello-n world + + + +=== TEST 21: proxy +--- config + location /main { + proxy_pass http://127.0.0.1:$server_port/echo; + } + location /echo { + echo hello; + echo world; + } +--- request + GET /main +--- response_headers +!Content-Length +--- response_body +hello +world + + + +=== TEST 22: if is evil +--- config + location /test { + set $a 3; + set_by_lua $a ' + if ngx.var.a == "3" then + return 4 + end + '; + echo $a; + } +--- request + GET /test +--- response_body +4 +--- SKIP + + + +=== TEST 23: HEAD +--- config + location /echo { + echo hello; + echo world; + } +--- request + HEAD /echo +--- response_body + + + +=== TEST 24: POST +--- config + location /echo { + echo hello; + echo world; + } +--- pipelined_requests eval +["POST /echo +blah blah", "POST /echo +foo bar baz"] +--- response_body eval +["hello\nworld\n","hello\nworld\n"] + + + +=== TEST 25: POST +--- config + location /echo { + echo_sleep 0.001; + echo hello; + echo world; + } +--- pipelined_requests eval +["POST /echo +blah blah", "POST /echo +foo bar baz"] +--- response_body eval +["hello\nworld\n","hello\nworld\n"] + + + +=== TEST 26: empty arg after -n (github issue #33) +--- config + location = /t { + set $empty ""; + echo -n $empty hello world; + } +--- request + GET /t +--- response_body chop + hello world + + + +=== TEST 27: image filter +--- config + location = /gif { + empty_gif; + } + + location = /t { + default_type image/gif; + image_filter resize 10 10; + set $gif1 ''; + set $gif2 ''; + rewrite_by_lua ' + local res = ngx.location.capture("/gif") + local data = res.body + ngx.var.gif1 = string.sub(data, 1, #data - 1) + ngx.var.gif2 = string.sub(data, #data) + '; + echo -n $gif1; + echo -n $gif2; + } +--- request + GET /t +--- stap +F(ngx_http_image_header_filter) { + println("image header filter") +} +--- stap_out +image header filter +--- response_body_like: . + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/exec.t b/modules_deb/libnginx-mod-http-echo-0.63/t/exec.t new file mode 100644 index 0000000..b7c1308 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/exec.t @@ -0,0 +1,228 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks() + 1); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: exec normal location +--- config + location /main { + echo_exec /bar; + echo end; + } + location = /bar { + echo "$echo_request_uri:"; + echo bar; + } +--- request + GET /main +--- response_body +/bar: +bar + + + +=== TEST 2: location with args (inlined in uri) +--- config + location /main { + echo_exec /bar?a=32; + echo end; + } + location /bar { + echo "a: [$arg_a]"; + } +--- request + GET /main +--- response_body +a: [32] + + + +=== TEST 3: location with args (in separate arg) +--- config + location /main { + echo_exec /bar a=56; + echo end; + } + location /bar { + echo "a: [$arg_a]"; + } +--- request + GET /main +--- response_body +a: [56] + + + +=== TEST 4: exec named location +--- config + location /main { + echo_exec @bar; + echo end; + } + location @bar { + echo bar; + } +--- request + GET /main +--- response_body +bar + + + +=== TEST 5: query string ignored for named locations +--- config + location /main { + echo_exec @bar?a=32; + echo end; + } + location @bar { + echo "a: [$arg_a]"; + } +--- request + GET /main +--- response_body +a: [] +--- error_log +querystring a=32 ignored when exec'ing named location @bar + + + +=== TEST 6: query string ignored for named locations +--- config + location /foo { + echo_exec @bar; + } + location @bar { + echo "uri: [$echo_request_uri]"; + } +--- request + GET /foo +--- response_body +uri: [/foo] + + + +=== TEST 7: exec(named location) in subrequests +--- config + location /entry { + echo_location /foo; + echo_sleep 0.001; + echo_location /foo2; + } + location /foo { + echo_exec @bar; + } + location /foo2 { + echo_exec @bar; + } + + location @bar { + proxy_pass http://127.0.0.1:$server_port/bar; + } + location /bar { + echo_sleep 0.01; + echo hello; + } +--- request + GET /entry +--- response_body +hello +hello + + + +=== TEST 8: exec(normal loctions) in subrequests +--- config + location /entry { + echo_location /foo; + echo_sleep 0.001; + echo_location /foo2; + } + location /foo { + echo_exec /baz; + } + location /foo2 { + echo_exec /baz; + } + + location /baz { + proxy_pass http://127.0.0.1:$server_port/bar; + } + location /bar { + echo_sleep 0.01; + echo hello; + } +--- request + GET /entry +--- response_body +hello +hello + + + +=== TEST 9: exec should clear ctx +--- config + location @bar { + echo hello; + echo world; + echo heh; + } + location /foo { + #echo_sleep 0.001; + echo_reset_timer; + echo_exec @bar; + } +--- request + GET /foo +--- response_body +hello +world +heh + + + +=== TEST 10: reset ctx +--- config + location @proxy { + rewrite_by_lua return; + echo hello; + } + location /main { + rewrite_by_lua return; + echo_exec @proxy; + } +--- request + GET /main +--- response_body +hello + + + +=== TEST 11: yield before exec +--- config + location @bar { + echo hello; + echo world; + echo heh; + } + location /foo { + echo_sleep 0.001; + echo_exec @bar; + } +--- request + GET /foo +--- response_body +hello +world +heh + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/filter-used.t b/modules_deb/libnginx-mod-http-echo-0.63/t/filter-used.t new file mode 100644 index 0000000..2835270 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/filter-used.t @@ -0,0 +1,59 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (3 * blocks()); + +no_long_string(); +log_level('warn'); + +#master_on(); +#workers(1); + +run_tests(); + +__DATA__ + +=== TEST 1: filter indeed used +--- http_config + postpone_output 1; +--- config + location /echo { + echo_after_body hello; + echo world; + } +--- request + GET /echo +--- stap +F(ngx_http_echo_header_filter) { + println("echo header filter called") +} +--- stap_out +echo header filter called +--- response_body +world +hello + + + +=== TEST 2: filter not used +--- http_config + postpone_output 1; +--- config + location /echo { + #echo_after_body hello; + echo world; + } +--- request + GET /echo +--- stap +F(ngx_http_echo_header_filter) { + println("echo header filter called") +} +--- stap_out +--- response_body +world + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/foreach-split.t b/modules_deb/libnginx-mod-http-echo-0.63/t/foreach-split.t new file mode 100644 index 0000000..266a701 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/foreach-split.t @@ -0,0 +1,283 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /main { + echo_foreach_split '&' $query_string; + echo_location_async $echo_it; + echo '/* end */'; + echo_end; + } + location /sub/1.css { + echo "body { font-size: 12pt; }"; + } + location /sub/2.css { + echo "table { color: 'red'; }"; + } +--- request + GET /main?/sub/1.css&/sub/2.css +--- response_body +body { font-size: 12pt; } +/* end */ +table { color: 'red'; } +/* end */ + + + +=== TEST 2: split in a url argument (echo_location_async) +--- config + location /main_async { + echo_foreach_split ',' $arg_cssfiles; + echo_location_async $echo_it; + echo_end; + } + location /foo.css { + echo foo; + } + location /bar.css { + echo bar; + } + location /baz.css { + echo baz; + } +--- request + GET /main_async?cssfiles=/foo.css,/bar.css,/baz.css +--- response_body +foo +bar +baz + + + +=== TEST 3: split in a url argument (echo_location) +--- config + location /main_sync { + echo_foreach_split ',' $arg_cssfiles; + echo_location $echo_it; + echo_end; + } + location /foo.css { + echo foo; + } + location /bar.css { + echo bar; + } + location /baz.css { + echo baz; + } +--- request + GET /main_sync?cssfiles=/foo.css,/bar.css,/baz.css +--- response_body +foo +bar +baz +--- SKIP + + + +=== TEST 4: empty loop +--- config + location /main { + echo "start"; + echo_foreach_split ',' $arg_cssfiles; + echo_end; + echo "end"; + } +--- request + GET /main?cssfiles=/foo.css,/bar.css,/baz.css +--- response_body +start +end + + + +=== TEST 5: trailing delimiter +--- config + location /main_t { + echo_foreach_split ',' $arg_cssfiles; + echo_location_async $echo_it; + echo_end; + } + location /foo.css { + echo foo; + } +--- request + GET /main_t?cssfiles=/foo.css, +--- response_body +foo + + + +=== TEST 6: multi-char delimiter +--- config + location /main_sleep { + echo_foreach_split '-a-' $arg_list; + echo $echo_it; + echo_end; + } +--- request + GET /main_sleep?list=foo-a-bar-a-baz +--- error_code: 500 +--- response_body_like: 500 Internal Server Error + + + +=== TEST 7: multi-char delimiter (the right way) +--- config + location /main_sleep { + echo_foreach_split -- '-a-' $arg_list; + echo $echo_it; + echo_end; + } +--- request + GET /main_sleep?list=foo-a-bar-a-baz +--- response_body +foo +bar +baz + + + +=== TEST 8: loop with sleep +--- config + location /main_sleep { + echo_foreach_split '-' $arg_list; + echo_sleep 0.001; + echo $echo_it; + echo_end; + } +--- request + GET /main_sleep?list=foo-a-bar-A-baz +--- response_body +foo +a +bar +A +baz + + + +=== TEST 9: empty +--- config + location /merge { + default_type 'text/javascript'; + echo_foreach_split '&' $query_string; + echo "/* JS File $echo_it */"; + echo_location_async $echo_it; + echo; + echo_end; + } +--- request + GET /merge +--- response_body + + + +=== TEST 10: single & +--- config + location /merge { + default_type 'text/javascript'; + echo_foreach_split '&' $query_string; + echo "/* JS File $echo_it */"; + echo_location_async $echo_it; + echo; + echo_end; + } +--- request + GET /merge?& +--- response_body + + + +=== TEST 11: pure &'s +--- config + location /merge { + default_type 'text/javascript'; + echo_foreach_split '&' $query_string; + echo "/* JS File $echo_it */"; + echo_location_async $echo_it; + echo; + echo_end; + } +--- request + GET /merge?&&& +--- response_body + + + +=== TEST 12: pure & and spaces +TODO: needs to uri_decode $echo_it... +--- config + location /merge { + default_type 'text/javascript'; + echo_foreach_split '&' $query_string; + echo "/* JS File $echo_it */"; + echo_location_async $echo_it; + echo; + echo_end; + } +--- request + GET /merge?&%20&%20& +--- response_body +--- SKIP + + + +=== TEST 13: multiple foreach_split +--- config + location /multi { + echo_foreach_split '&' $query_string; + echo [$echo_it]; + echo_end; + + echo '...'; + + echo_foreach_split '-' $query_string; + echo [$echo_it]; + echo_end; + } +--- request + GET /multi?a-b&c-d +--- response_body +[a-b] +[c-d] +... +[a] +[b&c] +[d] + + + +=== TEST 14: github issue #2: setting a variable from $echo_it results to crashing +--- config +location = /getFile { + set $filelist "a,b,c"; + echo_foreach_split ',' $filelist; + set $file $echo_it; + echo_subrequest GET '/getFile2' -q 'sha256=$file'; + echo_end; +} + +location = /getFile2 { + echo "sha256: $arg_sha256"; +} +--- request + GET /getFile +--- response_body +sha256: +sha256: +sha256: + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/gzip.t b/modules_deb/libnginx-mod-http-echo-0.63/t/gzip.t new file mode 100644 index 0000000..61eb4f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/gzip.t @@ -0,0 +1,31 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /gzip { + gzip on; + gzip_min_length 10; + gzip_types text/plain; + + echo_duplicate 1000 hello; + } +--- request + GET /gzip +--- more_headers +Accept-Encoding: gzip +--- response_headers +Content-Encoding: gzip +--- timeout: 20 diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/if.t b/modules_deb/libnginx-mod-http-echo-0.63/t/if.t new file mode 100644 index 0000000..054ec43 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/if.t @@ -0,0 +1,150 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity (hit) +--- config + location ^~ /if { + set $res miss; + if ($arg_val ~* '^a') { + set $res hit; + echo $res; + } + echo $res; + } +--- request + GET /if?val=abc +--- response_body +hit + + + +=== TEST 2: sanity (miss) +--- config + location ^~ /if { + set $res miss; + if ($arg_val ~* '^a') { + set $res hit; + echo $res; + } + echo $res; + } +--- request + GET /if?val=bcd +--- response_body +miss + + + +=== TEST 3: proxy in if (hit) +--- config + location ^~ /if { + set $res miss; + if ($arg_val ~* '^a') { + set $res hit; + proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; + } + proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; + } + location /foo { + echo "res = $arg_res"; + } +--- request + GET /if?val=abc +--- response_body +res = hit + + + +=== TEST 4: proxy in if (miss) +--- config + location ^~ /if { + set $res miss; + if ($arg_val ~* '^a') { + set $res hit; + proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; + } + proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; + } + location /foo { + echo "res = $arg_res"; + } +--- request + GET /if?val=bcd +--- response_body +res = miss + + + +=== TEST 5: if too long url (hit) +--- config + location /foo { + if ($request_uri ~ '.{20,}') { + echo too long; + } + echo ok; + } +--- request + GET /foo?a=12345678901234567890 +--- response_body +too long + + + +=== TEST 6: if too long url (miss) +--- config + location /foo { + if ($request_uri ~ '.{20,}') { + echo too long; + } + echo ok; + } +--- request + GET /foo?a=1234567890 +--- response_body +ok + + + +=== TEST 7: echo should be inherited by if blocks +--- config + location /foo { + if ($uri ~ 'foo') { + } + echo ok; + } +--- request + GET /foo +--- response_body +ok + + + +=== TEST 8: echo_after_body and echo_before_body should be inherited by if blocks +--- config + location /foo { + if ($uri ~ 'foo') { + } + echo_before_body -n 'hello'; + echo_location /comma; + echo_after_body 'world'; + } + + location = /comma { + internal; + echo -n ', '; + } +--- request + GET /foo +--- response_body +hello, world + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/incr.t b/modules_deb/libnginx-mod-http-echo-0.63/t/incr.t new file mode 100644 index 0000000..8ad6d98 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/incr.t @@ -0,0 +1,32 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /main { + echo "main pre: $echo_incr"; + echo_location_async /sub; + echo_location_async /sub; + echo "main post: $echo_incr"; + } + location /sub { + echo "sub: $echo_incr"; + } +--- request + GET /main +--- response_body +main pre: 1 +sub: 3 +sub: 4 +main post: 2 + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/location-async.t b/modules_deb/libnginx-mod-http-echo-0.63/t/location-async.t new file mode 100644 index 0000000..3494516 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/location-async.t @@ -0,0 +1,439 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks() + 1); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /main { + echo_location_async /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello + + + +=== TEST 2: trailing echo +--- config + location /main { + echo_location_async /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello +after subrequest + + + +=== TEST 3: leading echo +--- config + location /main { + echo before subrequest; + echo_location_async /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello + + + +=== TEST 4: leading & trailing echo +--- config + location /main { + echo before subrequest; + echo_location_async /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello +after subrequest + + + +=== TEST 5: multiple subrequests +--- config + location /main { + echo before sr 1; + echo_location_async /sub; + echo after sr 1; + echo before sr 2; + echo_location_async /sub; + echo after sr 2; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before sr 1 +hello +after sr 1 +before sr 2 +hello +after sr 2 + + + +=== TEST 6: timed multiple subrequests (blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_location_async /sub1; + echo_location_async /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_blocking_sleep 0.02; + echo hello; + } + location /sub2 { + echo_blocking_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.00[0-5] sec for total\.$ + + + +=== TEST 7: timed multiple subrequests (non-blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_location_async /sub1; + echo_location_async /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 0.02; + echo hello; + } + location /sub2 { + echo_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.00[0-5] sec for total\.$ + + + +=== TEST 8: location with args +--- config + location /main { + echo_location_async /sub 'foo=Foo&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 9: encoded chars in query strings +--- config + location /main { + echo_location_async /sub 'foo=a%20b&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +a%20b Bar + + + +=== TEST 10: UTF-8 chars in query strings +--- config + location /main { + echo_location_async /sub 'foo=你好'; + } + location /sub { + echo $arg_foo; + } +--- request + GET /main +--- response_body +你好 + + + +=== TEST 11: encoded chars in location url +--- config + location /main { + echo_location_async /sub%31 'foo=Foo&bar=Bar'; + } + location /sub%31 { + echo 'sub%31'; + } + location /sub1 { + echo 'sub1'; + } +--- request + GET /main +--- response_body +sub1 + + + +=== TEST 12: querystring in url +--- config + location /main { + echo_location_async /sub?foo=Foo&bar=Bar; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 13: querystring in url *AND* an explicit querystring +--- config + location /main { + echo_location_async /sub?foo=Foo&bar=Bar blah=Blah; + } + location /sub { + echo $arg_foo $arg_bar $arg_blah; + } +--- request + GET /main +--- response_body + Blah + + + +=== TEST 14: explicit flush in main request +flush won't really flush the buffer... +--- config + location /main_flush { + echo 'pre main'; + echo_location_async /sub; + echo 'post main'; + echo_flush; + } + + location /sub { + echo_sleep 0.02; + echo 'sub'; + } +--- request + GET /main_flush +--- response_body +pre main +sub +post main + + + +=== TEST 15: no varaiable inheritance +--- config + location /main { + echo $echo_cacheable_request_uri; + echo_location_async /sub; + echo_location_async /sub2; + } + location /sub { + echo $echo_cacheable_request_uri; + } + location /sub2 { + echo $echo_cacheable_request_uri; + } + +--- request + GET /main +--- response_body +/main +/sub +/sub2 + + + +=== TEST 16: unsafe uri +--- config + location /unsafe { + echo_location_async '/../foo'; + } +--- request + GET /unsafe +--- stap2 +F(ngx_http_send_header) { + printf("send header on req %p (header sent: %d)\n", $r, $r->header_sent) + print_ubacktrace() +} +--- ignore_response +--- error_log +echo_location_async sees unsafe uri: "/../foo" +--- no_error_log +[error] +[alert] + + + +=== TEST 17: access/deny (access phase handlers skipped in subrequests) +--- config + location /main { + echo_location_async /denied; + } + location /denied { + deny all; + echo No no no; + } +--- request + GET /main +--- error_code: 200 +--- response_body +No no no + + + +=== TEST 18: rewrite is honored. +--- config + location /main { + echo_location_async /rewrite; + } + location /rewrite { + rewrite ^ /foo break; + echo $uri; + } +--- request + GET /main +--- response_body +/foo + + + +=== TEST 19: let subrequest to read the main request's request body +--- SKIP +--- config + location /main { + echo_location_async /sub; + } + location /sub { + echo_read_request_body; + echo_request_body; + } +--- request +POST /main +hello, body! +--- response_body chomp +hello, body! + + + +=== TEST 20: leading subrequest & echo_before_body +--- config + location /main { + echo_before_body hello; + echo_location_async /foo; + } + location /foo { + echo world; + } +--- request + GET /main +--- response_body +hello +world + + + +=== TEST 21: leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_location_async /foo; + } + location /foo { + echo -n world; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world); + + + +=== TEST 22: multiple leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_location_async /foo; + echo_location_async /bar; + } + location /foo { + echo -n world; + } + location /bar { + echo -n ' people'; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world people); + + + +=== TEST 23: sanity (HEAD) +--- config + location /main { + echo_location_async /sub; + echo_location_async /sub; + } + location /sub { + echo hello; + } +--- request + HEAD /main +--- response_body + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/location.t b/modules_deb/libnginx-mod-http-echo-0.63/t/location.t new file mode 100644 index 0000000..48c851e --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/location.t @@ -0,0 +1,567 @@ +# vi:filetype= + +use lib 'lib'; + +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks() + 2); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /main { + echo_location /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello + + + +=== TEST 2: sanity with proxy in the middle +--- config + location /main { + echo_location /proxy; + } + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello + + + +=== TEST 3: trailing echo +--- config + location /main { + echo_location /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello +after subrequest + + + +=== TEST 4: leading echo +--- config + location /main { + echo before subrequest; + echo_location /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello + + + +=== TEST 5: leading & trailing echo +--- config + location /main { + echo before subrequest; + echo_location /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello +after subrequest + + + +=== TEST 6: multiple subrequests +--- config + location /main { + echo before sr 1; + echo_location /sub; + echo after sr 1; + echo before sr 2; + echo_location /sub; + echo after sr 2; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before sr 1 +hello +after sr 1 +before sr 2 +hello +after sr 2 + + + +=== TEST 7: timed multiple subrequests (blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_location /sub1; + echo_location /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_blocking_sleep 0.02; + echo hello; + } + location /sub2 { + echo_blocking_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ + + + +=== TEST 8: timed multiple subrequests (non-blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_location /sub1; + echo_location /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 0.02; + echo hello; + } + location /sub2 { + echo_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ + + + +=== TEST 9: location with args +--- config + location /main { + echo_location /sub 'foo=Foo&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 10: chained subrequests +--- config + location /main { + echo 'pre main'; + echo_location /sub; + echo 'post main'; + } + + location /sub { + echo 'pre sub'; + echo_location /subsub; + echo 'post sub'; + } + + location /subsub { + echo 'subsub'; + } +--- request + GET /main +--- response_body +pre main +pre sub +subsub +post sub +post main + + + +=== TEST 11: chained subrequests using named locations +as of 0.8.20, ngx_http_subrequest still does not support +named location. sigh. this case is a TODO. +--- config + location /main { + echo 'pre main'; + echo_location @sub; + echo 'post main'; + } + + location @sub { + echo 'pre sub'; + echo_location @subsub; + echo 'post sub'; + } + + location @subsub { + echo 'subsub'; + } +--- request + GET /main +--- response_body +pre main +pre sub +subsub +post sub +post main +--- SKIP + + + +=== TEST 12: explicit flush in main request +--- config + location /main { + echo 'pre main'; + echo_location /sub; + echo 'post main'; + echo_flush; + } + + location /sub { + echo_sleep 0.02; + echo 'sub'; + } +--- request + GET /main +--- response_body +pre main +sub +post main + + + +=== TEST 13: no varaiable inheritance +--- config + location /main { + echo $echo_cacheable_request_uri; + echo_location /sub; + echo_location /sub2; + } + location /sub { + echo $echo_cacheable_request_uri; + } + location /sub2 { + echo $echo_cacheable_request_uri; + } + +--- request + GET /main +--- response_body +/main +/sub +/sub2 + + + +=== TEST 14: unsafe uri +--- config + location /unsafe { + echo_location '/../foo'; + } +--- request + GET /unsafe +--- ignore_response +--- error_log +echo_location sees unsafe uri: "/../foo" +--- no_error_log +[error] +[alert] + + + +=== TEST 15: querystring in url +--- config + location /main { + echo_location /sub?foo=Foo&bar=Bar; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 16: querystring in url *AND* an explicit querystring +--- config + location /main { + echo_location /sub?foo=Foo&bar=Bar blah=Blah; + } + location /sub { + echo $arg_foo $arg_bar $arg_blah; + } +--- request + GET /main +--- response_body + Blah + + + +=== TEST 17: let subrequest to read the main request's request body +--- SKIP +--- config + location /main { + echo_location /sub; + } + location /sub { + echo_read_request_body; + echo_request_body; + } +--- request +POST /main +hello, body! +--- response_body chomp +hello, body! + + + +=== TEST 18: sleep after location +--- config + location /main { + echo_location /sub; + echo_sleep 0.001; + echo_location /sub; + } + location /sub { + echo_sleep 0.001; + echo sub; + } +--- request + GET /main +--- response_body +sub +sub +--- skip_nginx: 2: < 0.8.11 + + + +=== TEST 19: deep nested echo_location/echo_location_async +--- config + location /main { + echo_location /bar; + echo_location_async /bar; + echo_location_async /bar; + echo_location /group; + echo_location_async /group; + } + + location /group { + echo_location /bar; + echo_location_async /bar; + } + + location /bar { + #echo_sleep 0.001; + echo $echo_incr; + } +--- request +GET /main +--- response_body +1 +2 +3 +4 +5 +6 +7 +--- timeout: 2 + + + +=== TEST 20: deep nested echo_location/echo_location_async (with sleep) +--- config + location /main { + echo_location /bar; + echo_location_async /bar; + echo_location_async /bar; + echo_location /group; + echo_location_async /group; + } + + location /group { + echo_location /baz; + echo_location_async /bah; + } + + location ~ '^/ba[rzh]' { + echo_sleep 0.001; + echo $echo_incr; + } +--- request +GET /main +--- response_body +1 +2 +3 +4 +5 +6 +7 +--- timeout: 2 + + + +=== TEST 21: deep nested echo_location (with sleep) +--- config + location /main { + echo_location /bar; + echo_location /bar; + echo_location /bar; + echo_location /group; + echo_location /group; + } + + location /group { + echo_location /bar; + echo_location /bar; + } + + location /incr { + echo_sleep 0.001; + echo $echo_incr; + } + + location /bar { + proxy_pass $scheme://127.0.0.1:$server_port/incr; + } +--- request +GET /main +--- response_body +1 +1 +1 +1 +1 +1 +1 +--- timeout: 5 +--- no_error_log +[error] + + + +=== TEST 22: leading subrequest & echo_before_body +--- config + location /main { + echo_before_body hello; + echo_location /foo; + } + location /foo { + echo world; + } +--- request + GET /main +--- response_body +hello +world + + + +=== TEST 23: leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_location /foo; + } + location /foo { + echo -n world; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world); + + + +=== TEST 24: multiple leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_location /foo; + echo_location /bar; + } + location /main2 { + content_by_lua ' + local res = ngx.location.capture("/foo") + local res2 = ngx.location.capture("/bar") + ngx.say(res.body) + ngx.say(res2.body) + '; + } + location /foo { + echo -n world; + } + location /bar { + echo -n ' people'; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world people); + + + +=== TEST 25: sanity (HEAD) +--- config + location /main { + echo_location /sub; + echo_location /sub; + } + location /sub { + echo hello; + } +--- request + HEAD /main +--- response_body + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/mixed.t b/modules_deb/libnginx-mod-http-echo-0.63/t/mixed.t new file mode 100644 index 0000000..abf2599 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/mixed.t @@ -0,0 +1,82 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +run_tests(); + +__DATA__ + +=== TEST 1: echo before echo_client_request_headers +--- config + location /echo { + echo "headers:"; + echo -n $echo_client_request_headers; + } +--- request + GET /echo +--- response_body eval +"headers: +GET /echo HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" + + + +=== TEST 2: echo_client_request_headers before echo +--- config + location /echo { + echo -n $echo_client_request_headers; + echo "...these are the headers"; + } +--- request + GET /echo +--- response_body eval +"GET /echo HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +...these are the headers +" + + + +=== TEST 3: echo & headers & echo +--- config + location /echo { + echo "headers are"; + echo -n $echo_client_request_headers; + echo "...these are the headers"; + } +--- request + GET /echo +--- response_body eval +"headers are +GET /echo HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +...these are the headers +" + + + +=== TEST 4: mixed with echo_duplicate +--- config + location /mixed { + echo hello; + echo_duplicate 2 ---; + echo_duplicate 1 ' END '; + echo_duplicate 2 ---; + echo; + } +--- request + GET /mixed +--- response_body +hello +------ END ------ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/request-body.t b/modules_deb/libnginx-mod-http-echo-0.63/t/request-body.t new file mode 100644 index 0000000..d467b2e --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/request-body.t @@ -0,0 +1,58 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * 2 * blocks(); + +run_tests(); + +__DATA__ + +=== TEST 1: big client body buffered into temp files +--- config + location /echo { + client_body_buffer_size 1k; + echo_read_request_body; + echo_request_body; + } +--- request eval +"POST /echo +" . 'a' x 4096 . 'end'; +--- response_body eval +'a' x 4096 . 'end' + + + +=== TEST 2: in memory request body (trailing echo) +--- config + location /echo { + client_body_buffer_size 1k; + echo_read_request_body; + echo_request_body; + echo done; + } +--- request +POST /echo +hello world +--- response_body +hello worlddone + + + +=== TEST 3: big client body buffered into temp files (trailing echo) +--- config + location /echo { + client_body_buffer_size 1k; + echo_read_request_body; + echo_request_body; + echo done; + } +--- request eval +"POST /echo +" . 'a' x 4096 . "end\n"; +--- response_body eval +'a' x 4096 . "enddone\n" + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/request-info.t b/modules_deb/libnginx-mod-http-echo-0.63/t/request-info.t new file mode 100644 index 0000000..dd34da4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/request-info.t @@ -0,0 +1,870 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (3 * blocks() + 14); + +run_tests(); + +__DATA__ + +=== TEST 1: standalone directive +--- config + location /echo { + echo -n $echo_client_request_headers; + } +--- request + GET /echo +--- response_body eval +"GET /echo HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" +--- no_error_log +[error] + + + +=== TEST 2: multiple instances +--- config + location /echo { + echo -n $echo_client_request_headers; + echo -n $echo_client_request_headers; + } +--- request + GET /echo +--- response_body eval +"GET /echo HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +GET /echo HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" +--- no_error_log +[error] + + + +=== TEST 3: does not explicitly request_body +--- config + location /echo { + echo [$echo_request_body]; + } +--- request +POST /echo +body here +heh +--- response_body +[] +--- no_error_log +[error] + + + +=== TEST 4: let proxy read request_body +--- config + location /echo { + echo_before_body [$echo_request_body]; + proxy_pass $scheme://127.0.0.1:$server_port/blah; + } + location /blah { echo_duplicate 0 ''; } +--- request +POST /echo +body here +heh +--- response_body +[body here +heh] +--- no_error_log +[error] + + + +=== TEST 5: use echo_read_request_body to read it! +--- config + location /echo { + echo_read_request_body; + echo [$echo_request_body]; + } +--- request +POST /echo +body here +heh +--- response_body +[body here +heh] +--- no_error_log +[error] + + + +=== TEST 6: how about sleep after that? +--- config + location /echo { + echo_read_request_body; + echo_sleep 0.002; + echo [$echo_request_body]; + } +--- request +POST /echo +body here +heh +--- response_body +[body here +heh] +--- no_error_log +[error] + + + +=== TEST 7: echo back the whole client request +--- config + # echo back the client request + location /echoback { + echo -n $echo_client_request_headers; + echo_read_request_body; + echo $echo_request_body; + } +--- request +POST /echoback +body here +haha +--- response_body eval +"POST /echoback HTTP/1.1\r +Host: localhost\r +Connection: close\r +Content-Length: 14\r +\r +body here +haha +" +--- no_error_log +[error] + + + +=== TEST 8: echo_request_body +--- config + location /body { + client_body_buffer_size 5; + echo_read_request_body; + echo "[$echo_request_body]"; + echo_request_body; + } +--- request eval +"POST /body +" . ('a' x 2048) . "b" +--- response_body eval +"[]\n" . +('a' x 2048) . "b" +--- no_error_log +[error] + + + +=== TEST 9: $echo_response_status in content handler +--- config + location /status { + echo "status: $echo_response_status"; + } +--- request + GET /status +--- response_body +status: +--- no_error_log +[error] + + + +=== TEST 10: echo_request_body (empty body) +--- config + location /body { + echo_read_request_body; + echo_request_body; + } + location /main { + proxy_pass http://127.0.0.1:$server_port/body; + } +--- request eval +"POST /main" +--- response_body eval +"" +--- no_error_log +[error] + + + +=== TEST 11: small header +--- config + location /t { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +} +--- no_error_log +[error] +--- no_error_log +[error] + + + +=== TEST 12: large header +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 13: small header, with leading CRLF +--- config + location /t { + echo -n $echo_client_request_headers; + } +--- raw_request eval +"\r\nGET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +} +--- no_error_log +[error] + + + +=== TEST 14: large header, with leading CRLF +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + echo -n $echo_client_request_headers; + } + +--- raw_request eval +"\r\nGET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +". +(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 15: small header, pipelined +--- config + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /th"] + +--- more_headers +Foo: bar + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +Foo: bar\r +\r +}, qq{GET /th HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}] +--- no_error_log +[error] + + + +=== TEST 16: large header, pipelined +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] + +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +my $headers = (CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"; + +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +$headers}, +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +$headers}] + +--- no_error_log +[error] + + + +=== TEST 17: small header, multi-line header +multi-line header is not supported since 1.21 +--- config + location /t { + echo -n $echo_client_request_headers; + } +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar baz\r + blah\r +\r +" +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar baz\r + blah\r +\r +} +--- no_error_log +[error] +--- skip_nginx +3: >= 1.21.1 + + + +=== TEST 18: large header, multi-line header +multi-line header is not supported since 1.21 +--- config + client_header_buffer_size 10; + large_client_header_buffers 50 567; + location /t { + echo -n $echo_client_request_headers; + } + +--- raw_request eval +my $headers = (CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n"; + +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +$headers} + +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] +--- skip_nginx +3: >= 1.21.1 + + + +=== TEST 19: small header (POST body) +--- config + location /t { + echo_read_request_body; + echo -n $echo_client_request_headers; + } +--- request +POST /t +hello +--- response_body eval +qq{POST /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 20: small header (POST body) - in subrequests (location) +--- config + location /t { + echo -n $echo_client_request_headers; + } + location /main { + echo_location /t; + } + +--- request +POST /main +hello +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 21: large header (POST body) +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + echo_read_request_body; + echo -n $echo_client_request_headers; + } +--- request +POST /t +hello + +--- more_headers eval +CORE::join"\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{POST /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\nContent-Length: 5\r\n\r\n" + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 22: large header (POST body) - in subrequests +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + echo_read_request_body; + echo -n $echo_client_request_headers; + } + + location /main { + echo_location /t; + } +--- request +POST /main +hello +--- more_headers eval +CORE::join"\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\nContent-Length: 5\r\n\r\n" + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 23: raw headers - the default header buffer can hold the request line, but not the header entries +--- config + location /t { + echo_read_request_body; + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; +$s .= "Accept: */*\n"; +$s .= "Cookie: " . "C" x 1200 . "\n"; +$s +--- response_body eval +"GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +User-Agent: curl\r +Bah: bah\r +Accept: */*\r +Cookie: " . ("C" x 1200) . "\r\n\r\n" +--- no_error_log +[error] + + + +=== TEST 24: small header (POST body) - in subrequests (location_async) +--- config + location /t { + echo -n $echo_client_request_headers; + } + location /main { + echo_location_async /t; + } + +--- request +POST /main +hello +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 25: small header (POST body) - in subrequests (subrequest) +--- config + location /t { + echo -n $echo_client_request_headers; + } + location /main { + echo_subrequest GET /t; + } + +--- request +POST /main +hello +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 26: small header (POST body) - in subrequests (subrequest_async) +--- config + location /t { + echo -n $echo_client_request_headers; + } + location /main { + echo_subrequest_async GET /t; + } + +--- request +POST /main +hello +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 27: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers +--- config + location = /t { + proxy_buffering off; + proxy_pass http://127.0.0.1:$server_port/bad; + proxy_intercept_errors on; + error_page 500 = /500; + } + + location = /bad { + return 500; + } + + location = /500 { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- response_body eval +"GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" +--- no_error_log +[error] + + + +=== TEST 28: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers (exclusive LF in the request data) +--- config + location = /t { + proxy_buffering off; + proxy_pass http://127.0.0.1:$server_port/bad; + proxy_intercept_errors on; + error_page 500 = /500; + } + + location = /bad { + return 500; + } + + location = /500 { + internal; + echo -n $echo_client_request_headers; + } +--- raw_request eval +"GET /t HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 5 + +hello" +--- response_body eval +"GET /t HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 5 + +" +--- no_error_log +[error] + + + +=== TEST 29: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers (mixed LF and CRLF in the request data) +--- config + location = /t { + proxy_buffering off; + proxy_pass http://127.0.0.1:$server_port/bad; + proxy_intercept_errors on; + error_page 500 = /500; + } + + location = /bad { + return 500; + } + + location = /500 { + internal; + echo -n $echo_client_request_headers; + } +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost +Connection: close\r +Content-Length: 5\r + +hello" +--- response_body eval +"GET /t HTTP/1.1\r +Host: localhost +Connection: close\r +Content-Length: 5\r + +" +--- no_error_log +[error] + + + +=== TEST 30: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers (another way of mixing LF and CRLF in the request data) +--- config + location = /t { + proxy_buffering off; + proxy_pass http://127.0.0.1:$server_port/bad; + proxy_intercept_errors on; + error_page 500 = /500; + } + + location = /bad { + return 500; + } + + location = /500 { + internal; + echo -n $echo_client_request_headers; + } +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost +Connection: close\r +Content-Length: 5 +\r +hello" +--- response_body eval +"GET /t HTTP/1.1\r +Host: localhost +Connection: close\r +Content-Length: 5 +\r +" +--- no_error_log +[error] + + + +=== TEST 31: two pipelined requests with large headers +--- config + client_header_buffer_size 10; + large_client_header_buffers 3 5610; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..585 + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 32: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 33: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t" . ("a" x 512)] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t} . ("a" x 512) . qq{ HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 34: invalid header line started with whitespace since nginx 1.21.1 +--- config + client_header_buffer_size 10; + large_client_header_buffers 50 567; + location /t { + echo -n $echo_client_request_headers; + } + +--- raw_request eval +my $headers = (CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n"; + +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +$headers} + +--- error_code: 400 +--- no_error_log +[error] +--- skip_nginx +2: < 1.21.1 diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/sleep.t b/modules_deb/libnginx-mod-http-echo-0.63/t/sleep.t new file mode 100644 index 0000000..f8e741e --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/sleep.t @@ -0,0 +1,200 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 2 * blocks(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /echo { + echo_sleep 1; + } +--- request + GET /echo +--- response_body + + + +=== TEST 2: fractional delay +--- config + location /echo { + echo_sleep 0.01; + } +--- request + GET /echo +--- response_body + + + +=== TEST 3: leading echo +--- config + location /echo { + echo before...; + echo_sleep 0.01; + } +--- request + GET /echo +--- response_body +before... + + + +=== TEST 4: trailing echo +--- config + location /echo { + echo_sleep 0.01; + echo after...; + } +--- request + GET /echo +--- response_body +after... + + + +=== TEST 5: two echos around sleep +--- config + location /echo { + echo before...; + echo_sleep 0.01; + echo after...; + } +--- request + GET /echo +--- response_body +before... +after... + + + +=== TEST 6: interleaving sleep and echo +--- config + location /echo { + echo 1; + echo_sleep 0.01; + echo 2; + echo_sleep 0.01; + } +--- request + GET /echo +--- response_body +1 +2 + + + +=== TEST 7: interleaving sleep and echo with echo at the end... +--- config + location /echo { + echo 1; + echo_sleep 0.01; + echo 2; + echo_sleep 0.01; + echo 3; + } +--- request + GET /echo +--- response_body +1 +2 +3 + + + +=== TEST 8: flush before sleep +we didn't really test the actual effect of "echo_flush" here... +merely checks if it croaks if appears. +--- config + location /flush { + echo hi; + echo_flush; + echo_sleep 0.01; + echo trees; + } +--- request + GET /flush +--- response_body +hi +trees + + + +=== TEST 9: flush does not increment opcode pointer itself +--- config + location /flush { + echo hi; + echo_flush; + echo trees; + } +--- request + GET /flush +--- response_body +hi +trees + + + +=== TEST 10: sleep through a proxy +this reveals a bug in v0.19 and the bug is fixed in v0.20. +--- config + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/entry'; + } + location /entry { + echo_sleep 0.001; + echo done; + } +--- request + GET /proxy +--- response_body_like +done + + + +=== TEST 11: abnormally quit +--- config + location /quit { + echo before; + echo_flush; + echo_sleep 1; + echo after; + } +--- request + GET /quit +--- response_body +before +after + + + +=== TEST 12: two echos around sleep (HEAD) +--- config + location /echo { + echo before...; + echo_sleep 0.01; + echo after...; + } +--- request + HEAD /echo +--- response_body + + + +=== TEST 13: sleep by variable +--- config + location ~ ^/sleep/(.+) { + echo before...; + echo_sleep $1; + echo after...; + } +--- request + GET /sleep/0.01 +--- response_body +before... +after... + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/status.t b/modules_deb/libnginx-mod-http-echo-0.63/t/status.t new file mode 100644 index 0000000..d97b084 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/status.t @@ -0,0 +1,142 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (2 * blocks()); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +run_tests(); + +__DATA__ + +=== TEST 1: 200 +--- config + location /echo { + echo_status 200; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 200 + + + +=== TEST 2: if location (200) +--- config + location /echo { + set $true 1; + if ($true) { + } + echo_status 200; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 200 + + + +=== TEST 3: 404 +--- config + location /echo { + echo_status 404; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 404 + + + +=== TEST 4: if location (404) +--- config + location /echo { + set $true 1; + if ($true) { + } + echo_status 404; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 404 + + + +=== TEST 5: 500 +--- config + location /echo { + echo_status 500; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 500 + + + +=== TEST 6: if location (500) +--- config + location /echo { + set $true 1; + if ($true) { + } + echo_status 500; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 500 + + + +=== TEST 7: if location (500) no inherit +--- config + location /echo { + set $true 1; + if ($true) { + echo_status 503; + } + echo_status 500; + echo hello; + } +--- request + GET /echo +--- response_body +hello +--- error_code: 503 + + + +=== TEST 8: subrequest +--- config + location /echo { + echo_location /sub; + echo_status 503; + } + + location /sub { + echo blah blah; + } +--- request + GET /echo +--- response_body +blah blah +--- error_code: 503 + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/subrequest-async.t b/modules_deb/libnginx-mod-http-echo-0.63/t/subrequest-async.t new file mode 100644 index 0000000..882b368 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/subrequest-async.t @@ -0,0 +1,604 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 2 + 1); + +#$Test::Nginx::LWP::LogLevel = 'debug'; + +$ENV{TEST_NGINX_HTML_DIR} = html_dir; + +run_tests(); + +__DATA__ + +=== TEST 1: sanity - GET +--- config + location /main { + echo_subrequest_async GET /sub; + } + location /sub { + echo "sub method: $echo_request_method"; + echo "main method: $echo_client_request_method"; + } +--- request + GET /main +--- response_body +sub method: GET +main method: GET + + + +=== TEST 2: sanity - DELETE +--- config + location /main { + echo_subrequest_async DELETE /sub; + } + location /sub { + echo "sub method: $echo_request_method"; + echo "main method: $echo_client_request_method"; + } +--- request + GET /main +--- response_body +sub method: DELETE +main method: GET + + + +=== TEST 3: trailing echo +--- config + location /main { + echo_subrequest_async GET /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello +after subrequest + + + +=== TEST 4: leading echo +--- config + location /main { + echo before subrequest; + echo_subrequest_async GET /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello + + + +=== TEST 5: leading & trailing echo +--- config + location /main { + echo before subrequest; + echo_subrequest_async GET /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello +after subrequest + + + +=== TEST 6: multiple subrequests +--- config + location /main { + echo before sr 1; + echo_subrequest_async GET /sub; + echo after sr 1; + echo before sr 2; + echo_subrequest_async GET /sub; + echo after sr 2; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before sr 1 +hello +after sr 1 +before sr 2 +hello +after sr 2 + + + +=== TEST 7: timed multiple subrequests (blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_subrequest_async GET /sub1; + echo_subrequest_async GET /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_blocking_sleep 0.02; + echo hello; + } + location /sub2 { + echo_blocking_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.00[0-5] sec for total\.$ + + + +=== TEST 8: timed multiple subrequests (non-blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_subrequest_async GET /sub1; + echo_subrequest_async GET /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 0.02; + echo hello; + } + location /sub2 { + echo_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.00[0-5] sec for total\.$ + + + +=== TEST 9: location with args +--- config + location /main { + echo_subrequest_async GET /sub -q 'foo=Foo&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 10: encoded chars in query strings +--- config + location /main { + echo_subrequest_async GET /sub -q 'foo=a%20b&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +a%20b Bar + + + +=== TEST 11: UTF-8 chars in query strings +--- config + location /main { + echo_subrequest_async GET /sub -q 'foo=你好'; + } + location /sub { + echo $arg_foo; + } +--- request + GET /main +--- response_body +你好 + + + +=== TEST 12: encoded chars in location url +--- config + location /main { + echo_subrequest_async GET /sub%31 -q 'foo=Foo&bar=Bar'; + } + location /sub%31 { + echo 'sub%31'; + } + location /sub1 { + echo 'sub1'; + } +--- request + GET /main +--- response_body +sub1 + + + +=== TEST 13: querystring in url +--- config + location /main { + echo_subrequest_async GET /sub?foo=Foo&bar=Bar; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 14: querystring in url *AND* an explicit querystring +--- config + location /main { + echo_subrequest_async GET /sub?foo=Foo&bar=Bar -q blah=Blah; + } + location /sub { + echo $arg_foo $arg_bar $arg_blah; + } +--- request + GET /main +--- response_body + Blah + + + +=== TEST 15: explicit flush in main request +flush won't really flush the buffer... +--- config + location /main_flush { + echo 'pre main'; + echo_subrequest_async GET /sub; + echo 'post main'; + echo_flush; + } + + location /sub { + echo_sleep 0.02; + echo 'sub'; + } +--- request + GET /main_flush +--- response_body +pre main +sub +post main + + + +=== TEST 16: POST subrequest with body (with proxy in the middle) and without read body explicitly +--- config + location /main { + echo_subrequest_async POST /proxy -b 'hello, world'; + } + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/sub; + } + location /sub { + echo "sub method: $echo_request_method."; + # we need to read body explicitly here...or $echo_request_body + # will evaluate to empty ("") + echo "sub body: $echo_request_body."; + } +--- request + GET /main +--- response_body +sub method: POST. +sub body: . + + + +=== TEST 17: POST subrequest with body (with proxy in the middle) and read body explicitly +--- config + location /main { + echo_subrequest_async POST /proxy -b 'hello, world'; + } + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/sub; + } + location /sub { + echo "sub method: $echo_request_method."; + # we need to read body explicitly here...or $echo_request_body + # will evaluate to empty ("") + echo_read_request_body; + echo "sub body: $echo_request_body."; + } +--- request + GET /main +--- response_body +sub method: POST. +sub body: hello, world. + + + +=== TEST 18: multiple subrequests +--- config + location /multi { + echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi'; + echo_subrequest_async PUT '/sub' -q 'bar=Bar' -b 'hello'; + } + location /sub { + echo "querystring: $query_string"; + echo "method: $echo_request_method"; + echo "body: $echo_request_body"; + echo "content length: $http_content_length"; + echo '///'; + } +--- request + GET /multi +--- response_body +querystring: foo=Foo +method: POST +body: hi +content length: 2 +/// +querystring: bar=Bar +method: PUT +body: hello +content length: 5 +/// + + + +=== TEST 19: no varaiable inheritance +--- config + location /main { + echo $echo_cacheable_request_uri; + echo_subrequest_async GET /sub; + echo_subrequest_async GET /sub2; + } + location /sub { + echo $echo_cacheable_request_uri; + } + location /sub2 { + echo $echo_cacheable_request_uri; + } + +--- request + GET /main +--- response_body +/main +/sub +/sub2 + + + +=== TEST 20: unsafe uri +--- config + location /unsafe { + echo_subrequest_async GET '/../foo'; + } +--- request + GET /unsafe +--- ignore_response +--- error_log +echo_subrequest_async sees unsafe uri: "/../foo" +--- no_error_log +[error] +[alert] + + + +=== TEST 21: let subrequest to read the main request's request body +--- SKIP +--- config + location /main { + echo_subrequest_async POST /sub; + } + location /sub { + echo_read_request_body; + echo_request_body; + } +--- request +POST /main +hello, body! +--- response_body chomp +hello, body! + + + +=== TEST 22: POST subrequest with file body (relative paths) +--- config + location /main { + echo_subrequest_async POST /sub -f html/blah.txt; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world +--- request + GET /main +--- response_body +sub method: POST +Hello, world + + + +=== TEST 23: POST subrequest with file body (absolute paths) +--- config + location /main { + echo_subrequest_async POST /sub -f $TEST_NGINX_HTML_DIR/blah.txt; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world! +Haha +--- request + GET /main +--- response_body +sub method: POST +Hello, world! +Haha + + + +=== TEST 24: POST subrequest with file body (file not found) +--- config + location /main { + echo_subrequest_async POST /sub -f html/blah/blah.txt; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world +--- request + GET /main +--- ignore_response +--- error_log eval +qr/open\(\) ".*?" failed/ +--- no_error_log +[alert] + + + +=== TEST 25: POST subrequest with file body (absolute paths in vars) +--- config + location /main { + set $path $TEST_NGINX_HTML_DIR/blah.txt; + echo_subrequest_async POST /sub -f $path; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world! +Haha +--- request + GET /main +--- response_body +sub method: POST +Hello, world! +Haha + + + +=== TEST 26: leading subrequest & echo_before_body +--- config + location /main { + echo_before_body hello; + echo_subrequest_async GET /foo; + } + location /foo { + echo world; + } +--- request + GET /main +--- response_body +hello +world + + + +=== TEST 27: leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_subrequest_async GET /foo; + } + location /foo { + echo -n world; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world); + + + +=== TEST 28: multiple leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_subrequest_async GET /foo; + echo_subrequest_async GET /bar; + } + location /foo { + echo -n world; + } + location /bar { + echo -n ' people'; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world people); + + + +=== TEST 29: sanity (HEAD) +--- config + location /main { + echo_subrequest_async GET /sub; + echo_subrequest_async GET /sub; + } + location /sub { + echo hello; + } +--- request + HEAD /main +--- response_body + + + +=== TEST 30: HEAD subrequest +--- config + location /main { + echo_subrequest_async HEAD /sub; + echo_subrequest_async HEAD /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/subrequest.t b/modules_deb/libnginx-mod-http-echo-0.63/t/subrequest.t new file mode 100644 index 0000000..6d965d0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/subrequest.t @@ -0,0 +1,725 @@ +# vi:filetype= + +use lib 'lib'; + +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks() + 1); + +$ENV{TEST_NGINX_HTML_DIR} = html_dir; +$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /main { + echo_subrequest GET /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello + + + +=== TEST 2: trailing echo +--- config + location /main { + echo_subrequest GET /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +hello +after subrequest + + + +=== TEST 3: leading echo +--- config + location /main { + echo before subrequest; + echo_subrequest GET /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello + + + +=== TEST 4: leading & trailing echo +--- config + location /main { + echo before subrequest; + echo_subrequest GET /sub; + echo after subrequest; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before subrequest +hello +after subrequest + + + +=== TEST 5: multiple subrequests +--- config + location /main { + echo before sr 1; + echo_subrequest GET /sub; + echo after sr 1; + echo before sr 2; + echo_subrequest GET /sub; + echo after sr 2; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body +before sr 1 +hello +after sr 1 +before sr 2 +hello +after sr 2 + + + +=== TEST 6: timed multiple subrequests (blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_subrequest GET /sub1; + echo_subrequest GET /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_blocking_sleep 0.02; + echo hello; + } + location /sub2 { + echo_blocking_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ + + + +=== TEST 7: timed multiple subrequests (non-blocking sleep) +--- config + location /main { + echo_reset_timer; + echo_subrequest GET /sub1; + echo_subrequest GET /sub2; + echo "took $echo_timer_elapsed sec for total."; + } + location /sub1 { + echo_sleep 0.02; + echo hello; + } + location /sub2 { + echo_sleep 0.01; + echo world; + } + +--- request + GET /main +--- response_body_like +^hello +world +took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ + + + +=== TEST 8: location with args +--- config + location /main { + echo_subrequest GET /sub -q 'foo=Foo&bar=Bar'; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 9: chained subrequests +--- config + location /main { + echo 'pre main'; + echo_subrequest GET /sub; + echo 'post main'; + } + + location /sub { + echo 'pre sub'; + echo_subrequest GET /subsub; + echo 'post sub'; + } + + location /subsub { + echo 'subsub'; + } +--- request + GET /main +--- response_body +pre main +pre sub +subsub +post sub +post main + + + +=== TEST 10: chained subrequests using named locations +as of 0.8.20, ngx_http_subrequest still does not support +named location. sigh. this case is a TODO. +--- config + location /main { + echo 'pre main'; + echo_subrequest GET @sub; + echo 'post main'; + } + + location @sub { + echo 'pre sub'; + echo_subrequest GET @subsub; + echo 'post sub'; + } + + location @subsub { + echo 'subsub'; + } +--- request + GET /main +--- response_body +pre main +pre sub +subsub +post sub +post main +--- SKIP + + + +=== TEST 11: explicit flush in main request +--- config + location /main { + echo 'pre main'; + echo_subrequest GET /sub; + echo 'post main'; + echo_flush; + } + + location /sub { + echo_sleep 0.02; + echo 'sub'; + } +--- request + GET /main +--- response_body +pre main +sub +post main + + + +=== TEST 12: DELETE subrequest +--- config + location /main { + echo_subrequest DELETE /sub; + } + location /sub { + echo "sub method: $echo_request_method"; + echo "main method: $echo_client_request_method"; + } +--- request + GET /main +--- response_body +sub method: DELETE +main method: GET + + + +=== TEST 13: DELETE subrequest +--- config + location /main { + echo "main method: $echo_client_request_method"; + echo_subrequest GET /proxy; + echo_subrequest DELETE /proxy; + } + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/sub; + } + location /sub { + echo "sub method: $echo_request_method"; + } +--- request + GET /main +--- response_body +main method: GET +sub method: GET +sub method: DELETE + + + +=== TEST 14: POST subrequest with body +--- config + location /main { + echo_subrequest POST /sub -b 'hello, world'; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo "sub body: $echo_request_body"; + } +--- request + GET /main +--- response_body +sub method: POST +sub body: hello, world + + + +=== TEST 15: POST subrequest with body (explicitly read the body) +--- config + location /main { + echo_subrequest POST /sub -b 'hello, world'; + } + location /sub { + echo "sub method: $echo_request_method"; + # we call echo_read_client_body explicitly here even + # though it's not necessary. + echo_read_request_body; + echo "sub body: $echo_request_body"; + } +--- request + GET /main +--- response_body +sub method: POST +sub body: hello, world + + + +=== TEST 16: POST subrequest with body (with proxy in the middle) and without read body explicitly +--- config + location /main { + echo_subrequest POST /proxy -b 'hello, world'; + } + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/sub; + } + location /sub { + echo "sub method: $echo_request_method."; + # we need to read body explicitly here...or $echo_request_body + # will evaluate to empty ("") + echo "sub body: $echo_request_body."; + } +--- request + GET /main +--- response_body +sub method: POST. +sub body: . + + + +=== TEST 17: POST subrequest with body (with proxy in the middle) and read body explicitly +--- config + location /main { + echo_subrequest POST /proxy -b 'hello, world'; + } + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/sub; + } + location /sub { + echo "sub method: $echo_request_method."; + # we need to read body explicitly here...or $echo_request_body + # will evaluate to empty ("") + echo_read_request_body; + echo "sub body: $echo_request_body."; + } +--- request + GET /main +--- response_body +sub method: POST. +sub body: hello, world. + + + +=== TEST 18: multiple subrequests +--- config + location /multi { + echo_subrequest POST '/sub' -q 'foo=Foo' -b 'hi'; + echo_subrequest PUT '/sub' -q 'bar=Bar' -b 'hello'; + } + location /sub { + echo "querystring: $query_string"; + echo "method: $echo_request_method"; + echo "body: $echo_request_body"; + echo "content length: $http_content_length"; + echo '///'; + } +--- request + GET /multi +--- response_body +querystring: foo=Foo +method: POST +body: hi +content length: 2 +/// +querystring: bar=Bar +method: PUT +body: hello +content length: 5 +/// + + + +=== TEST 19: unsafe uri +--- config + location /unsafe { + echo_subrequest GET '/../foo'; + } +--- request + GET /unsafe +--- ignore_response +--- error_log +echo_subrequest sees unsafe uri: "/../foo" +--- no_error_log +[error] + + + +=== TEST 20: querystring in url +--- config + location /main { + echo_subrequest GET /sub?foo=Foo&bar=Bar; + } + location /sub { + echo $arg_foo $arg_bar; + } +--- request + GET /main +--- response_body +Foo Bar + + + +=== TEST 21: querystring in url *AND* an explicit querystring +--- config + location /main { + echo_subrequest GET /sub?foo=Foo&bar=Bar -q blah=Blah; + } + location /sub { + echo $arg_foo $arg_bar $arg_blah; + } +--- request + GET /main +--- response_body + Blah + + + +=== TEST 22: let subrequest to read the main request's request body +--- SKIP +--- config + location /main { + echo_subrequest POST /sub; + } + location /sub { + echo_read_request_body; + echo_request_body; + } +--- request +POST /main +hello, body! +--- response_body chomp +hello, body! + + + +=== TEST 23: deep nested echo_subrequest/echo_subrequest_async +--- config + location /main { + echo_subrequest GET /bar; + echo_subrequest_async GET /bar; + echo_subrequest_async GET /bar; + echo_subrequest GET /group; + echo_subrequest_async GET /group; + } + + location /group { + echo_subrequest GET /bar; + echo_subrequest_async GET /bar; + } + + location /bar { + echo $echo_incr; + } +--- request +GET /main +--- response_body +1 +2 +3 +4 +5 +6 +7 + + + +=== TEST 24: deep nested echo_subrequest/echo_subrequest_async +--- config + location /main { + echo_subrequest GET /bar?a; + echo_subrequest_async GET /bar?b; + echo_subrequest_async GET /bar?c; + echo_subrequest GET /group?a=d&b=e; + echo_subrequest_async GET /group?a=f&b=g; + } + + location /group { + echo_subrequest GET /bar?$arg_a; + echo_subrequest_async GET /bar?$arg_b; + } + + location /bar { + echo -n $query_string; + } +--- request +GET /main +--- response_body: abcdefg +--- timeout: 2 + + + +=== TEST 25: POST subrequest with file body (relative paths) +--- config + location /main { + echo_subrequest POST /sub -f html/blah.txt; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world +--- request + GET /main +--- response_body +sub method: POST +Hello, world + + + +=== TEST 26: POST subrequest with file body (absolute paths) +--- config + location /main { + echo_subrequest POST /sub -f $TEST_NGINX_HTML_DIR/blah.txt; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world! +Haha +--- request + GET /main +--- response_body +sub method: POST +Hello, world! +Haha + + + +=== TEST 27: POST subrequest with file body (file not found) +--- config + location /main { + echo_subrequest POST /sub -f html/blah/blah.txt; + } + location /sub { + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo_request_body; + } +--- user_files +>>> blah.txt +Hello, world +--- request + GET /main +--- ignore_response +--- error_log eval +qr/open\(\) ".*?" failed/ +--- no_error_log +[alert] + + + +=== TEST 28: leading subrequest & echo_before_body +--- config + location /main { + echo_before_body hello; + echo_subrequest GET /foo; + } + location /foo { + echo world; + } +--- request + GET /main +--- response_body +hello +world + + + +=== TEST 29: leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_subrequest GET /foo; + } + location /foo { + echo -n world; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world); + + + +=== TEST 30: multiple leading subrequest & xss +--- config + location /main { + default_type 'application/json'; + xss_get on; + xss_callback_arg c; + echo_subrequest GET /foo; + echo_subrequest GET /bar; + } + location /foo { + echo -n world; + } + location /bar { + echo -n ' people'; + } +--- request + GET /main?c=hi +--- response_body chop +hi(world people); + + + +=== TEST 31: sanity (HEAD) +--- config + location /main { + echo_subrequest GET /sub; + echo_subrequest GET /sub; + } + location /sub { + echo hello; + } +--- request + HEAD /main +--- response_body + + + +=== TEST 32: POST subrequest to ngx_proxy +--- config + location /hello { + default_type text/plain; + echo_subrequest POST '/proxy' -q 'foo=Foo&bar=baz' -b 'request_body=test&test=3'; + } + + location /proxy { + proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT/sub; + #proxy_pass http://127.0.0.1:1113/sub; + } + + location /sub { + echo_read_request_body; + echo "sub method: $echo_request_method"; + # we don't need to call echo_read_client_body explicitly here + echo "sub body: $echo_request_body"; + } +--- request + GET /hello +--- response_body +sub method: POST +sub body: request_body=test&test=3 + + + +=== TEST 33: HEAD subrequest +--- config + location /main { + echo_subrequest HEAD /sub; + echo_subrequest HEAD /sub; + } + location /sub { + echo hello; + } +--- request + GET /main +--- response_body + + + +=== TEST 34: method name as an nginx variable (github issue #34) +--- config + location ~ ^/delay/(?[0-9.]+)/(?.*)$ { + # echo_blocking_sleep $delay; + echo_subrequest '$echo_request_method' '/$originalURL' -q '$args'; + } + + location /api { + echo "args: $args"; + } +--- request + GET /delay/0.343/api/?a=b +--- response_body +args: a=b +--- no_error_log +[error] + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/t/unused.t b/modules_deb/libnginx-mod-http-echo-0.63/t/unused.t new file mode 100644 index 0000000..f3c6e9e --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/t/unused.t @@ -0,0 +1,119 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (5 * blocks()); + +no_long_string(); +log_level('warn'); + +#master_on(); +#workers(1); + +run_tests(); + +__DATA__ + +=== TEST 1: filters used +--- http_config + postpone_output 1; +--- config + location /echo { + echo world; + echo_after_body hello; + } +--- request + GET /echo?blah +--- response_body +world +hello +--- error_log +echo header filter, uri "/echo?blah" +echo body filter, uri "/echo?blah" +--- no_error_log +[error] +--- log_level: debug + + + +=== TEST 2: filters not used +--- http_config + postpone_output 1; +--- config + location /echo { + echo world; + #echo_after_body hello; + } +--- request + GET /echo?blah +--- response_body +world +--- no_error_log +echo header filter, uri "/echo?blah" +echo body filter, uri "/echo?blah" +[error] +--- log_level: debug + + + +=== TEST 3: (after) filters used (multiple http {} blocks) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP +--- http_config + postpone_output 1; +--- config + location /echo { + echo world; + echo_after_body hello; + } + +--- post_main_config + http { + } + +--- request + GET /echo?blah +--- response_body +world +hello +--- error_log +echo header filter, uri "/echo?blah" +echo body filter, uri "/echo?blah" +--- no_error_log +[error] +--- log_level: debug + + + +=== TEST 4: (before) filters used (multiple http {} blocks) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP +--- http_config + postpone_output 1; +--- config + location /echo { + echo world; + echo_before_body hello; + } + +--- post_main_config + http { + } + +--- request + GET /echo?blah +--- response_body +hello +world +--- error_log +echo header filter, uri "/echo?blah" +echo body filter, uri "/echo?blah" +--- no_error_log +[error] +--- log_level: debug + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/util/build.sh b/modules_deb/libnginx-mod-http-echo-0.63/util/build.sh new file mode 100755 index 0000000..45949bb --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/util/build.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +# this file is mostly meant to be used by the author himself. + +root=`pwd` +version=$1 +force=$2 +home=~ + + #--with-cc=gcc46 \ + +ngx-build $force $version \ + --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:/usr/local/lib" \ + --with-cc-opt="-DDEBUG_MALLOC" \ + --with-http_stub_status_module \ + --with-http_image_filter_module \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --without-mail_smtp_module \ + --without-http_upstream_ip_hash_module \ + --without-http_memcached_module \ + --without-http_referer_module \ + --without-http_autoindex_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + --add-module=$root/../ndk-nginx-module \ + --add-module=$root/../set-misc-nginx-module \ + --add-module=$root/../eval-nginx-module \ + --add-module=$root/../xss-nginx-module \ + --add-module=$root/../rds-json-nginx-module \ + --add-module=$root/../headers-more-nginx-module \ + --add-module=$root/../lua-nginx-module \ + --add-module=$root $opts \ + --with-http_v2_module \ + --with-select_module \ + --with-poll_module \ + --without-http_ssi_module \ + --with-debug || exit 1 + #--add-module=$root/../lz-session-nginx-module \ + #--add-module=$home/work/ndk \ + #--add-module=$home/work/ndk/examples/http/set_var \ + #--add-module=$root/../eval-nginx-module \ + #--add-module=/home/agentz/work/nginx_eval_module-1.0.1 \ + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/util/wiki2pod.pl b/modules_deb/libnginx-mod-http-echo-0.63/util/wiki2pod.pl new file mode 100644 index 0000000..cdd33a2 --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/util/wiki2pod.pl @@ -0,0 +1,131 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use bytes; + +my @nl_counts; +my $last_nl_count_level; + +my @bl_counts; +my $last_bl_count_level; + +sub fmt_pos ($) { + (my $s = $_[0]) =~ s{\#(.*)}{/"$1"}; + $s; +} + +sub fmt_mark ($$) { + my ($tag, $s) = @_; + my $max_level = 0; + while ($s =~ /([<>])\1*/g) { + my $level = length $&; + if ($level > $max_level) { + $max_level = $level; + } + } + + my $times = $max_level + 1; + if ($times > 1) { + $s = " $s "; + } + return $tag . ('<' x $times) . $s . ('>' x $times); +} + +print "=encoding utf-8\n\n"; + +while (<>) { + if ($. == 1) { + # strip the leading U+FEFF byte in MS-DOS text files + my $first = ord(substr($_, 0, 1)); + #printf STDERR "0x%x", $first; + #my $second = ord(substr($_, 2, 1)); + #printf STDERR "0x%x", $second; + if ($first == 0xEF) { + substr($_, 0, 1, ''); + #warn "Hit!"; + } + } + s{\[(http[^ \]]+) ([^\]]*)\]}{$2 (L<$1>)}gi; + s{ \[\[ ( [^\]\|]+ ) \| ([^\]]*) \]\] }{"L<$2|" . fmt_pos($1) . ">"}gixe; + s{(.*?)}{fmt_mark('C', $1)}gie; + s{'''(.*?)'''}{fmt_mark('B', $1)}ge; + s{''(.*?)''}{fmt_mark('I', $1)}ge; + if (s{^\s*<[^>]+>\s*$}{}) { + next; + } + + if (/^\s*$/) { + print "\n"; + next; + } + +=begin cmt + + if ($. == 1) { + warn $_; + for my $i (0..length($_) - 1) { + my $chr = substr($_, $i, 1); + warn "chr ord($i): ".ord($chr)." \"$chr\"\n"; + } + } + +=end cmt +=cut + + if (/(=+) (.*) \1$/) { + #warn "HERE! $_" if $. == 1; + my ($level, $title) = (length $1, $2); + collapse_lists(); + + print "\n=head$level $title\n\n"; + } elsif (/^(\#+) (.*)/) { + my ($level, $txt) = (length($1) - 1, $2); + if (defined $last_nl_count_level && $level != $last_nl_count_level) { + print "\n=back\n\n"; + } + $last_nl_count_level = $level; + $nl_counts[$level] ||= 0; + if ($nl_counts[$level] == 0) { + print "\n=over\n\n"; + } + $nl_counts[$level]++; + print "\n=item $nl_counts[$level].\n\n"; + print "$txt\n"; + } elsif (/^(\*+) (.*)/) { + my ($level, $txt) = (length($1) - 1, $2); + if (defined $last_bl_count_level && $level != $last_bl_count_level) { + print "\n=back\n\n"; + } + $last_bl_count_level = $level; + $bl_counts[$level] ||= 0; + if ($bl_counts[$level] == 0) { + print "\n=over\n\n"; + } + $bl_counts[$level]++; + print "\n=item *\n\n"; + print "$txt\n"; + } else { + collapse_lists(); + print; + } +} + +collapse_lists(); + +sub collapse_lists { + while (defined $last_nl_count_level && $last_nl_count_level >= 0) { + print "\n=back\n\n"; + $last_nl_count_level--; + } + undef $last_nl_count_level; + undef @nl_counts; + + while (defined $last_bl_count_level && $last_bl_count_level >= 0) { + print "\n=back\n\n"; + $last_bl_count_level--; + } + undef $last_bl_count_level; + undef @bl_counts; +} + diff --git a/modules_deb/libnginx-mod-http-echo-0.63/valgrind.suppress b/modules_deb/libnginx-mod-http-echo-0.63/valgrind.suppress new file mode 100644 index 0000000..975415e --- /dev/null +++ b/modules_deb/libnginx-mod-http-echo-0.63/valgrind.suppress @@ -0,0 +1,53 @@ +{ + + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl +} +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_event_process_init +} +{ + + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle +} diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/LICENSE b/modules_deb/libnginx-mod-http-geoip2-3.4/LICENSE new file mode 100644 index 0000000..fdc13a7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2014, Lee Valentine +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/README.md b/modules_deb/libnginx-mod-http-geoip2-3.4/README.md new file mode 100644 index 0000000..cea0d04 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/README.md @@ -0,0 +1,153 @@ +Description +=========== + +**ngx_http_geoip2_module** - creates variables with values from the maxmind geoip2 databases based on the client IP (default) or from a specific variable (supports both IPv4 and IPv6) + +The module now supports nginx streams and can be used in the same way the http module can be used. + +## Installing +First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as described in its [README.md +file](https://github.com/maxmind/libmaxminddb/blob/main/README.md#installing-from-a-tarball). + +#### Download nginx source +``` +wget http://nginx.org/download/nginx-VERSION.tar.gz +tar zxvf nginx-VERSION.tar.gz +cd nginx-VERSION +``` + +##### To build as a dynamic module (nginx 1.9.11+): +``` +./configure --add-dynamic-module=/path/to/ngx_http_geoip2_module +make +make install +``` + +This will produce ```objs/ngx_http_geoip2_module.so```. It can be copied to your nginx module path manually if you wish. + +Add the following line to your nginx.conf: +``` +load_module modules/ngx_http_geoip2_module.so; +``` + +##### To build as a static module: +``` +./configure --add-module=/path/to/ngx_http_geoip2_module +make +make install +``` + +##### If you need stream support, make sure to compile with stream: +``` +./configure --add-dynamic-module=/path/to/ngx_http_geoip2_module --with-stream +OR +./configure --add-module=/path/to/ngx_http_geoip2_module --with-stream +``` + + +## Download Maxmind GeoLite2 Database (optional) +The free GeoLite2 databases are available from [Maxminds website](http://dev.maxmind.com/geoip/geoip2/geolite2/) (requires signing up) + +## Example Usage: +``` +http { + ... + geoip2 /etc/maxmind-country.mmdb { + auto_reload 5m; + $geoip2_metadata_country_build metadata build_epoch; + $geoip2_data_country_code default=US source=$variable_with_ip country iso_code; + $geoip2_data_country_name country names en; + } + + geoip2 /etc/maxmind-city.mmdb { + $geoip2_data_city_name default=London city names en; + } + .... + + fastcgi_param COUNTRY_CODE $geoip2_data_country_code; + fastcgi_param COUNTRY_NAME $geoip2_data_country_name; + fastcgi_param CITY_NAME $geoip2_data_city_name; + .... +} + +stream { + ... + geoip2 /etc/maxmind-country.mmdb { + $geoip2_data_country_code default=US source=$remote_addr country iso_code; + } + ... +} +``` + +##### Metadata: +Retrieve metadata regarding the geoip database. +``` +$variable_name metadata +``` +Available fields: + - build_epoch: the build timestamp of the maxmind database. + - last_check: the last time the database was checked for changes (when using auto_reload) + - last_change: the last time the database was reloaded (when using auto_reload) + +##### Autoreload (default: disabled): +Enabling auto reload will have nginx check the modification time of the database at the specified +interval and reload it if it has changed. +``` +auto_reload +``` + +##### GeoIP: +``` +$variable_name [default= + "iso_code": + "US" + "names": + { + "de": + "USA" + "en": + "United States" + } + } + } + +$ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8 country names en + + "United States" +``` + +This translates to: + +``` +$country_name "default=United States" source=$remote_addr country names en +``` + +##### Additional Commands: +These commands works the same as the original ngx_http_geoip_module documented here: http://nginx.org/en/docs/http/ngx_http_geoip_module.html#geoip_proxy. + +However, if you provide the `source=$variable_with_ip` option on a variable, these settings will be ignored for that particular variable. + +``` +geoip2_proxy < cidr > +``` +Defines trusted addresses. When a request comes from a trusted address, an address from the "X-Forwarded-For" request header field will be used instead. + +``` +geoip2_proxy_recursive < on | off > +``` +If recursive search is disabled then instead of the original client address that matches one of the trusted addresses, the last address sent in "X-Forwarded-For" will be used. If recursive search is enabled then instead of the original client address that matches one of the trusted addresses, the last non-trusted address sent in "X-Forwarded-For" will be used. diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/config b/modules_deb/libnginx-mod-http-geoip2-3.4/config new file mode 100644 index 0000000..48bf15d --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/config @@ -0,0 +1,43 @@ +ngx_feature="MaxmindDB library" +ngx_feature_name= +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_libs=-lmaxminddb +ngx_feature_test="MMDB_s mmdb" +. auto/feature + +ngx_addon_name="ngx_geoip2_module" + +if [ $ngx_found = yes ]; then + if test -n "$ngx_module_link"; then + if [ $HTTP != NO ]; then + ngx_module_type=HTTP + ngx_module_name="ngx_http_geoip2_module" + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="$ngx_addon_dir/ngx_http_geoip2_module.c" + ngx_module_libs="$ngx_feature_libs" + . auto/module + fi + + nginx_version=`awk '/^#define nginx_version / {print $3}' src/core/nginx.h` + if [ $STREAM != NO -a $nginx_version -gt 1011001 ]; then + ngx_module_type=STREAM + ngx_module_name="ngx_stream_geoip2_module" + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="$ngx_addon_dir/ngx_stream_geoip2_module.c" + ngx_module_libs="$ngx_feature_libs" + . auto/module + fi + else + HTTP_MODULES="$HTTP_MODULES ngx_http_geoip2_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_geoip2_module.c" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + fi +else + cat << END +$0: error: the geoip2 module requires the maxminddb library. +END + exit 1 +fi diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/changelog b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/changelog new file mode 100644 index 0000000..0c0f22e --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/changelog @@ -0,0 +1,52 @@ +libnginx-mod-http-geoip2 (1:3.4-6) unstable; urgency=medium + + * d/control: update my email to janmojzis@debian.org + * d/copyright: update my email to janmojzis@debian.org + * d/control: bump Standards-Version: 4.7.2, no changes + * d/copyright: bump debian/* copyright year + * d/watch: use more generic template + + -- Jan Mojžíš Fri, 11 Apr 2025 14:26:59 +0200 + +libnginx-mod-http-geoip2 (1:3.4-5) unstable; urgency=medium + + * Better usage of dh-sequence-nginx + * d/rules: remove override_dh_auto_configure, override_dh_auto_test + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + * d/control: use Build-Depends libnginx-mod-stream instead of + libnginx-mod-stream (<<1.24.0.1~), libnginx-mod-stream (>=1.24.0) + * d/control: use Build-Depends nginx-dev (>= 1.24.0-2) + * d/control: remove Depends libnginx-mod-stream (<<1.24.0.1~), + libnginx-mod-stream (>=1.24.0) + + -- Jan Mojžíš Wed, 11 Oct 2023 07:37:12 +0200 + +libnginx-mod-http-geoip2 (1:3.4-4) unstable; urgency=medium + + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Tue, 27 Jun 2023 23:16:38 +0200 + +libnginx-mod-http-geoip2 (1:3.4-3) unstable; urgency=medium + + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/gbb.conf: switched to debian branch main (debian-branch = main) + * d/copyright: bump my copyright year + * d/copyright: reformat text to be compatible with 'cme update dpkg-copyright' + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 12:56:24 +0100 + +libnginx-mod-http-geoip2 (1:3.4-2) unstable; urgency=medium + + * d/control: added Multi-Arch: foreign + + -- Jan Mojžíš Fri, 09 Dec 2022 12:50:27 +0100 + +libnginx-mod-http-geoip2 (1:3.4-1) experimental; urgency=medium + + * Initial release. (Closes: 1024843) + + -- Jan Mojžíš Wed, 30 Nov 2022 14:46:51 +0100 diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/control b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/control new file mode 100644 index 0000000..3ccc4e3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/control @@ -0,0 +1,41 @@ +Source: libnginx-mod-http-geoip2 +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jan Mojžíš , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, + libmaxminddb-dev, + libnginx-mod-stream, + nginx-dev (>= 1.24.0-2), +Standards-Version: 4.7.2 +Homepage: https://github.com/leev/ngx_http_geoip2_module +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-geoip2.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-geoip2 +Rules-Requires-Root: no + +Package: libnginx-mod-http-geoip2 +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: GeoIP2 HTTP module for Nginx + The ngx_http_geoip2 module creates variables with values depending on the + client IP address, using the precompiled MaxMind GeoIP2 databases. + . + Those variables include country, region, city, latitude, longitude, postal + code, etc. + +Package: libnginx-mod-stream-geoip2 +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: GeoIP2 Stream module for Nginx + The ngx_stream_geoip2 module creates variables with values depending on the + client IP address, using the precompiled MaxMind GeoIP2 databases. + . + Those variables include country, region, city, latitude, longitude, postal + code, etc. diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/copyright b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/copyright new file mode 100644 index 0000000..ab01158 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/copyright @@ -0,0 +1,46 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ngx_http_geoip2_module +Upstream-Contact: Lee Valentine +Source: https://github.com/leev/ngx_http_geoip2_module + +Files: * +Copyright: 2014, Lee Valentine +License: BSD-2-clause + +Files: debian/* +Copyright: 2022, Miao Wang + 2022-2025, Jan Mojzis +License: BSD-2-clause + +Files: ngx_http_geoip2_module.c +Copyright: Lee Valentine +License: BSD-2-clause + +Files: ngx_stream_geoip2_module.c +Copyright: Lee Valentine + Andrei Belov +License: BSD-2-clause + +License: BSD-2-clause + All rights reserved. + . + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + . + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/gbp.conf b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/gbp.conf new file mode 100644 index 0000000..38c12c1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/gbp.conf @@ -0,0 +1,9 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-http-geoip2.install b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-http-geoip2.install new file mode 100644 index 0000000..2692817 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-http-geoip2.install @@ -0,0 +1 @@ +/usr/lib/nginx/modules/ngx_http_geoip2_module.so diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-stream-geoip2.install b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-stream-geoip2.install new file mode 100644 index 0000000..9f45e96 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/libnginx-mod-stream-geoip2.install @@ -0,0 +1 @@ +/usr/lib/nginx/modules/ngx_stream_geoip2_module.so diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/rules b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/rules new file mode 100755 index 0000000..d8309f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/source/format b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/control b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/control new file mode 100644 index 0000000..ca20b9f --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/control @@ -0,0 +1,6 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/generic b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/upstream/metadata b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/upstream/metadata new file mode 100644 index 0000000..5f50585 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/leev/ngx_http_geoip2_module/issues +Bug-Submit: https://github.com/leev/ngx_http_geoip2_module/issues/new +Repository-Browse: https://github.com/leev/ngx_http_geoip2_module \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/debian/watch b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/watch new file mode 100644 index 0000000..04e3a51 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/leev/ngx_http_geoip2_module/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/ngx_http_geoip2_module.c b/modules_deb/libnginx-mod-http-geoip2-3.4/ngx_http_geoip2_module.c new file mode 100644 index 0000000..4b3461c --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/ngx_http_geoip2_module.c @@ -0,0 +1,803 @@ +/* + * Copyright (C) Lee Valentine + * + * Based on nginx's 'ngx_http_geoip_module.c' by Igor Sysoev + */ + + +#include +#include +#include + +#include + + +typedef struct { + MMDB_s mmdb; + MMDB_lookup_result_s result; + time_t last_check; + time_t last_change; + time_t check_interval; +#if (NGX_HAVE_INET6) + uint8_t address[16]; +#else + unsigned long address; +#endif + ngx_queue_t queue; +} ngx_http_geoip2_db_t; + +typedef struct { + ngx_queue_t databases; + ngx_array_t *proxies; + ngx_flag_t proxy_recursive; +} ngx_http_geoip2_conf_t; + +typedef struct { + ngx_http_geoip2_db_t *database; + const char **lookup; + ngx_str_t default_value; + ngx_http_complex_value_t source; +} ngx_http_geoip2_ctx_t; + +typedef struct { + ngx_http_geoip2_db_t *database; + ngx_str_t metavalue; +} ngx_http_geoip2_metadata_t; + + +static ngx_int_t ngx_http_geoip2_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_geoip2_metadata(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static void *ngx_http_geoip2_create_conf(ngx_conf_t *cf); +static char *ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf); +static char *ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, + ngx_http_geoip2_db_t *database); +static char *ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, + ngx_http_geoip2_db_t *database); +static char *ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net, + ngx_cidr_t *cidr); +static void ngx_http_geoip2_cleanup(void *data); +static ngx_int_t ngx_http_geoip2_init(ngx_conf_t *cf); + + +#define FORMAT(fmt, ...) do { \ + p = ngx_palloc(r->pool, NGX_OFF_T_LEN); \ + if (p == NULL) { \ + return NGX_ERROR; \ + } \ + v->len = ngx_sprintf(p, fmt, __VA_ARGS__) - p; \ + v->data = p; \ +} while (0) + +static ngx_command_t ngx_http_geoip2_commands[] = { + + { ngx_string("geoip2"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_http_geoip2, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip2_proxy"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_geoip2_proxy, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip2_proxy_recursive"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_geoip2_conf_t, proxy_recursive), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_geoip2_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_geoip2_init, /* postconfiguration */ + + ngx_http_geoip2_create_conf, /* create main configuration */ + ngx_http_geoip2_init_conf, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_geoip2_module = { + NGX_MODULE_V1, + &ngx_http_geoip2_module_ctx, /* module context */ + ngx_http_geoip2_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_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_http_geoip2_ctx_t *geoip2 = (ngx_http_geoip2_ctx_t *) data; + ngx_http_geoip2_db_t *database = geoip2->database; + int mmdb_error; + MMDB_entry_data_s entry_data; + ngx_http_geoip2_conf_t *gcf; + ngx_addr_t addr; +#if defined(nginx_version) && nginx_version >= 1023000 + ngx_table_elt_t *xfwd; +#else + ngx_array_t *xfwd; +#endif + u_char *p; + ngx_str_t val; + +#if (NGX_HAVE_INET6) + uint8_t address[16], *addressp = address; +#else + unsigned long address; +#endif + + if (geoip2->source.value.len > 0) { + if (ngx_http_complex_value(r, &geoip2->source, &val) != NGX_OK) { + goto not_found; + } + + if (ngx_parse_addr(r->pool, &addr, val.data, val.len) != NGX_OK) { + goto not_found; + } + } else { + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); + addr.sockaddr = r->connection->sockaddr; + addr.socklen = r->connection->socklen; + +#if defined(nginx_version) && nginx_version >= 1023000 + xfwd = r->headers_in.x_forwarded_for; + + if (xfwd != NULL && gcf->proxies != NULL) { +#else + xfwd = &r->headers_in.x_forwarded_for; + + if (xfwd->nelts > 0 && gcf->proxies != NULL) { +#endif + (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, + gcf->proxies, gcf->proxy_recursive); + } + } + + switch (addr.sockaddr->sa_family) { + case AF_INET: +#if (NGX_HAVE_INET6) + ngx_memset(addressp, 0, 12); + ngx_memcpy(addressp + 12, &((struct sockaddr_in *) + addr.sockaddr)->sin_addr.s_addr, 4); + break; + + case AF_INET6: + ngx_memcpy(addressp, &((struct sockaddr_in6 *) + addr.sockaddr)->sin6_addr.s6_addr, 16); +#else + address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr; +#endif + break; + + default: + goto not_found; + } + +#if (NGX_HAVE_INET6) + if (ngx_memcmp(&address, &database->address, sizeof(address)) + != 0) { +#else + if (address != database->address) { +#endif + memcpy(&database->address, &address, sizeof(address)); + database->result = MMDB_lookup_sockaddr(&database->mmdb, + addr.sockaddr, &mmdb_error); + + if (mmdb_error != MMDB_SUCCESS) { + goto not_found; + } + } + + if (!database->result.found_entry + || MMDB_aget_value(&database->result.entry, &entry_data, + geoip2->lookup) != MMDB_SUCCESS) { + goto not_found; + } + + if (!entry_data.has_data) { + goto not_found; + } + + switch (entry_data.type) { + case MMDB_DATA_TYPE_BOOLEAN: + FORMAT("%d", entry_data.boolean); + break; + case MMDB_DATA_TYPE_UTF8_STRING: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.utf8_string, v->len); + break; + case MMDB_DATA_TYPE_BYTES: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.bytes, v->len); + break; + case MMDB_DATA_TYPE_FLOAT: + FORMAT("%.5f", entry_data.float_value); + break; + case MMDB_DATA_TYPE_DOUBLE: + FORMAT("%.5f", entry_data.double_value); + break; + case MMDB_DATA_TYPE_UINT16: + FORMAT("%uD", entry_data.uint16); + break; + case MMDB_DATA_TYPE_UINT32: + FORMAT("%uD", entry_data.uint32); + break; + case MMDB_DATA_TYPE_INT32: + FORMAT("%D", entry_data.int32); + break; + case MMDB_DATA_TYPE_UINT64: + FORMAT("%uL", entry_data.uint64); + break; + case MMDB_DATA_TYPE_UINT128: ; +#if MMDB_UINT128_IS_BYTE_ARRAY + uint8_t *val = (uint8_t *)entry_data.uint128; + FORMAT( "0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + val[0], val[1], val[2], val[3], + val[4], val[5], val[6], val[7], + val[8], val[9], val[10], val[11], + val[12], val[13], val[14], val[15]); +#else + mmdb_uint128_t val = entry_data.uint128; + FORMAT("0x%016uxL%016uxL", + (uint64_t) (val >> 64), (uint64_t) val); +#endif + break; + default: + goto not_found; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + if (geoip2->default_value.len > 0) { + v->data = geoip2->default_value.data; + v->len = geoip2->default_value.len; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip2_metadata(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_http_geoip2_metadata_t *metadata = (ngx_http_geoip2_metadata_t *) data; + ngx_http_geoip2_db_t *database = metadata->database; + u_char *p; + + if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) { + FORMAT("%uL", database->mmdb.metadata.build_epoch); + } else if (ngx_strncmp(metadata->metavalue.data, "last_check", 10) == 0) { + FORMAT("%T", database->last_check); + } else if (ngx_strncmp(metadata->metavalue.data, "last_change", 11) == 0) { + FORMAT("%T", database->last_change); + } else { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +static void * +ngx_http_geoip2_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_http_geoip2_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->proxy_recursive = NGX_CONF_UNSET; + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + ngx_queue_init(&conf->databases); + + cln->handler = ngx_http_geoip2_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip2_conf_t *gcf = conf; + ngx_str_t *value; + int status; + ngx_http_geoip2_db_t *database; + char *rv; + ngx_conf_t save; + ngx_queue_t *q; + + value = cf->args->elts; + + if (value[1].data && value[1].data[0] != '/') { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + if (!ngx_queue_empty(&gcf->databases)) { + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); + if (ngx_strcmp(value[1].data, database->mmdb.filename) == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "Duplicate GeoIP2 mmdb - %V", &value[1]); + return NGX_CONF_ERROR; + } + } + } + + database = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_db_t)); + if (database == NULL) { + return NGX_CONF_ERROR; + } + + ngx_queue_insert_tail(&gcf->databases, &database->queue); + database->last_check = database->last_change = ngx_time(); + + status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb); + + if (status != MMDB_SUCCESS) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "MMDB_open(\"%V\") failed - %s", &value[1], + MMDB_strerror(status)); + return NGX_CONF_ERROR; + } + + save = *cf; + cf->handler = ngx_http_geoip2_parse_config; + cf->handler_conf = (void *) database; + + rv = ngx_conf_parse(cf, NULL); + *cf = save; + return rv; +} + + +static char * +ngx_http_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_http_geoip2_db_t *database; + ngx_str_t *value; + time_t interval; + + value = cf->args->elts; + + if (value[0].data[0] == '$') { + return ngx_http_geoip2_add_variable(cf, dummy, conf); + } + + if (value[0].len == 11 + && ngx_strncmp(value[0].data, "auto_reload", 11) == 0) { + if ((int) cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of arguments for auto_reload"); + return NGX_CONF_ERROR; + } + + interval = ngx_parse_time(&value[1], true); + + if (interval == (time_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid interval for auto_reload \"%V\"", + value[1]); + return NGX_CONF_ERROR; + } + + + database = (ngx_http_geoip2_db_t *) conf; + database->check_interval = interval; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\"", &value[0]); + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_http_geoip2_db_t *database; + ngx_str_t *value; + int nelts; + + value = cf->args->elts; + + if (value[0].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + nelts = (int) cf->args->nelts; + database = (ngx_http_geoip2_db_t *) conf; + + if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) { + return ngx_http_geoip2_add_variable_metadata(cf, database); + } + + return ngx_http_geoip2_add_variable_geodata(cf, database); +} + + +static char * +ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database) +{ + ngx_http_geoip2_metadata_t *metadata; + ngx_str_t *value, name; + ngx_http_variable_t *var; + + metadata = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_metadata_t)); + if (metadata == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + name = value[0]; + + metadata->database = database; + metadata->metavalue = value[2]; + + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_http_geoip2_metadata; + var->data = (uintptr_t) metadata; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database) +{ + ngx_http_geoip2_ctx_t *geoip2; + ngx_http_compile_complex_value_t ccv; + ngx_str_t *value, name, source; + ngx_http_variable_t *var; + int i, nelts, idx; + + geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t)); + if (geoip2 == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->database = database; + ngx_str_null(&source); + + value = cf->args->elts; + name = value[0]; + + nelts = (int) cf->args->nelts; + idx = 1; + + if (nelts > idx) { + for (i = idx; i < nelts; i++) { + if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) { + break; + } + + if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) { + if (geoip2->default_value.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "default has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + geoip2->default_value.len = value[idx].len - 8; + geoip2->default_value.data = value[idx].data + 8; + } else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) { + if (source.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "source has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + source.len = value[idx].len - 7; + source.data = value[idx].data + 7; + + if (source.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid source variable name \"%V\"", &source); + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + ccv.cf = cf; + ccv.value = &source; + ccv.complex_value = &geoip2->source; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unable to compile \"%V\" for \"$%V\"", &source, &name); + return NGX_CONF_ERROR; + } + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\" for \"$%V\"", &value[idx], &name); + return NGX_CONF_ERROR; + } + + idx++; + } + } + + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->lookup = ngx_pcalloc(cf->pool, sizeof(const char *) * + (cf->args->nelts - (idx - 1))); + + if (geoip2->lookup == NULL) { + return NGX_CONF_ERROR; + } + + for (i = idx; i < nelts; i++) { + geoip2->lookup[i - idx] = (char *) value[i].data; + } + geoip2->lookup[i - idx] = NULL; + + var->get_handler = ngx_http_geoip2_variable; + var->data = (uintptr_t) geoip2; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_geoip2_conf_t *gcf = conf; + ngx_conf_init_value(gcf->proxy_recursive, 0); + return NGX_CONF_OK; +} + + +static char * +ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip2_conf_t *gcf = conf; + ngx_str_t *value; + ngx_cidr_t cidr, *c; + + value = cf->args->elts; + + if (ngx_http_geoip2_cidr_value(cf, &value[1], &cidr) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (gcf->proxies == NULL) { + gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t)); + if (gcf->proxies == NULL) { + return NGX_CONF_ERROR; + } + } + + c = ngx_array_push(gcf->proxies); + if (c == NULL) { + return NGX_CONF_ERROR; + } + + *c = cidr; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) +{ + ngx_int_t rc; + + if (ngx_strcmp(net->data, "255.255.255.255") == 0) { + cidr->family = AF_INET; + cidr->u.in.addr = 0xffffffff; + cidr->u.in.mask = 0xffffffff; + + return NGX_OK; + } + + rc = ngx_ptocidr(net, cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid network \"%V\"", net); + return NGX_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", net); + } + + return NGX_OK; +} + + +static void +ngx_http_geoip2_cleanup(void *data) +{ + ngx_http_geoip2_conf_t *gcf = data; + ngx_queue_t *q; + ngx_http_geoip2_db_t *database; + + while (!ngx_queue_empty(&gcf->databases)) { + q = ngx_queue_head(&gcf->databases); + ngx_queue_remove(q); + database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); + MMDB_close(&database->mmdb); + } +} + + +static ngx_int_t +ngx_http_geoip2_log_handler(ngx_http_request_t *r) +{ + int status; + MMDB_s tmpdb; + ngx_queue_t *q; + ngx_file_info_t fi; + ngx_http_geoip2_db_t *database; + ngx_http_geoip2_conf_t *gcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "geoip2 http log handler"); + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); + + if (ngx_queue_empty(&gcf->databases)) { + return NGX_OK; + } + + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); + if (database->check_interval == 0) { + continue; + } + + if ((database->last_check + database->check_interval) + > ngx_time()) + { + continue; + } + + database->last_check = ngx_time(); + + if (ngx_file_info(database->mmdb.filename, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, + ngx_file_info_n " \"%s\" failed", + database->mmdb.filename); + + continue; + } + + if (ngx_file_mtime(&fi) <= database->last_change) { + continue; + } + + /* do the reload */ + + ngx_memzero(&tmpdb, sizeof(MMDB_s)); + status = MMDB_open(database->mmdb.filename, MMDB_MODE_MMAP, &tmpdb); + + if (status != MMDB_SUCCESS) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "MMDB_open(\"%s\") failed to reload - %s", + database->mmdb.filename, MMDB_strerror(status)); + + continue; + } + + database->last_change = ngx_file_mtime(&fi); + MMDB_close(&database->mmdb); + database->mmdb = tmpdb; + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "Reload MMDB \"%s\"", + database->mmdb.filename); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip2_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_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_geoip2_log_handler; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-geoip2-3.4/ngx_stream_geoip2_module.c b/modules_deb/libnginx-mod-http-geoip2-3.4/ngx_stream_geoip2_module.c new file mode 100644 index 0000000..eb59082 --- /dev/null +++ b/modules_deb/libnginx-mod-http-geoip2-3.4/ngx_stream_geoip2_module.c @@ -0,0 +1,694 @@ +/* + * Copyright (C) Lee Valentine + * Copyright (C) Andrei Belov + * + * Based on nginx's 'ngx_stream_geoip_module.c' by Igor Sysoev + */ + + +#include +#include +#include + +#include + + +typedef struct { + MMDB_s mmdb; + MMDB_lookup_result_s result; + time_t last_check; + time_t last_change; + time_t check_interval; +#if (NGX_HAVE_INET6) + uint8_t address[16]; +#else + unsigned long address; +#endif + ngx_queue_t queue; +} ngx_stream_geoip2_db_t; + +typedef struct { + ngx_queue_t databases; +} ngx_stream_geoip2_conf_t; + +typedef struct { + ngx_stream_geoip2_db_t *database; + const char **lookup; + ngx_str_t default_value; + ngx_stream_complex_value_t source; +} ngx_stream_geoip2_ctx_t; + +typedef struct { + ngx_stream_geoip2_db_t *database; + ngx_str_t metavalue; +} ngx_stream_geoip2_metadata_t; + + +static ngx_int_t ngx_stream_geoip2_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip2_metadata(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static void *ngx_stream_geoip2_create_conf(ngx_conf_t *cf); +static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, + ngx_stream_geoip2_db_t *database); +static char *ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, + ngx_stream_geoip2_db_t *database); +static void ngx_stream_geoip2_cleanup(void *data); +static ngx_int_t ngx_stream_geoip2_init(ngx_conf_t *cf); + + +#define FORMAT(fmt, ...) do { \ + p = ngx_palloc(s->connection->pool, NGX_OFF_T_LEN); \ + if (p == NULL) { \ + return NGX_ERROR; \ + } \ + v->len = ngx_sprintf(p, fmt, __VA_ARGS__) - p; \ + v->data = p; \ +} while (0) + +static ngx_command_t ngx_stream_geoip2_commands[] = { + + { ngx_string("geoip2"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_stream_geoip2, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_geoip2_module_ctx = { + NULL, /* preconfiguration */ + ngx_stream_geoip2_init, /* postconfiguration */ + + ngx_stream_geoip2_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_geoip2_module = { + NGX_MODULE_V1, + &ngx_stream_geoip2_module_ctx, /* module context */ + ngx_stream_geoip2_commands, /* module directives */ + NGX_STREAM_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_stream_geoip2_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + int mmdb_error; + u_char *p; + ngx_str_t val; + ngx_addr_t addr; + MMDB_entry_data_s entry_data; + ngx_stream_geoip2_ctx_t *geoip2 = (ngx_stream_geoip2_ctx_t *) data; + ngx_stream_geoip2_db_t *database = geoip2->database; + +#if (NGX_HAVE_INET6) + uint8_t address[16], *addressp = address; +#else + unsigned long address; +#endif + + if (geoip2->source.value.len > 0) { + if (ngx_stream_complex_value(s, &geoip2->source, &val) != NGX_OK) { + goto not_found; + } + + if (ngx_parse_addr(s->connection->pool, &addr, val.data, val.len) != NGX_OK) { + goto not_found; + } + } else { + addr.sockaddr = s->connection->sockaddr; + addr.socklen = s->connection->socklen; + } + + switch (addr.sockaddr->sa_family) { + case AF_INET: +#if (NGX_HAVE_INET6) + ngx_memset(addressp, 0, 12); + ngx_memcpy(addressp + 12, &((struct sockaddr_in *) + addr.sockaddr)->sin_addr.s_addr, 4); + break; + + case AF_INET6: + ngx_memcpy(addressp, &((struct sockaddr_in6 *) + addr.sockaddr)->sin6_addr.s6_addr, 16); +#else + address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr; +#endif + break; + + default: + goto not_found; + } + +#if (NGX_HAVE_INET6) + if (ngx_memcmp(&address, &database->address, sizeof(address)) != 0) { +#else + if (address != database->address) { +#endif + memcpy(&database->address, &address, sizeof(address)); + database->result = MMDB_lookup_sockaddr(&database->mmdb, + addr.sockaddr, &mmdb_error); + + if (mmdb_error != MMDB_SUCCESS) { + goto not_found; + } + } + + if (!database->result.found_entry + || MMDB_aget_value(&database->result.entry, &entry_data, geoip2->lookup) + != MMDB_SUCCESS) + { + goto not_found; + } + + if (!entry_data.has_data) { + goto not_found; + } + + switch (entry_data.type) { + case MMDB_DATA_TYPE_BOOLEAN: + FORMAT("%d", entry_data.boolean); + break; + case MMDB_DATA_TYPE_UTF8_STRING: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(s->connection->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.utf8_string, v->len); + break; + case MMDB_DATA_TYPE_BYTES: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(s->connection->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.bytes, v->len); + break; + case MMDB_DATA_TYPE_FLOAT: + FORMAT("%.5f", entry_data.float_value); + break; + case MMDB_DATA_TYPE_DOUBLE: + FORMAT("%.5f", entry_data.double_value); + break; + case MMDB_DATA_TYPE_UINT16: + FORMAT("%uD", entry_data.uint16); + break; + case MMDB_DATA_TYPE_UINT32: + FORMAT("%uD", entry_data.uint32); + break; + case MMDB_DATA_TYPE_INT32: + FORMAT("%D", entry_data.int32); + break; + case MMDB_DATA_TYPE_UINT64: + FORMAT("%uL", entry_data.uint64); + break; + case MMDB_DATA_TYPE_UINT128: ; +#if MMDB_UINT128_IS_BYTE_ARRAY + uint8_t *val = (uint8_t *) entry_data.uint128; + FORMAT("0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + val[0], val[1], val[2], val[3], + val[4], val[5], val[6], val[7], + val[8], val[9], val[10], val[11], + val[12], val[13], val[14], val[15]); +#else + mmdb_uint128_t val = entry_data.uint128; + FORMAT("0x%016uxL%016uxL", + (uint64_t) (val >> 64), (uint64_t) val); +#endif + break; + default: + goto not_found; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + if (geoip2->default_value.len > 0) { + v->data = geoip2->default_value.data; + v->len = geoip2->default_value.len; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip2_metadata(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + ngx_stream_geoip2_metadata_t *metadata = (ngx_stream_geoip2_metadata_t *) data; + ngx_stream_geoip2_db_t *database = metadata->database; + u_char *p; + + if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) { + FORMAT("%uL", database->mmdb.metadata.build_epoch); + } else if (ngx_strncmp(metadata->metavalue.data, "last_check", 10) == 0) { + FORMAT("%T", database->last_check); + } else if (ngx_strncmp(metadata->metavalue.data, "last_change", 11) == 0) { + FORMAT("%T", database->last_change); + } else { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +static void * +ngx_stream_geoip2_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_stream_geoip2_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_conf_t)); + if (conf == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + ngx_queue_init(&conf->databases); + + cln->handler = ngx_stream_geoip2_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + int status; + char *rv; + ngx_str_t *value; + ngx_conf_t save; + ngx_stream_geoip2_db_t *database; + ngx_stream_geoip2_conf_t *gcf = conf; + ngx_queue_t *q; + + value = cf->args->elts; + + if (value[1].data && value[1].data[0] != '/') { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + if (!ngx_queue_empty(&gcf->databases)) { + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); + if (ngx_strcmp(value[1].data, database->mmdb.filename) == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "Duplicate GeoIP2 mmdb - %V", &value[1]); + return NGX_CONF_ERROR; + } + } + } + + database = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_db_t)); + if (database == NULL) { + return NGX_CONF_ERROR; + } + + ngx_queue_insert_tail(&gcf->databases, &database->queue); + database->last_check = database->last_change = ngx_time(); + + status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb); + + if (status != MMDB_SUCCESS) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "MMDB_open(\"%V\") failed - %s", &value[1], + MMDB_strerror(status)); + return NGX_CONF_ERROR; + } + + save = *cf; + cf->handler = ngx_stream_geoip2_parse_config; + cf->handler_conf = (void *) database; + + rv = ngx_conf_parse(cf, NULL); + *cf = save; + return rv; +} + + +static char * +ngx_stream_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_stream_geoip2_db_t *database; + ngx_str_t *value; + time_t interval; + + value = cf->args->elts; + + if (value[0].data[0] == '$') { + return ngx_stream_geoip2_add_variable(cf, dummy, conf); + } + + if (value[0].len == 11 + && ngx_strncmp(value[0].data, "auto_reload", 11) == 0) { + if ((int) cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of arguments for auto_reload"); + return NGX_CONF_ERROR; + } + + interval = ngx_parse_time(&value[1], true); + + if (interval == (time_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid interval for auto_reload \"%V\"", + value[1]); + return NGX_CONF_ERROR; + } + + + database = (ngx_stream_geoip2_db_t *) conf; + database->check_interval = interval; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\"", &value[0]); + return NGX_CONF_ERROR; +} + + +static char * +ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_stream_geoip2_db_t *database; + ngx_str_t *value; + int nelts; + + value = cf->args->elts; + + if (value[0].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + nelts = (int) cf->args->nelts; + database = (ngx_stream_geoip2_db_t *) conf; + + if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) { + return ngx_stream_geoip2_add_variable_metadata(cf, database); + } + + return ngx_stream_geoip2_add_variable_geodata(cf, database); +} + + +static char * +ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database) +{ + ngx_stream_geoip2_metadata_t *metadata; + ngx_str_t *value, name; + ngx_stream_variable_t *var; + + metadata = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_metadata_t)); + if (metadata == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + name = value[0]; + + metadata->database = database; + metadata->metavalue = value[2]; + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_stream_geoip2_metadata; + var->data = (uintptr_t) metadata; + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database) +{ + ngx_stream_geoip2_ctx_t *geoip2; + ngx_stream_compile_complex_value_t ccv; + ngx_str_t *value, name, source; + ngx_stream_variable_t *var; + int i, nelts, idx; + + geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_ctx_t)); + if (geoip2 == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->database = database; + ngx_str_null(&source); + + value = cf->args->elts; + name = value[0]; + + nelts = (int) cf->args->nelts; + idx = 1; + + if (nelts > idx) { + for (i = idx; i < nelts; i++) { + if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) { + break; + } + + if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) { + if (geoip2->default_value.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "default has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + geoip2->default_value.len = value[idx].len - 8; + geoip2->default_value.data = value[idx].data + 8; + + } else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) { + if (source.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "source has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + source.len = value[idx].len - 7; + source.data = value[idx].data + 7; + + if (source.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid source variable name \"%V\"", &source); + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + ccv.cf = cf; + ccv.value = &source; + ccv.complex_value = &geoip2->source; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unable to compile \"%V\" for \"$%V\"", &source, &name); + return NGX_CONF_ERROR; + } + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\" for \"$%V\"", &value[idx], &name); + return NGX_CONF_ERROR; + } + + idx++; + } + } + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->lookup = ngx_pcalloc(cf->pool, + sizeof(const char *) * (cf->args->nelts - (idx - 1))); + + if (geoip2->lookup == NULL) { + return NGX_CONF_ERROR; + } + + for (i = idx; i < nelts; i++) { + geoip2->lookup[i - idx] = (char *) value[i].data; + } + geoip2->lookup[i - idx] = NULL; + + var->get_handler = ngx_stream_geoip2_variable; + var->data = (uintptr_t) geoip2; + + return NGX_CONF_OK; +} + + +static void +ngx_stream_geoip2_cleanup(void *data) +{ + ngx_queue_t *q; + ngx_stream_geoip2_db_t *database; + ngx_stream_geoip2_conf_t *gcf = data; + + while (!ngx_queue_empty(&gcf->databases)) { + q = ngx_queue_head(&gcf->databases); + ngx_queue_remove(q); + database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); + MMDB_close(&database->mmdb); + } +} + + +static ngx_int_t +ngx_stream_geoip2_log_handler(ngx_stream_session_t *s) +{ + int status; + MMDB_s tmpdb; + ngx_queue_t *q; + ngx_file_info_t fi; + ngx_stream_geoip2_db_t *database; + ngx_stream_geoip2_conf_t *gcf; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "geoip2 stream log handler"); + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip2_module); + + if (ngx_queue_empty(&gcf->databases)) { + return NGX_OK; + } + + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); + if (database->check_interval == 0) { + continue; + } + + if ((database->last_check + database->check_interval) + > ngx_time()) + { + continue; + } + + database->last_check = ngx_time(); + + if (ngx_file_info(database->mmdb.filename, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, s->connection->log, ngx_errno, + ngx_file_info_n " \"%s\" failed", + database->mmdb.filename); + + continue; + } + + if (ngx_file_mtime(&fi) <= database->last_change) { + continue; + } + + /* do the reload */ + + ngx_memzero(&tmpdb, sizeof(MMDB_s)); + status = MMDB_open(database->mmdb.filename, MMDB_MODE_MMAP, &tmpdb); + + if (status != MMDB_SUCCESS) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "MMDB_open(\"%s\") failed to reload - %s", + database->mmdb.filename, MMDB_strerror(status)); + + continue; + } + + database->last_change = ngx_file_mtime(&fi); + MMDB_close(&database->mmdb); + database->mmdb = tmpdb; + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "Reload MMDB \"%s\"", + database->mmdb.filename); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip2_init(ngx_conf_t *cf) +{ + ngx_stream_handler_pt *h; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_geoip2_log_handler; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitattributes b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitattributes new file mode 100644 index 0000000..6fe6f35 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitattributes @@ -0,0 +1 @@ +*.t linguist-language=Text diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitignore b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitignore new file mode 100644 index 0000000..39c82fa --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.gitignore @@ -0,0 +1,54 @@ +reindex +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[78] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +genmobi.sh +*.mobi +misc/chunked +src/headers.c +src/headers.h +src/module.c +src/module.h +src/util.c +src/util.h +go +ctags +src/in.c +src/in.h +src/out.c +src/out.h +build[89] +build1[0-9] +buildroot/ +work/ +all +t/servroot +analyze +cov +nginx +*.plist +a.patch +Makefile diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.travis.yml b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.travis.yml new file mode 100644 index 0000000..6b346a8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/.travis.yml @@ -0,0 +1,58 @@ +sudo: required +dist: focal + +branches: + only: + - "master" + +os: linux + +language: c + +compiler: + - gcc + +addons: + apt: + packages: + - axel + - cpanminus + +env: + global: + - LUAJIT_PREFIX=/opt/luajit21 + - LUAJIT_LIB=$LUAJIT_PREFIX/lib + - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 + - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH + matrix: + - NGINX_VERSION=1.25.3 WITHOUT_PCRE2=1 + - NGINX_VERSION=1.27.1 WITHOUT_PCRE2=1 + +before_install: + - sudo apt-get update -y + - sudo apt-get install -y ca-certificates + - sudo cpanm -v --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1) + +install: + - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module + - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + - git clone https://github.com/openresty/nginx-eval-module.git ../eval-nginx-module + - git clone https://github.com/openresty/openresty.git ../openresty + - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + - git clone https://github.com/openresty/nginx-devel-utils.git + - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 + +before_script: + - cd luajit2/ + - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1) + - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) + - cd .. + +script: + - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH + - export NGX_BUILD_CC=$CC + - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - prove -I. -r t + diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/LICENSE b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/LICENSE new file mode 100644 index 0000000..c14f60a --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/LICENSE @@ -0,0 +1,20 @@ +This module is licensed under the terms of the BSD license. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/README.markdown b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/README.markdown new file mode 100644 index 0000000..6baea91 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/README.markdown @@ -0,0 +1,538 @@ +Name +==== + +**ngx_headers_more** - Set and clear input and output headers...more than "add"! + +*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). + +Table of Contents +================= + +* [Name](#name) +* [Version](#version) +* [Synopsis](#synopsis) +* [Description](#description) +* [Directives](#directives) + * [more_set_headers](#more_set_headers) + * [more_clear_headers](#more_clear_headers) + * [more_set_input_headers](#more_set_input_headers) + * [more_clear_input_headers](#more_clear_input_headers) +* [Limitations](#limitations) +* [Installation](#installation) +* [Compatibility](#compatibility) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Source Repository](#source-repository) +* [Changes](#changes) +* [Test Suite](#test-suite) +* [TODO](#todo) +* [Getting involved](#getting-involved) +* [Authors](#authors) +* [Copyright & License](#copyright--license) +* [See Also](#see-also) + +Version +======= + +This document describes headers-more-nginx-module [v0.34](https://github.com/openresty/headers-more-nginx-module/tags) released on 17 July 2022. + +Synopsis +======== + +```nginx + + # set the Server output header + more_set_headers 'Server: my-server'; + + # set and clear output headers + location /bar { + more_set_headers 'X-MyHeader: blah' 'X-MyHeader2: foo'; + more_set_headers -t 'text/plain text/css' 'Content-Type: text/foo'; + more_set_headers -s '400 404 500 503' -s 413 'Foo: Bar'; + more_clear_headers 'Content-Type'; + + # your proxy_pass/memcached_pass/or any other config goes here... + } + + # set output headers + location /type { + more_set_headers 'Content-Type: text/plain'; + # ... + } + + # set input headers + location /foo { + set $my_host 'my dog'; + more_set_input_headers 'Host: $my_host'; + more_set_input_headers -t 'text/plain' 'X-Foo: bah'; + + # now $host and $http_host have their new values... + # ... + } + + # replace input header X-Foo *only* if it already exists + more_set_input_headers -r 'X-Foo: howdy'; +``` + +Description +=========== + +This module allows you to add, set, or clear any output +or input header that you specify. + +This is an enhanced version of the standard +[headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module because it provides more utilities like +resetting or clearing "builtin headers" like `Content-Type`, +`Content-Length`, and `Server`. + +It also allows you to specify an optional HTTP status code +criteria using the `-s` option and an optional content +type criteria using the `-t` option while modifying the +output headers with the [more_set_headers](#more_set_headers) and +[more_clear_headers](#more_clear_headers) directives. For example, + +```nginx + more_set_headers -s 404 -t 'text/html' 'X-Foo: Bar'; +``` + +You can also specify multiple MIME types to filter out in a single `-t` option. +For example, + +```nginx +more_set_headers -t 'text/html text/plain' 'X-Foo: Bar'; +``` + +Never use other parameters like `charset=utf-8` in the `-t` option values; they will not +work as you would expect. + +Input headers can be modified as well. For example + +```nginx + location /foo { + more_set_input_headers 'Host: foo' 'User-Agent: faked'; + # now $host, $http_host, $user_agent, and + # $http_user_agent all have their new values. + } +``` + +The option `-t` is also available in the +[more_set_input_headers](#more_set_input_headers) and +[more_clear_input_headers](#more_clear_input_headers) directives (for request header filtering) while the `-s` option +is not allowed. + +Unlike the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module, this module's directives will by +default apply to all the status codes, including `4xx` and `5xx`. + +[Back to TOC](#table-of-contents) + +Directives +========== + +[Back to TOC](#table-of-contents) + +more_set_headers +---------------- +**syntax:** *more_set_headers [-t <content-type list>]... [-s <status-code list>]... [-a] <new-header>...* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +Replaces (if any) or adds (if not any) the specified output headers when the response status code matches the codes specified by the `-s` option *AND* the response content type matches the types specified by the `-t` option. + +If the "-a" option is specified, the specified output headers can be appended directly without clearing the old fields. The behavior of builtin headers such as "Content-Type", "Content-Length", "Server", etc. cannot be changed. + +If either `-s` or `-t` is not specified or has an empty list value, then no match is required. Therefore, the following directive set the `Server` output header to the custom value for *any* status code and *any* content type: + +```nginx + + more_set_headers "Server: my_server"; +``` + +Existing response headers with the same name are always overridden. If you want to add headers incrementally, use the standard [add_header](http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) directive instead. + +A single directive can set/add multiple output headers. For example + +```nginx + + more_set_headers 'Foo: bar' 'Baz: bah'; +``` + +Multiple occurrences of the options are allowed in a single directive. Their values will be merged together. For instance + +```nginx + + more_set_headers -s 404 -s '500 503' 'Foo: bar'; +``` + +is equivalent to + +```nginx + + more_set_headers -s '404 500 503' 'Foo: bar'; +``` + +The new header should be the one of the forms: + +1. `Name: Value` +1. `Name: ` +1. `Name` + +The last two effectively clear the value of the header `Name`. + +Nginx variables are allowed in header values. For example: + +```nginx + + set $my_var "dog"; + more_set_headers "Server: $my_var"; +``` + +But variables won't work in header keys due to performance considerations. + +Multiple set/clear header directives are allowed in a single location, and they're executed sequentially. + +Directives inherited from an upper level scope (say, http block or server blocks) are executed before the directives in the location block. + +Note that although `more_set_headers` is allowed in *location* if blocks, it is *not* allowed in the *server* if blocks, as in + +```nginx + + ? # This is NOT allowed! + ? server { + ? if ($args ~ 'download') { + ? more_set_headers 'Foo: Bar'; + ? } + ? ... + ? } +``` + +Behind the scene, use of this directive and its friend [more_clear_headers](#more_clear_headers) will (lazily) register an ouput header filter that modifies `r->headers_out` the way you specify. + +[Back to TOC](#table-of-contents) + +more_clear_headers +------------------ +**syntax:** *more_clear_headers [-t <content-type list>]... [-s <status-code list>]... <new-header>...* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +Clears the specified output headers. + +In fact, + +```nginx + + more_clear_headers -s 404 -t 'text/plain' Foo Baz; +``` + +is exactly equivalent to + +```nginx + + more_set_headers -s 404 -t 'text/plain' "Foo: " "Baz: "; +``` + +or + +```nginx + + more_set_headers -s 404 -t 'text/plain' Foo Baz +``` + +See [more_set_headers](#more_set_headers) for more details. + +The wildcard character, `*`, can also be used at the end of the header name to specify a pattern. For example, the following directive +effectively clears *any* output headers starting by "`X-Hidden-`": + +```nginx + + more_clear_headers 'X-Hidden-*'; +``` + +The `*` wildcard support was first introduced in [v0.09](#v009). + +[Back to TOC](#table-of-contents) + +more_set_input_headers +---------------------- +**syntax:** *more_set_input_headers [-r] [-t <content-type list>]... <new-header>...* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *rewrite tail* + +Very much like [more_set_headers](#more_set_headers) except that it operates on input headers (or request headers) and it only supports the `-t` option. + +Note that using the `-t` option in this directive means filtering by the `Content-Type` *request* header, rather than the response header. + +Behind the scene, use of this directive and its friend [more_clear_input_headers](#more_clear_input_headers) will (lazily) +register a `rewrite phase` handler that modifies `r->headers_in` the way you specify. Note that it always run at the *end* of +the `rewrite` phase so that it runs *after* the standard [rewrite module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) +and works in subrequests as well. + +If the `-r` option is specified, then the headers will be replaced to the new values *only if* they already exist. + +[Back to TOC](#table-of-contents) + +more_clear_input_headers +------------------------ +**syntax:** *more_clear_input_headers [-t <content-type list>]... <new-header>...* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *rewrite tail* + +Clears the specified input headers. + +In fact, + +```nginx + + more_clear_input_headers -t 'text/plain' Foo Baz; +``` + +is exactly equivalent to + +```nginx + + more_set_input_headers -t 'text/plain' "Foo: " "Baz: "; +``` + +or + +```nginx + + more_set_input_headers -t 'text/plain' Foo Baz +``` + +To remove request headers "Foo" and "Baz" for all incoming requests regardless of the content type, we can write + +```nginx + + more_clear_input_headers "Foo" "Baz"; +``` + +See [more_set_input_headers](#more_set_input_headers) for more details. + +The wildcard character, `*`, can also be used at the end of the header name to specify a pattern. For example, the following directive +effectively clears *any* input headers starting by "`X-Hidden-`": + +```nginx + + more_clear_input_headers 'X-Hidden-*'; +``` + +[Back to TOC](#table-of-contents) + +Limitations +=========== + +* Unlike the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module, this module does not automatically take care of the constraint among the `Expires`, `Cache-Control`, and `Last-Modified` headers. You have to get them right yourself or use the [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module together with this module. +* You cannot remove the `Connection` response header using this module because the `Connection` response header is generated by the standard `ngx_http_header_filter_module` in the Nginx core, whose output header filter runs always *after* the filter of this module. The only way to actually remove the `Connection` header is to patch the Nginx core, that is, editing the C function `ngx_http_header_filter` in the `src/http/ngx_http_header_filter_module.c` file. + +[Back to TOC](#table-of-contents) + +Installation +============ + +Grab the nginx source code from [nginx.org](http://nginx.org/), for example, +the version 1.17.8 (see [nginx compatibility](#compatibility)), and then build the source with this module: + +```bash + + wget 'http://nginx.org/download/nginx-1.17.8.tar.gz' + tar -xzvf nginx-1.17.8.tar.gz + cd nginx-1.17.8/ + + # Here we assume you would install you nginx under /opt/nginx/. + ./configure --prefix=/opt/nginx \ + --add-module=/path/to/headers-more-nginx-module + + make + make install +``` + +Download the latest version of the release tarball of this module from [headers-more-nginx-module file list](https://github.com/openresty/headers-more-nginx-module/tags). + +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ngx_http_headers_more_filter_module.so; +``` + +Also, this module is included and enabled by default in the [OpenResty bundle](http://openresty.org). + +[Back to TOC](#table-of-contents) + +Compatibility +============= + +The following versions of Nginx should work with this module: + +* **1.21.x** (last tested: 1.21.4) +* **1.19.x** (last tested: 1.19.9) +* **1.17.x** (last tested: 1.17.8) +* **1.16.x** +* **1.15.x** (last tested: 1.15.8) +* **1.14.x** +* **1.13.x** (last tested: 1.13.6) +* **1.12.x** +* **1.11.x** (last tested: 1.11.2) +* **1.10.x** +* **1.9.x** (last tested: 1.9.15) +* **1.8.x** +* **1.7.x** (last tested: 1.7.10) +* **1.6.x** (last tested: 1.6.2) +* **1.5.x** (last tested: 1.5.8) +* **1.4.x** (last tested: 1.4.4) +* **1.3.x** (last tested: 1.3.7) +* **1.2.x** (last tested: 1.2.9) +* **1.1.x** (last tested: 1.1.5) +* **1.0.x** (last tested: 1.0.11) +* **0.9.x** (last tested: 0.9.4) +* **0.8.x** (last tested: 0.8.54) +* **0.7.x >= 0.7.44** (last tested: 0.7.68) + +Earlier versions of Nginx like 0.6.x and 0.5.x will *not* work. + +If you find that any particular version of Nginx above 0.7.44 does not work with this module, please consider [reporting a bug](#report-bugs). + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please submit bug reports, wishlists, or patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/chaoslawful/lua-nginx-module/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Source Repository +================= + +Available on github at [openresty/headers-more-nginx-module](https://github.com/openresty/headers-more-nginx-module). + +[Back to TOC](#table-of-contents) + +Changes +======= + +The changes of every release of this module can be obtained from the OpenResty bundle's change logs: + + + +[Back to TOC](#table-of-contents) + +Test Suite +========== + +This module comes with a Perl-driven test suite. The [test cases](https://github.com/openresty/headers-more-nginx-module/tree/master/t/) are +[declarative](https://github.com/openresty/headers-more-nginx-module/blob/master/t/sanity.t) too. Thanks to the [Test::Nginx](http://search.cpan.org/perldoc?Test::Nginx) module in the Perl world. + +To run it on your side: + +```bash + + $ PATH=/path/to/your/nginx-with-headers-more-module:$PATH prove -r t +``` + +To run the test suite with valgrind's memcheck, use the following commands: + +```bash + + $ export PATH=/path/to/your/nginx-with-headers-more-module:$PATH + $ TEST_NGINX_USE_VALGRIND=1 prove -r t +``` + +You need to terminate any Nginx processes before running the test suite if you have changed the Nginx server binary. + +Because a single nginx server (by default, `localhost:1984`) is used across all the test scripts (`.t` files), it's meaningless to run the test suite in parallel by specifying `-jN` when invoking the `prove` utility. + +Some parts of the test suite requires modules [proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), and [echo](https://github.com/openresty/echo-nginx-module) to be enabled as well when building Nginx. + +[Back to TOC](#table-of-contents) + +TODO +==== + +* Support variables in new headers' keys. + +[Back to TOC](#table-of-contents) + +Getting involved +================ + +You'll be very welcomed to submit patches to the [author](#author) or just ask for a commit bit to the [source repository](#source-repository) on GitHub. + +[Back to TOC](#table-of-contents) + +Authors +======= + +* Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, OpenResty Inc. +* Bernd Dorn ( ) + +This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. + +[Back to TOC](#table-of-contents) + +Copyright & License +=================== + +The code base is borrowed directly from the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module in Nginx 0.8.24. This part of code is copyrighted by Igor Sysoev. + +Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. + +Copyright (c) 2010-2013, Bernd Dorn. + +The license text is available in the [LICENSE](LICENSE) file located in the root directory of the project. + +[Back to TOC](#table-of-contents) + +See Also +======== + +* The original thread on the Nginx mailing list that inspires this module's development: ["A question about add_header replication"](http://forum.nginx.org/read.php?2,11206,11738). +* The orginal announcement thread on the Nginx mailing list: ["The "headers_more" module: Set and clear output headers...more than 'add'!"](http://forum.nginx.org/read.php?2,23460). +* The original [blog post](http://agentzh.blogspot.com/2009/11/headers-more-module-scripting-input-and.html) about this module's initial development. +* The [echo module](https://github.com/openresty/echo-nginx-module) for Nginx module's automated testing. +* The standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module. + +[Back to TOC](#table-of-contents) + diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/config b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/config new file mode 100644 index 0000000..5707cc4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/config @@ -0,0 +1,32 @@ +ngx_addon_name=ngx_http_headers_more_filter_module + +HEADERS_MORE_SRCS=" \ + $ngx_addon_dir/src/ngx_http_headers_more_filter_module.c \ + $ngx_addon_dir/src/ngx_http_headers_more_headers_out.c \ + $ngx_addon_dir/src/ngx_http_headers_more_headers_in.c \ + $ngx_addon_dir/src/ngx_http_headers_more_util.c \ + " + +HEADERS_MORE_DEPS=" \ + $ngx_addon_dir/src/ddebug.h \ + $ngx_addon_dir/src/ngx_http_headers_more_filter_module.h \ + $ngx_addon_dir/src/ngx_http_headers_more_headers_in.h \ + $ngx_addon_dir/src/ngx_http_headers_more_headers_out.h \ + $ngx_addon_dir/src/ngx_http_headers_more_headers_in.h \ + $ngx_addon_dir/src/ngx_http_headers_more_util.h \ + " + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP_AUX_FILTER + ngx_module_name=$ngx_addon_name + ngx_module_incs= + ngx_module_deps="$HEADERS_MORE_DEPS" + ngx_module_srcs="$HEADERS_MORE_SRCS" + ngx_module_libs= + + . auto/module +else + HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HEADERS_MORE_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HEADERS_MORE_DEPS" +fi diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/changelog b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/changelog new file mode 100644 index 0000000..0fd56e3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/changelog @@ -0,0 +1,72 @@ +libnginx-mod-http-headers-more-filter (1:0.38-2) unstable; urgency=medium + + * d/control: bump Standards-Version: 4.7.2, no changes + + -- Jan Mojžíš Fri, 11 Apr 2025 14:26:59 +0200 + +libnginx-mod-http-headers-more-filter (1:0.38-1) unstable; urgency=medium + + * New upstream version 0.38 + * d/{control,copyright}: update my email to "janmojzis@debian.org" + * d/copyright: bump debian/* copyright year + * d/watch: use more generic template + * d/control: bump Standards-Version: 4.7.0, no changes + + -- Jan Mojžíš Mon, 10 Feb 2025 19:20:06 +0100 + +libnginx-mod-http-headers-more-filter (1:0.37-2) unstable; urgency=medium + + * d/watch: use new recommended github template + + -- Jan Mojžíš Sat, 13 Jan 2024 22:22:57 +0100 + +libnginx-mod-http-headers-more-filter (1:0.37-1) unstable; urgency=medium + + * New upstream version 0.37 + * d/gbp.conf: add [pull] track-missing = True + * d/copyright: bump my copyright year + * d/watch: remove filenamemangle + + -- Jan Mojžíš Sun, 07 Jan 2024 23:40:37 +0100 + +libnginx-mod-http-headers-more-filter (1:0.36-1) unstable; urgency=medium + + * New upstream version 0.36 + + -- Jan Mojžíš Mon, 18 Dec 2023 16:55:54 +0100 + +libnginx-mod-http-headers-more-filter (1:0.34-5) unstable; urgency=medium + + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + + -- Jan Mojžíš Sat, 07 Oct 2023 15:31:27 +0200 + +libnginx-mod-http-headers-more-filter (1:0.34-4) unstable; urgency=medium + + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Tue, 27 Jun 2023 23:16:38 +0200 + +libnginx-mod-http-headers-more-filter (1:0.34-3) unstable; urgency=medium + + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/gbb.conf: switched to debian branch main (debian-branch = main) + * d/copyright: bump my copyright year + * d/copyright: reformat text to be compatible with 'cme update dpkg-copyright' + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 12:56:26 +0100 + +libnginx-mod-http-headers-more-filter (1:0.34-2) unstable; urgency=medium + + * d/control: added Multi-Arch: foreign + + -- Jan Mojžíš Fri, 09 Dec 2022 12:50:28 +0100 + +libnginx-mod-http-headers-more-filter (1:0.34-1) experimental; urgency=medium + + * Initial release. (Closes: 1024151) + + -- Jan Mojžíš Wed, 30 Nov 2022 14:46:53 +0100 diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/control b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/control new file mode 100644 index 0000000..a8ebd83 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/control @@ -0,0 +1,26 @@ +Source: libnginx-mod-http-headers-more-filter +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jan Mojžíš , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, +Standards-Version: 4.7.2 +Homepage: https://github.com/openresty/headers-more-nginx-module +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-headers-more-filter.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-headers-more-filter +Rules-Requires-Root: no + +Package: libnginx-mod-http-headers-more-filter +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: Set and clear input and output headers for Nginx + The Headers More module allows you to add, set, or clear any output or input + header that you specify. + . + This is an enhanced version of the standard headers module because it provides + more utilities like resetting or clearing "builtin headers" like Content-Type, + Content-Length, and Server. diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/copyright b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/copyright new file mode 100644 index 0000000..251922c --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/copyright @@ -0,0 +1,62 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: headers-more-nginx-module +Upstream-Contact: Yichun "agentzh" Zhang (章亦春) +Source: https://github.com/openresty/headers-more-nginx-module + +Files: * +Copyright: 2010-2013, Bernd Dorn. + 2009-2017, Yichun "agentzh" Zhang (\x{7ae0}\x{4ea6}\x{6625}) , OpenResty Inc. +License: BSD-2-clause + +Files: config +Copyright: Igor Sysoev + 2010-2013, Bernd Dorn + 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +License: BSD-2-clause + +Files: debian/* +Copyright: 2022, Miao Wang + 2022-2025, Jan Mojzis +License: BSD-2-clause + +Files: src/* +Copyright: Yichun Zhang (agentzh) +License: BSD-2-clause + +Files: src/ddebug.h +Copyright: Igor Sysoev + 2010-2013, Bernd Dorn + 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +License: BSD-2-clause + +Files: t/* +Copyright: Igor Sysoev + 2010-2013, Bernd Dorn + 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +License: BSD-2-clause + +Files: util/* +Copyright: Igor Sysoev + 2010-2013, Bernd Dorn + 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +License: BSD-2-clause + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/gbp.conf b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/gbp.conf new file mode 100644 index 0000000..97cd209 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/gbp.conf @@ -0,0 +1,12 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace + +[pull] +track-missing = True diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/rules b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/rules new file mode 100755 index 0000000..d8309f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/source/format b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/control b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/control new file mode 100644 index 0000000..b95c6ff --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/control @@ -0,0 +1,13 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, + +Tests: helloworld +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/generic b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/helloworld b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/helloworld new file mode 100644 index 0000000..6a2e85b --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/tests/helloworld @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +cat < "/etc/nginx/sites-enabled/default" +server { + listen 80 default_server; + + location /helloworld { + more_set_headers 'Content-Type: text/helloworld'; + more_set_headers -s '200' 'Content-Type: text/helloworld200'; + return 200; + } +} +EOF + +exp="content_type: text/helloworld200 +response_code: 200" + +nginx -t +invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; } + +out=`curl --fail -w "content_type: %{content_type}\nresponse_code: %{http_code}\n" http://127.0.0.1/helloworld` + +if [ x"${out}" != x"${exp}" ]; then + echo "output:" + echo "=====================" + echo "${out}" + echo "=====================" + echo "expected output:" + echo "=====================" + echo "${exp}" + echo "=====================" + exit 1 +fi diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/upstream/metadata b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/upstream/metadata new file mode 100644 index 0000000..185ca21 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/openresty/headers-more-nginx-module/issues +Bug-Submit: https://github.com/openresty/headers-more-nginx-module/issues/new +Repository-Browse: https://github.com/openresty/headers-more-nginx-module diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/watch b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/watch new file mode 100644 index 0000000..426294e --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/openresty/headers-more-nginx-module/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ddebug.h b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ddebug.h new file mode 100644 index 0000000..13879af --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ddebug.h @@ -0,0 +1,124 @@ +#ifndef DDEBUG_H +#define DDEBUG_H + + +#include +#include +#include +#include + + +#if defined(DDEBUG) && (DDEBUG) + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) fprintf(stderr, "headers-more *** %s: ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) + +# else + +#include +#include + +#include + +static ngx_inline void +dd(const char * fmt, ...) { +} + +# endif + +# if DDEBUG > 1 + +# define dd_enter() dd_enter_helper(r, __func__) + +# if defined(nginx_version) && nginx_version >= 8011 +# define dd_main_req_count r->main->count +# else +# define dd_main_req_count 0 +# endif + +static ngx_inline void +dd_enter_helper(ngx_http_request_t *r, const char *func) +{ + ngx_http_posted_request_t *pr; + + fprintf(stderr, "headers-more *** enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", + func, + (int) r->method_name.len, r->method_name.data, + (int) r->uri.len, r->uri.data, + (int) r->args.len, r->args.data, + (int) dd_main_req_count, r->main, + r, r->connection->data, r->parent); + + if (r->posted_requests) { + fprintf(stderr, " posted:"); + + for (pr = r->posted_requests; pr; pr = pr->next) { + fprintf(stderr, "%p,", pr); + } + } + + fprintf(stderr, "\n"); +} + +# else + +# define dd_enter() + +# endif + +#else + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) + +# define dd_enter() + +# else + +#include + +static ngx_inline void +dd(const char * fmt, ...) { +} + +static ngx_inline void +dd_enter() { +} + +# endif + +#endif + +#if defined(DDEBUG) && (DDEBUG) + +#define dd_check_read_event_handler(r) \ + dd("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#define dd_check_write_event_handler(r) \ + dd("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + +#define dd_check_read_event_handler(r) +#define dd_check_write_event_handler(r) + +#endif + +#endif /* DDEBUG_H */ + diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.c b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.c new file mode 100644 index 0000000..0bb6fec --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.c @@ -0,0 +1,348 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_headers_more_filter_module.h" +#include "ngx_http_headers_more_headers_out.h" +#include "ngx_http_headers_more_headers_in.h" +#include "ngx_http_headers_more_util.h" +#include + + +/* config handlers */ + +static void *ngx_http_headers_more_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_headers_more_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static void *ngx_http_headers_more_create_main_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_headers_more_post_config(ngx_conf_t *cf); + +/* post-read-phase handler */ + +static ngx_int_t ngx_http_headers_more_handler(ngx_http_request_t *r); + +/* filter handlers */ + +static ngx_int_t ngx_http_headers_more_filter_init(ngx_conf_t *cf); + +ngx_uint_t ngx_http_headers_more_location_hash = 0; + + +static ngx_command_t ngx_http_headers_more_filter_commands[] = { + + { ngx_string("more_set_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE, + ngx_http_headers_more_set_headers, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + { ngx_string("more_clear_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE, + ngx_http_headers_more_clear_headers, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + { ngx_string("more_set_input_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE, + ngx_http_headers_more_set_input_headers, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + { ngx_string("more_clear_input_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE, + ngx_http_headers_more_clear_input_headers, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_headers_more_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_headers_more_post_config, /* postconfiguration */ + + ngx_http_headers_more_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_headers_more_create_loc_conf, /* create location configuration */ + ngx_http_headers_more_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_headers_more_filter_module = { + NGX_MODULE_V1, + &ngx_http_headers_more_filter_module_ctx, /* module context */ + ngx_http_headers_more_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; + + +static volatile ngx_cycle_t *ngx_http_headers_more_prev_cycle = NULL; + + +static ngx_int_t +ngx_http_headers_more_filter(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_uint_t i; + ngx_http_headers_more_loc_conf_t *conf; + ngx_http_headers_more_cmd_t *cmd; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "headers more header filter, uri \"%V\"", &r->uri); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_more_filter_module); + + if (conf->cmds) { + cmd = conf->cmds->elts; + for (i = 0; i < conf->cmds->nelts; i++) { + if (cmd[i].is_input) { + continue; + } + + rc = ngx_http_headers_more_exec_cmd(r, &cmd[i]); + + if (rc != NGX_OK) { + return rc; + } + } + } + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_headers_more_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_headers_more_filter; + + return NGX_OK; +} + + +static void * +ngx_http_headers_more_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_headers_more_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_more_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->cmds = NULL; + */ + + return conf; +} + + +static char * +ngx_http_headers_more_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_uint_t i; + ngx_uint_t orig_len; + ngx_http_headers_more_cmd_t *prev_cmd, *cmd; + ngx_http_headers_more_loc_conf_t *prev = parent; + ngx_http_headers_more_loc_conf_t *conf = child; + + if (conf->cmds == NULL || conf->cmds->nelts == 0) { + conf->cmds = prev->cmds; + + } else if (prev->cmds && prev->cmds->nelts) { + orig_len = conf->cmds->nelts; + + (void) ngx_array_push_n(conf->cmds, prev->cmds->nelts); + + cmd = conf->cmds->elts; + + for (i = 0; i < orig_len; i++) { + cmd[conf->cmds->nelts - 1 - i] = cmd[orig_len - 1 - i]; + } + + prev_cmd = prev->cmds->elts; + + for (i = 0; i < prev->cmds->nelts; i++) { + cmd[i] = prev_cmd[i]; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_headers_more_post_config(ngx_conf_t *cf) +{ + int multi_http_blocks; + ngx_int_t rc; + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + ngx_http_headers_more_main_conf_t *hmcf; + + ngx_http_headers_more_location_hash = + ngx_http_headers_more_hash_literal("location"); + + hmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_headers_more_filter_module); + + if (ngx_http_headers_more_prev_cycle != ngx_cycle) { + ngx_http_headers_more_prev_cycle = ngx_cycle; + multi_http_blocks = 0; + + } else { + multi_http_blocks = 1; + } + + if (multi_http_blocks || hmcf->requires_filter) { + rc = ngx_http_headers_more_filter_init(cf); + if (rc != NGX_OK) { + return rc; + } + } + + if (!hmcf->requires_handler) { + return NGX_OK; + } + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_headers_more_handler; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_headers_more_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_uint_t i; + ngx_http_headers_more_loc_conf_t *conf; + ngx_http_headers_more_main_conf_t *hmcf; + ngx_http_headers_more_cmd_t *cmd; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "headers more rewrite handler, uri \"%V\"", &r->uri); + + hmcf = ngx_http_get_module_main_conf(r, + ngx_http_headers_more_filter_module); + + if (!hmcf->postponed_to_phase_end) { + ngx_http_core_main_conf_t *cmcf; + ngx_http_phase_handler_t tmp; + ngx_http_phase_handler_t *ph; + ngx_http_phase_handler_t *cur_ph; + ngx_http_phase_handler_t *last_ph; + + hmcf->postponed_to_phase_end = 1; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + ph = cmcf->phase_engine.handlers; + cur_ph = &ph[r->phase_handler]; + last_ph = &ph[cur_ph->next - 1]; + + if (cur_ph < last_ph) { + dd("swaping the contents of cur_ph and last_ph..."); + + tmp = *cur_ph; + + memmove(cur_ph, cur_ph + 1, + (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); + + *last_ph = tmp; + + r->phase_handler--; /* redo the current ph */ + + return NGX_DECLINED; + } + } + + dd("running phase handler..."); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_more_filter_module); + + if (conf->cmds) { + if (r->http_version < NGX_HTTP_VERSION_10) { + return NGX_DECLINED; + } + + cmd = conf->cmds->elts; + for (i = 0; i < conf->cmds->nelts; i++) { + if (!cmd[i].is_input) { + continue; + } + + rc = ngx_http_headers_more_exec_input_cmd(r, &cmd[i]); + + if (rc != NGX_OK) { + return rc; + } + } + } + + return NGX_DECLINED; +} + + +static void * +ngx_http_headers_more_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_headers_more_main_conf_t *hmcf; + + hmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_more_main_conf_t)); + if (hmcf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * hmcf->postponed_to_phase_end = 0; + * hmcf->requires_filter = 0; + * hmcf->requires_handler = 0; + */ + + return hmcf; +} diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.h b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.h new file mode 100644 index 0000000..5f31ab4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_filter_module.h @@ -0,0 +1,81 @@ + +/* + * Copyright (c) Yichun Zhang (agentzh) + */ + + +#ifndef NGX_HTTP_HEADERS_MORE_FILTER_MODULE_H +#define NGX_HTTP_HEADERS_MORE_FILTER_MODULE_H + + +#include +#include +#include + + +typedef enum { + ngx_http_headers_more_opcode_set, + ngx_http_headers_more_opcode_clear +} ngx_http_headers_more_opcode_t; + + +typedef struct { + ngx_array_t *types; /* of ngx_str_t */ + ngx_array_t *statuses; /* of ngx_uint_t */ + ngx_array_t *headers; /* of ngx_http_header_val_t */ + ngx_flag_t is_input; +} ngx_http_headers_more_cmd_t; + + +typedef struct { + ngx_array_t *cmds; /* of ngx_http_headers_more_cmd_t */ +} ngx_http_headers_more_loc_conf_t; + + +typedef struct { + ngx_int_t postponed_to_phase_end; + ngx_int_t requires_filter; + ngx_int_t requires_handler; +} ngx_http_headers_more_main_conf_t; + + +typedef struct ngx_http_headers_more_header_val_s + ngx_http_headers_more_header_val_t; + + +typedef ngx_int_t (*ngx_http_headers_more_set_header_pt)(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); + + +typedef struct { + ngx_str_t name; + ngx_uint_t offset; + ngx_http_headers_more_set_header_pt handler; +} ngx_http_headers_more_set_header_t; + + +struct ngx_http_headers_more_header_val_s { + ngx_http_complex_value_t value; + ngx_uint_t hash; + ngx_str_t key; + ngx_http_headers_more_set_header_pt handler; + ngx_uint_t offset; + unsigned replace:1; + unsigned wildcard:1; + unsigned append:1; +}; + + +extern ngx_module_t ngx_http_headers_more_filter_module; + + +#ifndef ngx_str_set +#define ngx_str_set(str, text) \ + (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text +#endif + + +#define ngx_http_headers_more_assert(a) assert(a) + + +#endif /* NGX_HTTP_HEADERS_MORE_FILTER_MODULE_H */ diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.c b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.c new file mode 100644 index 0000000..983be5b --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.c @@ -0,0 +1,959 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_headers_more_headers_in.h" +#include "ngx_http_headers_more_util.h" +#include + + +static char *ngx_http_headers_more_parse_directive(ngx_conf_t *cf, + ngx_command_t *ngx_cmd, void *conf, + ngx_http_headers_more_opcode_t opcode); +static int ngx_http_headers_more_check_type(ngx_http_request_t *r, + ngx_array_t *types); +static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, + ngx_table_elt_t **output_header); +static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_headers_more_validate_host(ngx_str_t *host, + ngx_pool_t *pool, ngx_uint_t alloc); + + +static ngx_http_headers_more_set_header_t ngx_http_headers_more_set_handlers[] + = { + + { ngx_string("Host"), + offsetof(ngx_http_headers_in_t, host), + ngx_http_set_host_header }, + + { ngx_string("Connection"), + offsetof(ngx_http_headers_in_t, connection), + ngx_http_set_connection_header }, + + { ngx_string("If-Modified-Since"), + offsetof(ngx_http_headers_in_t, if_modified_since), + ngx_http_set_builtin_header }, + +#if defined(nginx_version) && nginx_version >= 9002 + { ngx_string("If-Unmodified-Since"), + offsetof(ngx_http_headers_in_t, if_unmodified_since), + ngx_http_set_builtin_header }, +#endif + +#if defined(nginx_version) && nginx_version >= 1003003 + { ngx_string("If-Match"), + offsetof(ngx_http_headers_in_t, if_match), + ngx_http_set_builtin_header }, + + { ngx_string("If-None-Match"), + offsetof(ngx_http_headers_in_t, if_none_match), + ngx_http_set_builtin_header }, +#endif + + { ngx_string("User-Agent"), + offsetof(ngx_http_headers_in_t, user_agent), + ngx_http_set_user_agent_header }, + + { ngx_string("Referer"), + offsetof(ngx_http_headers_in_t, referer), + ngx_http_set_builtin_header }, + + { ngx_string("Content-Length"), + offsetof(ngx_http_headers_in_t, content_length), + ngx_http_set_content_length_header }, + + { ngx_string("Content-Type"), + offsetof(ngx_http_headers_in_t, content_type), + ngx_http_set_builtin_header }, + + { ngx_string("Range"), + offsetof(ngx_http_headers_in_t, range), + ngx_http_set_builtin_header }, + + { ngx_string("If-Range"), + offsetof(ngx_http_headers_in_t, if_range), + ngx_http_set_builtin_header }, + + { ngx_string("Transfer-Encoding"), + offsetof(ngx_http_headers_in_t, transfer_encoding), + ngx_http_set_builtin_header }, + + { ngx_string("Expect"), + offsetof(ngx_http_headers_in_t, expect), + ngx_http_set_builtin_header }, + +#if defined(nginx_version) && nginx_version >= 1003013 + { ngx_string("Upgrade"), + offsetof(ngx_http_headers_in_t, upgrade), + ngx_http_set_builtin_header }, +#endif + +#if (NGX_HTTP_GZIP) + { ngx_string("Accept-Encoding"), + offsetof(ngx_http_headers_in_t, accept_encoding), + ngx_http_set_builtin_header }, + + { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via), + ngx_http_set_builtin_header }, +#endif + + { ngx_string("Authorization"), + offsetof(ngx_http_headers_in_t, authorization), + ngx_http_set_builtin_header }, + + { ngx_string("Keep-Alive"), + offsetof(ngx_http_headers_in_t, keep_alive), + ngx_http_set_builtin_header }, + +#if (NGX_HTTP_X_FORWARDED_FOR) + { ngx_string("X-Forwarded-For"), + offsetof(ngx_http_headers_in_t, x_forwarded_for), + ngx_http_set_builtin_multi_header }, + +#endif + +#if (NGX_HTTP_REALIP) + { ngx_string("X-Real-IP"), + offsetof(ngx_http_headers_in_t, x_real_ip), + ngx_http_set_builtin_header }, +#endif + +#if (NGX_HTTP_DAV) + { ngx_string("Depth"), offsetof(ngx_http_headers_in_t, depth), + ngx_http_set_builtin_header }, + + { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination), + ngx_http_set_builtin_header }, + + { ngx_string("Overwrite"), offsetof(ngx_http_headers_in_t, overwrite), + ngx_http_set_builtin_header }, + + { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date), + ngx_http_set_builtin_header }, +#endif + +#if defined(nginx_version) && nginx_version >= 1023000 + { ngx_string("Cookie"), + offsetof(ngx_http_headers_in_t, cookie), + ngx_http_set_builtin_multi_header }, +#else + { ngx_string("Cookie"), + offsetof(ngx_http_headers_in_t, cookies), + ngx_http_set_builtin_multi_header }, +#endif + + { ngx_null_string, 0, ngx_http_set_header } +}; + + +ngx_int_t +ngx_http_headers_more_exec_input_cmd(ngx_http_request_t *r, + ngx_http_headers_more_cmd_t *cmd) +{ + ngx_str_t value; + ngx_http_headers_more_header_val_t *h; + ngx_uint_t i; + + if (!cmd->headers) { + return NGX_OK; + } + + if (cmd->types && !ngx_http_headers_more_check_type(r, cmd->types)) { + return NGX_OK; + } + + h = cmd->headers->elts; + for (i = 0; i < cmd->headers->nelts; i++) { + + if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { + return NGX_ERROR; + } + + if (value.len) { + value.len--; /* remove the trailing '\0' added by + ngx_http_headers_more_parse_header */ + } + + if (h[i].handler(r, &h[i], &value) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + return ngx_http_set_header_helper(r, hv, value, NULL); +} + + +static ngx_int_t +ngx_http_set_header_helper(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, + ngx_table_elt_t **output_header) +{ + ngx_table_elt_t *h, *matched; + ngx_list_part_t *part; + ngx_uint_t i; + ngx_uint_t rc; + + dd_enter(); + + matched = NULL; + +retry: + + part = &r->headers_in.headers.part; + h = part->elts; + + for (i = 0; /* void */; i++) { + dd("i: %d, part: %p", (int) i, part); + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + if (!hv->wildcard + && h[i].key.len == hv->key.len + && ngx_strncasecmp(h[i].key.data, hv->key.data, + h[i].key.len) == 0) + { + goto matched; + } + + if (hv->wildcard + && value->len == 0 + && h[i].key.len >= hv->key.len - 1 + && ngx_strncasecmp(h[i].key.data, hv->key.data, + hv->key.len - 1) == 0) + { + goto matched; + } + + /* not matched */ + continue; + +matched: + + if (value->len == 0 || (matched && matched != &h[i])) { + h[i].hash = 0; + + rc = ngx_http_headers_more_rm_header_helper( + &r->headers_in.headers, part, i); + + ngx_http_headers_more_assert( + !(r->headers_in.headers.part.next == NULL + && r->headers_in.headers.last + != &r->headers_in.headers.part)); + + if (rc == NGX_OK) { + if (output_header) { + *output_header = NULL; + } + + goto retry; + } + + return NGX_ERROR; + } + + h[i].value = *value; + + if (output_header) { + *output_header = &h[i]; + dd("setting existing builtin input header"); + } + + if (matched == NULL) { + matched = &h[i]; + } + } + + if (matched) { + return NGX_OK; + } + + if (value->len == 0 || hv->replace) { + return NGX_OK; + } + + if (r->headers_in.headers.last == NULL) { + /* must be 400 bad request */ + return NGX_OK; + } + + h = ngx_list_push(&r->headers_in.headers); + + if (h == NULL) { + return NGX_ERROR; + } + + dd("created new header for %.*s", (int) hv->key.len, hv->key.data); + + if (value->len == 0) { + h->hash = 0; + + } else { + h->hash = hv->hash; + } + + h->key = hv->key; + h->value = *value; +#if defined(nginx_version) && nginx_version >= 1023000 + h->next = NULL; +#endif + + h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); + if (h->lowcase_key == NULL) { + return NGX_ERROR; + } + + ngx_strlow(h->lowcase_key, h->key.data, h->key.len); + + if (output_header) { + *output_header = h; + + while (r != r->main) { + r->parent->headers_in = r->headers_in; + r = r->parent; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + ngx_table_elt_t *h, **old; + + dd("entered set_builtin_header (input)"); + + if (hv->offset) { + old = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset); + + } else { + old = NULL; + } + + dd("old builtin ptr ptr: %p", old); + if (old) { + dd("old builtin ptr: %p", *old); + } + + if (old == NULL || *old == NULL) { + dd("set normal header"); + return ngx_http_set_header_helper(r, hv, value, old); + } + + h = *old; + + if (value->len == 0) { + h->hash = 0; + h->value = *value; + + return ngx_http_set_header_helper(r, hv, value, old); + } + + h->hash = hv->hash; + h->value = *value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_host_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + ngx_str_t host; + + if (value->len) { + host= *value; + + if (ngx_http_headers_more_validate_host(&host, r->pool, 0) != NGX_OK) { + return NGX_ERROR; + } + + r->headers_in.server = host; + + } else { + r->headers_in.server = *value; + } + + return ngx_http_set_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_set_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + off_t len; + + if (value->len == 0) { + return ngx_http_clear_content_length_header(r, hv, value); + } + + len = ngx_atosz(value->data, value->len); + if (len == NGX_ERROR) { + return NGX_ERROR; + } + + dd("reset headers_in.content_length_n to %d", (int) len); + + r->headers_in.content_length_n = len; + + return ngx_http_set_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_clear_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + r->headers_in.content_length_n = -1; + + return ngx_http_clear_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_clear_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + value->len = 0; + return ngx_http_set_builtin_header(r, hv, value); +} + + +char * +ngx_http_headers_more_set_input_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + return ngx_http_headers_more_parse_directive(cf, cmd, conf, + ngx_http_headers_more_opcode_set); +} + + +char * +ngx_http_headers_more_clear_input_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + return ngx_http_headers_more_parse_directive(cf, cmd, conf, + ngx_http_headers_more_opcode_clear); +} + + +static int +ngx_http_headers_more_check_type(ngx_http_request_t *r, ngx_array_t *types) +{ + ngx_uint_t i; + ngx_str_t *t; + ngx_str_t actual_type; + + if (r->headers_in.content_type == NULL) { + return 0; + } + + actual_type = r->headers_in.content_type->value; + if (actual_type.len == 0) { + return 0; + } + + dd("headers_in->content_type: %.*s", + (int) actual_type.len, + actual_type.data); + + t = types->elts; + for (i = 0; i < types->nelts; i++) { + dd("...comparing with type [%.*s]", (int) t[i].len, t[i].data); + + if (actual_type.len == t[i].len + && ngx_strncmp(actual_type.data, t[i].data, t[i].len) == 0) + { + return 1; + } + } + + return 0; +} + + +static char * +ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd, + void *conf, ngx_http_headers_more_opcode_t opcode) +{ + ngx_http_headers_more_loc_conf_t *hlcf = conf; + + ngx_uint_t i; + ngx_http_headers_more_cmd_t *cmd; + ngx_str_t *arg; + ngx_flag_t ignore_next_arg; + ngx_str_t *cmd_name; + ngx_int_t rc; + ngx_flag_t replace = 0; + ngx_http_headers_more_header_val_t *h; + + ngx_http_headers_more_main_conf_t *hmcf; + + if (hlcf->cmds == NULL) { + hlcf->cmds = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_headers_more_cmd_t)); + + if (hlcf->cmds == NULL) { + return NGX_CONF_ERROR; + } + } + + cmd = ngx_array_push(hlcf->cmds); + + if (cmd == NULL) { + return NGX_CONF_ERROR; + } + + cmd->headers = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_headers_more_header_val_t)); + + if (cmd->headers == NULL) { + return NGX_CONF_ERROR; + } + + cmd->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); + if (cmd->types == NULL) { + return NGX_CONF_ERROR; + } + + cmd->statuses = NULL; + + arg = cf->args->elts; + + cmd_name = &arg[0]; + + ignore_next_arg = 0; + + for (i = 1; i < cf->args->nelts; i++) { + if (ignore_next_arg) { + ignore_next_arg = 0; + continue; + } + + if (arg[i].len == 0) { + continue; + } + + if (arg[i].data[0] != '-') { + rc = ngx_http_headers_more_parse_header(cf, cmd_name, + &arg[i], cmd->headers, + opcode, + ngx_http_headers_more_set_handlers); + + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + + continue; + } + + if (arg[i].len == 2) { + if (arg[i].data[1] == 't') { + if (i == cf->args->nelts - 1) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: option -t takes an argument.", + cmd_name); + + return NGX_CONF_ERROR; + } + + rc = ngx_http_headers_more_parse_types(cf->log, cmd_name, + &arg[i + 1], + cmd->types); + + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + + ignore_next_arg = 1; + + continue; + } + + if (arg[i].data[1] == 'r') { + dd("Found replace flag"); + replace = 1; + continue; + } + } + + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: invalid option name: \"%V\"", cmd_name, &arg[i]); + + return NGX_CONF_ERROR; + } + + dd("Found %d types, and %d headers", + (int) cmd->types->nelts, + (int) cmd->headers->nelts); + + if (cmd->headers->nelts == 0) { + ngx_pfree(cf->pool, cmd->headers); + cmd->headers = NULL; + + } else { + h = cmd->headers->elts; + for (i = 0; i < cmd->headers->nelts; i++) { + h[i].replace = replace; + } + } + + if (cmd->types->nelts == 0) { + ngx_pfree(cf->pool, cmd->types); + cmd->types = NULL; + } + + cmd->is_input = 1; + + hmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_headers_more_filter_module); + + hmcf->requires_handler = 1; + + return NGX_CONF_OK; +} + + +/* borrowed the code from ngx_http_request.c:ngx_http_process_user_agent */ +static ngx_int_t +ngx_http_set_user_agent_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + u_char *user_agent, *msie; + + /* clear existing settings */ + + r->headers_in.msie = 0; + r->headers_in.msie6 = 0; + r->headers_in.opera = 0; + r->headers_in.gecko = 0; + r->headers_in.chrome = 0; + r->headers_in.safari = 0; + r->headers_in.konqueror = 0; + + if (value->len == 0) { + return ngx_http_set_builtin_header(r, hv, value); + } + + /* check some widespread browsers */ + + user_agent = value->data; + + msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1); + + if (msie && msie + 7 < user_agent + value->len) { + + r->headers_in.msie = 1; + + if (msie[6] == '.') { + + switch (msie[5]) { + case '4': + case '5': + r->headers_in.msie6 = 1; + break; + case '6': + if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { + r->headers_in.msie6 = 1; + } + break; + } + } + } + + if (ngx_strstrn(user_agent, "Opera", 5 - 1)) { + r->headers_in.opera = 1; + r->headers_in.msie = 0; + r->headers_in.msie6 = 0; + } + + if (!r->headers_in.msie && !r->headers_in.opera) { + + if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { + r->headers_in.gecko = 1; + + } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) { + r->headers_in.chrome = 1; + + } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1) + && ngx_strstrn(user_agent, "Mac OS X", 8 - 1)) + { + r->headers_in.safari = 1; + + } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { + r->headers_in.konqueror = 1; + } + } + + return ngx_http_set_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_set_connection_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + r->headers_in.connection_type = 0; + + if (value->len == 0) { + return ngx_http_set_builtin_header(r, hv, value); + } + + if (ngx_strcasestrn(value->data, "close", 5 - 1)) { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; + r->headers_in.keep_alive_n = -1; + r->keepalive = 0; + + } else if (ngx_strcasestrn(value->data, "keep-alive", 10 - 1)) { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; + } + + return ngx_http_set_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_set_builtin_multi_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ +#if defined(nginx_version) && nginx_version >= 1023000 + ngx_table_elt_t **headers, **ph, *h; +#if (DDEBUG) + int nelts; +#endif + + if (r->headers_out.status == 400 || r->headers_in.headers.last == NULL) { + /* must be a 400 Bad Request */ + return NGX_OK; + } + + headers = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset); + + if (*headers) { +#if (DDEBUG) + nelts = 0; + for (h = *headers; h; h = h->next) { + nelts++; + } + + dd("clear multi-value headers: %d", nelts); +#endif + + *headers = NULL; + } + + if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { + return NGX_ERROR; + } + + if (value->len == 0) { + return NGX_OK; + } + + dd("new multi-value header: %p", h); + + if (*headers) { + for (ph = headers; *ph; ph = &(*ph)->next) { /* void */ } + *ph = h; + + } else { + *headers = h; + } + + h->next = NULL; + + return NGX_OK; +#else + ngx_array_t *headers; + ngx_table_elt_t **v, *h; + + if (r->headers_out.status == 400 || r->headers_in.headers.last == NULL) { + /* must be a 400 Bad Request */ + return NGX_OK; + } + + headers = (ngx_array_t *) ((char *) &r->headers_in + hv->offset); + + if (headers->nelts > 0) { + ngx_array_destroy(headers); + + if (ngx_array_init(headers, r->pool, 2, + sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + + dd("clear multi-value headers: %d", (int) headers->nelts); + } + +#if 1 + if (headers->nalloc == 0) { + if (ngx_array_init(headers, r->pool, 2, + sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + } +#endif + + h = NULL; + if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { + return NGX_ERROR; + } + + if (value->len == 0) { + return NGX_OK; + } + + dd("new cookie header: %p", h); + + v = ngx_array_push(headers); + if (v == NULL) { + return NGX_ERROR; + } + + *v = h; + return NGX_OK; +#endif +} + + +static ngx_int_t +ngx_http_headers_more_validate_host(ngx_str_t *host, ngx_pool_t *pool, + ngx_uint_t alloc) +{ + u_char *h, ch; + size_t i, dot_pos, host_len; + + enum { + sw_usual = 0, + sw_literal, + sw_rest + } state; + + dot_pos = host->len; + host_len = host->len; + + h = host->data; + + state = sw_usual; + + for (i = 0; i < host->len; i++) { + ch = h[i]; + + switch (ch) { + + case '.': + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + + dot_pos = i; + break; + + case ':': + if (state == sw_usual) { + host_len = i; + state = sw_rest; + } + break; + + case '[': + if (i == 0) { + state = sw_literal; + } + break; + + case ']': + if (state == sw_literal) { + host_len = i + 1; + state = sw_rest; + } + break; + + case '\0': + return NGX_DECLINED; + + default: + + if (ngx_path_separator(ch)) { + return NGX_DECLINED; + } + + if (ch >= 'A' && ch <= 'Z') { + alloc = 1; + } + + break; + } + } + + if (dot_pos == host_len - 1) { + host_len--; + } + + if (host_len == 0) { + return NGX_DECLINED; + } + + if (alloc) { + host->data = ngx_pnalloc(pool, host_len); + if (host->data == NULL) { + return NGX_ERROR; + } + + ngx_strlow(host->data, h, host_len); + } + + host->len = host_len; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.h b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.h new file mode 100644 index 0000000..d2251da --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_in.h @@ -0,0 +1,26 @@ + +/* + * Copyright (c) Yichun Zhang (agentzh) + */ + + +#ifndef NGX_HTTP_HEADERS_MORE_INPUT_HEADERS_H +#define NGX_HTTP_HEADERS_MORE_INPUT_HEADERS_H + + +#include "ngx_http_headers_more_filter_module.h" + + +/* output header setters and clearers */ + +ngx_int_t ngx_http_headers_more_exec_input_cmd(ngx_http_request_t *r, + ngx_http_headers_more_cmd_t *cmd); + +char *ngx_http_headers_more_set_input_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +char *ngx_http_headers_more_clear_input_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +#endif /* NGX_HTTP_HEADERS_MORE_INPUT_HEADERS_H */ diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.c b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.c new file mode 100644 index 0000000..2a95b5f --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.c @@ -0,0 +1,814 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_headers_more_headers_out.h" +#include "ngx_http_headers_more_util.h" +#include + + +static char * +ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd, + void *conf, ngx_http_headers_more_opcode_t opcode); +static ngx_flag_t ngx_http_headers_more_check_type(ngx_http_request_t *r, + ngx_array_t *types); +static ngx_flag_t ngx_http_headers_more_check_status(ngx_http_request_t *r, + ngx_array_t *statuses); +static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, + ngx_table_elt_t **output_header, ngx_flag_t no_create); +static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_accept_ranges_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); + + +static ngx_http_headers_more_set_header_t ngx_http_headers_more_set_handlers[] + = { + + { ngx_string("Server"), + offsetof(ngx_http_headers_out_t, server), + ngx_http_set_builtin_header }, + + { ngx_string("Date"), + offsetof(ngx_http_headers_out_t, date), + ngx_http_set_builtin_header }, + + { ngx_string("Content-Encoding"), + offsetof(ngx_http_headers_out_t, content_encoding), + ngx_http_set_builtin_header }, + + { ngx_string("Location"), + offsetof(ngx_http_headers_out_t, location), + ngx_http_set_builtin_header }, + + { ngx_string("Refresh"), + offsetof(ngx_http_headers_out_t, refresh), + ngx_http_set_builtin_header }, + + { ngx_string("Last-Modified"), + offsetof(ngx_http_headers_out_t, last_modified), + ngx_http_set_builtin_header }, + + { ngx_string("Content-Range"), + offsetof(ngx_http_headers_out_t, content_range), + ngx_http_set_builtin_header }, + + { ngx_string("Accept-Ranges"), + offsetof(ngx_http_headers_out_t, accept_ranges), + ngx_http_set_accept_ranges_header }, + + { ngx_string("WWW-Authenticate"), + offsetof(ngx_http_headers_out_t, www_authenticate), + ngx_http_set_builtin_header }, + + { ngx_string("Expires"), + offsetof(ngx_http_headers_out_t, expires), + ngx_http_set_builtin_header }, + + { ngx_string("E-Tag"), + offsetof(ngx_http_headers_out_t, etag), + ngx_http_set_builtin_header }, + + { ngx_string("Content-Length"), + offsetof(ngx_http_headers_out_t, content_length), + ngx_http_set_content_length_header }, + + { ngx_string("Content-Type"), + 0, + ngx_http_set_content_type_header }, + + { ngx_string("Cache-Control"), + offsetof(ngx_http_headers_out_t, cache_control), + ngx_http_set_builtin_multi_header }, + + { ngx_null_string, 0, ngx_http_set_header } +}; + + +ngx_int_t +ngx_http_headers_more_exec_cmd(ngx_http_request_t *r, + ngx_http_headers_more_cmd_t *cmd) +{ + ngx_str_t value; + ngx_http_headers_more_header_val_t *h; + ngx_uint_t i; + + if (!cmd->headers) { + return NGX_OK; + } + + if (cmd->types && !ngx_http_headers_more_check_type(r, cmd->types)) { + return NGX_OK; + } + + if (cmd->statuses + && !ngx_http_headers_more_check_status(r, cmd->statuses)) + { + return NGX_OK; + } + + h = cmd->headers->elts; + for (i = 0; i < cmd->headers->nelts; i++) { + + if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { + return NGX_ERROR; + } + + if (value.len) { + value.len--; /* remove the trailing '\0' added by + ngx_http_headers_more_parse_header */ + } + + if (h[i].handler(r, &h[i], &value) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + return ngx_http_set_header_helper(r, hv, value, NULL, 0); +} + + +static ngx_int_t +ngx_http_set_header_helper(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, + ngx_table_elt_t **output_header, ngx_flag_t no_create) +{ + ngx_table_elt_t *h; + ngx_list_part_t *part; + ngx_uint_t i; + ngx_flag_t matched = 0; + + dd_enter(); + +#if 1 + if (r->headers_out.location + && r->headers_out.location->value.len + && r->headers_out.location->value.data[0] == '/') + { + /* XXX ngx_http_core_find_config_phase, for example, + * may not initialize the "key" and "hash" fields + * for a nasty optimization purpose, and + * we have to work-around it here */ + + r->headers_out.location->hash = ngx_http_headers_more_location_hash; + ngx_str_set(&r->headers_out.location->key, "Location"); + } +#endif + + if (hv->append) { + goto append; + } + + part = &r->headers_out.headers.part; + h = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + if (h[i].hash == 0) { + continue; + } + + if (!hv->wildcard + && h[i].key.len == hv->key.len + && ngx_strncasecmp(h[i].key.data, hv->key.data, + h[i].key.len) == 0) + { + goto matched; + } + + if (hv->wildcard + && h[i].key.len >= hv->key.len - 1 + && ngx_strncasecmp(h[i].key.data, hv->key.data, + hv->key.len - 1) == 0) + { + goto matched; + } + + /* not matched */ + continue; + +matched: + + if (value->len == 0 || matched) { + dd("clearing normal header for %.*s", (int) hv->key.len, + hv->key.data); + + h[i].value.len = 0; + h[i].hash = 0; + + } else { + h[i].value = *value; + h[i].hash = hv->hash; + } + + if (output_header) { + *output_header = &h[i]; + } + + matched = 1; + } + + if (matched){ + return NGX_OK; + } + + if ((hv->wildcard || no_create) && value->len == 0) { + return NGX_OK; + } + + /* XXX we still need to create header slot even if the value + * is empty because some builtin headers like Last-Modified + * relies on this to get cleared */ + +append: + + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + if (value->len == 0) { + h->hash = 0; + + } else { + h->hash = hv->hash; + } + + h->key = hv->key; + h->value = *value; + + h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); + if (h->lowcase_key == NULL) { + return NGX_ERROR; + } + + ngx_strlow(h->lowcase_key, h->key.data, h->key.len); + + if (output_header) { + *output_header = h; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + ngx_table_elt_t *h, **old; + + dd_enter(); + + if (hv->offset) { + old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); + + } else { + old = NULL; + } + + if (old == NULL || *old == NULL) { + return ngx_http_set_header_helper(r, hv, value, old, 0); + } + + h = *old; + + if (value->len == 0) { + dd("clearing the builtin header"); + + h->hash = 0; + h->value = *value; + + return NGX_OK; + } + + h->hash = hv->hash; + h->key = hv->key; + h->value = *value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_builtin_multi_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ +#if defined(nginx_version) && nginx_version >= 1023000 + ngx_table_elt_t **headers, *h, *ho, **ph; + + headers = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); + + if (*headers) { + for (h = (*headers)->next; h; h = h->next) { + h->hash = 0; + h->value.len = 0; + } + + h = *headers; + + h->value = *value; + + if (value->len == 0) { + h->hash = 0; + + } else { + h->hash = hv->hash; + } + + return NGX_OK; + } + + for (ph = headers; *ph; ph = &(*ph)->next) { /* void */ } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + ho->value = *value; + ho->hash = hv->hash; + ngx_str_set(&ho->key, "Cache-Control"); + ho->next = NULL; + *ph = ho; + + return NGX_OK; +#else + ngx_array_t *pa; + ngx_table_elt_t *ho, **ph; + ngx_uint_t i; + + pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset); + + if (pa->elts == NULL) { + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + /* override old values (if any) */ + + if (pa->nelts > 0) { + ph = pa->elts; + for (i = 1; i < pa->nelts; i++) { + ph[i]->hash = 0; + ph[i]->value.len = 0; + } + + ph[0]->value = *value; + + if (value->len == 0) { + ph[0]->hash = 0; + + } else { + ph[0]->hash = hv->hash; + } + + return NGX_OK; + } + + ph = ngx_array_push(pa); + if (ph == NULL) { + return NGX_ERROR; + } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + ho->value = *value; + ho->hash = hv->hash; + ngx_str_set(&ho->key, "Cache-Control"); + *ph = ho; + + return NGX_OK; +#endif +} + + +static ngx_int_t +ngx_http_set_content_type_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + u_char *p, *last, *end; + + r->headers_out.content_type_len = value->len; + r->headers_out.content_type = *value; + r->headers_out.content_type_hash = hv->hash; + r->headers_out.content_type_lowcase = NULL; + + p = value->data; + end = p + value->len; + + for (; p != end; p++) { + + if (*p != ';') { + continue; + } + + last = p; + + while (*++p == ' ') { /* void */ } + + if (p == end) { + break; + } + + if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) { + continue; + } + + p += 8; + + r->headers_out.content_type_len = last - value->data; + + if (*p == '"') { + p++; + } + + last = end; + + if (*(last - 1) == '"') { + last--; + } + + r->headers_out.charset.len = last - p; + r->headers_out.charset.data = p; + + break; + } + + value->len = 0; + + return ngx_http_set_header_helper(r, hv, value, NULL, 1); +} + + +static ngx_int_t +ngx_http_set_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + off_t len; + + if (value->len == 0) { + return ngx_http_clear_content_length_header(r, hv, value); + } + + len = ngx_atosz(value->data, value->len); + if (len == NGX_ERROR) { + return NGX_ERROR; + } + + r->headers_out.content_length_n = len; + + return ngx_http_set_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_set_accept_ranges_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + if (value->len == 0) { + r->allow_ranges = 0; + } + + return ngx_http_set_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_clear_content_length_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + r->headers_out.content_length_n = -1; + + return ngx_http_clear_builtin_header(r, hv, value); +} + + +static ngx_int_t +ngx_http_clear_builtin_header(ngx_http_request_t *r, + ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) +{ + dd_enter(); + + value->len = 0; + + return ngx_http_set_builtin_header(r, hv, value); +} + + +char * +ngx_http_headers_more_set_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + return ngx_http_headers_more_parse_directive(cf, cmd, conf, + ngx_http_headers_more_opcode_set); +} + + +char * +ngx_http_headers_more_clear_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + return ngx_http_headers_more_parse_directive(cf, cmd, conf, + ngx_http_headers_more_opcode_clear); +} + + +static ngx_flag_t +ngx_http_headers_more_check_type(ngx_http_request_t *r, ngx_array_t *types) +{ + ngx_uint_t i; + ngx_str_t *t; + + dd("headers_out->content_type: %.*s (len %d)", + (int) r->headers_out.content_type.len, + r->headers_out.content_type.data, + (int) r->headers_out.content_type.len); + + t = types->elts; + + for (i = 0; i < types->nelts; i++) { + dd("...comparing with type [%.*s]", (int) t[i].len, t[i].data); + + if (r->headers_out.content_type_len == t[i].len + && ngx_strncmp(r->headers_out.content_type.data, + t[i].data, t[i].len) == 0) + { + return 1; + } + } + + return 0; +} + + +static ngx_flag_t +ngx_http_headers_more_check_status(ngx_http_request_t *r, ngx_array_t *statuses) +{ + ngx_uint_t i; + ngx_uint_t *status; + + dd("headers_out.status = %d", (int) r->headers_out.status); + + status = statuses->elts; + for (i = 0; i < statuses->nelts; i++) { + dd("...comparing with specified status %d", (int) status[i]); + + if (r->headers_out.status == status[i]) { + return 1; + } + } + + return 0; +} + + +static char * +ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd, + void *conf, ngx_http_headers_more_opcode_t opcode) +{ + ngx_http_headers_more_loc_conf_t *hlcf = conf; + + ngx_uint_t i, j; + ngx_http_headers_more_cmd_t *cmd; + ngx_str_t *arg; + ngx_flag_t ignore_next_arg; + ngx_str_t *cmd_name; + ngx_int_t rc; + ngx_flag_t append = 0; + ngx_flag_t is_builtin_header = 0; + ngx_http_headers_more_header_val_t *h; + ngx_http_headers_more_set_header_t *handlers; + + ngx_http_headers_more_main_conf_t *hmcf; + + if (hlcf->cmds == NULL) { + hlcf->cmds = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_headers_more_cmd_t)); + + if (hlcf->cmds == NULL) { + return NGX_CONF_ERROR; + } + } + + cmd = ngx_array_push(hlcf->cmds); + if (cmd == NULL) { + return NGX_CONF_ERROR; + } + + cmd->headers = + ngx_array_create(cf->pool, 1, + sizeof(ngx_http_headers_more_header_val_t)); + if (cmd->headers == NULL) { + return NGX_CONF_ERROR; + } + + cmd->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); + if (cmd->types == NULL) { + return NGX_CONF_ERROR; + } + + cmd->statuses = ngx_array_create(cf->pool, 1, sizeof(ngx_uint_t)); + if (cmd->statuses == NULL) { + return NGX_CONF_ERROR; + } + + arg = cf->args->elts; + + cmd_name = &arg[0]; + + ignore_next_arg = 0; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ignore_next_arg) { + ignore_next_arg = 0; + continue; + } + + if (arg[i].len == 0) { + continue; + } + + if (arg[i].data[0] != '-') { + rc = ngx_http_headers_more_parse_header(cf, cmd_name, + &arg[i], cmd->headers, + opcode, + ngx_http_headers_more_set_handlers); + + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + + continue; + } + + if (arg[i].len == 2) { + if (arg[i].data[1] == 't') { + if (i == cf->args->nelts - 1) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: option -t takes an argument.", + cmd_name); + + return NGX_CONF_ERROR; + } + + rc = ngx_http_headers_more_parse_types(cf->log, cmd_name, + &arg[i + 1], + cmd->types); + + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + + ignore_next_arg = 1; + + continue; + + } else if (arg[i].data[1] == 's') { + + if (i == cf->args->nelts - 1) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: option -s takes an argument.", + cmd_name); + + return NGX_CONF_ERROR; + } + + rc = ngx_http_headers_more_parse_statuses(cf->log, cmd_name, + &arg[i + 1], + cmd->statuses); + + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + + ignore_next_arg = 1; + + continue; + + } else if (arg[i].data[1] == 'a') { + + if (ngx_strncasecmp((u_char *) "more_set_headers", + cmd_name->data, cmd_name->len) != 0) + { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: invalid option name: \"%V\"", + cmd_name, &arg[i]); + + return NGX_CONF_ERROR; + } + + dd("Found append flag"); + append = 1; + continue; + } + } + + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: invalid option name: \"%V\"", cmd_name, &arg[i]); + + return NGX_CONF_ERROR; + } + + dd("Found %d statuses, %d types, and %d headers", + (int) cmd->statuses->nelts, (int) cmd->types->nelts, + (int) cmd->headers->nelts); + + if (cmd->headers->nelts == 0) { + cmd->headers = NULL; + + } else { + + h = cmd->headers->elts; + for (i = 0; i < cmd->headers->nelts; i++) { + h[i].append = 0; + + handlers = ngx_http_headers_more_set_handlers; + + for (j = 0; handlers[j].name.len; j++) { + if (h[i].key.len == handlers[j].name.len + && ngx_strncasecmp(h[i].key.data, handlers[j].name.data, + h[i].key.len) == 0) + { + is_builtin_header = 1; + break; + } + } + + if (is_builtin_header && append) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: can not append builtin headers \"%V\"", + cmd_name, &h[i].key); + + return NGX_CONF_ERROR; + } + + if (!is_builtin_header) { + h[i].append = append; + } + } + } + + if (cmd->types->nelts == 0) { + cmd->types = NULL; + } + + if (cmd->statuses->nelts == 0) { + cmd->statuses = NULL; + } + + cmd->is_input = 0; + + hmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_headers_more_filter_module); + + hmcf->requires_filter = 1; + + return NGX_CONF_OK; +} diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.h b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.h new file mode 100644 index 0000000..c939507 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_headers_out.h @@ -0,0 +1,26 @@ + +/* + * Copyright (c) Yichun Zhang (agentzh) + */ + + +#ifndef NGX_HTTP_HEADERS_MORE_OUTPUT_HEADERS_H +#define NGX_HTTP_HEADERS_MORE_OUTPUT_HEADERS_H + + +#include "ngx_http_headers_more_filter_module.h" + + +/* output header setters and clearers */ + +ngx_int_t ngx_http_headers_more_exec_cmd(ngx_http_request_t *r, + ngx_http_headers_more_cmd_t *cmd); + +char *ngx_http_headers_more_set_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +char *ngx_http_headers_more_clear_headers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +#endif /* NGX_HTTP_HEADERS_MORE_OUTPUT_HEADERS_H */ diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.c b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.c new file mode 100644 index 0000000..e1f3636 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.c @@ -0,0 +1,382 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_headers_more_util.h" +#include + + +ngx_int_t +ngx_http_headers_more_parse_header(ngx_conf_t *cf, ngx_str_t *cmd_name, + ngx_str_t *raw_header, ngx_array_t *headers, + ngx_http_headers_more_opcode_t opcode, + ngx_http_headers_more_set_header_t *handlers) +{ + ngx_http_headers_more_header_val_t *hv; + + ngx_uint_t i; + ngx_str_t key = ngx_null_string; + ngx_str_t value = ngx_null_string; + ngx_flag_t seen_end_of_key; + ngx_http_compile_complex_value_t ccv; + u_char *p; + + hv = ngx_array_push(headers); + if (hv == NULL) { + return NGX_ERROR; + } + + seen_end_of_key = 0; + for (i = 0; i < raw_header->len; i++) { + if (key.len == 0) { + if (isspace(raw_header->data[i])) { + continue; + } + + key.data = raw_header->data; + key.len = 1; + + continue; + } + + if (!seen_end_of_key) { + if (raw_header->data[i] == ':' + || isspace(raw_header->data[i])) + { + seen_end_of_key = 1; + continue; + } + + key.len++; + + continue; + } + + if (value.len == 0) { + if (raw_header->data[i] == ':' + || isspace(raw_header->data[i])) + { + continue; + } + + value.data = &raw_header->data[i]; + value.len = 1; + + continue; + } + + value.len++; + } + + if (key.len == 0) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: no key found in the header argument: %V", + cmd_name, raw_header); + + return NGX_ERROR; + } + + hv->wildcard = (key.data[key.len - 1] == '*'); + if (hv->wildcard && key.len<2){ + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "%V: wildcard key too short: %V", + cmd_name, raw_header); + return NGX_ERROR; + } + + hv->hash = ngx_hash_key_lc(key.data, key.len); + hv->key = key; + + hv->offset = 0; + + for (i = 0; handlers[i].name.len; i++) { + if (hv->key.len != handlers[i].name.len + || ngx_strncasecmp(hv->key.data, handlers[i].name.data, + handlers[i].name.len) != 0) + { + dd("hv key comparison: %s <> %s", handlers[i].name.data, + hv->key.data); + + continue; + } + + hv->offset = handlers[i].offset; + hv->handler = handlers[i].handler; + + break; + } + + if (handlers[i].name.len == 0 && handlers[i].handler) { + hv->offset = handlers[i].offset; + hv->handler = handlers[i].handler; + } + + if (opcode == ngx_http_headers_more_opcode_clear) { + value.len = 0; + } + + if (value.len == 0) { + ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t)); + return NGX_OK; + + } + + /* Nginx request header value requires to be a null-terminated + * C string */ + + p = ngx_palloc(cf->pool, value.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, value.data, value.len); + p[value.len] = '\0'; + value.data = p; + value.len++; /* we should also compile the trailing '\0' */ + + /* compile the header value as a complex value */ + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value; + ccv.complex_value = &hv->value; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_headers_more_parse_statuses(ngx_log_t *log, ngx_str_t *cmd_name, + ngx_str_t *value, ngx_array_t *statuses) +{ + u_char *p, *last; + ngx_uint_t *s = NULL; + + p = value->data; + last = p + value->len; + + for (; p != last; p++) { + if (s == NULL) { + if (isspace(*p)) { + continue; + } + + s = ngx_array_push(statuses); + if (s == NULL) { + return NGX_ERROR; + } + + if (*p >= '0' && *p <= '9') { + *s = *p - '0'; + + } else { + ngx_log_error(NGX_LOG_ERR, log, 0, + "%V: invalid digit \"%c\" found in " + "the status code list \"%V\"", + cmd_name, *p, value); + + return NGX_ERROR; + } + + continue; + } + + if (isspace(*p)) { + dd("Parsed status %d", (int) *s); + + s = NULL; + continue; + } + + if (*p >= '0' && *p <= '9') { + *s *= 10; + *s += *p - '0'; + + } else { + ngx_log_error(NGX_LOG_ERR, log, 0, + "%V: invalid digit \"%c\" found in " + "the status code list \"%V\"", + cmd_name, *p, value); + + return NGX_ERROR; + } + } + + if (s) { + dd("Parsed status %d", (int) *s); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_headers_more_parse_types(ngx_log_t *log, ngx_str_t *cmd_name, + ngx_str_t *value, ngx_array_t *types) +{ + u_char *p, *last; + ngx_str_t *t = NULL; + + p = value->data; + last = p + value->len; + + for (; p != last; p++) { + if (t == NULL) { + if (isspace(*p) || *p == ';') { + continue; + } + + t = ngx_array_push(types); + if (t == NULL) { + return NGX_ERROR; + } + + t->len = 1; + t->data = p; + + continue; + } + + if (isspace(*p) || *p == ';') { + t = NULL; + continue; + } + + t->len++; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_headers_more_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, + ngx_uint_t i) +{ + ngx_table_elt_t *data; + ngx_list_part_t *new, *part; + + dd("list rm item: part %p, i %d, nalloc %d", cur, (int) i, + (int) l->nalloc); + + data = cur->elts; + + dd("cur: nelts %d, nalloc %d", (int) cur->nelts, + (int) l->nalloc); + + if (i == 0) { + cur->elts = (char *) cur->elts + l->size; + cur->nelts--; + + if (cur == l->last) { + if (cur->nelts == 0) { +#if 1 + part = &l->part; + + if (part == cur) { + cur->elts = (char *) cur->elts - l->size; + /* do nothing */ + + } else { + while (part->next != cur) { + if (part->next == NULL) { + return NGX_ERROR; + } + + part = part->next; + } + + l->last = part; + part->next = NULL; + dd("part nelts: %d", (int) part->nelts); + l->nalloc = part->nelts; + } +#endif + + } else { + l->nalloc--; + } + + return NGX_OK; + } + + if (cur->nelts == 0) { + part = &l->part; + + if (part == cur) { + ngx_http_headers_more_assert(cur->next != NULL); + + dd("remove 'cur' from the list by rewriting 'cur': " + "l->last: %p, cur: %p, cur->next: %p, part: %p", + l->last, cur, cur->next, part); + + if (l->last == cur->next) { + dd("last is cur->next"); + l->part = *(cur->next); + l->last = part; + l->nalloc = part->nelts; + + } else { + l->part = *(cur->next); + } + + } else { + dd("remove 'cur' from the list"); + while (part->next != cur) { + if (part->next == NULL) { + return NGX_ERROR; + } + + part = part->next; + } + + part->next = cur->next; + } + + return NGX_OK; + } + + return NGX_OK; + } + + if (i == cur->nelts - 1) { + cur->nelts--; + + if (cur == l->last) { + l->nalloc = cur->nelts; + } + + return NGX_OK; + } + + new = ngx_palloc(l->pool, sizeof(ngx_list_part_t)); + if (new == NULL) { + return NGX_ERROR; + } + + new->elts = &data[i + 1]; + new->nelts = cur->nelts - i - 1; + new->next = cur->next; + + cur->nelts = i; + cur->next = new; + if (cur == l->last) { + l->last = new; + l->nalloc = new->nelts; + } + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.h b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.h new file mode 100644 index 0000000..6c4614b --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/src/ngx_http_headers_more_util.h @@ -0,0 +1,52 @@ + +/* + * Copyright (c) Yichun Zhang (agentzh) + */ + + +#ifndef NGX_HTTP_HEADERS_MORE_UTIL_H +#define NGX_HTTP_HEADERS_MORE_UTIL_H + + +#include "ngx_http_headers_more_filter_module.h" + + +#define ngx_http_headers_more_hash_literal(s) \ + ngx_http_headers_more_hash_str((u_char *) s, sizeof(s) - 1) + + +static ngx_inline ngx_uint_t +ngx_http_headers_more_hash_str(u_char *src, size_t n) +{ + ngx_uint_t key; + + key = 0; + + while (n--) { + key = ngx_hash(key, *src); + src++; + } + + return key; +} + + +extern ngx_uint_t ngx_http_headers_more_location_hash; + + +ngx_int_t ngx_http_headers_more_parse_header(ngx_conf_t *cf, + ngx_str_t *cmd_name, ngx_str_t *raw_header, ngx_array_t *headers, + ngx_http_headers_more_opcode_t opcode, + ngx_http_headers_more_set_header_t *handlers); + +ngx_int_t ngx_http_headers_more_parse_statuses(ngx_log_t *log, + ngx_str_t *cmd_name, ngx_str_t *value, ngx_array_t *statuses); + +ngx_int_t ngx_http_headers_more_parse_types(ngx_log_t *log, + ngx_str_t *cmd_name, ngx_str_t *value, ngx_array_t *types); + +ngx_int_t ngx_http_headers_more_rm_header_helper(ngx_list_t *l, + ngx_list_part_t *cur, ngx_uint_t i); + + +#endif /* NGX_HTTP_HEADERS_MORE_UTIL_H */ diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/bug.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/bug.t new file mode 100644 index 0000000..2339401 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/bug.t @@ -0,0 +1,416 @@ +# vi:filetype= + +use Test::Nginx::Socket; # 'no_plan'; + +repeat_each(2); + +plan tests => 56 * repeat_each(); + +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: set Server +--- config + #more_set_headers 'Last-Modified: x'; + more_clear_headers 'Last-Modified'; +--- request + GET /index.html +--- response_headers +! Last-Modified +--- response_body_like: It works! + + + +=== TEST 2: variables in the Ranges header +--- config + location /index.html { + set $rfrom 1; + set $rto 3; + more_set_input_headers 'Range: bytes=$rfrom - $rto'; + #more_set_input_headers 'Range: bytes=1 - 3'; + #echo $http_range; + } +--- request +GET /index.html +--- error_code: 206 +--- response_body chomp +htm + + + +=== TEST 3: mime type overriding (inlined types) +--- config + more_clear_headers 'X-Powered-By' 'X-Runtime' 'ETag'; + + types { + text/html html htm shtml; + text/css css; + } +--- user_files +>>> a.css +hello +--- request +GET /a.css +--- error_code: 200 +--- response_headers +Content-Type: text/css +--- response_body +hello + + + +=== TEST 4: mime type overriding (included types file) +--- config + more_clear_headers 'X-Powered-By' 'X-Runtime' 'ETag'; + include mime.types; +--- user_files +>>> a.css +hello +>>> ../conf/mime.types +types { + text/html html htm shtml; + text/css css; +} +--- request +GET /a.css +--- error_code: 200 +--- response_headers +Content-Type: text/css +--- response_body +hello + + + +=== TEST 5: empty variable as the header value +--- config + location /foo { + more_set_headers 'X-Foo: $arg_foo'; + echo hi; + } +--- request + GET /foo +--- response_headers +! X-Foo +--- response_body +hi + + + +=== TEST 6: range bug +--- config + location /index.html { + more_clear_input_headers "Range*" ; + more_clear_input_headers "Content-Range*" ; + + more_set_input_headers 'Range: bytes=1-5'; + more_set_headers 'Content-Range: bytes 1-5/1000'; + } +--- request + GET /index.html +--- more_headers +Range: bytes=1-3 +--- raw_response_headers_like: Content-Range: bytes 1-5/1000$ +--- response_body chop +html> +--- error_code: 206 +--- SKIP + + + +=== TEST 7: Allow-Ranges +--- config + location /index.html { + more_clear_headers 'Accept-Ranges'; + } +--- request + GET /index.html +--- response_headers +! Accept-Ranges +--- response_body_like: It works + + + +=== TEST 8: clear hand-written Allow-Ranges headers +--- config + location /index.html { + more_set_headers 'Accept-Ranges: bytes'; + more_clear_headers 'Accept-Ranges'; + } +--- request + GET /index.html +--- response_headers +! Accept-Ranges +--- response_body_like: It works + + + +=== TEST 9: clear first, then add +--- config + location /bug { + more_clear_headers 'Foo'; + more_set_headers 'Foo: a'; + echo hello; + } +--- request + GET /bug +--- raw_response_headers_like eval +".*Foo: a.*" +--- response_body +hello + + + +=== TEST 10: first add, then clear, then add again +--- config + location /bug { + more_set_headers 'Foo: a'; + more_clear_headers 'Foo'; + more_set_headers 'Foo: b'; + echo hello; + } +--- request + GET /bug +--- raw_response_headers_like eval +".*Foo: b.*" +--- response_body +hello + + + +=== TEST 11: override charset +--- config + location /foo { + charset iso-8859-1; + default_type "text/html"; + echo hiya; + } + + location /bug { + more_set_headers "Content-Type: text/html; charset=UTF-8"; + proxy_pass http://127.0.0.1:$server_port/foo; + } +--- request + GET /bug +--- response_body +hiya +--- response_headers +Content-Type: text/html; charset=UTF-8 + + + +=== TEST 12: set multi-value header to a single value +--- config + location /main { + set $footer ''; + proxy_pass http://127.0.0.1:$server_port/foo; + more_set_headers 'Foo: b'; + header_filter_by_lua ' + ngx.var.footer = ngx.header.Foo + '; + echo_after_body $footer; + } + location /foo { + echo foo; + add_header Foo a; + add_header Foo c; + } +--- request + GET /main +--- response_headers +Foo: b +--- response_body +foo +b + + + +=== TEST 13: set multi values to cache-control and override it with multiple values (to reproduce a bug) +--- config + location /lua { + content_by_lua ' + ngx.header.cache_control = { "private", "no-store", "foo", "bar", "baz" } + ngx.send_headers() + ngx.say("Cache-Control: ", ngx.var.sent_http_cache_control) + '; + more_clear_headers Cache-Control; + add_header Cache-Control "blah"; + } +--- request + GET /lua +--- response_headers +Cache-Control: blah +--- response_body +Cache-Control: blah + + + +=== TEST 14: set 20+ headers +--- config + location /test { + more_clear_input_headers "Authorization"; + echo $http_a1; + echo $http_authorization; + echo $http_a2; + echo $http_a3; + echo $http_a23; + echo $http_a24; + echo $http_a25; + } +--- request + GET /test +--- more_headers eval +my $i = 1; +my $s; +while ($i <= 25) { + $s .= "A$i: $i\n"; + if ($i == 22) { + $s .= "Authorization: blah\n"; + } + $i++; +} +#warn $s; +$s +--- response_body +1 + +2 +3 +23 +24 +25 + + + +=== TEST 15: github #20: segfault caused by the nasty optimization in the nginx core (set) +--- config + location = /t/ { + more_set_headers "Foo: 1"; + proxy_pass http://127.0.0.1:$server_port; + } +--- request +GET /t +--- more_headers +Foo: bar +Bah: baz +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 16: github #20: segfault caused by the nasty optimization in the nginx core (clear) +--- config + location = /t/ { + more_clear_headers Foo; + proxy_pass http://127.0.0.1:$server_port; + } +--- request +GET /t +--- more_headers +Foo: bar +Bah: baz +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 17: Content-Type response headers with a charset param (correct -t values) +--- config + location = /t { + more_set_headers -t 'text/html' 'X-Foo: Bar'; + proxy_pass http://127.0.0.1:$server_port/fake; + } + + location = /fake { + default_type text/html; + charset utf-8; + echo ok; + } +--- request +GET /t +--- response_headers +X-Foo: Bar +--- response_body +ok + + + +=== TEST 18: Content-Type response headers with a charset param (WRONG -t values) +--- config + location = /t { + more_set_headers -t 'text/html; charset=utf-8' 'X-Foo: Bar'; + proxy_pass http://127.0.0.1:$server_port/fake; + } + + location = /fake { + default_type text/html; + charset utf-8; + echo ok; + } +--- request +GET /t +--- response_headers +X-Foo: Bar +--- response_body +ok + + + +=== TEST 19: for bad requests (bad request method letter case) +--- config + error_page 400 = /err; + + location = /err { + more_set_input_headers "Foo: bar"; + echo ok; + } +--- raw_request +GeT / HTTP/1.1 +--- response_body +ok +--- no_check_leak + + + +=== TEST 20: for bad requests (bad request method names) +--- config + error_page 400 = /err; + + location = /err { + more_set_input_headers "Foo: bar"; + echo ok; + } +--- raw_request +GET x HTTP/1.1 +--- response_body +ok +--- no_check_leak + + + +=== TEST 21: override Cache-Control header sent by proxy module +--- config + location = /back { + content_by_lua_block { + ngx.header['Cache-Control'] = 'max-age=0, no-cache' + ngx.send_headers() + ngx.say("Cache-Control: ", ngx.var.sent_http_cache_control) + } + } + + location = /t { + more_set_headers "Cache-Control: max-age=1800"; + proxy_pass http://127.0.0.1:$server_port/back; + } +--- request + GET /t +--- response_headers +Cache-Control: max-age=1800 +--- response_body +Cache-Control: max-age=0, no-cache diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/builtin.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/builtin.t new file mode 100644 index 0000000..27b20af --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/builtin.t @@ -0,0 +1,338 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; # 'no_plan'; + +plan tests => 60; + +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: set Server +--- config + location /foo { + echo hi; + more_set_headers 'Server: Foo'; + } +--- request + GET /foo +--- response_headers +Server: Foo +--- response_body +hi + + + +=== TEST 2: clear Server +--- config + location /foo { + echo hi; + more_clear_headers 'Server: '; + } +--- request + GET /foo +--- response_headers +! Server +--- response_body +hi + + + +=== TEST 3: set Content-Type +--- config + location /foo { + default_type 'text/plan'; + more_set_headers 'Content-Type: text/css'; + echo hi; + } +--- request + GET /foo +--- response_headers +Content-Type: text/css +--- response_body +hi + + + +=== TEST 4: set Content-Type +--- config + location /foo { + default_type 'text/plan'; + more_set_headers 'Content-Type: text/css'; + return 404; + } +--- request + GET /foo +--- response_headers +Content-Type: text/css +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 5: clear Content-Type +--- config + location /foo { + default_type 'text/plain'; + more_clear_headers 'Content-Type: '; + return 404; + } +--- request + GET /foo +--- response_headers +! Content-Type +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 6: clear Content-Type (colon not required) +--- config + location /foo { + default_type 'text/plain'; + more_set_headers 'Content-Type: Hello'; + more_clear_headers 'Content-Type'; + return 404; + } +--- request + GET /foo +--- response_headers +! Content-Type +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 7: clear Content-Type (value ignored) +--- config + location /foo { + default_type 'text/plain'; + more_set_headers 'Content-Type: Hello'; + more_clear_headers 'Content-Type: blah'; + return 404; + } +--- request + GET /foo +--- response_headers +! Content-Type +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 8: clear Content-Type (case insensitive) +--- config + location /foo { + default_type 'text/plain'; + more_set_headers 'Content-Type: Hello'; + more_clear_headers 'content-type: blah'; + return 404; + } +--- request + GET /foo +--- response_headers +! Content-Type +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 9: clear Content-Type using set empty +--- config + location /foo { + default_type 'text/plain'; + more_set_headers 'Content-Type: Hello'; + more_set_headers 'content-type:'; + return 404; + } +--- request + GET /foo +--- response_headers +! Content-Type +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 10: clear Content-Type using setting key only +--- config + location /foo { + default_type 'text/plain'; + more_set_headers 'Content-Type: Hello'; + more_set_headers 'content-type'; + return 404; + } +--- request + GET /foo +--- response_headers +! Content-Type +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 11: set content-length +--- config + location /len { + more_set_headers 'Content-Length: 2'; + echo hello; + } +--- request + GET /len +--- response_headers +Content-Length: 2 +--- response_body chop +he + + + +=== TEST 12: set content-length multiple times +--- config + location /len { + more_set_headers 'Content-Length: 2'; + more_set_headers 'Content-Length: 4'; + echo hello; + } +--- request + GET /len +--- response_headers +Content-Length: 4 +--- response_body chop +hell + + + +=== TEST 13: clear content-length +--- config + location /len { + more_set_headers 'Content-Length: 4'; + more_set_headers 'Content-Length:'; + echo hello; + } +--- request + GET /len +--- response_headers +! Content-Length +--- response_body +hello + + + +=== TEST 14: clear content-length (another way) +--- config + location /len { + more_set_headers 'Content-Length: 4'; + more_clear_headers 'Content-Length'; + echo hello; + } +--- request + GET /len +--- response_headers +! Content-Length +--- response_body +hello + + + +=== TEST 15: clear content-type +--- config + location /len { + default_type 'text/plain'; + more_set_headers 'Content-Type:'; + echo hello; + } +--- request + GET /len +--- response_headers +! Content-Type +--- response_body +hello + + + +=== TEST 16: clear content-type (the other way) +--- config + location /len { + default_type 'text/plain'; + more_clear_headers 'Content-Type:'; + echo hello; + } +--- request + GET /len +--- response_headers +! Content-Type +--- response_body +hello + + + +=== TEST 17: set Charset +--- config + location /len { + default_type 'text/plain'; + more_set_headers 'Charset: gbk'; + echo hello; + } +--- request + GET /len +--- response_headers +Charset: gbk +--- response_body +hello + + + +=== TEST 18: clear Charset +--- config + location /len { + default_type 'text/plain'; + more_set_headers 'Charset: gbk'; + more_clear_headers 'Charset'; + echo hello; + } +--- request + GET /len +--- response_headers +! Charset +--- response_body +hello + + + +=== TEST 19: clear Charset (the other way: using set) +--- config + location /len { + default_type 'text/plain'; + more_set_headers 'Charset: gbk'; + more_set_headers 'Charset: '; + echo hello; + } +--- request + GET /len +--- response_headers +! Charset +--- response_body +hello + + + +=== TEST 20: set Vary +--- config + location /foo { + more_set_headers 'Vary: gbk'; + echo hello; + } + location /len { + default_type 'text/plain'; + more_set_headers 'Vary: hello'; + proxy_pass http://127.0.0.1:$server_port/foo; + } +--- request + GET /len +--- response_headers +Vary: hello +--- response_body +hello diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/eval.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/eval.t new file mode 100644 index 0000000..febd306 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/eval.t @@ -0,0 +1,36 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; # 'no_plan'; + +repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +#no_long_string(); +#no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: set request header at client side +--- config + location /foo { + eval_subrequest_in_memory off; + eval_override_content_type text/plain; + eval $res { + echo -n 1; + } + #echo "[$res]"; + if ($res = '1') { + more_set_input_headers 'Foo: Bar'; + echo "OK"; + break; + } + echo "NOT OK"; + } +--- request + GET /foo +--- response_body +OK diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-conn.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-conn.t new file mode 100644 index 0000000..f53e80f --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-conn.t @@ -0,0 +1,137 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (4 * blocks()); + +#no_diff(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: clear the Connection req header +--- config + location /req-header { + more_clear_input_headers Connection; + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 0 + +--- response_body +connection: +--- no_error_log +[error] + + + +=== TEST 2: set custom Connection req header (close) +--- config + location /req-header { + more_set_input_headers "Connection: CLOSE"; + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 1 + +--- response_body +connection: CLOSE +--- no_error_log +[error] + + + +=== TEST 3: set custom Connection req header (keep-alive) +--- config + location /req-header { + more_set_input_headers "Connection: keep-alive"; + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 2 + +--- response_body +connection: keep-alive +--- no_error_log +[error] + + + +=== TEST 4: set custom Connection req header (bad) +--- config + location /req-header { + more_set_input_headers "Connection: bad"; + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 0 + +--- response_body +connection: bad +--- no_error_log +[error] diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-cookie.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-cookie.t new file mode 100644 index 0000000..3e5257b --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-cookie.t @@ -0,0 +1,183 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (4 * blocks()); + +#no_diff(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: clear cookie (with existing cookies) +--- config + location /t { + more_clear_input_headers Cookie; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t +--- more_headers +Cookie: foo=bar +Cookie: baz=blah + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 2 +content: cookies: 0 + +--- response_body +Cookie foo: +Cookie baz: +Cookie: + +--- no_error_log +[error] + + + +=== TEST 2: clear cookie (without existing cookies) +--- config + location /t { + more_clear_input_headers Cookie; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 0 +content: cookies: 0 + +--- response_body +Cookie foo: +Cookie baz: +Cookie: + +--- no_error_log +[error] + + + +=== TEST 3: set one custom cookie (with existing cookies) +--- config + location /t { + more_set_input_headers "Cookie: boo=123"; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie boo: $cookie_boo"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t +--- more_headers +Cookie: foo=bar +Cookie: baz=blah + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 2 +content: cookies: 1 + +--- response_body +Cookie foo: +Cookie baz: +Cookie boo: 123 +Cookie: boo=123 + +--- no_error_log +[error] + + + +=== TEST 4: set one custom cookie (without existing cookies) +--- config + location /t { + more_set_input_headers "Cookie: boo=123"; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie boo: $cookie_boo"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 0 +content: cookies: 1 + +--- response_body +Cookie foo: +Cookie baz: +Cookie boo: 123 +Cookie: boo=123 + +--- no_error_log +[error] + + + +=== TEST 5: for bad requests causing segfaults when setting & getting multi-value headers +--- config + error_page 400 = /err; + + location = /err { + more_set_input_headers "Cookie: foo=bar"; + echo -n $cookie_foo; + echo ok; + } +--- raw_request +GeT / HTTP/1.1 +--- response_body +ok +--- no_error_log +[warn] +[error] +--- no_check_leak diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-ua.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-ua.t new file mode 100644 index 0000000..da9a60d --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input-ua.t @@ -0,0 +1,628 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (4 * blocks()); + +#no_diff(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: clear Opera user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.7.4; U; en) Presto/2.10.229 Version/11.62 + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: opera: %d\n", $r->headers_in->opera) +} + +F(ngx_http_core_content_phase) { + printf("content: opera: %d\n", $r->headers_in->opera) +} + +--- stap_out +rewrite: opera: 1 +content: opera: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 2: clear MSIE 4 user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0) + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=1 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 3: set custom MSIE 4 user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0)"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=1 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0) +--- no_error_log +[error] + + + +=== TEST 4: clear MSIE 5 user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler) + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=1 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 5: set custom MSIE 5 user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler)"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=1 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler) +--- no_error_log +[error] + + + +=== TEST 6: clear MSIE 6 (without SV1) user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;) + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=1 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 7: set custom MSIE 6 (without SV1) user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;)"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=1 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;) +--- no_error_log +[error] + + + +=== TEST 8: clear MSIE 6 (with SV1) user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1) + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=0 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 9: set custom MSIE 6 (with SV1) user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=0 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1) +--- no_error_log +[error] + + + +=== TEST 10: set custom MSIE 7 user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; winfx; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0)"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=0 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; winfx; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0) +--- no_error_log +[error] + + + +=== TEST 11: clear Gecko user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: gecko: %d\n", $r->headers_in->gecko) +} + + +F(ngx_http_core_content_phase) { + printf("content: gecko: %d\n", $r->headers_in->gecko) +} + +--- stap_out +rewrite: gecko: 1 +content: gecko: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 12: set custom Gecko user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: gecko: %d\n", $r->headers_in->gecko) +} + + +F(ngx_http_core_content_phase) { + printf("content: gecko: %d\n", $r->headers_in->gecko) +} + +--- stap_out +rewrite: gecko: 0 +content: gecko: 1 + +--- response_body +User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 +--- no_error_log +[error] + + + +=== TEST 13: clear Chrome user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: chrome: %d\n", $r->headers_in->chrome) +} + + +F(ngx_http_core_content_phase) { + printf("content: chrome: %d\n", $r->headers_in->chrome) +} + +--- stap_out +rewrite: chrome: 1 +content: chrome: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 14: set custom Chrome user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: chrome: %d\n", $r->headers_in->chrome) +} + + +F(ngx_http_core_content_phase) { + printf("content: chrome: %d\n", $r->headers_in->chrome) +} + +--- stap_out +rewrite: chrome: 0 +content: chrome: 1 + +--- response_body +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 +--- no_error_log +[error] + + + +=== TEST 15: clear Safari (Mac OS X) user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: safari: %d\n", $r->headers_in->safari) +} + + +F(ngx_http_core_content_phase) { + printf("content: safari: %d\n", $r->headers_in->safari) +} + +--- stap_out +rewrite: safari: 1 +content: safari: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 16: set custom Safari user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: safari: %d\n", $r->headers_in->safari) +} + + +F(ngx_http_core_content_phase) { + printf("content: safari: %d\n", $r->headers_in->safari) +} + +--- stap_out +rewrite: safari: 0 +content: safari: 1 + +--- response_body +User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +--- no_error_log +[error] + + + +=== TEST 17: clear Konqueror user-agent +--- config + location /t { + more_clear_input_headers User-Agent; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: konqueror: %d\n", $r->headers_in->konqueror) +} + + +F(ngx_http_core_content_phase) { + printf("content: konqueror: %d\n", $r->headers_in->konqueror) +} + +--- stap_out +rewrite: konqueror: 1 +content: konqueror: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 18: set custom Konqueror user-agent +--- config + location /t { + more_set_input_headers "User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu)"; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + printf("rewrite: konqueror: %d\n", $r->headers_in->konqueror) +} + + +F(ngx_http_core_content_phase) { + printf("content: konqueror: %d\n", $r->headers_in->konqueror) +} + +--- stap_out +rewrite: konqueror: 0 +content: konqueror: 1 + +--- response_body +User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) +--- no_error_log +[error] diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input.t new file mode 100644 index 0000000..01ae73f --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/input.t @@ -0,0 +1,1331 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; # 'no_plan'; + +repeat_each(2); + +plan tests => repeat_each() * 128; + +no_long_string(); +#no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: set request header at client side +--- config + location /foo { + #more_set_input_headers 'X-Foo: howdy'; + echo $http_x_foo; + } +--- request + GET /foo +--- more_headers +X-Foo: blah +--- response_headers +! X-Foo +--- response_body +blah + + + +=== TEST 2: set request header at client side and rewrite it +--- config + location /foo { + more_set_input_headers 'X-Foo: howdy'; + echo $http_x_foo; + } +--- request + GET /foo +--- more_headers +X-Foo: blah +--- response_headers +! X-Foo +--- response_body +howdy + + + +=== TEST 3: rewrite content length +--- config + location /bar { + more_set_input_headers 'Content-Length: 2048'; + echo_read_request_body; + echo_request_body; + } +--- request eval +"POST /bar\n" . +"a" x 4096 +--- response_body eval +"a" x 2048 +--- timeout: 15 + + + +=== TEST 4: try to rewrite content length using the rewrite module +Thisshould not take effect ;) +--- config + location /bar { + set $http_content_length 2048; + echo_read_request_body; + echo_request_body; + } +--- request eval +"POST /bar\n" . +"a" x 4096 +--- response_body eval +"a" x 4096 + + + +=== TEST 5: rewrite host and user-agent +--- config + location /bar { + more_set_input_headers 'Host: foo' 'User-Agent: blah'; + echo "Host: $host"; + echo "User-Agent: $http_user_agent"; + } +--- request +GET /bar +--- response_body +Host: foo +User-Agent: blah + + + +=== TEST 6: clear host and user-agent +$host always has a default value and cannot be really cleared. +--- config + location /bar { + more_clear_input_headers 'Host: foo' 'User-Agent: blah'; + echo "Host: $host"; + echo "Host (2): $http_host"; + echo "User-Agent: $http_user_agent"; + } +--- request +GET /bar +--- response_body +Host: localhost +Host (2): +User-Agent: + + + +=== TEST 7: clear host and user-agent (the other way) +--- config + location /bar { + more_set_input_headers 'Host:' 'User-Agent:' 'X-Foo:'; + echo "Host: $host"; + echo "User-Agent: $http_user_agent"; + echo "X-Foo: $http_x_foo"; + } +--- request +GET /bar +--- more_headers +X-Foo: bar +--- response_body +Host: localhost +User-Agent: +X-Foo: + + + +=== TEST 8: clear content-length +--- config + location /bar { + more_set_input_headers 'Content-Length: '; + echo "Content-Length: $http_content_length"; + } +--- request +POST /bar +hello +--- more_headers +--- response_body +Content-Length: + + + +=== TEST 9: clear content-length (the other way) +--- config + location /bar { + more_clear_input_headers 'Content-Length: '; + echo "Content-Length: $http_content_length"; + } +--- request +POST /bar +hello +--- more_headers +--- response_body +Content-Length: + + + +=== TEST 10: rewrite type +--- config + location /bar { + more_set_input_headers 'Content-Type: text/css'; + echo "Content-Type: $content_type"; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/plain +--- response_body +Content-Type: text/css + + + +=== TEST 11: clear type +--- config + location /bar { + more_set_input_headers 'Content-Type:'; + echo "Content-Type: $content_type"; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/plain +--- response_body +Content-Type: + + + +=== TEST 12: clear type (the other way) +--- config + location /bar { + more_clear_input_headers 'Content-Type:foo'; + echo "Content-Type: $content_type"; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/plain +--- response_body +Content-Type: + + + +=== TEST 13: add type constraints +--- config + location /bar { + more_set_input_headers -t 'text/plain' 'X-Blah:yay'; + echo $http_x_blah; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/plain +--- response_body +yay + + + +=== TEST 14: add type constraints (not matched) +--- config + location /bar { + more_set_input_headers -t 'text/plain' 'X-Blah:yay'; + echo $http_x_blah; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/css +--- response_body eval: "\n" + + + +=== TEST 15: add type constraints (OR'd) +--- config + location /bar { + more_set_input_headers -t 'text/plain text/css' 'X-Blah:yay'; + echo $http_x_blah; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/css +--- response_body +yay + + + +=== TEST 16: add type constraints (OR'd) +--- config + location /bar { + more_set_input_headers -t 'text/plain text/css' 'X-Blah:yay'; + echo $http_x_blah; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/plain +--- response_body +yay + + + +=== TEST 17: add type constraints (OR'd) (not matched) +--- config + location /bar { + more_set_input_headers -t 'text/plain text/css' 'X-Blah:yay'; + echo $http_x_blah; + } +--- request +POST /bar +hello +--- more_headers +Content-Type: text/html +--- response_body eval: "\n" + + + +=== TEST 18: mix input and output cmds +--- config + location /bar { + more_set_input_headers 'X-Blah:yay'; + more_set_headers 'X-Blah:hiya'; + echo $http_x_blah; + } +--- request +GET /bar +--- response_headers +X-Blah: hiya +--- response +yay + + + +=== TEST 19: set request header at client side and replace +--- config + location /foo { + more_set_input_headers -r 'X-Foo: howdy'; + echo $http_x_foo; + } +--- request + GET /foo +--- more_headers +X-Foo: blah +--- response_headers +! X-Foo +--- response_body +howdy + + + +=== TEST 20: do no set request header at client, so no replace with -r option +--- config + location /foo { + more_set_input_headers -r 'X-Foo: howdy'; + echo "empty_header:" $http_x_foo; + } +--- request + GET /foo +--- response_headers +! X-Foo +--- response_body +empty_header: + + + +=== TEST 21: clear input headers +--- config + location /foo { + set $val 'dog'; + + more_clear_input_headers 'User-Agent'; + + proxy_pass http://127.0.0.1:$server_port/proxy; + } + location /proxy { + echo -n $echo_client_request_headers; + } +--- request + GET /foo +--- more_headers +User-Agent: my-sock +--- response_body eval +"GET /proxy HTTP/1.0\r +Host: 127.0.0.1:\$ServerPort\r +Connection: close\r +\r +" +--- skip_nginx: 3: < 0.7.46 + + + +=== TEST 22: clear input headers +--- config + location /foo { + more_clear_input_headers 'User-Agent'; + + proxy_pass http://127.0.0.1:$server_port/proxy; + } + location /proxy { + echo -n $echo_client_request_headers; + } +--- request + GET /foo +--- response_body eval +"GET /proxy HTTP/1.0\r +Host: 127.0.0.1:\$ServerPort\r +Connection: close\r +\r +" +--- skip_nginx: 3: < 0.7.46 + + + +=== TEST 23: clear input headers +--- config + location /foo { + more_clear_input_headers 'X-Foo19'; + more_clear_input_headers 'X-Foo20'; + more_clear_input_headers 'X-Foo21'; + + proxy_pass http://127.0.0.1:$server_port/proxy; + } + location /proxy { + echo -n $echo_client_request_headers; + } +--- request + GET /foo +--- more_headers eval +my $s; +for my $i (3..21) { + $s .= "X-Foo$i: $i\n"; +} +$s; +--- response_body eval +"GET /proxy HTTP/1.0\r +Host: 127.0.0.1:\$ServerPort\r +Connection: close\r +X-Foo3: 3\r +X-Foo4: 4\r +X-Foo5: 5\r +X-Foo6: 6\r +X-Foo7: 7\r +X-Foo8: 8\r +X-Foo9: 9\r +X-Foo10: 10\r +X-Foo11: 11\r +X-Foo12: 12\r +X-Foo13: 13\r +X-Foo14: 14\r +X-Foo15: 15\r +X-Foo16: 16\r +X-Foo17: 17\r +X-Foo18: 18\r +\r +" +--- skip_nginx: 3: < 0.7.46 + + + +=== TEST 24: Accept-Encoding +--- config + location /bar { + default_type 'text/plain'; + more_set_input_headers 'Accept-Encoding: gzip'; + gzip on; + gzip_min_length 1; + gzip_buffers 4 8k; + gzip_types text/plain; + } +--- user_files +">>> bar +" . ("hello" x 512) +--- request +GET /bar +--- response_headers +Content-Encoding: gzip +--- response_body_like: . + + + +=== TEST 25: rewrite + set request header +--- config + location /t { + rewrite ^ /foo last; + } + + location /foo { + more_set_input_headers 'X-Foo: howdy'; + proxy_pass http://127.0.0.1:$server_port/echo; + } + + location /echo { + echo "X-Foo: $http_x_foo"; + } +--- request + GET /foo +--- response_headers +! X-Foo +--- response_body +X-Foo: howdy + + + +=== TEST 26: clear_header should clear all the instances of the user custom header +--- config + location = /t { + more_clear_input_headers Foo; + + proxy_pass http://127.0.0.1:$server_port/echo; + } + + location = /echo { + echo "Foo: [$http_foo]"; + echo "Test-Header: [$http_test_header]"; + } +--- request +GET /t +--- more_headers +Foo: foo +Foo: bah +Test-Header: 1 +--- response_body +Foo: [] +Test-Header: [1] + + + +=== TEST 27: clear_header should clear all the instances of the builtin header +--- config + location = /t { + more_clear_input_headers Content-Type; + + proxy_pass http://127.0.0.1:$server_port/echo; + } + + location = /echo { + echo "Content-Type: [$http_content_type]"; + echo "Test-Header: [$http_test_header]"; + #echo $echo_client_request_headers; + } +--- request +GET /t +--- more_headers +Content-Type: foo +Content-Type: bah +Test-Header: 1 +--- response_body +Content-Type: [] +Test-Header: [1] + + + +=== TEST 28: Converting POST to GET - clearing headers (bug found by Matthieu Tourne, 411 error page) +--- config + location /t { + more_clear_input_headers Content-Type; + more_clear_input_headers Content-Length; + + #proxy_pass http://127.0.0.1:8888; + proxy_pass http://127.0.0.1:$server_port/back; + } + + location /back { + echo $echo_client_request_headers; + } +--- request +POST /t +hello world +--- more_headers +Content-Type: application/ocsp-request +Test-Header: 1 +--- response_body_like eval +qr/Connection: close\r +Test-Header: 1\r +\r +$/ +--- no_error_log +[error] + + + +=== TEST 29: clear_header() does not duplicate subsequent headers (old bug) +--- config + location = /t { + more_clear_input_headers Foo; + + proxy_pass http://127.0.0.1:$server_port/echo; + } + + location = /echo { + echo $echo_client_request_headers; + } +--- request +GET /t +--- more_headers +Bah: bah +Foo: foo +Test-Header: 1 +Foo1: foo1 +Foo2: foo2 +Foo3: foo3 +Foo4: foo4 +Foo5: foo5 +Foo6: foo6 +Foo7: foo7 +Foo8: foo8 +Foo9: foo9 +Foo10: foo10 +Foo11: foo11 +Foo12: foo12 +Foo13: foo13 +Foo14: foo14 +Foo15: foo15 +Foo16: foo16 +Foo17: foo17 +Foo18: foo18 +Foo19: foo19 +Foo20: foo20 +Foo21: foo21 +Foo22: foo22 +--- response_body_like eval +qr/Bah: bah\r +Test-Header: 1\r +Foo1: foo1\r +Foo2: foo2\r +Foo3: foo3\r +Foo4: foo4\r +Foo5: foo5\r +Foo6: foo6\r +Foo7: foo7\r +Foo8: foo8\r +Foo9: foo9\r +Foo10: foo10\r +Foo11: foo11\r +Foo12: foo12\r +Foo13: foo13\r +Foo14: foo14\r +Foo15: foo15\r +Foo16: foo16\r +Foo17: foo17\r +Foo18: foo18\r +Foo19: foo19\r +Foo20: foo20\r +Foo21: foo21\r +Foo22: foo22\r +/ + + + +=== TEST 30: clear input header (just more than 20 headers) +--- config + location = /t { + more_clear_input_headers "R"; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +Q: q\r +\r +" + + + +=== TEST 31: clear input header (just more than 20 headers, and add more) +--- config + location = /t { + more_clear_input_headers R; + more_set_input_headers "foo-1: 1" "foo-2: 2" "foo-3: 3" "foo-4: 4" + "foo-5: 5" "foo-6: 6" "foo-7: 7" "foo-8: 8" "foo-9: 9" + "foo-10: 10" "foo-11: 11" "foo-12: 12" "foo-13: 13" + "foo-14: 14" "foo-15: 15" "foo-16: 16" "foo-17: 17" "foo-18: 18" + "foo-19: 19" "foo-20: 20" "foo-21: 21"; + + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +Q: q\r +foo-1: 1\r +foo-2: 2\r +foo-3: 3\r +foo-4: 4\r +foo-5: 5\r +foo-6: 6\r +foo-7: 7\r +foo-8: 8\r +foo-9: 9\r +foo-10: 10\r +foo-11: 11\r +foo-12: 12\r +foo-13: 13\r +foo-14: 14\r +foo-15: 15\r +foo-16: 16\r +foo-17: 17\r +foo-18: 18\r +foo-19: 19\r +foo-20: 20\r +foo-21: 21\r +\r +" + + + +=== TEST 32: clear input header (just more than 21 headers) +--- config + location = /t { + more_clear_input_headers R Q; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +Bah: bah\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +\r +" + + + +=== TEST 33: clear input header (just more than 21 headers) +--- config + location = /t { + more_clear_input_headers R Q; + more_set_input_headers "foo-1: 1" "foo-2: 2" "foo-3: 3" "foo-4: 4" + "foo-5: 5" "foo-6: 6" "foo-7: 7" "foo-8: 8" "foo-9: 9" + "foo-10: 10" "foo-11: 11" "foo-12: 12" "foo-13: 13" + "foo-14: 14" "foo-15: 15" "foo-16: 16" "foo-17: 17" "foo-18: 18" + "foo-19: 19" "foo-20: 20" "foo-21: 21"; + + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo -n $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +Bah: bah\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +foo-1: 1\r +foo-2: 2\r +foo-3: 3\r +foo-4: 4\r +foo-5: 5\r +foo-6: 6\r +foo-7: 7\r +foo-8: 8\r +foo-9: 9\r +foo-10: 10\r +foo-11: 11\r +foo-12: 12\r +foo-13: 13\r +foo-14: 14\r +foo-15: 15\r +foo-16: 16\r +foo-17: 17\r +foo-18: 18\r +foo-19: 19\r +foo-20: 20\r +foo-21: 21\r +\r +" + + + +=== TEST 34: clear X-Real-IP +--- config + location /t { + more_clear_input_headers X-Real-IP; + echo "X-Real-IP: $http_x_real_ip"; + } +--- request +GET /t +--- more_headers +X-Real-IP: 8.8.8.8 + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("rewrite: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("rewrite: no x-real-ip") + } +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("content: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("content: no x-real-ip") + } +} + +--- stap_out +rewrite: x-real-ip: 8.8.8.8 +content: no x-real-ip + +--- response_body +X-Real-IP: + +--- no_error_log +[error] + + + +=== TEST 35: set custom X-Real-IP +--- config + location /t { + more_set_input_headers "X-Real-IP: 8.8.4.4"; + echo "X-Real-IP: $http_x_real_ip"; + } +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("rewrite: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("rewrite: no x-real-ip") + } + +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("content: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("content: no x-real-ip") + } +} + +--- stap_out +rewrite: no x-real-ip +content: x-real-ip: 8.8.4.4 + +--- response_body +X-Real-IP: 8.8.4.4 + +--- no_error_log +[error] + + + +=== TEST 36: clear Via +--- config + location /t { + more_clear_input_headers Via; + echo "Via: $http_via"; + } +--- request +GET /t +--- more_headers +Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("rewrite: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("rewrite: no via") + } +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("content: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("content: no via") + } +} + +--- stap_out +rewrite: via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) +content: no via + +--- response_body +Via: + +--- no_error_log +[error] + + + +=== TEST 37: set custom Via +--- config + location /t { + more_set_input_headers "Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)"; + echo "Via: $http_via"; + } +--- request +GET /t + +--- stap +F(ngx_http_headers_more_exec_input_cmd) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("rewrite: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("rewrite: no via") + } + +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("content: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("content: no via") + } +} + +--- stap_out +rewrite: no via +content: via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + +--- response_body +Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + +--- no_error_log +[error] + + + +=== TEST 38: HTTP 0.9 (set) +--- config + location /foo { + more_set_input_headers 'X-Foo: howdy'; + echo "x-foo: $http_x_foo"; + } +--- raw_request eval +"GET /foo\r\n" +--- response_headers +! X-Foo +--- response_body +x-foo: +--- http09 + + + +=== TEST 39: HTTP 0.9 (clear) +--- config + location /foo { + more_clear_input_headers 'X-Foo'; + echo "x-foo: $http_x_foo"; + } +--- raw_request eval +"GET /foo\r\n" +--- response_headers +! X-Foo +--- response_body +x-foo: +--- http09 + + + +=== TEST 40: Host header with port and $host +--- config + location /bar { + more_set_input_headers 'Host: agentzh.org:1984'; + echo "host var: $host"; + echo "http_host var: $http_host"; + } +--- request +GET /bar +--- response_body +host var: agentzh.org +http_host var: agentzh.org:1984 + + + +=== TEST 41: Host header with upper case letters and $host +--- config + location /bar { + more_set_input_headers 'Host: agentZH.org:1984'; + echo "host var: $host"; + echo "http_host var: $http_host"; + } +--- request +GET /bar +--- response_body +host var: agentzh.org +http_host var: agentZH.org:1984 + + + +=== TEST 42: clear all and re-insert +--- config + location = /t { + more_clear_input_headers Host Connection Cache-Control Accept + User-Agent Accept-Encoding Accept-Language + Cookie; + + more_set_input_headers "Host: a" "Connection: b" "Cache-Control: c" + "Accept: d" "User-Agent: e" "Accept-Encoding: f" + "Accept-Language: g" "Cookie: h"; + + more_clear_input_headers Host Connection Cache-Control Accept + User-Agent Accept-Encoding Accept-Language + Cookie; + + more_set_input_headers "Host: a" "Connection: b" "Cache-Control: c" + "Accept: d" "User-Agent: e" "Accept-Encoding: f" + "Accept-Language: g" "Cookie: h"; + + echo ok; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Cache-Control: max-age=0\r +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36\r +Accept-Encoding: gzip,deflate,sdch\r +Accept-Language: en-US,en;q=0.8\r +Cookie: test=cookie;\r +\r +" +--- response_body +ok +--- no_error_log +[error] + + + +=== TEST 43: more_set_input_header does not override request headers with multiple values +--- config + #lua_code_cache off; + location = /t { + more_set_input_headers "AAA: 111"; + + content_by_lua ' + local headers = ngx.req.get_headers() + ngx.say(headers["AAA"]) + '; + } +--- request +GET /t +--- more_headers +AAA: 123 +AAA: 456 +AAA: 678 + +--- response_body +111 +--- no_error_log +[error] + + + +=== TEST 44: clear If-Unmodified-Since req header +--- config + location = /t { + more_clear_input_headers 'If-Unmodified-Since'; + content_by_lua ' + ngx.header["Last-Modified"] = "Tue, 30 Jun 2011 12:16:36 GMT" + ngx.say("If-Unmodified-Since: ", ngx.var.http_if_unmodified_since) + '; + } +--- request +GET /t +--- more_headers +If-Unmodified-Since: Tue, 28 Jun 2011 12:16:36 GMT +--- response_body +If-Unmodified-Since: nil +--- no_error_log +[error] + + + +=== TEST 45: clear If-Match req header +--- config + location = /t { + more_clear_input_headers 'If-Match'; + echo "If-Match: $http_if_match"; + } +--- request +GET /t +--- more_headers +If-Match: abc +--- response_body +If-Match: +--- no_error_log +[error] + + + +=== TEST 46: clear If-None-Match req header +--- config + location = /t { + more_clear_input_headers 'If-None-Match'; + echo "If-None-Match: $http_if_none_match"; + } +--- request +GET /t +--- more_headers +If-None-Match: * +--- response_body +If-None-Match: +--- no_error_log +[error] + + + +=== TEST 47: set the Destination request header for WebDav +--- config + location = /a.txt { + more_set_input_headers "Destination: /b.txt"; + dav_methods MOVE; + dav_access all:rw; + root html; + } + +--- user_files +>>> a.txt +hello, world! + +--- request +MOVE /a.txt + +--- response_body +--- no_error_log +client sent no "Destination" header +[error] +--- error_code: 204 + + + +=== TEST 48: more_set_input_headers + X-Forwarded-For +--- config + location = /t { + more_set_input_headers "X-Forwarded-For: 8.8.8.8"; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Foo $proxy_add_x_forwarded_for; + } + + location = /back { + echo "Foo: $http_foo"; + } + +--- request +GET /t + +--- response_body +Foo: 8.8.8.8, 127.0.0.1 +--- no_error_log +[error] + + + +=== TEST 49: more_clear_input_headers + X-Forwarded-For +--- config + location = /t { + more_clear_input_headers "X-Forwarded-For"; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Foo $proxy_add_x_forwarded_for; + } + + location = /back { + echo "Foo: $http_foo"; + } + +--- request +GET /t + +--- more_headers +X-Forwarded-For: 8.8.8.8 +--- response_body +Foo: 127.0.0.1 +--- no_error_log +[error] + + + +=== TEST 50: clear input headers with wildcard +--- config + location /hello { + more_clear_input_headers 'X-Hidden-*'; + content_by_lua ' + ngx.say("X-Hidden-One: ", ngx.var.http_x_hidden_one) + ngx.say("X-Hidden-Two: ", ngx.var.http_x_hidden_two) + '; + } +--- request + GET /hello +--- more_headers +X-Hidden-One: i am hidden +X-Hidden-Two: me 2 +--- response_body +X-Hidden-One: nil +X-Hidden-Two: nil + + + +=== TEST 51: make sure wildcard doesn't affect more_set_input_headers +--- config + location /hello { + more_set_input_headers 'X-Hidden-*: lol'; + content_by_lua ' + ngx.say("X-Hidden-One: ", ngx.var.http_x_hidden_one) + ngx.say("X-Hidden-Two: ", ngx.var.http_x_hidden_two) + '; + } +--- request + GET /hello +--- more_headers +X-Hidden-One: i am hidden +X-Hidden-Two: me 2 +--- response_body +X-Hidden-One: i am hidden +X-Hidden-Two: me 2 diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/phase.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/phase.t new file mode 100644 index 0000000..11183db --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/phase.t @@ -0,0 +1,25 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => 3; + +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: simple set (1 arg) +--- config + location /foo { + deny all; + more_set_headers 'X-Foo: Blah'; + } +--- request + GET /foo +--- response_headers +X-Foo: Blah +--- response_body_like: 403 Forbidden +--- error_code: 403 diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/sanity.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/sanity.t new file mode 100644 index 0000000..47d65e3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/sanity.t @@ -0,0 +1,628 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * 123; + +#master_on(); +#workers(2); +log_level("warn"); +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: simple set (1 arg) +--- config + location /foo { + echo hi; + more_set_headers 'X-Foo: Blah'; + } +--- request + GET /foo +--- response_headers +X-Foo: Blah +--- response_body +hi + + + +=== TEST 2: simple set (2 args) +--- config + location /foo { + echo hi; + more_set_headers 'X-Foo: Blah' 'X-Bar: hi'; + } +--- request + GET /foo +--- response_headers +X-Foo: Blah +X-Bar: hi +--- response_body +hi + + + +=== TEST 3: two sets in a single location +--- config + location /two { + echo hi; + more_set_headers 'X-Foo: Blah' + more_set_headers 'X-Bar: hi'; + } +--- request + GET /two +--- response_headers +X-Foo: Blah +X-Bar: hi +--- response_body +hi + + + +=== TEST 4: two sets in a single location (for 404 too) +--- config + location /two { + more_set_headers 'X-Foo: Blah' + more_set_headers 'X-Bar: hi'; + return 404; + } +--- request + GET /two +--- response_headers +X-Foo: Blah +X-Bar: hi +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 5: set a header then clears it (500) +--- config + location /two { + more_set_headers 'X-Foo: Blah'; + more_set_headers 'X-Foo:'; + return 500; + } +--- request + GET /two +--- response_headers +! X-Foo +! X-Bar +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 6: set a header only when 500 (matched) +--- config + location /bad { + more_set_headers -s 500 'X-Mine: Hiya'; + more_set_headers -s 404 'X-Yours: Blah'; + return 500; + } +--- request + GET /bad +--- response_headers +X-Mine: Hiya +! X-Yours +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 7: set a header only when 500 (not matched with 200) +--- config + location /bad { + more_set_headers -s 500 'X-Mine: Hiya'; + more_set_headers -s 404 'X-Yours: Blah'; + echo hello; + } +--- request + GET /bad +--- response_headers +! X-Mine +! X-Yours +--- response_body +hello +--- error_code: 200 + + + +=== TEST 8: set a header only when 500 (not matched with 404) +--- config + location /bad { + more_set_headers -s 500 'X-Mine: Hiya'; + more_set_headers -s 404 'X-Yours: Blah'; + return 404; + } +--- request + GET /bad +--- response_headers +! X-Mine +X-Yours: Blah +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 9: more conditions +--- config + location /bad { + more_set_headers -s '503 404' 'X-Mine: Hiya'; + more_set_headers -s ' 404 413 ' 'X-Yours: Blah'; + return 503; + } +--- request + GET /bad +--- response_headers +X-Mine: Hiya +! X-Yours +--- response_body_like: 503 Service +--- error_code: 503 + + + +=== TEST 10: more conditions +--- config + location /bad { + more_set_headers -s '503 404' 'X-Mine: Hiya'; + more_set_headers -s ' 404 413 ' 'X-Yours: Blah'; + return 404; + } +--- request + GET /bad +--- response_headers +X-Mine: Hiya +X-Yours: Blah +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 11: more conditions +--- config + location /bad { + more_set_headers -s '503 404' 'X-Mine: Hiya'; + more_set_headers -s ' 404 413 ' 'X-Yours: Blah'; + return 413; + } +--- request + GET /bad +--- response_headers +! X-Mine +X-Yours: Blah +--- response_body_like: 413 Request Entity Too Large +--- error_code: 413 + + + +=== TEST 12: simple -t +--- config + location /bad { + default_type 'text/css'; + more_set_headers -t 'text/css' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-CSS: yes +--- response_body +hi + + + +=== TEST 13: simple -t (not matched) +--- config + location /bad { + default_type 'text/plain'; + more_set_headers -t 'text/css' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +! X-CSS +--- response_body +hi + + + +=== TEST 14: multiple -t (not matched) +--- config + location /bad { + default_type 'text/plain'; + more_set_headers -t 'text/javascript' -t 'text/css' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +! X-CSS +--- response_body +hi + + + +=== TEST 15: multiple -t (matched) +--- config + location /bad { + default_type 'text/plain'; + more_set_headers -t 'text/javascript' -t 'text/plain' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-CSS: yes +--- response_body +hi + + + +=== TEST 16: multiple -t (matched) +--- config + location /bad { + default_type 'text/javascript'; + more_set_headers -t 'text/javascript' -t 'text/plain' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-CSS: yes +--- response_body +hi + + + +=== TEST 17: multiple -t (matched) with extra spaces +--- config + location /bad { + default_type 'text/javascript'; + more_set_headers -t ' text/javascript ' -t 'text/plain' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-CSS: yes +--- response_body +hi + + + +=== TEST 18: multiple -t merged +--- config + location /bad { + default_type 'text/javascript'; + more_set_headers -t ' text/javascript text/plain' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-CSS: yes +--- response_body +hi + + + +=== TEST 19: multiple -t merged (2) +--- config + location /bad { + default_type 'text/plain'; + more_set_headers -t ' text/javascript text/plain' 'X-CSS: yes'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-CSS: yes +--- response_body +hi + + + +=== TEST 20: multiple -s option in a directive (not matched) +--- config + location /bad { + more_set_headers -s 404 -s 500 'X-status: howdy'; + echo hi; + } +--- request + GET /bad +--- response_headers +! X-status +--- response_body +hi + + + +=== TEST 21: multiple -s option in a directive (matched 404) +--- config + location /bad { + more_set_headers -s 404 -s 500 'X-status: howdy'; + return 404; + } +--- request + GET /bad +--- response_headers +X-status: howdy +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 22: multiple -s option in a directive (matched 500) +--- config + location /bad { + more_set_headers -s 404 -s 500 'X-status: howdy'; + return 500; + } +--- request + GET /bad +--- response_headers +X-status: howdy +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 23: -s mixed with -t +--- config + location /bad { + default_type 'text/html'; + more_set_headers -s 404 -s 200 -t 'text/html' 'X-status: howdy2'; + return 404; + } +--- request + GET /bad +--- response_headers +X-status: howdy2 +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 24: -s mixed with -t +--- config + location /bad { + default_type 'text/html'; + more_set_headers -s 404 -s 200 -t 'text/plain' 'X-status: howdy2'; + return 404; + } +--- request + GET /bad +--- response_headers +! X-status +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 25: -s mixed with -t +--- config + location /bad { + default_type 'text/html'; + more_set_headers -s 404 -s 200 -t 'text/html' 'X-status: howdy2'; + echo hi; + } +--- request + GET /bad +--- response_headers +X-status: howdy2 +--- response_body +hi +--- error_code: 200 + + + +=== TEST 26: -s mixed with -t +--- config + location /bad { + default_type 'text/html'; + more_set_headers -s 500 -s 200 -t 'text/html' 'X-status: howdy2'; + return 404; + } +--- request + GET /bad +--- response_headers +! X-status +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 27: merge from the upper level +--- config + more_set_headers -s 404 -t 'text/html' 'X-status2: howdy3'; + location /bad { + default_type 'text/html'; + more_set_headers -s 500 -s 200 -t 'text/html' 'X-status: howdy2'; + return 404; + } +--- request + GET /bad +--- response_headers +X-status2: howdy3 +! X-status +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 28: merge from the upper level +--- config + more_set_headers -s 404 -t 'text/html' 'X-status2: howdy3'; + location /bad { + default_type 'text/html'; + more_set_headers -s 500 -s 200 -t 'text/html' 'X-status: howdy2'; + echo yeah; + } +--- request + GET /bad +--- response_headers +! X-status2 +X-status: howdy2 +--- response_body +yeah +--- error_code: 200 + + + +=== TEST 29: override settings by inheritance +--- config + more_set_headers -s 404 -t 'text/html' 'X-status: yeah'; + location /bad { + default_type 'text/html'; + more_set_headers -s 404 -t 'text/html' 'X-status: nope'; + return 404; + } +--- request + GET /bad +--- response_headers +X-status: nope +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 30: append settings by inheritance +--- config + more_set_headers -s 404 -t 'text/html' 'X-status: yeah'; + location /bad { + default_type 'text/html'; + more_set_headers -s 404 -t 'text/html' 'X-status2: nope'; + return 404; + } +--- request + GET /bad +--- response_headers +X-status: yeah +X-status2: nope +--- response_body_like: 404 Not Found +--- error_code: 404 + + + +=== TEST 31: clear headers with wildcard +--- config + location = /backend { + add_header X-Hidden-One "i am hidden"; + add_header X-Hidden-Two "me 2"; + echo hi; + } + location /hello { + more_clear_headers 'X-Hidden-*'; + proxy_pass http://127.0.0.1:$server_port/backend; + } +--- request + GET /hello +--- response_headers +! X-Hidden-One +! X-Hidden-Two +--- response_body +hi + + + +=== TEST 32: clear duplicate headers +--- config + location = /backend { + add_header pragma no-cache; + add_header pragma no-cache; + echo hi; + } + location /hello { + more_clear_headers 'pragma'; + proxy_pass http://127.0.0.1:$server_port/backend; + } +--- request + GET /hello +--- response_headers +!pragma +--- response_body +hi + + + +=== TEST 33: HTTP 0.9 (set) +--- config + location /foo { + more_set_headers 'X-Foo: howdy'; + echo ok; + } +--- raw_request eval +"GET /foo\r\n" +--- response_headers +! X-Foo +--- response_body +ok +--- http09 + + + +=== TEST 34: use the -a option to append the cookie field +--- config + location /cookie { + more_set_headers -a 'Set-Cookie: name=lynch'; + echo ok; + } +--- request + GET /cookie +--- response_headers +Set-Cookie: name=lynch +--- response_body +ok + + + +=== TEST 35: the original Set-Cookie fields will not be overwritten, when using the -a option +--- config + location /cookie { + more_set_headers 'Set-Cookie: name=lynch'; + more_set_headers -a 'Set-Cookie: born=1981'; + echo ok; + } +--- request + GET /cookie +--- raw_response_headers_like eval +"Set-Cookie: name=lynch\r\nSet-Cookie: born=1981\r\n" +--- response_body +ok + + + +=== TEST 36: The behavior of builtin headers can not be changed +--- config + location /foo { + more_set_headers -a "Server: myServer"; + echo ok; + } +--- request + GET /foo +--- must_die +--- error_log chomp +can not append builtin headers +--- suppress_stderr + + + +=== TEST 37: can not use -a option with more_clear_headers +--- config + location /foo { + more_clear_headers -a 'Content-Type'; + echo ok; + } +--- request + GET /foo +--- must_die +--- error_log chomp +invalid option name: "-a" +--- suppress_stderr diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/subrequest.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/subrequest.t new file mode 100644 index 0000000..9443eca --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/subrequest.t @@ -0,0 +1,68 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; # 'no_plan'; + +plan tests => blocks() * 3; + +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: vars in input header directives +--- config + location /main { + echo_location /foo; + echo "main: $http_user_agent"; + } + location /foo { + set $val 'dog'; + + more_set_input_headers 'User-Agent: $val'; + + proxy_pass http://127.0.0.1:$server_port/proxy; + } + location /proxy { + echo "sub: $http_user_agent"; + } +--- request + GET /main +--- more_headers +User-Agent: my-sock +--- response_body +sub: dog +main: dog +--- response_headers +! Host +--- skip_nginx: 3: < 0.7.46 + + + +=== TEST 2: vars in input header directives +--- config + location /main { + #more_set_input_headers 'User-Agent: cat'; + echo_location /foo; + echo "main: $http_user_agent"; + } + location /foo { + set $val 'dog'; + + more_set_input_headers 'User-Agent: $val'; + + proxy_pass http://127.0.0.1:$server_port/proxy; + #echo $http_user_agent; + } + location /proxy { + echo "sub: $http_user_agent"; + } +--- request + GET /main +--- response_body +sub: dog +main: dog +--- response_headers +! Host +--- skip_nginx: 3: < 0.7.46 diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/unused.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/unused.t new file mode 100644 index 0000000..c51f91c --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/unused.t @@ -0,0 +1,174 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 2); + +#master_on(); +#workers(2); +log_level("warn"); +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: used output filter +--- config + location /foo { + echo hi; + more_set_headers "Foo: bar"; + } +--- request + GET /foo +--- response_headers +Foo: bar +--- response_body +hi +--- error_log +headers more header filter +--- no_error_log +[error] +--- log_level: debug + + + +=== TEST 2: unused output filter (none) +--- config + location /foo { + echo hi; + } +--- request + GET /foo +--- response_body +hi +--- no_error_log +headers more header filter +[error] +--- log_level: debug + + + +=== TEST 3: unused output filter (with more_set_input_headers only) +--- config + location /foo { + more_set_input_headers "Foo: bar"; + echo hi; + } +--- request + GET /foo +--- response_body +hi +--- no_error_log +headers more header filter +[error] +--- log_level: debug + + + +=== TEST 4: used rewrite handler +--- config + location /foo { + more_set_input_headers "Foo: bar"; + echo hi; + } +--- request + GET /foo +--- response_body +hi +--- error_log +headers more rewrite handler +--- no_error_log +[error] +--- log_level: debug + + + +=== TEST 5: unused rewrite handler (none) +--- config + location /foo { + #more_set_input_headers "Foo: bar"; + echo hi; + } +--- request + GET /foo +--- response_body +hi +--- no_error_log +headers more rewrite handler +[error] +--- log_level: debug + + + +=== TEST 6: unused rewrite handler (with output header filters) +--- config + location /foo { + #more_set_input_headers "Foo: bar"; + echo hi; + more_set_headers "Foo: bar"; + } +--- request + GET /foo +--- response_headers +Foo: bar +--- response_body +hi +--- no_error_log +headers more rewrite handler +[error] +--- log_level: debug + + + +=== TEST 7: multiple http {} blocks (filter) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP +--- config + location /foo { + echo hi; + more_set_headers 'Foo: bar'; + } +--- post_main_config + http { + } + +--- request + GET /foo +--- response_body +hi +--- response_headers +Foo: bar +--- no_error_log +[error] +--- error_log +headers more header filter +--- log_level: debug + + + +=== TEST 8: multiple http {} blocks (handler) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP +--- config + location /foo { + more_set_input_headers 'Foo: bar'; + echo $http_foo; + } +--- post_main_config + http { + } + +--- request + GET /foo +--- response_body +bar +--- no_error_log +headers more header handler +[error] +--- log_level: debug diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/vars.t b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/vars.t new file mode 100644 index 0000000..04c75c3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/t/vars.t @@ -0,0 +1,58 @@ +# vi:ft= + +use lib 'lib'; +use Test::Nginx::Socket; # 'no_plan'; + +plan tests => 9; + +no_diff; + +run_tests(); + +__DATA__ + +=== TEST 1: vars +--- config + location /foo { + echo hi; + set $val 'hello, world'; + more_set_headers 'X-Foo: $val'; + } +--- request + GET /foo +--- response_headers +X-Foo: hello, world +--- response_body +hi + + + +=== TEST 2: vars in both key and val +--- config + location /foo { + echo hi; + set $val 'hello, world'; + more_set_headers '$val: $val'; + } +--- request + GET /foo +--- response_headers +$val: hello, world +--- response_body +hi + + + +=== TEST 3: vars in input header directives +--- config + location /foo { + set $val 'dog'; + more_set_input_headers 'Host: $val'; + echo $host; + } +--- request + GET /foo +--- response_body +dog +--- response_headers +Host: diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/util/build.sh b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/util/build.sh new file mode 100755 index 0000000..00a191f --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/util/build.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# this file is mostly meant to be used by the author himself. + +root=`pwd` +version=$1 +home=~ +force=$2 +pcre2_opt="" +if [ "$WITHOUT_PCRE2" = "1" ]; then + pcre2_opt="--without-pcre2" +fi + + #--with-cc=gcc46 \ + +ngx-build $force $version \ + --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB" \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --without-mail_smtp_module \ + --without-http_upstream_ip_hash_module \ + --without-http_empty_gif_module \ + --without-http_memcached_module \ + --without-http_referer_module \ + --without-http_autoindex_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + $pcre2_opt \ + --with-http_realip_module \ + --with-http_dav_module \ + --add-module=$root/../eval-nginx-module \ + --add-module=$root/../lua-nginx-module \ + --add-module=$root/../echo-nginx-module \ + --add-module=$root $opts \ + --with-debug + #--add-module=$root/../ndk-nginx-module \ + #--without-http_ssi_module # we cannot disable ssi because echo_location_async depends on it (i dunno why?!) + diff --git a/modules_deb/libnginx-mod-http-headers-more-filter-0.38/valgrind.suppress b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/valgrind.suppress new file mode 100644 index 0000000..d51de70 --- /dev/null +++ b/modules_deb/libnginx-mod-http-headers-more-filter-0.38/valgrind.suppress @@ -0,0 +1,135 @@ +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + obj:* +} +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_calloc + fun:ngx_event_process_init +} +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_event_process_init +} +{ + + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl +} +{ + + Memcheck:Cond + fun:memcpy + fun:ngx_vslprintf + fun:ngx_log_error_core + fun:ngx_http_charset_header_filter +} +{ + nginx-core-process-init + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_event_process_init +} +{ + nginx-core-crc32-init + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_crc32_table_init + fun:main +} +{ + palloc_large_for_init_request + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_palloc_large + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_init_request + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers +} +{ + palloc_large_for_create_temp_buf + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_palloc_large + fun:ngx_palloc + fun:ngx_create_temp_buf + fun:ngx_http_init_request + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers +} +{ + accept_create_pool + Memcheck:Leak + fun:memalign + fun:posix_memalign + fun:ngx_memalign + fun:ngx_create_pool + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers +} +{ + create_pool_for_init_req + Memcheck:Leak + fun:memalign + fun:posix_memalign + fun:ngx_memalign + fun:ngx_create_pool + fun:ngx_http_init_request + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers +} +{ + + Memcheck:Addr8 + fun:getenv + fun:gcov_exit + fun:exit + fun:ngx_master_process_exit +} +{ + + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle +} diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/.gitignore b/modules_deb/libnginx-mod-http-ndk-0.3.4/.gitignore new file mode 100644 index 0000000..0fd79d0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/.gitignore @@ -0,0 +1,4 @@ +tags +cscope.* +*~ +*.swp diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/LICENSE b/modules_deb/libnginx-mod-http-ndk-0.3.4/LICENSE new file mode 100644 index 0000000..e1a5221 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2010-2018, Marcus Clyne + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/README.md b/modules_deb/libnginx-mod-http-ndk-0.3.4/README.md new file mode 100644 index 0000000..d9d3972 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/README.md @@ -0,0 +1,254 @@ +Name +==== + +Nginx Development Kit (NDK) + +Table of Contents +================= + +* [Name](#name) +* [Synopsis](#synopsis) +* [Status](#status) +* [Features](#features) +* [Design](#design) + * [modular](#modular) + * [auto-generated & easily extensible](#auto-generated--easily-extensible) +* [Usage for users](#usage-for-users) + * [Building as a dynamic module](#building-as-a-dynamic-module) +* [Usage for developers](#usage-for-developers) + * [Warning: using NDK_ALL](#warning-using-ndk_all) +* [Modules using NDK](#modules-using-ndk) +* [TODO](#todo) +* [License](#license) +* [Contributing / Feedback](#contributing--feedback) +* [Authors](#authors) +* [Special Thanks](#special-thanks) + +Synopsis +======== + +The NDK is an Nginx module that is designed to extend the core functionality of the +excellent Nginx webserver in a way that can be used as a basis of other Nginx modules. + +It has functions and macros to deal with generic tasks that don't currently have +generic code as part of the core distribution. The NDK itself adds few features +that are seen from a user's point of view - it's just designed to help reduce the +code that Nginx module developers need to write. + +Nginx module developers wishing to use any of the features in the NDK should specify +that the NDK is a dependency of their module, and that users will need to compile +it as well when they compile their own modules. They will also need to declare in +their own modules which features of the NDK they wish to use (explained below). + +If you are not an Nginx module developer, then the only useful part of this project +will be the 'usage for users' section below. + +[Back to TOC](#table-of-contents) + +Status +====== + +The NDK is now considered to be stable. It is already being used in quite a few third +party modules (see list below). + +[Back to TOC](#table-of-contents) + +Features +======== + +* additional conf_set functions for regexes, complex/script values, paths... +* macros to simplify tasks like checking for NULL values when doing ngx_array_push +* patches to the main source code +* ngx_auto_lib_core generic external library handler is included (see separate readme) + +[Back to TOC](#table-of-contents) + +Design +====== + +modular +------- + +The kit itself is designed in a modular way, so that only the required code is compiled. +It's possible to add just a single NDK module, a few or all of them. + +[Back to TOC](#table-of-contents) + +auto-generated & easily extensible +---------------------------------- + +Many of the macros available in the NDK are auto-generated from simple configuration +files. This makes creating similar macros for your own code very simple - it's usually +just the case of adding an extra line to a config file and re-running the build script. + +[Back to TOC](#table-of-contents) + +Usage for users +=============== + +If another Nginx module you wish to use specifies that the NDK is a dependency, you +will need to do the following : + +1. download the source (https://github.com/simpl/ngx_devel_kit) +2. unpack the source (tar -xzf $name) +3. compile Nginx with the following extra option `--add-module=/path/to/ngx_devel_kit`. + +e.g. + +```bash +./configure --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/another/module +``` + +[Back to TOC](#table-of-contents) + +Building as a dynamic module +---------------------------- + +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ndk_http_module.so; +load_module /path/to/another/module.so; +``` + +[Back to TOC](#table-of-contents) + +Usage for developers +==================== + +To use the NDK in your own module, you need to add the following: + +1. add this line to your module + +```C +#include +``` + +Note: since the NDK includes the following lines + +```C +#include +#include +#include +``` + +you can replace these with the single include above. +2. add the following line in the config file for your module: + +```bash +have=NDK_[module_name] . auto/have +``` + +for each NDK module that you wish to use (you need to include auto/have multiple +times if you wish to use multiple NDK modules. + +Note: the old method of setting + +```config +CFLAGS="$CFLAGS -DNDK_[module_name]" +``` + +is now deprecated. It will still work, but results in unnecessary lines being +displayed when compiling Nginx. + +[Back to TOC](#table-of-contents) + +Warning: Using NDK_ALL +---------------------- + +You can also set `NDK_ALL` to include all the NDK modules. This is primarily as +a convenience in the early stages of development of another module. However, + +DO NOT LEAVE `NDK_ALL` IN YOUR CONFIG FILE WHEN PUBLISHING + +Although the NDK is fairly small now, it could in time become a large repository +of code that would, if using NDK_ALL, result in considerably more code being compiled +than is necessary. + +[Back to TOC](#table-of-contents) + +Modules using NDK +================= + +The following 3rd-party modules make use of NDK. + +* [ngx_http_lua_module](https://github.com/openresty/lua-nginx-module#readme) +* [ngx_http_set_misc_module](https://github.com/openresty/set-misc-nginx-module#readme) +* [ngx_http_encrypted_session_module](https://github.com/openresty/encrypted-session-nginx-module#readme) +* [ngx_http_form_input_module](https://github.com/calio/form-input-nginx-module#readme) +* [ngx_http_iconv_module](https://github.com/calio/iconv-nginx-module#readme) +* [ngx_http_array_var_module](https://github.com/openresty/array-var-nginx-module#readme) + +If you would like to add your module to this list, please let us know. + +[Back to TOC](#table-of-contents) + +TODO +==== + +* documentation for modules that don't already have it +* additional phase-handler functions +* generically testing for needing to add a handler +* remove dependency of set_var on OpenSSL being compiled in +* for backward compatability, add the ndk_macros + +[Back to TOC](#table-of-contents) + +License +======= + +Copyright (c) 2010-2018, Marcus Clyne + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +Contributing / Feedback +======================= + +If you are an Nginx module developer, and have developed some functions that are +generic in nature (or would be easily adapted to be so), then please send them to +me at the address below, and I'll addmclyne to the kit. + +[Back to TOC](#table-of-contents) + +Author +====== + +[Marcus Clyne](https://github.com/mclyne) + +[Back to TOC](#table-of-contents) + + +Special Thanks +============== + +A special thanks goes to [Yichun Zhang](https://github.com/agentzh) for helping to maintain +this module. + +[Back to TOC](#table-of-contents) diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/README_AUTO_LIB.md b/modules_deb/libnginx-mod-http-ndk-0.3.4/README_AUTO_LIB.md new file mode 100644 index 0000000..f2c3371 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/README_AUTO_LIB.md @@ -0,0 +1,394 @@ +Nginx Auto Lib Core +=================== + +Nginx Auto Lib Core is a generic external library-handler that has been designed to +facilitate the inclusion of external libraries in modules for the Nginx web server. +It has been written both for the benefit of Nginx module developers and for the end +users of those Nginx modules, and can provide a consistent, intelligent, flexible +cross-platform way to include external libraries. + +Any developers of Nginx modules are encouraged to use Auto Lib Core to handle library +dependencies for their modules rather than writing their own custom handler from scratch. + +Note : The latest version can be found [here](https://github.com/simplresty/ngx_auto_lib). + + +Information for end users +========================= + +To include external libraries using Auto Lib to you may need or wish to export some +variables before you run configure. e.g. + +$ export MOZJS=/path/to/mozjs +$ export MOZJS_SHARED=NO +$ ./configure ... + +In all cases below [PFX] should be replaced with the name of the library (e.g. MOZJS). The +specific value for [PFX] should be mentioned in the README file for the module that +uses Auto Lib Core. + + +Search order for paths +---------------------- + +(1) [PFX]_INC and [PFX]_LIB +(2) [PFX] (source or install dir) +(3) any dirs under [PFX]_BASE (see below) +(4) any dirs under the parent directory of the Nginx source dir beginning with '[pfx]-' +(5) standard system paths (including /usr/local, /usr, /opt/local, /opt, /usr/pkg) + +If any of 1-3 are specified, then any set values will be searched, and the the Nginx +source's parent directory and system paths are not searched unless [PFX]_SEARCH_[PLACE] +variable is set to YES, where PLACE ::= PARENT | SYSTEM. e.g. + +$ export OPENSSL_LIB=/path/to/openssl/lib +$ export OPENSSL_INC=/path/to/openssl/inc +$ ./configure + +will search only in the lib and include paths specified, and + +$ export OPENSSL_LIB=/path/to/openssl/lib +$ export OPENSSL_INC=/path/to/openssl/inc +$ export OPENSSL_BASE=/path/to/openssl/base +$ export OPENSSL_SEARCH_PARENT=YES +$ ./configure --with-openssl=/path/to/openssl + +will search first in the lib & inc dirs specified, then in /path/to/openssl, then will +look for directories in /path/to/openssl/base and then in the Nginx source parent +directory, but will skip checking the system paths. + +Note : apart from system paths, all dirs are checked as both source and install directories, +so static versions of installed OpenSSL, PCRE, Zlib etc libraries can be used with Nginx +if desired. + + +Specifying a path to find a library +----------------------------------- + +If the version of a library you wish to include is in any of the standard paths (e.g. +/usr/local, /usr ...), you will not need to specify a path to include the library. + +If you do wish to specify a specific path, in most cases just specifying +[PFX]=/path/to/library will be sufficient. e.g. + +$ export MOZJS=/path/to/mozjs +$ ./configure ... + +The path can be either a source directory or an install directory. Auto Lib will search + + +Searching under base paths +-------------------------- + +Rather than specifying a specific path to find new libraries in non-standard locations, +you may wish to specify a base path (or just let Auto Lib search the directory that the +Nginx source is located in). This will then automatically find the most recent versions +of libraries and check them before older versions. + +e.g. + +You have installations + +/openssl/version/0.9.8m +/openssl/version/1.0.0a +... + +$ export OPENSSL_BASE=/openssl/version +$ ./configure ... + +Any directories under /openssl/version will be searched IN REVERSE ORDER, i.e. most recent +version first. Here /openssl/version/1.0.0a would be searched before /openssl/version/0.9.8m. + +If [PFX]_BASE_SEARCH_PREFIX=YES, then only directories beginning with '[pfx]-' are searched. +If [PFX]_BASE_SEARCH_PREFIX=something, then only directories beginning with 'something' are +searched. + +When searching under [PFX]_BASE no prefix is added to the search, but when searching under +the directory that the Nginx source is located in, the prefix [pfx]- is automatically added. + +Note : there is currently a minor bug (due to the implementation of the 'sort' command) +means versions that include hyphens (e.g. 1.0.0-beta5) are checked before versions like +1.0.0a. This will be fixed soon, and searching of -build folders before normal source ones +will be added too. + + + +Shared or static? +----------------- + +The default for most libraries is to look for shared libraries, though this can be overridden +by the user by setting [PFX]_SHARED=NO. + +In the near future the default action will be to look for shared libraries then to look +for static libraries in each directory searched unless one of [PFX]_SHARED and/or +[PFX]_STATIC = NO. If both are set to NO, then Auto Lib will not be used at all. + + + +Variables that users can set to help find libraries +--------------------------------------------------- + +[PFX] Location of dir where the library can be found (PATH, see below) +[PFX]_INC Include dir for library headers (PATH) +[PFX]_LIB Lib dir for library archive/shared objects (PATH) +[PFX]_BASE Base dir under which to search for other dirs (PATH) +[PFX]_SEARCH_LIB_INC Search in [PFX]_INC and [PFX]_LIB if set (YES|NO, def=YES) +[PFX]_SEARCH_DIR Search [PFX] if set (YES|NO, def=YES) +[PFX]_SEARCH_BASE Search under [PFX]_BASE if set (YES|NO, def=YES) +[PFX]_SEARCH_PARENT Search under the dir that the Nginx source is in (YES|NO, see above) +[PFX]_SEARCH_SYSTEM Search in standard system paths (YES|NO, see above) +[PFX]_SHARED Use shared library rather than static (YES|NO, def=YES) +[PFX]_SYSTEM_DIRS System dirs to search in (PATHS, space-separated, overrides the defaults) +USE_[PFX] Whether or not to install the library (YES|NO, def=YES) + + +Note : for libraries that have configure options (e.g. --with-openssl=/path), the [PFX] +variable is set automatically by configure, so will not be used if exported. + + + +Information for module developers +================================= + +How Auto Lib Core works +----------------------- + +Auto Lib Core works as an interface layer between the module and the auto/feature part of +the Nginx source. This is the file that results in the 'checking for ...' lines that you +see when you call ./configure. + +auto/feature works by using a few key variables (see below) to generate some C code, trying +to compile it to see if it works and optionally running the code. This output file is called +autotest.c (located under the objs/ directory whilst configure is running, but is deleted +after each call to auto/feature). + +Normally, whenever an external library is required, a module developer will write a number +of calls to auto/feature manually in their config files - e.g. to check under a range of +different possible locations to find a library. Apart from being tedious, this is obviously +potentially error-prone. + +Auto Lib Core will automatically generate all the calls to auto/feature for you, and will +take into account different operating systems etc in a consistent way, 'intelligent' way. + + +Including Nginx Auto Lib Core with custom modules +------------------------------------------------- + +Option 1 : + +- include ngx_auto_lib_core in the same directory that your module config file is + located +- add the following line to your config file + + . $ngx_addon_dir/ngx_auto_lib_core + +NOTE : if you want to include the file in a different directory to your config +file, you will need to change both the include line in your config file AND +the line in the ngx_auto_lib_core file that points to the file (it's the line that +has $ngx_addon_dir/ngx_auto_lib_core in it) + +Option 2 : + +- make the Nginx Development Kit (github.com/simpl-it/ngx_devel_kit) a dependency + for your module (Auto Lib Core is included automatically with it) + + +Recommended way of including Auto Lib Core +------------------------------------------ + +If the Nginx Development Kit (NDK) is already a dependency for your module, then you do +not need to do anything - just follow the 'using Auto Lib Core' instructions below. + +If the NDK is not a dependency for your module, then it is recommended to include a +copy of ngx_auto_lib_core with your module, but to recommend to users of your module +to include the NDK when compiling. If the module is not required for anything else, this +will not make any difference to the Nginx binary that they compile, but will mean they +will get the latest version of Auto Lib Core (which probably won't change much anyway, +but you never know). + +You will also probably want to include a copy of this readme file for Auto Lib Core +(at least the user section), and mention what the relevant [PFX] you use for your module +is in your module's readme file so that users will know what to write for any variables +that they might use to control the search paths for libraries (see above user section). + + +Using Auto Lib Core +------------------- + +To use Auto Lib Core, you should do the following in your config file for each +external library that you want to include : + +1 - Call ngx_auto_lib_init +2 - Define any variables used for testing +3 - Define any hooks (custom functions) +4 - Call ngx_auto_lib_run + + +Calling ngx_auto_lib_init() and ngx_auto_lib_run() +-------------------------------------------------- + +You can pass either one or two variables to ngx_auto_lib_init(). The first is the name of +the library as it will appear when running ./configure, the second is the prefix that is +used for internal variables and looking for directory prefixes. If the second is not +specified, it defaults to the first. + +The init function resets all key variables and functions, so it must be called before +setting any other variables or functions that are to be used as hooks (see the notes below). + +ngx_auto_lib_run() should be called in the config files after all the variables and hooks +have been defined. This will then run through all the tests to try to find the external +library. + + +Variables you can set in your config files +------------------------------------------ + +All the variables that you set in Auto Lib Core are similar to the ones you set for +including libraries in the normal way. + + name description +---------------------------------------------------------------------------------------- + +core variables (i.e. the ones in the core Nginx source) + +ngx_feature_inc_path CFLAGS and include path info (including -I) +ngx_feature_incs Include/define code inserted before main() in autotest.c +ngx_feature_libs External libraries to add (see below) +ngx_feature_path Space-separated include path +ngx_feature_run Whether to run the autotest binary (default = no) +ngx_feature_test C-code inserted inside main() in autotest.c + +extended variables (only work in NALC) : + +ngx_feature_add_libs Add libraries (but do not add include files) +ngx_feature_add_path Add extra directories to include path +ngx_feature_build_dirs Sub dirs that builds might be found +ngx_feature_build_inc_dirs Sub dirs that include files might be found +ngx_feature_build_lib_dirs Sub dirs that lib files might be found +ngx_feature_check_macros_defined Lib required only if one of these macros is defined +ngx_feature_check_macros_non_zero Lib required only if one of these macros is non-zero +ngx_feature_defines Define these macros if the library is found +ngx_feature_deps Deps to add (e.g. to CORE_DEPS) if the library is found +ngx_feature_exit_if_not_found Quit configure if the library is not found +ngx_feature_haves Set these macros to 1 if the library is found +ngx_feature_inc_names Names for include files (not including the .h) +ngx_feature_lib_files Add these files under the lib dir for static inclusions +ngx_feature_lib_names Names for lib files (not including -l or .a) +ngx_feature_modules Modules to add if the library is found +ngx_feature_srcs Sources to add (e.g. to ADDON_SRCS) if the lib is found +ngx_feature_shared If set to 'no', then only use static lib versions +ngx_feature_test_libs Add these libs when testing, but not to the final binary +ngx_feature_variables Set these variables if the library is found + +standard variables that are completely over-written (i.e. they won't work with NALC) : + +ngx_feature_name Message that is displayed after 'checking for' in configure + + +Using these variables +--------------------- + +You do not need to set most of these variables, since 'intelligent' guesses are made that +will work for most cases. With the exception of ngx_feature_test, you should generally use +the extended variables rather than the core ones, since sensible core variables will be +automatically generated from them, and will work for both static and shared libraries. + + +Variable defaults +----------------- + +ngx_feature_incs for i in $ngx_feature_inc_names { #include <$i.h> } +ngx_feature_libs for l in $ngx_feature_lib_names { -l$l or $LIB/lib$l.a } + + $ngx_feature_add_libs +ngx_feature_inc_names $ngx_feature_lib_names +ngx_feature_lib_names $pfx +pfx str_to_lower (if two variables are passed to ngx_auto_lib_init, then + then $2, otherwise, $1) + +The easiest way to understand how all the defaults work is probably to look at the source code +of ngx_auto_lib_test_setup() and to look at the examples in the standard Nginx Auto Lib module +which has code for OpenSSL, PCRE, Zlib, MD5 and SHA1. + + +Hooks +----- + +To facilitate using Auto Lib Core in a flexible way, a number of 'hooks' have been +placed in the testing cycle. These hooks are implemented as functions that you define +in your config file which are called if required by the core library. In the core +library they are left as empty functions that return either 0 or 1. Any functions +you write will + +Note : ngx_auto_lib_init() resets the variables and functions each time it is called, so +you must DEFINE HOOKS AFTER YOU CALL ngx_auto_lib_init. + +Note : an update on what hooks are available will be added later. To see what hooks are +available, just look in the source code of ngx_auto_lib_core for any functions that just +return 0 or 1. + +See the MD5 and SHA1 libraries of Nginx Auto Lib module for examples. + + + +Checking that a library is required +----------------------------------- + +Although in most cases Auto Lib Core will be used where external libraries are +definitely required (for a module to work), this may not always be the case. In the +standard Nginx Auto Lib module (github.com/simpl-it/ngx_auto_lib) - which is designed +to improve the inclusion of OpenSSL, PCRE and Zlib libraries and increase compilation +speed where possible - the libraries are not always required, so checks are made to +see if it is necessary. + + + +How Auto Lib Core checks if a library is required - ngx_auto_lib_check_require() +------------------------------------------------------------------------------------ + +- search for USE_[PFX]=YES (it is set to YES by default for most modules) +- search for any external libraries that have been included in the CORE_LIBS or ADDON_LIBS + variables that use the same lib name as any set in ngx_feature_lib_names +- search for any macros that have been defined either in the CFLAGS variable or using + auto/have or auto/define as set in the ngx_feature_check_macros_defined and + ngx_feature_ngx_macros_non_zero variables +- any custom checks implemented by creating an ngx_auto_lib_check hook function (which + should return 0 if the library is required and return 1 at the end if the module is + not required) + + + +Guaranteeing that the correct version of a shared library is linked at run time +------------------------------------------------------------------------------- + +Sometimes users will want to use shared libraries that are in non-standard locations +that the linker may have a problem in locating at run time - even if the correct +linker path (-L/path/to/lib) is supplied when checking. To make sure that the linker +can find the library at run time, and to make sure that the linker will use the correct +version of a library if the library is also located in a standard directory, a run path +is added to the linker flags (using -Wl,--rpath -Wl,/path/to/lib/dir). In most cases this +will guarantee that the correct library is used when linking - though care should be taken +by any users specifying specific paths for libraries that the correct version of the +library has been linked at run time (e.g. using ldd etc). + +As an additional check when running auto/feature, as well as the compilation of the +autotest.c file, a check is made by ldd to see that the path of the shared library +that the linker links to is the same as the one specified. This is done because + + +To do +----- + +- Change how library paths are searched to include both shared and static libraries +- Touch up documentation + + +License +------- + + BSD + + +Copyright +--------- + + [Marcus Clyne](https://github.com/mclyne) (c) 2010 diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/array b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/array new file mode 100644 index 0000000..04cd889 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/array @@ -0,0 +1,10 @@ + +array_create (a,pl,n,sz) a = %1%_array_create (pl,n,sz); if (a == NULL) %A% +array_init (a,pl,n,sz) if (%1%_array_init (a,pl,n,sz) == %E%) %A% +array_push (p,a) p = %1%_array_push (a); if (p == NULL) %A% +array_push_clean (p,a) p = %1%_array_push (a); if (p == NULL) %A%; %2%_zerop (p) +array_push_n (p,a,n) p = %1%_array_push_n (a,n); if (p == NULL) %A% +array_push_n_clean (p,a,n) p = %1%_array_push_n (a,n); if (p == NULL) %A%; %2%_zeropn (p,n) + + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/palloc b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/palloc new file mode 100644 index 0000000..6d430bd --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/actions/palloc @@ -0,0 +1,8 @@ + +palloc (p,pl,sz) p = %1%_palloc (pl,sz); if (p == NULL) %A% +pallocp (p,pl) %2%_pallocp (p,pl); if (p == NULL) %A% +pallocpn (p,pl,n) %2%_pallocpn (p,pl,n); if (p == NULL) %A% +pcalloc (p,pl,sz) p = %1%_pcalloc (pl,sz); if (p == NULL) %A% +pcallocp (p,pl) %2%_pcallocp (p,pl); if (p == NULL) %A% +pcallocpn (p,pl,n) %2%_pcallocpn (p,pl,n); if (p == NULL) %A% + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/build b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/build new file mode 100644 index 0000000..feb84b3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/build @@ -0,0 +1,597 @@ +#! /bin/bash + +cd `dirname $0` + +if [ $# -eq 2 ]; +then + if [ `expr $2 : /` -eq 1 ]; + then + output_dir=$2 + else + output_dir=$1/$2 + fi +else + output_dir=../objs +fi + +list_file=data/action_list +types_file=data/action_types +reps_file=data/action_replacements +prefix_file=data/prefixes +header_file=data/header_files +optional_modules_file=data/modules_optional +headers_file=data/headers +module_dependencies_file=data/module_dependencies +conf_macros_file=data/conf_macros +conf_locs_file=data/conf_locs +conf_args_file=data/conf_args + +autogen_notice=text/autogen + +actions_dir=actions +srcs_dir=src +include_prefix= +file_prefix=ndk_ +auto_file_name=config +auto_includes_name=includes + +conf_merge_filename=conf_merge.h +conf_cmd_basic_filename=conf_cmd_basic.h +conf_cmd_extra_filename=conf_cmd_extra.h + + +spacer=¬ + +sed_delete_empty_lines='t_NEL;d;:_NEL' + + +function trim_lines { + sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba' -e '}' +} + + +function strtoupper { + [ $# -eq 1 ] || return 1 + local _str _cu _cl _x + _cu=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) + _cl=(a b c d e f g h i j k l m n o p q r s t u v w x y z) + _str=$1 + for ((_x=0;_x<${#_cl[*]};_x++)); do + _str=${_str//${_cl[$_x]}/${_cu[$_x]}} + done + echo $_str +} + + +function sed_pad_right { + len=$1 + spacer=$2 + prefix=_PR$3 + + # returns a SED script that pads out (spaces) to the right to alignment $len + # this script should be used inside a call to sed + # NOTE : a spacer character $spacer should have already been written into the parsed string + + echo "t${prefix}a;:${prefix}a;s/^[^$spacer]{$len}/&/;\ +t${prefix}b;s/^[^$spacer]*/& /;t${prefix}a;:${prefix}b;s/$spacer/ /" +} + + +function sed_pad_left { + + len=$1 + spacer=$2 + prefix=_PL$3 + + # echo "t${prefix}a;:${prefix}a;s/^[^$spacer]{$len}/& /;t${prefix}a" # NOT CORRECT? +} + + +function add_notice { + + echo > $1 + cat $autogen_notice | trim_lines >> $1 + echo >> $1 + echo >> $1 +} + +function add_non_generated_content { + + file=src/$1.h + [ ! -f $file ] && return + + echo "/* Non-generated macros */" >> $2 + echo >> $2 + + cat $file | trim_lines >> $2 + + echo >> $2 + echo >> $2 +} + + +function add_action_macros { + + list_file=$actions_dir/$1 + + [ ! -f $list_file ] && return + + out=$2 + + + # alignment settings + + align1=20 + align2=35 + align3=62 + base_shrink=12 + define="#define " + + + + # base macros + + echo "/* base action macro macros */" >> $out + echo >> $out + + cat $list_file | trim_lines | sed -r \ + -e "s/^[ ]*([a-zA-Z0-9_]+)([ ]*)\(([a-zA-Z0-9_,]+)\)([ ]*)(.*)/$define%2%_\1_ac(\3,ac)\2\4 {\5;}/" \ + -e "s/[ ]{$base_shrink}\{/\{/" \ + -e 's/%A%/ac/g' \ + >> $out + + echo >> $out + echo >> $out + + + + # generated macros + + echo "/* generated action macros */" >> $out + echo >> $out + + cat -s $list_file | while read list_line; do + + [ "x`echo $list_line`" = 'x' ] && continue + + cat $types_file | while read type_line; do + + [ "x`echo $type_line`" = 'x' ] && continue + + #ext=`echo $type_line | grep -E '^[a-zA-Z0-9_]+' | cut -d " " -f1` + ext=`echo $type_line | sed -r 's/^([a-zA-Z0-9_]+).*/\1/'` + params=`echo $type_line | sed -r 's/^[a-zA-Z0-9_]+[ ]*\((.*)\).*/\1/;ta;d;:a'` + act=`echo $type_line | sed -r 's/^[a-zA-Z0-9_]+[ ]*(\(.*\))?(.*)/\2/'` + [ "x$params" != "x" ] && params=",$params" + + echo $list_line | sed -r \ + -e "s/^([a-zA-Z0-9_]+)[ ]*\(([a-zA-Z0-9_,]+)\).*/%2%_\1_$ext(\2$params)$spacer%2%_\1_ac$spacer(\2,$act)/" \ + -e 's/[ ]*,[ ]*/,/g' \ + -e "`sed_pad_right $align2 $spacer 1`" \ + -e "`sed_pad_right $align3 $spacer 2`" \ + -e "s/.*/$define&/" \ + >> $out + done + echo >> $out + done +} + + +function replace_prefixes { + + temp=.temp + + file=`cat $prefix_file` + + prefix1= + prefix2= + + for prefix in $file ; do + [ "x$prefix2" != "x" ] && echo "Too many prefixes in prefix file $prefix_file" && exit 1 + [ "x$prefix1" != "x" ] && prefix2=$prefix && continue + prefix1=$prefix + done + + sed -r "s/%1%/$prefix1/g;s/%2%/$prefix2/g" < $1 > $temp + + mv -f $temp $1 +} + + +function replace_other_strings { + + temp=.temp + + cat $reps_file | while read line; do + + rep1= + rep2= + + for rep in $line ; do + [ "x$rep2" != "x" ] && echo "Too many replacments in replacements file $reps_file" && exit 1 + [ "x$rep1" != "x" ] && rep2=$rep && continue + rep1=$rep + done + + sed -r "s/%$rep1%/$rep2/g" < $1 > $temp + mv -f $temp $1 + done +} + + +function generate_header_file { + + name=$1 + out=$output_dir/$file_prefix$name.h + + add_notice $out + add_non_generated_content $name $out + add_action_macros $name $out + replace_prefixes $out + replace_other_strings $out +} + + +function add_auto_include { + echo "#include <${file_prefix}$2>" >> $1 +} + + +function add_include { + echo "#include <${include_prefix}${file_prefix}$2>" >> $1 +} + + +function generate_non_optional_h_includes { + + # TODO : split into auto-generated and non-auto-generated ones + + echo "/* non-optional includes */" >> $1 + echo >> $1 + + for mod in `cat $headers_file | sort`; do + + add_auto_include $1 $mod.h + done + + echo >> $1 + echo >> $1 +} + + +function generate_include_all_includes { + + echo "/* include all optional modules */" >> $1 + echo >> $1 + echo "#ifdef NDK_ALL" >> $1 + echo >> $1 + + modules=`cat $optional_modules_file | sed 's/*//g' | sort` + + for mod in $modules; do + def="NDK_`strtoupper $mod`" + echo "#ifndef $def" >> $1 + echo "#define $def 1" >> $1 + echo "#endif" >> $1 + done + + echo >> $1 + echo "#endif" >> $1 + echo >> $1 + echo >> $1 +} + + +function generate_dependent_includes { + + echo "/* module dependencies */" >> $1 + echo >> $1 + + cat $module_dependencies_file | while read line; do + + first=1 + + for mod in $line; do + + def="NDK_`strtoupper $mod`" + + if [ $first = 1 ] ; then + + echo "#ifdef $def" >> $1 + first=0 + else + echo "#ifndef $def" >> $1 + echo "#define $def 1" >> $1 + echo "#endif" >> $1 + fi + done + + [ $first = 0 ] && echo "#endif" >> $1 + done + + echo >> $1 + echo >> $1 +} + + + +function generate_optional_h_includes { + + echo "/* optional includes */" >> $1 + echo >> $1 + + for mod in $modules; do + def="NDK_`strtoupper $mod`" + echo "#if ($def)" >> $1 + add_include $1 $mod.h + echo "#endif" >> $1 + done + + echo >> $1 + echo >> $1 +} + + + + + +function generate_conf_merge_macros_file { + + file=$conf_merge_filename + out_file=${file_prefix}$file + out=$output_dir/$out_file + + add_notice $out + + echo "/* conf-merge-value macros */" >> $out + echo >> $out + + cat $srcs_dir/$file | trim_lines >> $out + echo >> $out + echo >> $out + + echo "/* conf-merge-prop macros */" >> $out + echo >> $out + + echo "#define ndk_conf_merge_prop(prop,default)\\" >> $out + echo " ndk_conf_merge_value\\" >> $out + echo " (conf->prop, prev->prop, default)" >> $out + echo >> $out + + # loads macros, removes empty elements, sorts and translates to merge-prop macros + + cat $conf_macros_file | sed -r 's/^[A-Z0-9_]+[ ]*[A-Z0-9_]+[ ]*([a-z0-9_]+).*$/\1/;ta;d;:a' \ + | sort | sed -r \ + 's/(.*)/#define ndk_conf_merge_\1_prop(prop,default,...)\\\ + ndk_conf_merge_\1_value\\\ + (conf->prop, prev->prop, default,##__VA_ARGS__)\ + /' \ + >> $out + + add_auto_include $1 $file +} + + + + +function generate_conf_cmd_basic_file { + + temp=.rep + file=$conf_cmd_basic_filename + out_file=${file_prefix}$file + out=$output_dir/$out_file + + align1=35 + + # initial text + + add_notice $out + + + # add ndk bitmasks + + echo "/* conf cmd core values/bitmasks */" >> $out + echo >> $out + + + cat $conf_args_file | sort | trim_lines | sed -r \ + -e "s/^([A-Z0-9_]+)/${define}NDK_\1${spacer}NGX_\1/" \ + -e $sed_delete_empty_lines \ + -e "`sed_pad_right $align1 $spacer`" \ + >> $out + + echo >> $out + echo >> $out + + + # add additional bitmasks stored in file + + echo "/* conf cmd bitmasks */" >> $out + echo >> $out + + cat $srcs_dir/$conf_cmd_basic_filename | trim_lines >> $out + + echo >> $out + echo >> $out + + echo "/* conf cmd basic macros */" >> $out + echo >> $out + + + # build replacement string + + echo -n "s/^([A-Z0-9_]+)$/" > $temp + + cat $conf_locs_file | sed \ + -r -e 's/^([A-Z0-9_]+) *([A-Z0-9_]+).*/#define NDK_\1_CONF_\\1\(name,func,off1,off2,post)\\\\\\\ + {ngx_string (name),\\\\\\\ + NGX_CONF_\\1|NDK_\1_CONF,\\\\\\\ + func, off1, off2, post},\\\ +\\/' -e $sed_delete_empty_lines \ + >> $temp + + echo -n "/;$sed_delete_empty_lines" >> $temp + + + # apply the replacement string to the + + cat $conf_args_file | sort | trim_lines | sed -rf $temp >> $out + rm -f $temp + + add_auto_include $1 $file +} + + + +function generate_conf_cmd_extra_file { + + temp=.rep + file=$conf_cmd_extra_filename + out=$output_dir/${file_prefix}$file + + align1=35 + + # initial text + + add_notice $out + + echo "/* conf command macros */" >> $out + echo >> $out + + + # build replacement string + + echo -n 's/^([A-Z0-9_]+)[ ]*([A-Z0-9_]+)[ ]*([a-z0-9_]+).*$/' > $temp + + cat $conf_locs_file | sed \ + -r -e 's/^([A-Z0-9_]+)[ ]*([A-Z0-9_]+)[ ]*([a-zA-Z0-9_]+)/#define NDK_\1_CONF_\\1(name,p,post\)\\\\\\\ + NDK_\1_CONF_\\2\\\\\\\ + (name,\\\\\\\ + ndk_conf_set_\\3_slot,\\\\\\\ + NGX_\2_CONF_OFFSET,\\\\\\\ + offsetof (ndk_module_\3_conf_t, p),\\\\\\\ + post)\\\ +\\/' -e $sed_delete_empty_lines \ + >> $temp + + echo -n "/;$sed_delete_empty_lines" >> $temp + #echo -n ";`sed_pad_right 60 $spacer`" >> $temp + + + # apply the replacement string to the + + cat $conf_macros_file | sort | trim_lines | sed -rf $temp -e "`sed_pad_right 60 $spacer`" >> $out + rm -f $temp + + add_auto_include $1 $file +} + + + +function generate_auto_generated_h_includes { + + echo "/* auto-generated headers */" >> $1 + echo >> $1 + + for name in `cat $header_file | sort` ; do + + generate_header_file $name + add_auto_include $1 $name.h + done + + generate_conf_merge_macros_file $1 + generate_conf_cmd_basic_file $1 + generate_conf_cmd_extra_file $1 + + echo >> $1 + echo >> $1 +} + + + +function generate_optional_c_includes { + + echo "/* optional includes */" >> $1 + echo >> $1 + + modules=`cat $optional_modules_file | sed 's/*//g' | sort` + + for mod in $modules; do + def="NDK_`strtoupper "$mod"`" + echo "#if ($def)" >> $1 + add_include $1 $mod.c + echo "#endif" >> $1 + done + + echo >> $1 + echo >> $1 +} + + +function generate_commands { + + echo "/* module commands */" >> $1 + echo >> $1 + echo "static ngx_command_t ndk_http_commands[] = {" >> $1 + + cat $optional_modules_file | sort | while read line; do + + cmds=`echo "$line" | grep -E '\*'` + + [ "x$cmds" = "x" ] && continue + + mod=`echo "$line" | grep -E '^[a-zA-Z0-9_]+' | cut -d " " -f1` + up=`strtoupper $mod` + def="NDK_$up" + defcmd="NDK_${up}_CMDS" + + echo "#if ($def)" >> $1 + echo "#define $defcmd 1" >> $1 + add_include $1 $mod.h + echo "#undef $defcmd" >> $1 + echo "#endif" >> $1 + + done + + echo -e " ngx_null_command\n};" >> $1 +} + + +function generate_all_h_files { + + out=$output_dir/${file_prefix}$auto_file_name.h + + add_notice $out + + generate_include_all_includes $out + generate_dependent_includes $out + + out=$output_dir/${file_prefix}$auto_includes_name.h + + generate_optional_h_includes $out + generate_non_optional_h_includes $out + generate_auto_generated_h_includes $out $list +} + + +function generate_all_c_files { + + out=$output_dir/${file_prefix}$auto_file_name.c + + add_notice $out + generate_optional_c_includes $out + generate_commands $out +} + + + +function generate_all_files { + + mkdir -p $output_dir + rm -f $output_dir/* + + generate_all_h_files + generate_all_c_files +} + +generate_all_files diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_replacements b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_replacements new file mode 100644 index 0000000..f419bc3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_replacements @@ -0,0 +1,5 @@ + +OK NGX_OK +E NGX_ERROR +CE NGX_CONF_ERROR +COK NGX_CONF_OK diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_types b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_types new file mode 100644 index 0000000..284a5cb --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/action_types @@ -0,0 +1,12 @@ +r0 return 0 +r1 return 1 +r_1 return -1 +rok return %OK% +rce return %CE% +rcok return %COK% +re return %E% +rn return NULL +rse {ngx_script_error (e); return;} +sce {ngx_script_configure_error (c); return;} +g(_lb) goto _lb +ge goto error diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_args b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_args new file mode 100644 index 0000000..752b533 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_args @@ -0,0 +1,22 @@ + +TAKE1 +TAKE2 +TAKE3 +TAKE4 +TAKE5 +TAKE6 +TAKE7 +TAKE8 +TAKE12 +TAKE13 +TAKE23 +TAKE123 +TAKE1234 +1MORE +2MORE +ANY +FLAG +BLOCK +MULTI +ARGS_NUMBER + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_locs b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_locs new file mode 100644 index 0000000..f5352c3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_locs @@ -0,0 +1,25 @@ + +HTTP_MAIN HTTP_MAIN main +HTTP_SRV HTTP_SRV srv +HTTP_SIF HTTP_SRV srv +HTTP_LOC HTTP_LOC loc +HTTP_LIF HTTP_LOC loc + +HTTP_MAIN_SRV HTTP_SRV srv +HTTP_MAIN_SIF HTTP_SRV srv +HTTP_MAIN_LOC HTTP_LOC loc +HTTP_MAIN_LIF HTTP_LOC loc + +HTTP_SRV_LOC HTTP_LOC loc +HTTP_SRV_LIF HTTP_LOC loc +HTTP_SIF_LOC HTTP_LOC loc +HTTP_SIF_LIF HTTP_LOC loc + +HTTP_MAIN_SRV_LOC HTTP_LOC loc +HTTP_MAIN_SRV_LIF HTTP_LOC loc +HTTP_MAIN_SIF_LOC HTTP_LOC loc +HTTP_MAIN_SRV_SIF_LOC HTTP_LOC loc +HTTP HTTP_LOC loc +HTTP_UPS HTTP_LOC loc +HTTP_ANY HTTP_LOC loc +ANY HTTP_LOC loc diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_macros b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_macros new file mode 100644 index 0000000..f42206a --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/conf_macros @@ -0,0 +1,35 @@ + +BITMASK 1MORE bitmask +BUFS TAKE1 bufs +COMPLEX_KEYVAL TAKE2 http_complex_keyval +COMPLEX_PATH TAKE1 http_complex_path +COMPLEX_VALUE TAKE1 http_complex_value +COMPLEX_VALUE_ARRAY 1MORE http_complex_value_array +ENCODING TAKE1 encoding +ENUM TAKE1 enum +FALSE NOARGS false +FULL_PATH TAKE1 full_path +KEYVAL TAKE2 keyval +KEYVAL1 TAKE2 keyval1 +MSEC TAKE1 msec +NULL NOARGS null +NUM TAKE1 num +NUM64 TAKE1 num64 +NUM_FLAG TAKE1 num_flag +ONOFF FLAG flag +OFF TAKE1 off +PATH TAKE1 split_path +REXEX TAKE1 regex +REGEX_CL TAKE1 regex_caseless +REGEX_ARRAY 1MORE regex_array +REGEX_ARRAY_CL 1MORE regex_array_caseless +PTR NOARGS ptr +SEC TAKE1 sec +SEC_FLAG TAKE2 sec_flag +SIZE TAKE1 size +STR TAKE1 str +STR_ARRAY 1MORE str_array_multi +STR_ARRAY1 TAKE1 str_array +TRUE NOARGS true + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/contexts b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/contexts new file mode 100644 index 0000000..e7e8ff0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/contexts @@ -0,0 +1,22 @@ + +MAIN +SRV +SIF +LOC +LIF + +MAIN_SRV +MAIN_SIF +MAIN_LOC +MAIN_LIF +SRV_LOC +SRV_LIF +SIF_LOC +SIF_LIF + +MAIN_SRV_LOC +MAIN_SRV_LIF +MAIN_SIF_LOC +MAIN_SIF_LIF +ANY_MAIN + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/header_files b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/header_files new file mode 100644 index 0000000..aa0f11c --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/header_files @@ -0,0 +1,3 @@ +array +palloc + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/headers b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/headers new file mode 100644 index 0000000..7583cb9 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/headers @@ -0,0 +1,4 @@ +http_headers +log +parse +string_util diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/module_dependencies b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/module_dependencies new file mode 100644 index 0000000..a179316 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/module_dependencies @@ -0,0 +1,5 @@ +complex_path complex_value path +conf_file string +hash string +set_var rewrite +upstream_list http_create_main_conf diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/modules_optional b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/modules_optional new file mode 100644 index 0000000..bbd6ec5 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/modules_optional @@ -0,0 +1,15 @@ +buf +complex_path +complex_value +conf_file +encoding +hash +http +path +process +regex +rewrite +set_var +string +upstream_list * +uri diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/prefixes b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/prefixes new file mode 100644 index 0000000..ee53474 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/data/prefixes @@ -0,0 +1,2 @@ +ngx +ndk diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/array.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/array.h new file mode 100644 index 0000000..a583759 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/array.h @@ -0,0 +1,7 @@ + +#define %2%_array_count(a) ((a)->nelts) +#define %2%_array_get_first(a) ((a)->elts) +#define %2%_array_get_index(a,n) ((void*) ((char*) (a)->elts + (a)->size * n)) +#define %2%_array_get_last(a) ((void*) ((char*) (a)->elts + (a)->size * ((a)->nelts - 1))) +#define %2%_array_get_reverse_index(a,n) ((void*) ((char*) (a)->elts + (a)->size * ((a)->nelts - 1 - n))) +#define %2%_array_push_clean(p,a) {p = %1%_array_push (a); %2%_zerop (p);} diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_cmd_basic.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_cmd_basic.h new file mode 100644 index 0000000..38743a6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_cmd_basic.h @@ -0,0 +1,43 @@ + +/* TODO : finish this */ + +#define NDK_HTTP_MAIN_CONF NGX_HTTP_MAIN_CONF +#define NDK_HTTP_SRV_CONF NGX_HTTP_SRV_CONF +#define NDK_HTTP_SIF_CONF NGX_HTTP_SIF_CONF +#define NDK_HTTP_LOC_CONF NGX_HTTP_LOC_CONF +#define NDK_HTTP_LIF_CONF NGX_HTTP_LIF_CONF +#define NDK_HTTP_UPS_CONF NGX_HTTP_UPS_CONF +#define NDK_MAIN_CONF NGX_MAIN_CONF +#define NDK_ANY_CONF NGX_ANY_CONF + + +/* compound locations */ + +#define NDK_HTTP_MAIN_SRV_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_CONF +#define NDK_HTTP_MAIN_SIF_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_SIF_CONF +#define NDK_HTTP_MAIN_LOC_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_LOC_CONF +#define NDK_HTTP_MAIN_LIF_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_LOC_LIF_CONF + +#define NDK_HTTP_SRV_SIF_CONF NDK_HTTP_SRV_CONF|NDK_HTTP_SIF_CONF +#define NDK_HTTP_SRV_LOC_CONF NDK_HTTP_SRV_CONF|NDK_HTTP_LOC_CONF +#define NDK_HTTP_SRV_LOC_LIF_CONF NDK_HTTP_SRV_CONF|NDK_HTTP_LOC_LIF_CONF +#define NDK_HTTP_SRV_SIF_LOC_CONF NDK_HTTP_SRV_SIF_CONF|NDK_HTTP_LOC_CONF +#define NDK_HTTP_SRV_SIF_LOC_LIF_CONF NDK_HTTP_SRV_SIF_CONF|NDK_HTTP_LOC_LIF_CONF + +#define NDK_HTTP_LOC_LIF_CONF NDK_HTTP_LOC_CONF|NDK_HTTP_LIF_CONF + +#define NDK_HTTP_MAIN_SRV_LOC_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_LOC_CONF +#define NDK_HTTP_MAIN_SRV_LIF_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_LIF_CONF +#define NDK_HTTP_MAIN_SIF_LOC_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SIF_LOC_CONF +#define NDK_HTTP_MAIN_SRV_SIF_LOC_LIF_CONF NDK_HTTP_SRV_SIF_LOC_LIF_CONF|NDK_MAIN_CONF +#define NDK_HTTP_CONF NDK_HTTP_MAIN_SRV_SIF_LOC_LIF_CONF +#define NDK_HTTP_ANY_CONF NDK_HTTP_CONF|NDK_HTTP_UPS_CONF + + +/* property offsets NOTE : ngx_module_main_conf_t etc should be defined in the module's .c file before the commands */ + +#define NDK_HTTP_MAIN_CONF_PROP(p) NGX_HTTP_MAIN_CONF_OFFSET, offsetof (ndk_module_main_conf_t, p) +#define NDK_HTTP_SRV_CONF_PROP(p) NGX_HTTP_SRV_CONF_OFFSET, offsetof (ndk_module_srv_conf_t, p) +#define NDK_HTTP_LOC_CONF_PROP(p) NGX_HTTP_LOC_CONF_OFFSET, offsetof (ndk_module_loc_conf_t, p) + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_merge.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_merge.h new file mode 100644 index 0000000..1e3ba70 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/conf_merge.h @@ -0,0 +1,78 @@ + +/* TODO : check that all the main types have a corresponding merge function */ + +#define ndk_conf_merge_value ngx_conf_merge_value +#define ndk_conf_merge_off_value ngx_conf_merge_off_value +#define ndk_conf_merge_ptr_value ngx_conf_merge_ptr_value +#define ndk_conf_merge_str_value ngx_conf_merge_str_value +#define ndk_conf_merge_size_value ngx_conf_merge_size_value + + +#define ndk_conf_merge_keyval_value(conf,prev,default) \ + \ + conf = prev ? prev : default; + +#define ndk_conf_merge_str_array_value(conf,prev,val1,...) \ + \ + if (conf == NGX_CONF_UNSET_PTR) { \ + if (prev == NGX_CONF_UNSET_PTR) { \ + if (val1 == NULL) { \ + conf = NULL; \ + } else { \ + char * elts[] = {val1,##__VA_ARGS__}; \ + int n = sizeof(elts)/sizeof(char*); \ + \ + conf = ndk_str_array_create (cf->pool, elts, n); \ + \ + if (conf == NULL) \ + return NGX_CONF_ERROR; \ + } \ + } else { \ + conf = prev; \ + } \ + } + +#define ndk_conf_merge_http_complex_value_value(conf,prev,default) \ + \ + if (!conf.str.len) { \ + if (prev.str.len) { \ + conf = prev; \ + } else { \ + conf.str.data = (u_char *) default; \ + conf.str.len = sizeof (default) - 1; \ + \ + if (ndk_http_complex_value_compile (cf, &conf)) \ + return NGX_CONF_ERROR; \ + } \ + } + +#define ndk_conf_merge_http_complex_value_array_value(conf,prev,val1,...) \ + \ + if (conf == NGX_CONF_UNSET_PTR) { \ + if (prev == NGX_CONF_UNSET_PTR) { \ + if (val1 == NULL) \ + conf = NULL; \ + else { \ + char * elts[] = {val1,##__VA_ARGS__}; \ + int n = sizeof(elts)/sizeof(char*); \ + \ + conf = ndk_http_complex_value_array_create (cf, elts, n); \ + \ + if (conf == NULL) \ + return NGX_CONF_ERROR; \ + } \ + } else { \ + conf = prev; \ + } \ + } + +#define ndk_conf_merge_http_complex_path_value(conf,prev,...) \ + ndk_conf_merge_http_complex_value_array_value (conf.a, prev.a, __VA_ARGS__) + +#define ndk_conf_merge_split_path_value(conf,prev,path) \ + \ + if (conf == NGX_CONF_UNSET_PTR) { \ + conf = (prev == NGX_CONF_UNSET_PTR ? \ + ndk_split_path_create_raw (cf, path) : prev); \ + } + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/palloc.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/palloc.h new file mode 100644 index 0000000..798e360 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/src/palloc.h @@ -0,0 +1,6 @@ + +#define %2%_pallocp(p,pl) p = %1%_palloc (pl,sizeof(*p)) +#define %2%_pallocpn(p,pl,n) p = %1%_palloc (pl,sizeof(*p)*(n)) + +#define %2%_pcallocp(p,pl) p = %1%_pcalloc (pl,sizeof(*p)) +#define %2%_pcallocpn(p,pl,n) p = %1%_pcalloc (pl,sizeof(*p)*(n)) diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/text/autogen b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/text/autogen new file mode 100644 index 0000000..6a244c2 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/auto/text/autogen @@ -0,0 +1,12 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/config b/modules_deb/libnginx-mod-http-ndk-0.3.4/config new file mode 100644 index 0000000..8cb7ad0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/config @@ -0,0 +1,65 @@ + +############### +## FUNCTIONS ## +############### + +# TODO : provide information about checking versions of sed etc +# TODO : an optional patch function + +ndk_generate_files() { + echo "building Nginx Development Kit utility functions and macros ..." + + autobuild="$ngx_addon_dir/auto/build" + chmod +x $autobuild + $autobuild `pwd` $NGX_OBJS/addon/ndk || exit 1 +} + +ndk_get_nginx_version() { + # We get the Nginx version number from the string form rather than + # nginx_version because it is available in more (every?) version + + cat src/core/nginx.h | + grep '#define NGINX_VERSION' | + sed -r \ + -e 's/[^0-9.]*([0-9.]+).*/\1/' \ + -e 's/([0-9]+\.[0-9]+\.)([0-9]{1})$/\100\2/' \ + -e 's/([0-9]+\.[0-9]+\.)([0-9]{2})$/\10\2/' \ + -e 's/\.//g' \ + -e 's/^0+(.*)/\1/' +} + +##################### +## CONFIG SETTINGS ## +##################### + +ngx_addon_name=ngx_devel_kit +ngx_objs_dirs="$ngx_addon_dir/objs $NGX_OBJS/addon/ndk" + +NDK_SRCS="$ngx_addon_dir/src/ndk.c" +NDK_DEPS="$ngx_addon_dir/src/ndk.h" +NDK_INCS="$ngx_addon_dir/src $ngx_objs_dirs" + +CORE_INCS="$CORE_INCS $ngx_objs_dirs" +HTTP_INCS="$HTTP_INCS $ngx_addon_dir/src $ngx_objs_dir" + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name="ndk_http_module" + ngx_module_srcs="$NDK_SRCS" + ngx_module_deps="$NDK_DEPS" + ngx_module_incs="$NDK_INCS" + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES ndk_http_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $NDK_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_SRCS $NDK_DEPS" +fi + +have=NDK . auto/have + +############## +## INCLUDES ## +############## + +. $ngx_addon_dir/ngx_auto_lib_core diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/changelog b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/changelog new file mode 100644 index 0000000..93ab9b1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/changelog @@ -0,0 +1,58 @@ +libnginx-mod-http-ndk (1:0.3.4-2) unstable; urgency=medium + + * d/control: bump Standards-Version: 4.7.2, no changes + + -- Jan Mojžíš Fri, 11 Apr 2025 14:27:01 +0200 + +libnginx-mod-http-ndk (1:0.3.4-1) unstable; urgency=medium + + * New upstream version 0.3.4 + * d/{control,copyright}: update my email to "janmojzis@debian.org" + * d/copyright: bump debian/* copyright year + * d/watch: use more generic template + * d/control: bump Standards-Version: 4.7.0, no changes + * d/gbp.conf: add [pull] track-missing = True + + -- Jan Mojžíš Fri, 21 Mar 2025 08:50:27 +0100 + +libnginx-mod-http-ndk (1:0.3.3-1) unstable; urgency=medium + + * New upstream version 0.3.3 + + -- Jan Mojžíš Mon, 18 Dec 2023 16:23:15 +0100 + +libnginx-mod-http-ndk (1:0.3.2-5) unstable; urgency=medium + + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + + -- Jan Mojžíš Sat, 07 Oct 2023 15:31:27 +0200 + +libnginx-mod-http-ndk (1:0.3.2-4) unstable; urgency=medium + + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Tue, 27 Jun 2023 23:16:39 +0200 + +libnginx-mod-http-ndk (1:0.3.2-3) unstable; urgency=medium + + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/gbb.conf: switched to debian branch main (debian-branch = main) + * d/copyright: bump my copyright year + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 12:56:32 +0100 + +libnginx-mod-http-ndk (1:0.3.2-2) unstable; urgency=medium + + * d/rules: enabled NDK upstream list module NDK_UPSTREAM_LIST + * d/control: added Multi-Arch: foreign + + -- Jan Mojžíš Tue, 06 Dec 2022 17:28:22 +0100 + +libnginx-mod-http-ndk (1:0.3.2-1) experimental; urgency=medium + + * Initial release. (Closes: 1024150) + + -- Jan Mojžíš Wed, 30 Nov 2022 14:46:55 +0100 diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/control b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/control new file mode 100644 index 0000000..b5eec8e --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/control @@ -0,0 +1,47 @@ +Source: libnginx-mod-http-ndk +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jan Mojžíš , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, +Standards-Version: 4.7.2 +Homepage: https://github.com/simpl/ngx_devel_kit +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-ndk.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-ndk +Rules-Requires-Root: no + +Package: libnginx-mod-http-ndk +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: Nginx Development Kit module + The NDK is an Nginx module that is designed to extend the core functionality of + the excellent Nginx webserver in a way that can be used as a basis of other + Nginx modules. + . + It has functions and macros to deal with generic tasks that don't currently + have generic code as part of the core distribution. The NDK itself adds few + features that are seen from a user's point of view - it's just designed to help + reduce the code that Nginx module developers need to write. + +Package: libnginx-mod-http-ndk-dev +Architecture: all +Multi-Arch: foreign +Depends: libnginx-mod-http-ndk (<< ${source:Version}.1~), + libnginx-mod-http-ndk (>= ${source:Version}), + ${misc:Depends}, + ${shlibs:Depends}, +Description: Nginx Development Kit module - development files + The NDK is an Nginx module that is designed to extend the core functionality of + the excellent Nginx webserver in a way that can be used as a basis of other + Nginx modules. + . + This package provides development headers and necessary config scripts + for the Nginx development kit module, useful to develop and link third party + additions to the Debian nginx web/proxy server packages using Nginx + development kit module. + . + Development files. diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright new file mode 100644 index 0000000..50da8f9 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright @@ -0,0 +1,155 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ngx_devel_kit +Upstream-Contact: Marcus Clyne +Source: https://github.com/simpl/ngx_devel_kit + +Files: * +Copyright: 2010-2018, Marcus Clyne +License: BSD-3-clause + +Files: auto/text/* +Copyright: Marcus Clyne +License: BSD-3-clause + +Files: debian/* +Copyright: 2022, Miao Wang + 2022 - 2025, Jan Mojzis +License: BSD-3-clause + +Files: docs/patches/* +Copyright: Brian Moran - bmoran@onehub.com +License: BSD-3-clause + +Files: examples/* +Copyright: Marcus Clyne +License: BSD-3-clause + +Files: examples/http/* +Copyright: 2010-2018, Marcus Clyne +License: BSD-3-clause + +Files: examples/http/set_var/ngx_http_set_var_examples_module.c +Copyright: Marcus Clyne +License: BSD-3-clause + +Files: notes/* +Copyright: 2010, Marcus Clyne, Simpl (simpl.it) +License: BSD-3-clause + +Files: notes/CHANGES +Copyright: 2010-2018, Marcus Clyne +License: BSD-3-clause + +Files: objs/* +Copyright: Marcus Clyne +License: BSD-3-clause + +Files: objs/ndk_includes.h +Copyright: 2010-2018, Marcus Clyne +License: BSD-3-clause + +Files: patches/expose_rewrite_functions +Copyright: Marcus Clyne +License: BSD-3-clause + +Files: src/hash/* +Copyright: 1995-1998, Eric Young (eay@cryptsoft.com) +License: SSLeay + +Files: src/hash/murmurhash2.c +Copyright: Austin Appleby +License: BSD-3-clause + +Files: src/ndk.c + src/ndk.h + src/ndk_set_var.h +Copyright: Marcus Clyne +License: BSD-3-clause + +License: BSD-3-clause + All rights reserved. + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: SSLeay + This software is Copyright (c) 2022 by X. Ample. + . + This is free software, licensed under: + . + Original SSLeay License + . + Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved. + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + This library is free for commercial and non-commercial use as long as + the following conditions are aheared to. The following conditions + apply to all code found in this distribution, be it the RC4, RSA, + lhash, DES, etc., code; not just the SSL code. The SSL documentation + included with this distribution is covered by the same copyright terms + except that the holder is Tim Hudson (tjh@cryptsoft.com). + . + Copyright remains Eric Young’s, and as such any Copyright notices in the code + are not to be removed. If this package is used in a product, Eric Young + should be given attribution as the author of the parts of the library used. + This can be in the form of a textual message at program startup or in + documentation (online or textual) provided with the package. + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + 1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + “This product includes cryptographic software written by + Eric Young (eay@cryptsoft.com)” + The word ‘cryptographic’ can be left out if the rouines from the library + being used are not cryptographic related :-). + 4. If you include any Windows specific code (or a derivative thereof) from + the apps directory (application code) you must include an + acknowledgement: “This product includes software written by Tim Hudson + (tjh@cryptsoft.com)” + . + THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ‘‘AS IS’’ AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + . + The licence and distribution terms for any publically available version or + derivative of this code cannot be changed. i.e. this code cannot simply be + copied and put under another distribution licence + [including the GNU Public Licence.] diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright-scan-patterns.yml b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright-scan-patterns.yml new file mode 100644 index 0000000..044c11d --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/copyright-scan-patterns.yml @@ -0,0 +1,4 @@ +--- +ignore: + pattern: + - README_AUTO_LIB\.md diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/fix.scanned.copyright b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/fix.scanned.copyright new file mode 100644 index 0000000..b5e57b8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/fix.scanned.copyright @@ -0,0 +1 @@ +! copyright Files:"docs/patches/*" Copyright=~s/\s\(.*// diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/gbp.conf b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/gbp.conf new file mode 100644 index 0000000..97cd209 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/gbp.conf @@ -0,0 +1,12 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace + +[pull] +track-missing = True diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk-dev.install b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk-dev.install new file mode 100644 index 0000000..d9988f1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk-dev.install @@ -0,0 +1,5 @@ +debian/build-src/auto usr/share/nginx-ndk/src/ +debian/build-src/config usr/share/nginx-ndk/src/ +debian/build-src/ngx_auto_lib_core usr/share/nginx-ndk/src/ +debian/build-src/objs usr/share/nginx-ndk/src/ +debian/build-src/src usr/share/nginx-ndk/src/ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.install b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.install new file mode 100644 index 0000000..c7a20b4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.install @@ -0,0 +1 @@ +/usr/lib/nginx/modules/ndk_http_module.so diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.nginx b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.nginx new file mode 100644 index 0000000..ec2f484 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/libnginx-mod-http-ndk.nginx @@ -0,0 +1 @@ +mod debian/mod-http-ndk.conf 10 diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/mod-http-ndk.conf b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/mod-http-ndk.conf new file mode 100644 index 0000000..3908af6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/mod-http-ndk.conf @@ -0,0 +1 @@ +load_module modules/ndk_http_module.so; diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/rules b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/rules new file mode 100755 index 0000000..42e9c85 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/rules @@ -0,0 +1,35 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +BUILDDIR_SRC = $(CURDIR)/debian/build-src +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +objdir = $(CURDIR)/obj-$(DEB_BUILD_GNU_TYPE) + +%: + dh $@ + +override_dh_auto_configure: + dh_auto_configure --buildsystem=nginx_mod + for have in NDK_SET_VAR NDK_UPSTREAM_LIST; do \ + ( \ + echo "#ifndef $$have"; \ + echo "#define $$have 1"; \ + echo "#endif"; \ + echo; \ + ) >> $(objdir)/ngx_auto_config.h; \ + done + +override_dh_auto_build: build.src + dh_auto_build --buildsystem=nginx_mod + +build.src: + mkdir -p $(BUILDDIR_SRC) + cp -Pa $(CURDIR)/auto config ngx_auto_lib_core $(BUILDDIR_SRC)/ + for i in src objs; do \ + find $(CURDIR)/$$i -type f -name '*.h' -printf "$$i/%P\0" | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_SRC)/ -x; \ + done + +override_dh_clean: + rm -rf $(BUILDDIR_SRC) + dh_clean diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/source/format b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/control b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/control new file mode 100644 index 0000000..ca20b9f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/control @@ -0,0 +1,6 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/generic b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/upstream/metadata b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/upstream/metadata new file mode 100644 index 0000000..51ef420 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/simpl/ngx_devel_kit/issues +Bug-Submit: https://github.com/simpl/ngx_devel_kit/issues/new +Repository-Browse: https://github.com/simpl/ngx_devel_kit \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/watch b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/watch new file mode 100644 index 0000000..e0b5b75 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/simpl/ngx_devel_kit/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/action_macros b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/action_macros new file mode 100644 index 0000000..802eb1f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/action_macros @@ -0,0 +1,63 @@ + + GENERAL NOTES + ------------- + + These functions and macros have been provided as a tool for Nginx module developers. They have + been created with four main purposes: + + - to speed up code-writing + - to reduce the code you have to read on file + - to add additional generic functionality similar to exising Nginx functions + - to reduce code errors + + Most of the utility macros are just wrappers around commonly used code, especially checking for + NULL and returning a value, zeroing data etc. The functions add things like extra conf_set_X_slot + functions that don't exist in the standard Nginx distribution, but which might be useful in more + than one module. + + A consistent approach has been taken to creating the macros, so that in theory you should be able + to 'know' the macro name from using the few rules below and your knowledge of the existing Nginx + functions. As much as possible, the ordering of variables used within the underlying functions + remain the same, to reduce the learning time. Also, a constent naming pattern has been used to + make it easier to read the macros above. + + Obviously not all programmers will want to use all or any of these macros, but they are provided + as a tool for those who wish to use them. + + If you have any comments about them, including any additions or errors please let me know at + 'eugaia at gmail dot com'. I don't promise to include all additions people send, but if they seem + like they could be of use to multiple developers, I will. + + + UTILITY MACRO PARAMS + -------------------- + p pointer - used to set the result of a function to a pointer + a array + pl pool + n multiplication factor - for allocating multiple pointers & pushing 'n' elts in arrays etc + sz size + l log + rv return value + + + + UTILITY MACRO FUNCTION SUFFIXES + ------------------------------- + + - general + + p p = [FUNCTION] () + _r [ if result of function is NULL | NGX_ERROR (as appropriate) ] return rv + _rce rv = NGX_CONF_ERROR + _re rv = NGX_ERROR + _rn rv = NULL + + - (p)(c)alloc functions + + p p = [function] (pool, sizeof (*p)) + pn p = [function] (pool, sizeof (*p) * n) + + + UTILITY MACRO PARAMS ORDER + -------------------------- + p, pl|a, sz|n, l, rv diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/conf_cmds b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/conf_cmds new file mode 100644 index 0000000..70978b1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/core/conf_cmds @@ -0,0 +1,62 @@ + +Conf command macros +------------------- + +The build script generates a large number of macros for reducing the code required for command +definitions. + +There are basically three types of macros : + +- combination bitmasks + + e.g. NDK_HTTP_MAIN_SRV_CONF = (NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF) + +- base command structures + + e.g. NDK_HTTP_MAIN_CONF_TAKE1 + +- conf-set command structures + + e.g. NDK_HTTP_CONF_STR + + +Combination bitmasks +-------------------- + +Basically combinations of existing bitmasks for locations, with general > specific order + +NDK_HTTP_CONF = (NGX_HTTP_MAIN_CONF | NGX_HTTP_SVR_CONF | NGX_HTTP_SIF_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF) + + +Base command structures +----------------------- + +These macros are basically there as wrappers for the conf-set command structures, and but incorporate +the bitmask element into the name of the macro. + + +Conf-set command structures +--------------------------- + +These macros simplify creating commands that use any of the build-in conf-set functions or any of those +added by the NDK. + +e.g. NGX_HTTP_MAIN_SRV_STR ("name", prop, NULL) + +where prop is the name of the property that is a ngx_str_t. Whether this is in the loc conf, main conf +or svr conf is generated automatically in by the macro. + +NOTE : you need to set the following if they will be used (using macro definitions) : + +ndk_module_main_conf_t +ndk_module_srv_conf_t +ndk_module_loc_conf_t + +e.g + +#define ndk_module_loc_conf_t ngx_http_my_module_loc_conf_t + + +TODO +---- +Much better documentation for this diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/modules/set_var b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/modules/set_var new file mode 100644 index 0000000..6be5c0f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/modules/set_var @@ -0,0 +1,124 @@ + +set var tools +============= + +OVERVIEW +-------- +This collection of tools is designed to make it easier to set Nginx variables +using a common interface. It works by plugging into and extending the features +of the internal rewrite module, and operations performed by this module are +therefore done at the rewrite phase of handling. + + +ADVANTAGES OF USING THIS MODULE +------------------------------- + +- simple interface - you don't have to worry about lots of http script compiling +- it plugs into the rewrite module, so setting (and getting) vars will happen + in the order you expect based on how they appear in the configuration file +- you do not have to worry about overriding the v->get_handler (useful if + a variable of a specific name could be set in multiple different ways) + + +WHEN TO USE THIS AND WHEN TO USE v->get_handler = my_func +--------------------------------------------------------- + +- if you want a variable to always be generated using a specific function, + and should not be over-ridden by 'set' functions (e.g. $request_uri, + $document_root), then you should use v->get_handler + +- if you want to allow a variable to be set using many possible methods, + including using the 'set' directive, then this module provides an easy way + for you to do so (if you use the v->get_handler method in this case, you may + run into problems because the get_handler may over-ride previous uses of the + set directive) + + +USAGE +----- + +- decide on the type of function you'll need to write + + type use when there are these requirements + ---- ------------------------------------- + NDK_SET_VAR_BASIC 0 variable values, no extra data + NDK_SET_VAR_DATA 0 variable values, extra data + NDK_SET_VAR_VALUE 1 variable value, no extra data + NDK_SET_VAR_VALUE_DATA 1 variable value, extra data + NDK_SET_VAR_MULTI_VALUE 2+ variable values, no extra data + NDK_SET_VAR_MULTI_VALUE_DATA 2+ variable values, extra data + NDK_SET_VAR_HASH the space needed for the result string + value is known in advance (usually + used in a hash function) + + NOTE : if none of these generic calling types suit your needs, it is + easy to extend the list of types in the .c file (and you if you let me know + I'll add them to the list + + +- define the filter function with the respective prototype + + type prototype + ---- --------- + NDK_SET_VAR_BASIC ndk_set_var_pt + NDK_SET_VAR_DATA ndk_set_var_data_pt + NDK_SET_VAR_VALUE ndk_set_var_value_pt + NDK_SET_VAR_DATA_VALUE ndk_set_var_value_data_pt + NDK_SET_VAR_MULTI_VALUE ndk_set_var_value_pt + NDK_SET_VAR_MULTI_VALUE_DATA ndk_set_var_value_data_pt + NDK_SET_VAR_HASH ndk_set_var_hash_pt + + (See ngx_tools_module.h for the prototype definitions.) + + Note : For the multi_value functions, the variable value pointer is to the + first value (with the others being in an array following it) + + +to use one of the default setup functions +----------------------------------------- + +- define one or multiple ngx_http_var_filter_t's at the global scope, setting : + + type = (one of types above) + func = function to call + size = (for multi value) the number of variable values + (for hash) length of buffer to allocate + data = (for data functions) additional data (see note below) + +- define a configuration directive (see in the .c file for examples), where the + function is 'ngx_http_set_var' and the 'post' is a pointer your filter definition + + +to setup in a customized way +---------------------------- + +- define a configuration directive which has your own specific configuration function + +- inside your config function, define one or several ngx_http_var_filter_t's like + above, and call one of the ngx_http_set_var_..._core functions, passing the + variable name and value pointers as appropriate - see examples section + +Note : if you're passing extra data to the function, then you will probably want +to use this second method and store the data either in the loc conf, or just +allocate the space for it using one of the ngx_palloc functions. + +If the values that will be used for processing are in the same order as in the +config file and there aren't any additional values that are input, then you can +just use the (ngx_str_t *) (cf->args->elts) + 1 as your base for the values or +possibly not use the _core versions of the functions. + + +That's it! + + +FEEDBACK +-------- + +If you have any comments (good/bad), or have found any bugs, please let me know at: +ngx.eugaia AT gmail DOT com + + +TODO +---- +- add more documentation/examples + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/patches/more_logging_info b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/patches/more_logging_info new file mode 100644 index 0000000..3685916 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/patches/more_logging_info @@ -0,0 +1,48 @@ +When tracking down some potential issues in the nginx constellation, +we've found it useful to understand where particular error messages +are coming from, since many of the same messages are repeated in +various places. This patch will write the source file from which the +message originated, the function name, and the line number if you're +using GCC to compile nginx. Here's an example: + +Old Output: +2010/01/12 14:43:10 [notice] 67772#0: nginx/0.7.64 +2010/01/12 14:43:10 [notice] 67772#0: built by gcc 4.0.1 (Apple Inc. build 5490) +2010/01/12 14:43:10 [notice] 67772#0: OS: Darwin 9.8.0 +2010/01/12 14:43:10 [notice] 67772#0: hw.ncpu: 2 +2010/01/12 14:43:10 [notice] 67772#0: net.inet.tcp.sendspace: 65536 +2010/01/12 14:43:10 [notice] 67772#0: kern.ipc.somaxconn: 128 +2010/01/12 14:43:10 [notice] 67772#0: getrlimit(RLIMIT_NOFILE): +256:9223372036854775807 +2010/01/12 14:43:10 [notice] 67772#0: start worker processes +2010/01/12 14:43:10 [notice] 67772#0: start worker process 67785 +2010/01/12 14:43:16 [notice] 67772#0: signal 20 (SIGCHLD) received + +New Output: +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_posix_init.c +ngx_os_status( 80) nginx/0.7.64 +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_posix_init.c +ngx_os_status( 83) built by gcc 4.0.1 (Apple Inc. build 5490) +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_darwin_init.c +ngx_os_specific_status( 153) OS: Darwin 9.8.0 +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_darwin_init.c +ngx_os_specific_status( 166) hw.ncpu: 2 +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_darwin_init.c +ngx_os_specific_status( 166) net.inet.tcp.sendspace: 65536 +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_darwin_init.c +ngx_os_specific_status( 166) kern.ipc.somaxconn: 128 +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_posix_init.c +ngx_os_status( 92) getrlimit(RLIMIT_NOFILE): +2560:9223372036854775807 +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_process_cycle.c +ngx_start_worker_processes( 337) start worker processes +2010/01/14 16:35:09 [notice] 27241#0: src/os/unix/ngx_process.c +ngx_spawn_process( 201) start worker process 27254 +2010/01/14 16:35:14 [notice] 27241#0: src/os/unix/ngx_process.c +ngx_signal_handler( 420) signal 20 (SIGCHLD) received + +Formatting the filename and function name fields into fixed-width +fields would be nicer, however that would require further changes in +src/core/ngx_string.c + +(C) Brian Moran - bmoran@onehub.com (posted to nginx-devel mailing list on 15/01/10) diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/upstream/list b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/upstream/list new file mode 100644 index 0000000..3ad485d --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/docs/upstream/list @@ -0,0 +1,45 @@ + +NDK_UPSTREAM_LIST +----------------- + +This submodule provides a directive that creates a list of upstreams, with +optional weighting. This list can then be used by other modules to hash over +the upstreams however they choose. + + +USAGE IN CONF FILE +------------------ + +e.g. upstream_list name backend1 4:backend2 3:backend3; + + + +USAGE WITH OTHER MODULES +------------------------ + +Add a line like + +CFLAGS="$CFLAGS -DNDK_UPSTREAM_LIST" + +to the config file of your module. + + + +INTEGRATING WITH YOUR MODULE +---------------------------- + +The upstream lists are stored in the array given in the lists.h file, which is +an array of ndk_upstream_list_t elts. The elts are currently all pointers to +strings which have been distributed according to the weight - so if there are +two backends, with weight 3 and 4 respectively, there will be 7 pointers in +total with the first 3 pointing to the first backend and the last 4 to the +second. + + + +TODO +---- +- replace strings with pointers to upstreams if they are available (and if + this is possible) +- add additional 'http://' to strings if necessary +- improve this documentation diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/README b/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/README new file mode 100644 index 0000000..22e2417 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/README @@ -0,0 +1,12 @@ + +2010 (C) Marcus Clyne + + +Examples +-------- + +In this section there are a number of examples of the various features of the tools +module. These have been given in the form of dummy modules, to make it easier to +use as templates for your own module should you choose to do so. + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/config b/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/config new file mode 100644 index 0000000..aa58f77 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/config @@ -0,0 +1,4 @@ +ngx_addon_name=ngx_http_set_var_examples_module +HTTP_MODULES="$HTTP_MODULES ngx_http_set_var_examples_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_set_var_examples_module.c" +have=NDK_SET_VAR . auto/have \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/ngx_http_set_var_examples_module.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/ngx_http_set_var_examples_module.c new file mode 100644 index 0000000..7a4daae --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/examples/http/set_var/ngx_http_set_var_examples_module.c @@ -0,0 +1,136 @@ + +/* + * 2010 (C) Marcus Clyne + */ + + +#include + + +static ngx_int_t ngx_http_set_var_concat2 (ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *v); +static char * ngx_http_set_prepend_hello (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ndk_set_var_t ngx_http_var_set_concat2 = { + NDK_SET_VAR_MULTI_VALUE, + ngx_http_set_var_concat2, + 2, + NULL +}; + + +static ngx_command_t ngx_http_set_var_examples_commands[] = { + { + ngx_string ("set_concat2"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3, + ndk_set_var_multi_value, + 0, + 0, + &ngx_http_var_set_concat2 + }, + { + ngx_string ("set_prepend_hello"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_http_set_prepend_hello, + 0, + 0, + NULL + }, + ngx_null_command +}; + + +ngx_http_module_t ngx_http_set_var_examples_module_ctx = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +ngx_module_t ngx_http_set_var_examples_module = { + + NGX_MODULE_V1, + &ngx_http_set_var_examples_module_ctx, // module context + ngx_http_set_var_examples_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 +}; + + +/* + This function is called by both examples, takes two variable values and concatenates them + to give a third string. +*/ + +static ngx_int_t +ngx_http_set_var_concat2 (ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *v) +{ + size_t len; + ngx_http_variable_value_t *v2; + u_char *p; + + v2 = v + 1; + + len = v->len + v2->len; + + /* + * NDK provided abbreviation for the following code: + * + * p = ngx_palloc (r->pool, len); + * if (p == NULL) + * return NGX_ERROR; + * + * */ + ndk_palloc_re(p, r->pool, len); + + val->data = p; + val->len = len; + + ngx_memzero (p, len); + + p = ngx_cpymem (p, v->data, v->len); + ngx_memcpy (p, v2->data, v2->len); + + return NGX_OK; +} + + + +/* + This function demonstrates using the 'core' function in a function that appends the word + 'hello_' to the beginning of a variable. + + set $var world; + set_prepend_hello $var $var; + + If the arguments used in the variable value filter do not all come directly from the conf + file, or are not given in the order + + direcive $var_name val1 "val2 string $var" ... + + then the _core functions should be used inside the function that is called when the directive + is read. +*/ + +static char * +ngx_http_set_prepend_hello (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t s[2], *var_name; + ndk_set_var_t filter; + + var_name = cf->args->elts; + var_name++; + + s[0].data = (u_char*) "hello_"; + s[0].len = 6; + + s[1] = *(var_name + 1); + + filter.type = NDK_SET_VAR_MULTI_VALUE; + filter.func = ngx_http_set_var_concat2; + filter.size = 2; + + return ndk_set_var_multi_value_core (cf, var_name, (ngx_str_t *) s, &filter); +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/ngx_auto_lib_core b/modules_deb/libnginx-mod-http-ndk-0.3.4/ngx_auto_lib_core new file mode 100644 index 0000000..d5441fb --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/ngx_auto_lib_core @@ -0,0 +1,797 @@ + +## Directories to search for usable builds: +## +## - [$PFX]_INC and [$PFX]_LIB +## - the dir specified by --with-[$pfx]=* +## - each dir named [$pfx]-* under [$PFX]_BASE (descending order) +## - each dir named [$pfx]-* under $ngx_src_dir/.. (descending order) +## - system_paths (see below) +## +## Note : specifying [$PFX]_INC or [$PFX]_LIB prevents other dirs being tried +## specifying --with-[$pfx]= prevents autodiscovery of dirs +## +## Note : if this file is not in the same directory as the config file, the value +## for ngx_auto_lib_file should be changed to a relative path from that file +## e.g. : $ngx_addon_dir/libs/ngx_auto_lib +## +## TODO : explain hooks + +############# +## VERSION ## +############# + +ngx_auto_lib_version=1001 + +if [ ! $ngx_auto_lib_file_version ] || [ $ngx_auto_lib_file_version -lt $ngx_auto_lib_version ]; then + + if [ ! $ngx_addon_dir ]; then + ngx_addon_dir=`cd $(dirname $0); pwd` + fi + + ngx_auto_lib_file="$ngx_addon_dir/ngx_auto_lib_core" + ngx_auto_lib_file_version="$ngx_auto_lib_version" +fi + +############### +## VARIABLES ## +############### + +v= +v="$v inc_path" +v="$v incs" +v="$v libs" +v="$v name" +v="$v path" +v="$v run" +v="$v test" +ev= +ev="$ev add_libs" +ev="$ev add_path" +ev="$ev build_dirs" +ev="$ev build_inc_dirs" +ev="$ev build_lib_dirs" +ev="$ev check_macros_defined" +ev="$ev check_macros_non_zero" +ev="$ev defines" +ev="$ev deps" +ev="$ev exit_if_not_found" +ev="$ev haves" +ev="$ev inc_names" +ev="$ev lib_files" +ev="$ev lib_names" +ev="$ev libs_to_add" +ev="$ev modules" +ev="$ev srcs" +ev="$ev shared" +ev="$ev test_libs" +ev="$ev variables" + +ngx_feature_vars="$v" +ngx_feature_extra_vars="$ev" +ngx_feature_all_vars="$v $ev" + +NGX_AUTO_LIB_DEFAULT_SYSTEM_DIRS='/usr/local /usr /opt/local /opt /usr/pkg' + +#################### +## UTIL FUNCTIONS ## +#################### + +to_upper() { + echo "$@" | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +} + +to_lower() { + echo "$@" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' +} + +#################### +## INIT FUNCTIONS ## +#################### + +ngx_auto_lib_init() { + + . $ngx_auto_lib_file + + ngx_auto_lib_init_latest $@ +} + +ngx_auto_lib_init_latest() { + + # set name and prefixes + + if [ ! $1 ]; then + echo "ngx_auto_lib_init() requires that a name be passed" + exit 1 + fi + + ngx_auto_lib_name=$1 + ngx_auto_lib_module_name=$2 + + if [ $2 ]; then + NGX_AUTO_LIB_PFX=`to_upper $2` + else + NGX_AUTO_LIB_PFX=`to_upper $1` + fi + + ngx_auto_lib_pfx=`to_lower $NGX_AUTO_LIB_PFX` + + ngx_auto_lib_clean_feature_vars +} + +ngx_auto_lib_clean_feature_vars() { + for var in $ngx_feature_all_vars; do + eval ngx_feature_$var= + done +} + +ngx_auto_lib_get_variables() { + + local pfx=$ngx_auto_lib_pfx + local PFX=$NGX_AUTO_LIB_PFX + + eval NGX_AUTO_LIB_INC=\"\$${PFX}_INC\" + eval NGX_AUTO_LIB_LIB=\"\$${PFX}_LIB\" + eval NGX_AUTO_LIB_DIR=\"\$${PFX}\" + eval NGX_AUTO_LIB_BASE=\"\$${PFX}_BASE\" + eval NGX_AUTO_LIB_SEARCH_LIB_INC=\"\$${PFX}_SEARCH_LIB_INC\" + eval NGX_AUTO_LIB_SEARCH_DIR=\"\$${PFX}_SEARCH_DIR\" + eval NGX_AUTO_LIB_SEARCH_BASE=\"\$${PFX}_SEARCH_BASE\" + eval NGX_AUTO_LIB_SEARCH_BASE_PREFIX=\"\$${PFX}_SEARCH_BASE_PREFIX\" + eval NGX_AUTO_LIB_SEARCH_PARENT=\"\$${PFX}_SEARCH_PARENT\" + eval NGX_AUTO_LIB_SEARCH_SYSTEM=\"\$${PFX}_SEARCH_SYSTEM\" + eval NGX_AUTO_LIB_SHARED=\"\$${PFX}_SHARED\" + eval NGX_AUTO_LIB_SYSTEM_DIRS=\"\$${PFX}_SYSTEM_DIR\" + eval USE_NGX_AUTO_LIB=\"\$USE_${LIB}\" + + if [ ! "$NGX_AUTO_LIB_DIR" ]; then + NGX_AUTO_LIB_DIR=NONE + fi + + if [ ! "$USE_NGX_AUTO_LIB" ]; then + if [ $ngx_feature_check_macros_defined -o $ngx_feature_check_macros_non_zero ]; then + USE_NGX_AUTO_LIB=MAYBE + elif [ "$ngx_feature_required" = no ]; then + USE_NGX_AUTO_LIB=MAYBE + else + USE_NGX_AUTO_LIB=YES + fi + fi + + if [ ! "$NGX_AUTO_LIB_SYSTEM_DIRS" ]; then + NGX_AUTO_LIB_SYSTEM_DIRS=$NGX_AUTO_LIB_DEFAULT_SYSTEM_DIRS + fi + + # TODO : add _STATIC, and do searches for both static and shared libs + + if [ ! "$NGX_AUTO_LIB_SHARED" ]; then + if [ "$ngx_feature_shared" = no ]; then + NGX_AUTO_LIB_SHARED=NO + else + NGX_AUTO_LIB_SHARED=YES + fi + fi + + NGX_AUTO_LIB_SEARCH_DEP=NO + + # set default search methods + # Note : these can be over-ridden by setting NGX_AUTO_LIB_SEARCH_[type]=YES|NO + + local auto=y + + if [ "$NGX_AUTO_LIB_INC" ] || [ "$NGX_AUTO_LIB_LIB" ]; then + ngx_auto_lib_search LIB_INC YES + auto=n + fi + + if [ "$NGX_AUTO_LIB_DIR" != NONE ]; then + ngx_auto_lib_search DIR YES + auto=n + fi + + if [ "$NGX_AUTO_LIB_BASE" ]; then + ngx_auto_lib_search BASE YES + auto=n + fi + + if [ $auto = y ]; then + ngx_auto_lib_search PARENT YES + ngx_auto_lib_search SYSTEM YES + fi + + ngx_auto_lib_search LIB_INC NO + ngx_auto_lib_search DIR NO + ngx_auto_lib_search BASE NO + ngx_auto_lib_search PARENT NO + ngx_auto_lib_search SYSTEM NO + + if [ ! "$ngx_feature_lib_names" ]; then + ngx_feature_lib_names=$pfx + fi + + if [ ! "$ngx_feature_inc_names" ]; then + ngx_feature_inc_names=$ngx_feature_lib_names + fi + + if [ ! "$ngx_feature_exit_if_not_found" ]; then + ngx_feature_exit_if_not_found=yes + fi +} + +####################### +## DEFAULT FUNCTIONS ## +####################### + +ngx_auto_lib_set_default() { + + local suffix= + if [ $1 ]; then + suffix="_$1" + fi + + local def=$2 + local var="NGX_AUTO_LIB$suffix" + + val= + if [ ! `eval echo '$'$var` ]; then + eval $var=\"$def\" + fi + + #eval echo "$var = \$$var" +} + +ngx_auto_lib_search() { + ngx_auto_lib_set_default "SEARCH_$1" $2 +} + +#################### +## SAVE FUNCTIONS ## +#################### + +ngx_auto_lib_save_vars() { + OLD_CORE_DEPS=$CORE_DEPS + OLD_CORE_INCS=$CORE_INCS + OLD_CORE_LIBS=$CORE_LIBS + OLD_CORE_SRCS=$CORE_SRCS + OLD_LINK_DEPS=$LINK_DEPS + + CORE_DEPS= + CORE_INCS= + CORE_LIBS= + CORE_SRCS= + LINK_DEPS= +} + +ngx_auto_lib_reset_vars() { + CORE_DEPS=$OLD_CORE_DEPS + CORE_INCS=$OLD_CORE_INCS + CORE_LIBS=$OLD_CORE_LIBS + CORE_SRCS=$OLD_CORE_SRCS + LINK_DEPS=$OLD_LINK_DEPS +} + +ngx_auto_lib_save_feature_vars() { + for var in $ngx_feature_all_vars; do + eval main_ngx_feature_$var=\"\$ngx_feature_$var\" + done +} + +ngx_auto_lib_reset_feature_vars() { + for var in $ngx_feature_all_vars; do + eval ngx_feature_$var=\"\$main_ngx_feature_$var\" + done +} + +######################## +## CHECKING FUNCTIONS ## +######################## + +ngx_auto_lib_check_auto_config() { + + ngx_auto_lib_save_feature_vars + ngx_auto_lib_clean_feature_vars + + ngx_feature=$1 + ngx_feature_inc_path="`echo $CFLAGS | tr ' ' '\n' | grep -- -D | tr '\n' ' '`" + ngx_feature_incs="#include <$NGX_AUTO_CONFIG_H>" + ngx_feature_libs= + ngx_feature_path=`pwd` + ngx_feature_run=no + ngx_feature_test=$2 + + #ngx_auto_lib_print_feature_vars + + . auto/feature + + if [ $ngx_found = yes ]; then + rv=0 + else + rv=1 + fi + + ngx_auto_lib_reset_feature_vars + + return $rv +} + +ngx_auto_lib_check_macro_defined() { + + for m in $@; do + ngx_auto_lib_check_auto_config "$m" " + #ifndef $m + rubbish + #endif" && return 0 + done + + return 1 +} + +ngx_auto_lib_check_macro_non_zero() { + + for m in $@; do + ngx_auto_lib_check_auto_config "$m" " + #if !($m) + rubbish + #endif" && return 0 + done + + return 1 +} + +ngx_auto_lib_check_require() { + + if [ $USE_NGX_AUTO_LIB = YES ]; then + return 0 + elif [ $USE_NGX_AUTO_LIB = NO ]; then + return 1 + fi + + + # check if the libraries are required elsewhere + + for l in $ngx_feature_lib_names; do + [ ! "`echo $CORE_LIBS $ADDON_LIBS | grep -w -- -l$l`" ] && return 0 + done + + + + # check that any required macros are set + + local d=$ngx_feature_check_macros_defined + local nz=$ngx_feature_check_macros_non_zero + + if [ "$d" ] || [ "$nz" ]; then + + ngx_auto_lib_check_macro_defined $d && return 0 + ngx_auto_lib_check_macro_non_zero $nz && return 0 + fi + + + ngx_auto_lib_check +} + +ngx_auto_lib_check() { + return 1 +} + +################################## +## TEST PHASE HANDLER FUNCTIONS ## +################################## + +ngx_auto_lib_test() { + ngx_auto_lib_test_pre_setup "$@" + ngx_auto_lib_test_setup "$@" + ngx_auto_lib_test_post_setup "$@" + ngx_auto_lib_test_feature +} + +ngx_auto_lib_test_pre_setup() { + return 0 +} + +ngx_auto_lib_test_setup() { + + local INC=$1 + local LIB=$2 + + ngx_auto_lib_inc_dir=$INC + ngx_auto_lib_lib_dir=$LIB + + ngx_auto_lib_reset_feature_vars + + if [ ! "$ngx_feature_path" ]; then + ngx_feature_path="$INC" + fi + + ngx_feature_path="$ngx_feature_path $ngx_feature_add_path" + + for sfx in $ngx_feature_path_suffixes; do + ngx_feature_path="$ngx_feature_path $INC/$sfx" + done + + + local inc= + local lib= + local incs="$ngx_feature_inc_names" + local libs="$ngx_feature_lib_names" + local lib_files="$ngx_feature_lib_files" + + for inc in $incs; do + ngx_feature_incs="$ngx_feature_incs +#include <$inc.h>" + done + + + if [ ! "$ngx_feature_libs" ]; then + + if [ $NGX_AUTO_LIB_SHARED = YES ]; then + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R$LIB" + fi + ngx_feature_libs="$ngx_feature_libs -L$LIB" + + for lib in $libs; do + ngx_feature_libs="$ngx_feature_libs -l$lib" + done + + # TODO : only add --rpath when the path is not a standard system path - warn if /usr + + ngx_feature_libs="$ngx_feature_libs -Wl,--rpath -Wl,$LIB" + + else + + for lib in $lib_files; do + ngx_feature_libs="$ngx_feature_libs $LIB/$lib" + done + + for lib in $libs; do + ngx_feature_libs="$ngx_feature_libs $LIB/lib$lib.a" + done + fi + fi + + if [ ! $ngx_feature_run ]; then + ngx_feature_run=no + fi + + if [ $NGX_AUTO_LIB_SHARED = YES ]; then + + # Add a test to be called in auto/feature after compilation that will check + # whether any libraries that are linked are in fact using the path provided to + # link libraries rather than a standard path. Note : this test will work on + # all linked shared objects, even if supplied directly by setting + # $ngx_feature_libs instead of usign $ngx_feature_lib_names + + # TODO : allow for some libraries to not be checked here if desired - if part of system paths + + libs="`echo $ngx_feature_libs | tr ' ' '\n' | grep -- -l | sed 's|-l||g'`" + + local test=" + for l in $libs; do + o="'\`ldd '$NGX_AUTOTEST' | grep '$LIB'/lib\$l\\.so\`; + if [ ! \"\$o\" ]; then + chmod -x $NGX_AUTOTEST; + echo Linker does not link to correct version + else + chmod +x $NGX_AUTOTEST; + fi + done' + test="`echo "$test" | tr '\n' ' '`" + + ngx_feature_test_libs="$ngx_feature_test_libs; $test" + fi + + ngx_feature_libs="$ngx_feature_libs $ngx_feature_add_libs" + ngx_feature_libs_to_add="$ngx_feature_libs" + ngx_feature_libs="$ngx_feature_libs $ngx_feature_test_libs" + ngx_feature="$ngx_auto_lib_name library $ngx_feature" +} + +ngx_auto_lib_test_post_setup() { + return 0 +} + +ngx_auto_lib_test_feature() { + #ngx_auto_lib_print_feature_vars + . auto/feature + [ $ngx_found = yes ] && return 0 + return 1 +} + +######################## +## TEST DIR FUNCTIONS ## +######################## + +ngx_auto_lib_test_dir_pair() { + ngx_auto_lib_test_inc_dir=$1 + ngx_auto_lib_test_lib_dir=$2 + + if [ $1 = $2 ]; then + ngx_feature="in $1$3" + else + ngx_feature="in $1 and $2$3" + fi + ngx_auto_lib_test "$1" "$2" "$3" +} + +ngx_auto_lib_test_dir_pairs() { + ngx_auto_lib_test_dir_pair "$1/include" "$2/lib" "$3" && return 0 + ngx_auto_lib_test_dir_pair "$1" "$2" "$3" && return 0 + return 1 +} + +ngx_auto_lib_test_dirs() { + + local msg="$1" + local bdir idir ldir + + local bdirs=$ngx_feature_build_dirs + local idirs=$ngx_feature_build_inc_dirs + local ldirs=$ngx_feature_build_lib_dirs + + shift + + for dir in "$@"; do + ngx_auto_lib_test_dir=$dir + + for ldir in $ldirs; do + for idir in $idirs; do + ngx_auto_lib_test_dir_pair "$dir/$idir" "$dir/$ldir" "$msg" && return 0 + done + done + + for ldir in $ldirs; do + ngx_auto_lib_test_dir_pair "$dir" "$dir/$ldir" "$msg" && return 0 + done + + for idir in $idirs; do + ngx_auto_lib_test_dir_pair "$dir/$idir" "$dir" "$msg" && return 0 + done + + for bdir in $bdirs; do + ngx_auto_lib_test_dir_pairs "$dir/$bdir" "$dir/$bdir" "$msg" && return 0 + done + + ngx_auto_lib_test_dir_pairs "$dir" "$dir" "$msg" && return 0 + ngx_auto_lib_test_dir= + done + + return 1 +} + +ngx_auto_lib_test_install_dirs() { + + local msg="$1" + local dir= + + shift + + for dir in "$@"; do + ngx_auto_lib_test_dir=$dir + ngx_auto_lib_test_dir_pair "$dir/include" "$dir/lib" "$msg" && return 0 + ngx_auto_lib_test_dir= + done + + return 1 +} + +ngx_auto_lib_run_tests() { + + local name="$ngx_auto_lib_name" + local pfx="$ngx_auto_lib_pfx" + local PFX="$NGX_AUTO_LIB_PFX" + local INC="$NGX_AUTO_LIB_INC" + local LIB="$NGX_AUTO_LIB_LIB" + local DIR="$NGX_AUTO_LIB_DIR" + local BASE="$NGX_AUTO_LIB_BASE" + local MSG="$NGX_AUTO_LIB_MSG" + + + ngx_found=no + + + # dependency + + if [ $NGX_AUTO_LIB_SEARCH_DEP = YES ]; then + ngx_auto_lib_test_dir_pair "$INC" "$LIB" "$MSG" + return $? + fi + + + # lib and include dirs set explicitly (e.g. $OPENSSL_INC, $OPENSSL_LIB) + + if [ $NGX_AUTO_LIB_SEARCH_LIB_INC = YES ]; then + ngx_auto_lib_test_dir_pair "$INC" "$LIB" " (specified by \$${PFX}_INC and \$${PFX}_LIB)" && return 0 + fi + + + # path specified by ${PFX} (e.g. $OPENSSL, $PCRE) + # Note : these will be set automatically by configure for OpenSSL, PCRE, Zlib etc + # TODO : change to searching more than one path + + if [ $NGX_AUTO_LIB_SEARCH_DIR = YES ] && [ $DIR != NONE ]; then + ngx_auto_lib_test_dirs " (specified by \$${PFX})" $DIR && return 0 + fi + + + # directories beginning with '$pfx-' that are in $NGX_AUTO_LIB_BASE (e.g. $OPENSSL_BASE) + + if [ $NGX_AUTO_LIB_SEARCH_BASE = YES ] && [ $BASE ]; then + + p=$NGX_AUTO_LIB_SEARCH_BASE_PREFIX + + if [ "$p" = YES ]; then + p="!ame $pfx-*" + elif [ "$p" ]; then + p="!ame $p*" + fi + + ngx_auto_lib_test_dirs " (found under \$${PFX}_BASE)" \ + `find $BASE/* -maxdepth 0 -type d $p 2> /dev/null | sort -r` && return 0 + fi + + + # directories beginning with '$pfx-' that are in the same directory as the Nginx source + + if [ $NGX_AUTO_LIB_SEARCH_PARENT = YES ]; then + local src_dir=`cd ..; pwd` + ngx_auto_lib_test_dirs " (found under Nginx source parent dir)" \ + `find $src_dir/* -maxdepth 0 -type d !ame $pfx-* 2> /dev/null | sort -r` && return 0 + fi + + + # system folders + + if [ $NGX_AUTO_LIB_SEARCH_SYSTEM = YES ]; then + ngx_auto_lib_test_install_dirs "" $NGX_AUTO_LIB_SYSTEM_DIRS && return 0 + fi + + return 1 +} + +####################### +## HANDLER FUNCTIONS ## +####################### + +ngx_auto_lib_run() { + ngx_auto_lib_get_variables + eval AUTO_$NGX_AUTO_LIB_PFX=NO + + ngx_auto_lib_check_require || return + ngx_auto_lib_setup || return + ngx_auto_lib_save_feature_vars + ngx_auto_lib_run_tests + ngx_auto_lib_post_tests || return + ngx_auto_lib_finalize +} + +ngx_auto_lib_print_feature_vars() { + echo ---------------------------- + for var in $ngx_feature_vars; do + eval "echo ngx_feature_$var = \$ngx_feature_$var" + done + echo ---------------------------- +} + +ngx_auto_lib_setup() { + return 0 +} + +ngx_auto_lib_post_tests() { + return 0 +} + +############################# +## SET VARIABLES FUNCTIONS ## +############################# + +# TODO : add HTTP/ADDON settings too + +ngx_auto_lib_set_core_variables() { + # TODO : don't add includes / libs more than once + + eval CORE_DEPS=\"$CORE_DEPS $ngx_feature_deps\" + eval CORE_INCS=\"$CORE_INCS $ngx_feature_path\" + eval CORE_LIBS=\"$CORE_LIBS $ngx_feature_libs_to_add\" + eval CORE_SRCS=\"$CORE_SRCS $ngx_feature_srcs\" +} + +ngx_auto_lib_set_generic_variables() { + local INC=$ngx_auto_lib_test_inc_dir + local LIB=$ngx_auto_lib_test_lib_dir + + modules="$modules $ngx_feature_modules" + + for have in $ngx_feature_haves; do + . auto/have + done + + set - $ngx_feature_defines + + while [ $1 ]; do + have=$1 + value=$2 + . auto/define + done + + local PFX=$NGX_AUTO_LIB_PFX + + eval USE_$PFX=NO + + if [ $ngx_auto_lib_test_dir ]; then + eval $PFX=$ngx_auto_lib_test_dir + else + eval $PFX=$ngx_auto_lib_lib_dir + fi + + if [ $NGX_AUTO_LIB_SHARED != YES ]; then + for l in $ngx_feature_lib_names; do + CORE_LIBS=`echo $CORE_LIBS | sed 's|-\||g'` + ADDON_LIBS=`echo $ADDON_LIBS | sed 's|-\||g'` + done + fi + + eval ${PFX}_INC=$INC + eval ${PFX}_LIB=$LIB + eval ${PFX}_SHARED=$NGX_AUTO_LIB_SHARED + eval AUTO_$PFX=YES +} + +ngx_auto_lib_set_custom_variables() { + return 0 +} + +######################## +## FINALIZE FUNCTIONS ## +######################## + +ngx_auto_lib_finalize() { + ngx_auto_lib_finalize_core +} + +ngx_auto_lib_finalize_core() { + + if [ $ngx_found = yes ]; then + + ngx_auto_lib_set_core_variables + ngx_auto_lib_set_generic_variables + + if [ "$ngx_feature_variables" ]; then + eval $ngx_feature_variables + fi + + ngx_auto_lib_set_custom_variables + + elif [ $ngx_feature_exit_if_not_found = yes ]; then + + if [ $ngx_auto_lib_module_name ]; then + module_txt=" by the $ngx_auto_lib_module_name module" + else + module_text= + fi + + lib=$ngx_auto_lib_name + pfx=$ngx_auto_lib_pfx + PFX=$NGX_AUTO_LIB_PFX + +cat << END + +$0: error: the $lib library is required$module_txt, but cannot +be found using the current configuration. In order for the compilation to succeed, +you will need to install the library using your system's package installer or point +the configure script to the library using one of the following variables : + +to define a dir to find $pfx library (source or install dir) $PFX +to define $pfx lib and include dirs separately ${PFX}_LIB & ${PFX}_INC +to define a base dir to search for dirs beginning with $pfx- ${PFX}_BASE + +e.g. + +$ export ${PFX}_LIB=/path/to/library/lib +$ export ${PFX}_LIB=/path/to/library/include +$ $0 ... + +END + exit 1 + fi +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/notes/CHANGES b/modules_deb/libnginx-mod-http-ndk-0.3.4/notes/CHANGES new file mode 100644 index 0000000..eaaef0b --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/notes/CHANGES @@ -0,0 +1,17 @@ +Changelog +--------- + +0.1 feature : set_var functions +0.1.1 feature : upstream_list directive and functions +0.2 feature : conf merge functions + feature : conf command macros + feature : 'action' macros +0.2.1 bugfix : ndk_map_uri_to_path_add_suffix +0.2.2 feature : regex conf functions +0.2.3 feature : version number +0.2.4 change : the auto/build script is now executed automatically on compilation +0.2.9 feature : ngx_auto_lib included with source +0.2.11 bugfix : hash functions did not display properly +0.2.12 feature : patches for rewrite functions and rewrite phase handler +0.2.13 change : revert to old behaviour rewrite functions + change : pre-generated config and macro files now provided \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/notes/LICENSE b/modules_deb/libnginx-mod-http-ndk-0.3.4/notes/LICENSE new file mode 100644 index 0000000..7074f57 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/notes/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2010, Marcus Clyne, Simpl (simpl.it) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization (Simpl) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL MARCUS CLYNE OR SIMPL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_array.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_array.h new file mode 100644 index 0000000..4e0d518 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_array.h @@ -0,0 +1,113 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* Non-generated macros */ + +#define ndk_array_count(a) ((a)->nelts) +#define ndk_array_get_first(a) ((a)->elts) +#define ndk_array_get_index(a,n) ((void*) ((char*) (a)->elts + (a)->size * n)) +#define ndk_array_get_last(a) ((void*) ((char*) (a)->elts + (a)->size * ((a)->nelts - 1))) +#define ndk_array_get_reverse_index(a,n) ((void*) ((char*) (a)->elts + (a)->size * ((a)->nelts - 1 - n))) +#define ndk_array_push_clean(p,a) {p = ngx_array_push (a); ndk_zerop (p);} + + +/* base action macro macros */ + +#define ndk_array_create_ac(a,pl,n,sz,ac) {a = ngx_array_create (pl,n,sz); if (a == NULL) ac;} +#define ndk_array_init_ac(a,pl,n,sz,ac) {if (ngx_array_init (a,pl,n,sz) == NGX_ERROR) ac;} +#define ndk_array_push_ac(p,a,ac) {p = ngx_array_push (a); if (p == NULL) ac;} +#define ndk_array_push_clean_ac(p,a,ac) {p = ngx_array_push (a); if (p == NULL) ac; ndk_zerop (p);} +#define ndk_array_push_n_ac(p,a,n,ac) {p = ngx_array_push_n (a,n); if (p == NULL) ac;} +#define ndk_array_push_n_clean_ac(p,a,n,ac) {p = ngx_array_push_n (a,n); if (p == NULL) ac; ndk_zeropn (p,n);} + + +/* generated action macros */ + +#define ndk_array_create_r0(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return 0) +#define ndk_array_create_r1(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return 1) +#define ndk_array_create_r_1(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return -1) +#define ndk_array_create_rok(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return NGX_OK) +#define ndk_array_create_rce(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return NGX_CONF_ERROR) +#define ndk_array_create_rcok(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return NGX_CONF_OK) +#define ndk_array_create_re(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return NGX_ERROR) +#define ndk_array_create_rn(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,return NULL) +#define ndk_array_create_rse(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,{ngx_script_error (e); return;}) +#define ndk_array_create_sce(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,{ngx_script_configure_error (c); return;}) +#define ndk_array_create_g(a,pl,n,sz,_lb) ndk_array_create_ac (a,pl,n,sz,goto _lb) +#define ndk_array_create_ge(a,pl,n,sz) ndk_array_create_ac (a,pl,n,sz,goto error) + +#define ndk_array_init_r0(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return 0) +#define ndk_array_init_r1(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return 1) +#define ndk_array_init_r_1(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return -1) +#define ndk_array_init_rok(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return NGX_OK) +#define ndk_array_init_rce(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return NGX_CONF_ERROR) +#define ndk_array_init_rcok(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return NGX_CONF_OK) +#define ndk_array_init_re(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return NGX_ERROR) +#define ndk_array_init_rn(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,return NULL) +#define ndk_array_init_rse(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,{ngx_script_error (e); return;}) +#define ndk_array_init_sce(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,{ngx_script_configure_error (c); return;}) +#define ndk_array_init_g(a,pl,n,sz,_lb) ndk_array_init_ac (a,pl,n,sz,goto _lb) +#define ndk_array_init_ge(a,pl,n,sz) ndk_array_init_ac (a,pl,n,sz,goto error) + +#define ndk_array_push_r0(p,a) ndk_array_push_ac (p,a,return 0) +#define ndk_array_push_r1(p,a) ndk_array_push_ac (p,a,return 1) +#define ndk_array_push_r_1(p,a) ndk_array_push_ac (p,a,return -1) +#define ndk_array_push_rok(p,a) ndk_array_push_ac (p,a,return NGX_OK) +#define ndk_array_push_rce(p,a) ndk_array_push_ac (p,a,return NGX_CONF_ERROR) +#define ndk_array_push_rcok(p,a) ndk_array_push_ac (p,a,return NGX_CONF_OK) +#define ndk_array_push_re(p,a) ndk_array_push_ac (p,a,return NGX_ERROR) +#define ndk_array_push_rn(p,a) ndk_array_push_ac (p,a,return NULL) +#define ndk_array_push_rse(p,a) ndk_array_push_ac (p,a,{ngx_script_error (e); return;}) +#define ndk_array_push_sce(p,a) ndk_array_push_ac (p,a,{ngx_script_configure_error (c); return;}) +#define ndk_array_push_g(p,a,_lb) ndk_array_push_ac (p,a,goto _lb) +#define ndk_array_push_ge(p,a) ndk_array_push_ac (p,a,goto error) + +#define ndk_array_push_clean_r0(p,a) ndk_array_push_clean_ac (p,a,return 0) +#define ndk_array_push_clean_r1(p,a) ndk_array_push_clean_ac (p,a,return 1) +#define ndk_array_push_clean_r_1(p,a) ndk_array_push_clean_ac (p,a,return -1) +#define ndk_array_push_clean_rok(p,a) ndk_array_push_clean_ac (p,a,return NGX_OK) +#define ndk_array_push_clean_rce(p,a) ndk_array_push_clean_ac (p,a,return NGX_CONF_ERROR) +#define ndk_array_push_clean_rcok(p,a) ndk_array_push_clean_ac (p,a,return NGX_CONF_OK) +#define ndk_array_push_clean_re(p,a) ndk_array_push_clean_ac (p,a,return NGX_ERROR) +#define ndk_array_push_clean_rn(p,a) ndk_array_push_clean_ac (p,a,return NULL) +#define ndk_array_push_clean_rse(p,a) ndk_array_push_clean_ac (p,a,{ngx_script_error (e); return;}) +#define ndk_array_push_clean_sce(p,a) ndk_array_push_clean_ac (p,a,{ngx_script_configure_error (c); return;}) +#define ndk_array_push_clean_g(p,a,_lb) ndk_array_push_clean_ac (p,a,goto _lb) +#define ndk_array_push_clean_ge(p,a) ndk_array_push_clean_ac (p,a,goto error) + +#define ndk_array_push_n_r0(p,a,n) ndk_array_push_n_ac (p,a,n,return 0) +#define ndk_array_push_n_r1(p,a,n) ndk_array_push_n_ac (p,a,n,return 1) +#define ndk_array_push_n_r_1(p,a,n) ndk_array_push_n_ac (p,a,n,return -1) +#define ndk_array_push_n_rok(p,a,n) ndk_array_push_n_ac (p,a,n,return NGX_OK) +#define ndk_array_push_n_rce(p,a,n) ndk_array_push_n_ac (p,a,n,return NGX_CONF_ERROR) +#define ndk_array_push_n_rcok(p,a,n) ndk_array_push_n_ac (p,a,n,return NGX_CONF_OK) +#define ndk_array_push_n_re(p,a,n) ndk_array_push_n_ac (p,a,n,return NGX_ERROR) +#define ndk_array_push_n_rn(p,a,n) ndk_array_push_n_ac (p,a,n,return NULL) +#define ndk_array_push_n_rse(p,a,n) ndk_array_push_n_ac (p,a,n,{ngx_script_error (e); return;}) +#define ndk_array_push_n_sce(p,a,n) ndk_array_push_n_ac (p,a,n,{ngx_script_configure_error (c); return;}) +#define ndk_array_push_n_g(p,a,n,_lb) ndk_array_push_n_ac (p,a,n,goto _lb) +#define ndk_array_push_n_ge(p,a,n) ndk_array_push_n_ac (p,a,n,goto error) + +#define ndk_array_push_n_clean_r0(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return 0) +#define ndk_array_push_n_clean_r1(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return 1) +#define ndk_array_push_n_clean_r_1(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return -1) +#define ndk_array_push_n_clean_rok(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return NGX_OK) +#define ndk_array_push_n_clean_rce(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return NGX_CONF_ERROR) +#define ndk_array_push_n_clean_rcok(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return NGX_CONF_OK) +#define ndk_array_push_n_clean_re(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return NGX_ERROR) +#define ndk_array_push_n_clean_rn(p,a,n) ndk_array_push_n_clean_ac (p,a,n,return NULL) +#define ndk_array_push_n_clean_rse(p,a,n) ndk_array_push_n_clean_ac (p,a,n,{ngx_script_error (e); return;}) +#define ndk_array_push_n_clean_sce(p,a,n) ndk_array_push_n_clean_ac (p,a,n,{ngx_script_configure_error (c); return;}) +#define ndk_array_push_n_clean_g(p,a,n,_lb) ndk_array_push_n_clean_ac (p,a,n,goto _lb) +#define ndk_array_push_n_clean_ge(p,a,n) ndk_array_push_n_clean_ac (p,a,n,goto error) + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_basic.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_basic.h new file mode 100644 index 0000000..c2db894 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_basic.h @@ -0,0 +1,2203 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* conf cmd core values/bitmasks */ + +#define NDK_1MORE NGX_1MORE +#define NDK_2MORE NGX_2MORE +#define NDK_ANY NGX_ANY +#define NDK_ARGS_NUMBER NGX_ARGS_NUMBER +#define NDK_BLOCK NGX_BLOCK +#define NDK_FLAG NGX_FLAG +#define NDK_MULTI NGX_MULTI +#define NDK_TAKE1 NGX_TAKE1 +#define NDK_TAKE12 NGX_TAKE12 +#define NDK_TAKE123 NGX_TAKE123 +#define NDK_TAKE1234 NGX_TAKE1234 +#define NDK_TAKE13 NGX_TAKE13 +#define NDK_TAKE2 NGX_TAKE2 +#define NDK_TAKE23 NGX_TAKE23 +#define NDK_TAKE3 NGX_TAKE3 +#define NDK_TAKE4 NGX_TAKE4 +#define NDK_TAKE5 NGX_TAKE5 +#define NDK_TAKE6 NGX_TAKE6 +#define NDK_TAKE7 NGX_TAKE7 +#define NDK_TAKE8 NGX_TAKE8 + + +/* conf cmd bitmasks */ + +/* TODO : finish this */ + +#define NDK_HTTP_MAIN_CONF NGX_HTTP_MAIN_CONF +#define NDK_HTTP_SRV_CONF NGX_HTTP_SRV_CONF +#define NDK_HTTP_SIF_CONF NGX_HTTP_SIF_CONF +#define NDK_HTTP_LOC_CONF NGX_HTTP_LOC_CONF +#define NDK_HTTP_LIF_CONF NGX_HTTP_LIF_CONF +#define NDK_HTTP_UPS_CONF NGX_HTTP_UPS_CONF +#define NDK_MAIN_CONF NGX_MAIN_CONF +#define NDK_ANY_CONF NGX_ANY_CONF + + +/* compound locations */ + +#define NDK_HTTP_MAIN_SRV_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_CONF +#define NDK_HTTP_MAIN_SIF_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_SIF_CONF +#define NDK_HTTP_MAIN_LOC_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_LOC_CONF +#define NDK_HTTP_MAIN_LIF_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_LOC_LIF_CONF + +#define NDK_HTTP_SRV_SIF_CONF NDK_HTTP_SRV_CONF|NDK_HTTP_SIF_CONF +#define NDK_HTTP_SRV_LOC_CONF NDK_HTTP_SRV_CONF|NDK_HTTP_LOC_CONF +#define NDK_HTTP_SRV_LOC_LIF_CONF NDK_HTTP_SRV_CONF|NDK_HTTP_LOC_LIF_CONF +#define NDK_HTTP_SRV_SIF_LOC_CONF NDK_HTTP_SRV_SIF_CONF|NDK_HTTP_LOC_CONF +#define NDK_HTTP_SRV_SIF_LOC_LIF_CONF NDK_HTTP_SRV_SIF_CONF|NDK_HTTP_LOC_LIF_CONF + +#define NDK_HTTP_LOC_LIF_CONF NDK_HTTP_LOC_CONF|NDK_HTTP_LIF_CONF + +#define NDK_HTTP_MAIN_SRV_LOC_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_LOC_CONF +#define NDK_HTTP_MAIN_SRV_LIF_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SRV_LIF_CONF +#define NDK_HTTP_MAIN_SIF_LOC_CONF NDK_HTTP_MAIN_CONF|NDK_HTTP_SIF_LOC_CONF +#define NDK_HTTP_MAIN_SRV_SIF_LOC_LIF_CONF NDK_HTTP_SRV_SIF_LOC_LIF_CONF|NDK_MAIN_CONF +#define NDK_HTTP_CONF NDK_HTTP_MAIN_SRV_SIF_LOC_LIF_CONF +#define NDK_HTTP_ANY_CONF NDK_HTTP_CONF|NDK_HTTP_UPS_CONF + + +/* property offsets NOTE : ngx_module_main_conf_t etc should be defined in the module's .c file before the commands */ + +#define NDK_HTTP_MAIN_CONF_PROP(p) NGX_HTTP_MAIN_CONF_OFFSET, offsetof (ndk_module_main_conf_t, p) +#define NDK_HTTP_SRV_CONF_PROP(p) NGX_HTTP_SRV_CONF_OFFSET, offsetof (ndk_module_srv_conf_t, p) +#define NDK_HTTP_LOC_CONF_PROP(p) NGX_HTTP_LOC_CONF_OFFSET, offsetof (ndk_module_loc_conf_t, p) + + +/* conf cmd basic macros */ + +#define NDK_HTTP_MAIN_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_1MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_1MORE|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_2MORE(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_2MORE|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_ANY(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ANY|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_ARGS_NUMBER(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_ARGS_NUMBER|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_BLOCK(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_BLOCK|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_FLAG(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_FLAG|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_MULTI(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_MULTI|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE1(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE12(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE12|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE123(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE123|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE1234(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE1234|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE13(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE13|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE2(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE2|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE23(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE23|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE3(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE3|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE4(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE4|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE5(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE5|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE6(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE6|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE7(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE7|NDK_ANY_CONF,\ + func, off1, off2, post}, + + +#define NDK_HTTP_MAIN_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_LIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_SRV_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_SIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_LIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SRV_LIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_SIF_LIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_SIF_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_SRV_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_SRV_LIF_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_MAIN_SRV_SIF_LOC_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_UPS_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_UPS_CONF,\ + func, off1, off2, post}, + +#define NDK_HTTP_ANY_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_HTTP_ANY_CONF,\ + func, off1, off2, post}, + +#define NDK_ANY_CONF_TAKE8(name,func,off1,off2,post)\ + {ngx_string (name),\ + NGX_CONF_TAKE8|NDK_ANY_CONF,\ + func, off1, off2, post}, + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_extra.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_extra.h new file mode 100644 index 0000000..68e276f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_cmd_extra.h @@ -0,0 +1,5423 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* conf command macros */ + +#define NDK_HTTP_MAIN_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_BITMASK(name,p,post)\ + NDK_HTTP_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_BITMASK(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_BITMASK(name,p,post)\ + NDK_HTTP_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_BITMASK(name,p,post)\ + NDK_HTTP_UPS_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_BITMASK(name,p,post)\ + NDK_HTTP_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_BITMASK(name,p,post)\ + NDK_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_bitmask_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_BUFS(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_BUFS(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_BUFS(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_BUFS(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_BUFS(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_BUFS(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_bufs_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_COMPLEX_KEYVAL(name,p,post)\ + NDK_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_http_complex_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_COMPLEX_PATH(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_COMPLEX_PATH(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_UPS_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_HTTP_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_COMPLEX_VALUE_ARRAY(name,p,post)\ + NDK_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_http_complex_value_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_COMPLEX_VALUE(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_http_complex_value_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_ENCODING(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_ENCODING(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_ENCODING(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_ENCODING(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_ENCODING(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_ENCODING(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_encoding_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_ENUM(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_ENUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_ENUM(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_ENUM(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_ENUM(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_ENUM(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_enum_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_FALSE(name,p,post)\ + NDK_HTTP_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_FALSE(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_FALSE(name,p,post)\ + NDK_HTTP_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_FALSE(name,p,post)\ + NDK_HTTP_UPS_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_FALSE(name,p,post)\ + NDK_HTTP_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_FALSE(name,p,post)\ + NDK_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_false_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_FULL_PATH(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_FULL_PATH(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_full_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_KEYVAL1(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_KEYVAL1(name,p,post)\ + NDK_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval1_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_KEYVAL(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_KEYVAL(name,p,post)\ + NDK_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_keyval_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_MSEC(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_MSEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_MSEC(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_MSEC(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_MSEC(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_MSEC(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_msec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_NULL(name,p,post)\ + NDK_HTTP_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_NULL(name,p,post)\ + NDK_HTTP_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_NULL(name,p,post)\ + NDK_HTTP_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_NULL(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_NULL(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NULL(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_NULL(name,p,post)\ + NDK_HTTP_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_NULL(name,p,post)\ + NDK_HTTP_UPS_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_NULL(name,p,post)\ + NDK_HTTP_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_NULL(name,p,post)\ + NDK_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_null_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_NUM64(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NUM64(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_NUM64(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_NUM64(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_NUM64(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_NUM64(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_num64_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_NUM_FLAG(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_NUM_FLAG(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_NUM(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_NUM(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_NUM(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_NUM(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_NUM(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NUM(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_NUM(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_NUM(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_NUM(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_NUM(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_num_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_OFF(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_OFF(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_OFF(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_OFF(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_OFF(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_OFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_OFF(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_OFF(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_OFF(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_OFF(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_off_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_ONOFF(name,p,post)\ + NDK_HTTP_SRV_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_SIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_LIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_ONOFF(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_ONOFF(name,p,post)\ + NDK_HTTP_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_ONOFF(name,p,post)\ + NDK_HTTP_UPS_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_ONOFF(name,p,post)\ + NDK_HTTP_ANY_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_ONOFF(name,p,post)\ + NDK_ANY_CONF_FLAG\ + (name,\ + ndk_conf_set_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_PATH(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_PATH(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_PATH(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_PATH(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_PATH(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_PATH(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_PATH(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_PATH(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_PATH(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_PATH(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_split_path_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_PTR(name,p,post)\ + NDK_HTTP_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_PTR(name,p,post)\ + NDK_HTTP_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_PTR(name,p,post)\ + NDK_HTTP_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_PTR(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_PTR(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_PTR(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_PTR(name,p,post)\ + NDK_HTTP_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_PTR(name,p,post)\ + NDK_HTTP_UPS_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_PTR(name,p,post)\ + NDK_HTTP_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_PTR(name,p,post)\ + NDK_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_ptr_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_UPS_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_REGEX_ARRAY(name,p,post)\ + NDK_HTTP_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_REGEX_ARRAY(name,p,post)\ + NDK_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_UPS_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_HTTP_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_REGEX_ARRAY_CL(name,p,post)\ + NDK_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_regex_array_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_REGEX_CL(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_REGEX_CL(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_caseless_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_REXEX(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_REXEX(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_REXEX(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_REXEX(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_REXEX(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_REXEX(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_regex_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_SEC_FLAG(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_SEC_FLAG(name,p,post)\ + NDK_ANY_CONF_TAKE2\ + (name,\ + ndk_conf_set_sec_flag_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_SEC(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_SEC(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_SEC(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_SEC(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_SEC(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_SEC(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_SEC(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_SEC(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_SEC(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_SEC(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_sec_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_SIZE(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_SIZE(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_SIZE(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_SIZE(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_SIZE(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_SIZE(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_size_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_UPS_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_STR_ARRAY(name,p,post)\ + NDK_HTTP_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_STR_ARRAY(name,p,post)\ + NDK_ANY_CONF_1MORE\ + (name,\ + ndk_conf_set_str_array_multi_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_STR_ARRAY1(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_STR_ARRAY1(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_array_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_STR(name,p,post)\ + NDK_HTTP_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_STR(name,p,post)\ + NDK_HTTP_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_STR(name,p,post)\ + NDK_HTTP_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_STR(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_STR(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_STR(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_STR(name,p,post)\ + NDK_HTTP_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_STR(name,p,post)\ + NDK_HTTP_UPS_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_STR(name,p,post)\ + NDK_HTTP_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_STR(name,p,post)\ + NDK_ANY_CONF_TAKE1\ + (name,\ + ndk_conf_set_str_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + +#define NDK_HTTP_MAIN_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_MAIN_CONF_OFFSET,\ + offsetof (ndk_module_main_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_CONF_TRUE(name,p,post)\ + NDK_HTTP_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_LIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_SIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_SRV_CONF_OFFSET,\ + offsetof (ndk_module_srv_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_LIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SRV_LIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_SIF_LIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_SIF_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_LIF_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_LIF_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SIF_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_TRUE(name,p,post)\ + NDK_HTTP_MAIN_SRV_SIF_LOC_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_CONF_TRUE(name,p,post)\ + NDK_HTTP_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_UPS_CONF_TRUE(name,p,post)\ + NDK_HTTP_UPS_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_HTTP_ANY_CONF_TRUE(name,p,post)\ + NDK_HTTP_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + +#define NDK_ANY_CONF_TRUE(name,p,post)\ + NDK_ANY_CONF_NOARGS\ + (name,\ + ndk_conf_set_true_slot,\ + NGX_HTTP_LOC_CONF_OFFSET,\ + offsetof (ndk_module_loc_conf_t, p),\ + post) + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_merge.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_merge.h new file mode 100644 index 0000000..4f7855f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_conf_merge.h @@ -0,0 +1,227 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* conf-merge-value macros */ + +/* TODO : check that all the main types have a corresponding merge function */ + +#define ndk_conf_merge_value ngx_conf_merge_value +#define ndk_conf_merge_off_value ngx_conf_merge_off_value +#define ndk_conf_merge_ptr_value ngx_conf_merge_ptr_value +#define ndk_conf_merge_str_value ngx_conf_merge_str_value +#define ndk_conf_merge_size_value ngx_conf_merge_size_value + + +#define ndk_conf_merge_keyval_value(conf,prev,default) \ + \ + conf = prev ? prev : default; + +#define ndk_conf_merge_str_array_value(conf,prev,val1,...) \ + \ + if (conf == NGX_CONF_UNSET_PTR) { \ + if (prev == NGX_CONF_UNSET_PTR) { \ + if (val1 == NULL) { \ + conf = NULL; \ + } else { \ + char * elts[] = {val1,##__VA_ARGS__}; \ + int n = sizeof(elts)/sizeof(char*); \ + \ + conf = ndk_str_array_create (cf->pool, elts, n); \ + \ + if (conf == NULL) \ + return NGX_CONF_ERROR; \ + } \ + } else { \ + conf = prev; \ + } \ + } + +#define ndk_conf_merge_http_complex_value_value(conf,prev,default) \ + \ + if (!conf.str.len) { \ + if (prev.str.len) { \ + conf = prev; \ + } else { \ + conf.str.data = (u_char *) default; \ + conf.str.len = sizeof (default) - 1; \ + \ + if (ndk_http_complex_value_compile (cf, &conf)) \ + return NGX_CONF_ERROR; \ + } \ + } + +#define ndk_conf_merge_http_complex_value_array_value(conf,prev,val1,...) \ + \ + if (conf == NGX_CONF_UNSET_PTR) { \ + if (prev == NGX_CONF_UNSET_PTR) { \ + if (val1 == NULL) \ + conf = NULL; \ + else { \ + char * elts[] = {val1,##__VA_ARGS__}; \ + int n = sizeof(elts)/sizeof(char*); \ + \ + conf = ndk_http_complex_value_array_create (cf, elts, n); \ + \ + if (conf == NULL) \ + return NGX_CONF_ERROR; \ + } \ + } else { \ + conf = prev; \ + } \ + } + +#define ndk_conf_merge_http_complex_path_value(conf,prev,...) \ + ndk_conf_merge_http_complex_value_array_value (conf.a, prev.a, __VA_ARGS__) + +#define ndk_conf_merge_split_path_value(conf,prev,path) \ + \ + if (conf == NGX_CONF_UNSET_PTR) { \ + conf = (prev == NGX_CONF_UNSET_PTR ? \ + ndk_split_path_create_raw (cf, path) : prev); \ + } + + +/* conf-merge-prop macros */ + +#define ndk_conf_merge_prop(prop,default)\ + ndk_conf_merge_value\ + (conf->prop, prev->prop, default) + +#define ndk_conf_merge_bitmask_prop(prop,default,...)\ + ndk_conf_merge_bitmask_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_bufs_prop(prop,default,...)\ + ndk_conf_merge_bufs_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_encoding_prop(prop,default,...)\ + ndk_conf_merge_encoding_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_enum_prop(prop,default,...)\ + ndk_conf_merge_enum_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_false_prop(prop,default,...)\ + ndk_conf_merge_false_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_flag_prop(prop,default,...)\ + ndk_conf_merge_flag_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_full_path_prop(prop,default,...)\ + ndk_conf_merge_full_path_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_http_complex_keyval_prop(prop,default,...)\ + ndk_conf_merge_http_complex_keyval_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_http_complex_path_prop(prop,default,...)\ + ndk_conf_merge_http_complex_path_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_http_complex_value_prop(prop,default,...)\ + ndk_conf_merge_http_complex_value_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_http_complex_value_array_prop(prop,default,...)\ + ndk_conf_merge_http_complex_value_array_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_keyval_prop(prop,default,...)\ + ndk_conf_merge_keyval_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_keyval1_prop(prop,default,...)\ + ndk_conf_merge_keyval1_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_msec_prop(prop,default,...)\ + ndk_conf_merge_msec_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_null_prop(prop,default,...)\ + ndk_conf_merge_null_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_num_prop(prop,default,...)\ + ndk_conf_merge_num_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_num64_prop(prop,default,...)\ + ndk_conf_merge_num64_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_num_flag_prop(prop,default,...)\ + ndk_conf_merge_num_flag_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_off_prop(prop,default,...)\ + ndk_conf_merge_off_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_ptr_prop(prop,default,...)\ + ndk_conf_merge_ptr_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_regex_prop(prop,default,...)\ + ndk_conf_merge_regex_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_regex_array_prop(prop,default,...)\ + ndk_conf_merge_regex_array_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_regex_array_caseless_prop(prop,default,...)\ + ndk_conf_merge_regex_array_caseless_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_regex_caseless_prop(prop,default,...)\ + ndk_conf_merge_regex_caseless_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_sec_prop(prop,default,...)\ + ndk_conf_merge_sec_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_sec_flag_prop(prop,default,...)\ + ndk_conf_merge_sec_flag_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_size_prop(prop,default,...)\ + ndk_conf_merge_size_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_split_path_prop(prop,default,...)\ + ndk_conf_merge_split_path_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_str_prop(prop,default,...)\ + ndk_conf_merge_str_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_str_array_prop(prop,default,...)\ + ndk_conf_merge_str_array_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_str_array_multi_prop(prop,default,...)\ + ndk_conf_merge_str_array_multi_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + +#define ndk_conf_merge_true_prop(prop,default,...)\ + ndk_conf_merge_true_value\ + (conf->prop, prev->prop, default,##__VA_ARGS__) + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.c new file mode 100644 index 0000000..d2e572f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.c @@ -0,0 +1,72 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* optional includes */ + +#if (NDK_BUF) +#include +#endif +#if (NDK_COMPLEX_PATH) +#include +#endif +#if (NDK_COMPLEX_VALUE) +#include +#endif +#if (NDK_CONF_FILE) +#include +#endif +#if (NDK_ENCODING) +#include +#endif +#if (NDK_HASH) +#include +#endif +#if (NDK_HTTP) +#include +#endif +#if (NDK_PATH) +#include +#endif +#if (NDK_PROCESS) +#include +#endif +#if (NDK_REGEX) +#include +#endif +#if (NDK_REWRITE) +#include +#endif +#if (NDK_SET_VAR) +#include +#endif +#if (NDK_STRING) +#include +#endif +#if (NDK_UPSTREAM_LIST) +#include +#endif +#if (NDK_URI) +#include +#endif + + +/* module commands */ + +static ngx_command_t ndk_http_commands[] = { +#if (NDK_UPSTREAM_LIST) +#define NDK_UPSTREAM_LIST_CMDS 1 +#include +#undef NDK_UPSTREAM_LIST_CMDS +#endif + ngx_null_command +}; diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.h new file mode 100644 index 0000000..7223950 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_config.h @@ -0,0 +1,98 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* include all optional modules */ + +#ifdef NDK_ALL + +#ifndef NDK_BUF +#define NDK_BUF 1 +#endif +#ifndef NDK_COMPLEX_PATH +#define NDK_COMPLEX_PATH 1 +#endif +#ifndef NDK_COMPLEX_VALUE +#define NDK_COMPLEX_VALUE 1 +#endif +#ifndef NDK_CONF_FILE +#define NDK_CONF_FILE 1 +#endif +#ifndef NDK_ENCODING +#define NDK_ENCODING 1 +#endif +#ifndef NDK_HASH +#define NDK_HASH 1 +#endif +#ifndef NDK_HTTP +#define NDK_HTTP 1 +#endif +#ifndef NDK_PATH +#define NDK_PATH 1 +#endif +#ifndef NDK_PROCESS +#define NDK_PROCESS 1 +#endif +#ifndef NDK_REGEX +#define NDK_REGEX 1 +#endif +#ifndef NDK_REWRITE +#define NDK_REWRITE 1 +#endif +#ifndef NDK_SET_VAR +#define NDK_SET_VAR 1 +#endif +#ifndef NDK_STRING +#define NDK_STRING 1 +#endif +#ifndef NDK_UPSTREAM_LIST +#define NDK_UPSTREAM_LIST 1 +#endif +#ifndef NDK_URI +#define NDK_URI 1 +#endif + +#endif + + +/* module dependencies */ + +#ifdef NDK_COMPLEX_PATH +#ifndef NDK_COMPLEX_VALUE +#define NDK_COMPLEX_VALUE 1 +#endif +#ifndef NDK_PATH +#define NDK_PATH 1 +#endif +#endif +#ifdef NDK_CONF_FILE +#ifndef NDK_STRING +#define NDK_STRING 1 +#endif +#endif +#ifdef NDK_HASH +#ifndef NDK_STRING +#define NDK_STRING 1 +#endif +#endif +#ifdef NDK_SET_VAR +#ifndef NDK_REWRITE +#define NDK_REWRITE 1 +#endif +#endif +#ifdef NDK_UPSTREAM_LIST +#ifndef NDK_HTTP_CREATE_MAIN_CONF +#define NDK_HTTP_CREATE_MAIN_CONF 1 +#endif +#endif + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_includes.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_includes.h new file mode 100644 index 0000000..cbbf60a --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_includes.h @@ -0,0 +1,66 @@ +/* optional includes */ + +#if (NDK_BUF) +#include +#endif +#if (NDK_COMPLEX_PATH) +#include +#endif +#if (NDK_COMPLEX_VALUE) +#include +#endif +#if (NDK_CONF_FILE) +#include +#endif +#if (NDK_ENCODING) +#include +#endif +#if (NDK_HASH) +#include +#endif +#if (NDK_HTTP) +#include +#endif +#if (NDK_PATH) +#include +#endif +#if (NDK_PROCESS) +#include +#endif +#if (NDK_REGEX) +#include +#endif +#if (NDK_REWRITE) +#include +#endif +#if (NDK_SET_VAR) +#include +#endif +#if (NDK_STRING) +#include +#endif +#if (NDK_UPSTREAM_LIST) +#include +#endif +#if (NDK_URI) +#include +#endif + + +/* non-optional includes */ + +#include +#include +#include +#include + + +/* auto-generated headers */ + +#include +#include +#include +#include +#include + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_palloc.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_palloc.h new file mode 100644 index 0000000..db8aaf1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/objs/ndk_palloc.h @@ -0,0 +1,112 @@ + +/* + * 2010 (C) Marcus Clyne + * + * DO NOT EDIT THIS FILE MANUALLY + * ------------------------------ + * This file has been generated automatically from scripts in the $base/auto dir and + * data in the $base/auto/data dir. If you wish to edit the output of this file, then + * you should edit these files instead. + * +*/ + + +/* Non-generated macros */ + +#define ndk_pallocp(p,pl) p = ngx_palloc (pl,sizeof(*p)) +#define ndk_pallocpn(p,pl,n) p = ngx_palloc (pl,sizeof(*p)*(n)) + +#define ndk_pcallocp(p,pl) p = ngx_pcalloc (pl,sizeof(*p)) +#define ndk_pcallocpn(p,pl,n) p = ngx_pcalloc (pl,sizeof(*p)*(n)) + + +/* base action macro macros */ + +#define ndk_palloc_ac(p,pl,sz,ac) {p = ngx_palloc (pl,sz); if (p == NULL) ac;} +#define ndk_pallocp_ac(p,pl,ac) {ndk_pallocp (p,pl); if (p == NULL) ac;} +#define ndk_pallocpn_ac(p,pl,n,ac) {ndk_pallocpn (p,pl,n); if (p == NULL) ac;} +#define ndk_pcalloc_ac(p,pl,sz,ac) {p = ngx_pcalloc (pl,sz); if (p == NULL) ac;} +#define ndk_pcallocp_ac(p,pl,ac) {ndk_pcallocp (p,pl); if (p == NULL) ac;} +#define ndk_pcallocpn_ac(p,pl,n,ac) {ndk_pcallocpn (p,pl,n); if (p == NULL) ac;} + + +/* generated action macros */ + +#define ndk_palloc_r0(p,pl,sz) ndk_palloc_ac (p,pl,sz,return 0) +#define ndk_palloc_r1(p,pl,sz) ndk_palloc_ac (p,pl,sz,return 1) +#define ndk_palloc_r_1(p,pl,sz) ndk_palloc_ac (p,pl,sz,return -1) +#define ndk_palloc_rok(p,pl,sz) ndk_palloc_ac (p,pl,sz,return NGX_OK) +#define ndk_palloc_rce(p,pl,sz) ndk_palloc_ac (p,pl,sz,return NGX_CONF_ERROR) +#define ndk_palloc_rcok(p,pl,sz) ndk_palloc_ac (p,pl,sz,return NGX_CONF_OK) +#define ndk_palloc_re(p,pl,sz) ndk_palloc_ac (p,pl,sz,return NGX_ERROR) +#define ndk_palloc_rn(p,pl,sz) ndk_palloc_ac (p,pl,sz,return NULL) +#define ndk_palloc_rse(p,pl,sz) ndk_palloc_ac (p,pl,sz,{ngx_script_error (e); return;}) +#define ndk_palloc_sce(p,pl,sz) ndk_palloc_ac (p,pl,sz,{ngx_script_configure_error (c); return;}) +#define ndk_palloc_g(p,pl,sz,_lb) ndk_palloc_ac (p,pl,sz,goto _lb) +#define ndk_palloc_ge(p,pl,sz) ndk_palloc_ac (p,pl,sz,goto error) + +#define ndk_pallocp_r0(p,pl) ndk_pallocp_ac (p,pl,return 0) +#define ndk_pallocp_r1(p,pl) ndk_pallocp_ac (p,pl,return 1) +#define ndk_pallocp_r_1(p,pl) ndk_pallocp_ac (p,pl,return -1) +#define ndk_pallocp_rok(p,pl) ndk_pallocp_ac (p,pl,return NGX_OK) +#define ndk_pallocp_rce(p,pl) ndk_pallocp_ac (p,pl,return NGX_CONF_ERROR) +#define ndk_pallocp_rcok(p,pl) ndk_pallocp_ac (p,pl,return NGX_CONF_OK) +#define ndk_pallocp_re(p,pl) ndk_pallocp_ac (p,pl,return NGX_ERROR) +#define ndk_pallocp_rn(p,pl) ndk_pallocp_ac (p,pl,return NULL) +#define ndk_pallocp_rse(p,pl) ndk_pallocp_ac (p,pl,{ngx_script_error (e); return;}) +#define ndk_pallocp_sce(p,pl) ndk_pallocp_ac (p,pl,{ngx_script_configure_error (c); return;}) +#define ndk_pallocp_g(p,pl,_lb) ndk_pallocp_ac (p,pl,goto _lb) +#define ndk_pallocp_ge(p,pl) ndk_pallocp_ac (p,pl,goto error) + +#define ndk_pallocpn_r0(p,pl,n) ndk_pallocpn_ac (p,pl,n,return 0) +#define ndk_pallocpn_r1(p,pl,n) ndk_pallocpn_ac (p,pl,n,return 1) +#define ndk_pallocpn_r_1(p,pl,n) ndk_pallocpn_ac (p,pl,n,return -1) +#define ndk_pallocpn_rok(p,pl,n) ndk_pallocpn_ac (p,pl,n,return NGX_OK) +#define ndk_pallocpn_rce(p,pl,n) ndk_pallocpn_ac (p,pl,n,return NGX_CONF_ERROR) +#define ndk_pallocpn_rcok(p,pl,n) ndk_pallocpn_ac (p,pl,n,return NGX_CONF_OK) +#define ndk_pallocpn_re(p,pl,n) ndk_pallocpn_ac (p,pl,n,return NGX_ERROR) +#define ndk_pallocpn_rn(p,pl,n) ndk_pallocpn_ac (p,pl,n,return NULL) +#define ndk_pallocpn_rse(p,pl,n) ndk_pallocpn_ac (p,pl,n,{ngx_script_error (e); return;}) +#define ndk_pallocpn_sce(p,pl,n) ndk_pallocpn_ac (p,pl,n,{ngx_script_configure_error (c); return;}) +#define ndk_pallocpn_g(p,pl,n,_lb) ndk_pallocpn_ac (p,pl,n,goto _lb) +#define ndk_pallocpn_ge(p,pl,n) ndk_pallocpn_ac (p,pl,n,goto error) + +#define ndk_pcalloc_r0(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return 0) +#define ndk_pcalloc_r1(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return 1) +#define ndk_pcalloc_r_1(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return -1) +#define ndk_pcalloc_rok(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return NGX_OK) +#define ndk_pcalloc_rce(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return NGX_CONF_ERROR) +#define ndk_pcalloc_rcok(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return NGX_CONF_OK) +#define ndk_pcalloc_re(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return NGX_ERROR) +#define ndk_pcalloc_rn(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,return NULL) +#define ndk_pcalloc_rse(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,{ngx_script_error (e); return;}) +#define ndk_pcalloc_sce(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,{ngx_script_configure_error (c); return;}) +#define ndk_pcalloc_g(p,pl,sz,_lb) ndk_pcalloc_ac (p,pl,sz,goto _lb) +#define ndk_pcalloc_ge(p,pl,sz) ndk_pcalloc_ac (p,pl,sz,goto error) + +#define ndk_pcallocp_r0(p,pl) ndk_pcallocp_ac (p,pl,return 0) +#define ndk_pcallocp_r1(p,pl) ndk_pcallocp_ac (p,pl,return 1) +#define ndk_pcallocp_r_1(p,pl) ndk_pcallocp_ac (p,pl,return -1) +#define ndk_pcallocp_rok(p,pl) ndk_pcallocp_ac (p,pl,return NGX_OK) +#define ndk_pcallocp_rce(p,pl) ndk_pcallocp_ac (p,pl,return NGX_CONF_ERROR) +#define ndk_pcallocp_rcok(p,pl) ndk_pcallocp_ac (p,pl,return NGX_CONF_OK) +#define ndk_pcallocp_re(p,pl) ndk_pcallocp_ac (p,pl,return NGX_ERROR) +#define ndk_pcallocp_rn(p,pl) ndk_pcallocp_ac (p,pl,return NULL) +#define ndk_pcallocp_rse(p,pl) ndk_pcallocp_ac (p,pl,{ngx_script_error (e); return;}) +#define ndk_pcallocp_sce(p,pl) ndk_pcallocp_ac (p,pl,{ngx_script_configure_error (c); return;}) +#define ndk_pcallocp_g(p,pl,_lb) ndk_pcallocp_ac (p,pl,goto _lb) +#define ndk_pcallocp_ge(p,pl) ndk_pcallocp_ac (p,pl,goto error) + +#define ndk_pcallocpn_r0(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return 0) +#define ndk_pcallocpn_r1(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return 1) +#define ndk_pcallocpn_r_1(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return -1) +#define ndk_pcallocpn_rok(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return NGX_OK) +#define ndk_pcallocpn_rce(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return NGX_CONF_ERROR) +#define ndk_pcallocpn_rcok(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return NGX_CONF_OK) +#define ndk_pcallocpn_re(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return NGX_ERROR) +#define ndk_pcallocpn_rn(p,pl,n) ndk_pcallocpn_ac (p,pl,n,return NULL) +#define ndk_pcallocpn_rse(p,pl,n) ndk_pcallocpn_ac (p,pl,n,{ngx_script_error (e); return;}) +#define ndk_pcallocpn_sce(p,pl,n) ndk_pcallocpn_ac (p,pl,n,{ngx_script_configure_error (c); return;}) +#define ndk_pcallocpn_g(p,pl,n,_lb) ndk_pcallocpn_ac (p,pl,n,goto _lb) +#define ndk_pcallocpn_ge(p,pl,n) ndk_pcallocpn_ac (p,pl,n,goto error) + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/auto_config b/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/auto_config new file mode 100644 index 0000000..ba4fdd4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/auto_config @@ -0,0 +1,16 @@ +diff -pNr a/src/core/ngx_config.h b/src/core/ngx_config.h +*** a/src/core/ngx_config.h 2008-09-19 13:47:13.000000000 +0100 +--- b/src/core/ngx_config.h 2010-10-09 17:14:13.000000000 +0100 +*************** typedef intptr_t ngx_flag_t; +*** 127,131 **** + #define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff + #endif + +! + #endif /* _NGX_CONFIG_H_INCLUDED_ */ +--- 127,131 ---- + #define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff + #endif + +! #include + #endif /* _NGX_CONFIG_H_INCLUDED_ */ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/expose_rewrite_functions b/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/expose_rewrite_functions new file mode 100644 index 0000000..ec1d6d8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/expose_rewrite_functions @@ -0,0 +1,291 @@ +diff -rNp a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c +*** a/src/http/modules/ngx_http_rewrite_module.c 2010-06-18 16:15:20.000000000 +0100 +--- b/src/http/modules/ngx_http_rewrite_module.c 2010-10-09 14:47:10.000000000 +0100 +*************** +*** 8,14 **** + #include + #include + +! + typedef struct { + ngx_array_t *codes; /* uintptr_t */ + +--- 8,14 ---- + #include + #include + +! #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) + typedef struct { + ngx_array_t *codes; /* uintptr_t */ + +*************** typedef struct { +*** 17,23 **** + ngx_flag_t log; + ngx_flag_t uninitialized_variable_warn; + } ngx_http_rewrite_loc_conf_t; +! + + static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf); + static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, +--- 17,23 ---- + ngx_flag_t log; + ngx_flag_t uninitialized_variable_warn; + } ngx_http_rewrite_loc_conf_t; +! #endif + + static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf); + static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, +*************** static char *ngx_http_rewrite_return(ngx +*** 28,44 **** + void *conf); + static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf); + static char *ngx_http_rewrite_variable(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value); + static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static char * ngx_http_rewrite_value(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value); +! + + static ngx_command_t ngx_http_rewrite_commands[] = { + +--- 28,47 ---- + void *conf); + static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); ++ #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) + static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf); + static char *ngx_http_rewrite_variable(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value); ++ #endif + static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); ++ #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) + static char * ngx_http_rewrite_value(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value); +! #endif + + static ngx_command_t ngx_http_rewrite_commands[] = { + +*************** ngx_http_rewrite_handler(ngx_http_reques +*** 178,185 **** + return r->err_status; + } + +! +! static ngx_int_t + ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) + { +--- 181,190 ---- + return r->err_status; + } + +! #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) +! static +! #endif +! ngx_int_t + ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) + { +*************** ngx_http_rewrite_break(ngx_conf_t *cf, n +*** 511,517 **** + } + + +! static char * + ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { + ngx_http_rewrite_loc_conf_t *lcf = conf; +--- 516,525 ---- + } + + +! #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) +! static +! #endif +! char * + ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { + ngx_http_rewrite_loc_conf_t *lcf = conf; +*************** ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ +*** 627,633 **** + } + + +! static char * + ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf) + { + u_char *p; +--- 635,644 ---- + } + + +! #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) +! static +! #endif +! char * + ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf) + { + u_char *p; +*************** ngx_http_rewrite_if_condition(ngx_conf_t +*** 847,853 **** + } + + +! static char * + ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) + { +--- 858,867 ---- + } + + +! #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) +! static +! #endif +! char * + ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) + { +*************** ngx_http_rewrite_set(ngx_conf_t *cf, ngx +*** 948,954 **** + } + + +! static char * + ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) + { +--- 962,971 ---- + } + + +! #if !(NDK_EXPOSE_REWRITE_FUNCTIONS) +! static +! #endif +! char * + ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) + { +diff -rNp a/src/http/modules/ngx_http_rewrite_module.h b/src/http/modules/ngx_http_rewrite_module.h +*** a/src/http/modules/ngx_http_rewrite_module.h 1970-01-01 01:00:00.000000000 +0100 +--- b/src/http/modules/ngx_http_rewrite_module.h 2010-10-09 14:38:04.000000000 +0100 +*************** +*** 0 **** +--- 1,47 ---- ++ ++ /* ++ * Copyright (C) Marcus Clyne ++ * ++ * Note : this file has been created by the Nginx Development Kit using ++ * some code from ngx_http_rewrite_module.c ++ */ ++ ++ #if (NDK_EXPOSE_REWRITE_FUNCTIONS) ++ ++ #ifndef _NGX_HTTP_REWRITE_H_INCLUDED_ ++ #define _NGX_HTTP_REWRITE_H_INCLUDED_ ++ ++ #include ++ #include ++ #include ++ ++ ++ extern ngx_module_t ngx_http_rewrite_module; ++ ++ ++ typedef struct { ++ ngx_array_t *codes; /* uintptr_t */ ++ ++ ngx_uint_t stack_size; ++ ++ ngx_flag_t log; ++ ngx_flag_t uninitialized_variable_warn; ++ } ngx_http_rewrite_loc_conf_t; ++ ++ ++ char * ++ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ++ char * ++ ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf); ++ char * ++ ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, ++ ngx_str_t *value); ++ char * ++ ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, ++ ngx_str_t *value); ++ ngx_int_t ++ ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v, ++ uintptr_t data); ++ ++ #endif ++ #endif +diff -rNp a/src/http/ngx_http.h b/src/http/ngx_http.h +*** a/src/http/ngx_http.h 2010-06-15 16:13:34.000000000 +0100 +--- b/src/http/ngx_http.h 2010-10-09 14:25:56.000000000 +0100 +*************** typedef u_char *(*ngx_http_log_handler_p +*** 43,48 **** +--- 43,52 ---- + #include + #endif + ++ #if (NDK_EXPOSE_REWRITE_FUNCTIONS) ++ #include ++ #endif ++ + + struct ngx_http_log_ctx_s { + ngx_connection_t *connection; +diff -rNp a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c +*** a/src/http/ngx_http_script.c 2010-09-13 13:44:43.000000000 +0100 +--- b/src/http/ngx_http_script.c 2010-10-09 14:36:10.000000000 +0100 +*************** static size_t ngx_http_script_full_name_ +*** 26,35 **** +--- 26,43 ---- + static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e); + + ++ #if (NDK_EXPOSE_REWRITE_FUNCTIONS) ++ ++ uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL; ++ ++ #else ++ + #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code + + static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL; + ++ #endif ++ + + void + ngx_http_script_flush_complex_value(ngx_http_request_t *r, +diff -rNp a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h +*** a/src/http/ngx_http_script.h 2010-09-13 13:44:43.000000000 +0100 +--- b/src/http/ngx_http_script.h 2010-10-09 14:33:40.000000000 +0100 +*************** +*** 12,17 **** +--- 12,25 ---- + #include + #include + ++ #if (NDK_EXPOSE_REWRITE_FUNCTIONS) ++ ++ #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code ++ ++ extern uintptr_t ngx_http_script_exit_code; ++ ++ #endif ++ + + typedef struct { + u_char *ip; diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/rewrite_phase_handler b/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/rewrite_phase_handler new file mode 100644 index 0000000..bd5161f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/patches/rewrite_phase_handler @@ -0,0 +1,19 @@ +diff -p -r a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c +*** a/src/http/ngx_http_core_module.c 2010-09-27 12:48:12.000000000 +0100 +--- b/src/http/ngx_http_core_module.c 2010-10-09 13:44:09.000000000 +0100 +*************** ngx_http_core_rewrite_phase(ngx_http_req +*** 910,915 **** +--- 910,922 ---- + return NGX_AGAIN; + } + ++ #if defined(nginx_version) && nginx_version >= 8042 && (NDK_REWRITE_PHASE) ++ ++ if (rc == NGX_AGAIN || rc == NGX_DONE) { ++ return NGX_OK; ++ } ++ ++ #endif + /* rc == NGX_OK || rc == NGX_ERROR || rc == NGX_HTTP_... */ + + ngx_http_finalize_request(r, rc); diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/md5.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/md5.h new file mode 100644 index 0000000..4cbf843 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/md5.h @@ -0,0 +1,117 @@ +/* crypto/md5/md5.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD5_H +#define HEADER_MD5_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_NO_MD5 +#error MD5 is disabled. +#endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! MD5_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! MD5_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(__LP32__) +#define MD5_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define MD5_LONG unsigned long +#define MD5_LONG_LOG2 3 +/* + * _CRAY note. I could declare short, but I have no idea what impact + * does it have on performance on none-T3E machines. I could declare + * int, but at least on C90 sizeof(int) can be chosen at compile time. + * So I've chosen long... + * + */ +#else +#define MD5_LONG unsigned int +#endif + +#define MD5_CBLOCK 64 +#define MD5_LBLOCK (MD5_CBLOCK/4) +#define MD5_DIGEST_LENGTH 16 + +typedef struct MD5state_st + { + MD5_LONG A,B,C,D; + MD5_LONG Nl,Nh; + MD5_LONG data[MD5_LBLOCK]; + unsigned int num; + } MD5_CTX; + +int MD5_Init(MD5_CTX *c); +int MD5_Update(MD5_CTX *c, const void *data, size_t len); +int MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md); +void MD5_Transform(MD5_CTX *c, const unsigned char *b); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/murmurhash2.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/murmurhash2.c new file mode 100644 index 0000000..ac899b4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/murmurhash2.c @@ -0,0 +1,77 @@ + + +#ifndef MURMURHASH2_C +#define MURMURHASH2_C + +#define MURMURHASH2_DIGEST_LENGTH 4 + +/* + * ----------------------------------------------------------------------------- + * MurmurHash2, by Austin Appleby + + * Note - This code makes a few assumptions about how your machine behaves - + + * 1. We can read a 4-byte value from any address without crashing + * 2. sizeof(int) == 4 + + * And it has a few limitations - + + * 1. It will not work incrementally. + * 2. It will not produce the same results on little-endian and big-endian + * machines. + */ + +unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) +{ + /* + * 'm' and 'r' are mixing constants generated offline. + * They're not really 'magic', they just happen to work well. + */ + + const unsigned int m = 0x5bd1e995; + const int r = 24; + + /* Initialize the hash to a 'random' value */ + + unsigned int h = seed ^ len; + + /* Mix 4 bytes at a time into the hash */ + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + unsigned int k = *(unsigned int *)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + /* Handle the last few bytes of the input array */ + + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + /* Do a few final mixes of the hash to ensure the last few + * bytes are well-incorporated. */ + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/sha.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/sha.h new file mode 100644 index 0000000..16cacf9 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/hash/sha.h @@ -0,0 +1,200 @@ +/* crypto/sha/sha.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_SHA_H +#define HEADER_SHA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1)) +#error SHA is disabled. +#endif + +#if defined(OPENSSL_FIPS) +#define FIPS_SHA_SIZE_T size_t +#endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! SHA_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(__LP32__) +#define SHA_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define SHA_LONG unsigned long +#define SHA_LONG_LOG2 3 +#else +#define SHA_LONG unsigned int +#endif + +#define SHA_LBLOCK 16 +#define SHA_CBLOCK (SHA_LBLOCK*4) /* SHA treats input data as a + * contiguous array of 32 bit + * wide big-endian values. */ +#define SHA_LAST_BLOCK (SHA_CBLOCK-8) +#define SHA_DIGEST_LENGTH 20 + +typedef struct SHAstate_st + { + SHA_LONG h0,h1,h2,h3,h4; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num; + } SHA_CTX; + +#ifndef OPENSSL_NO_SHA0 +int SHA_Init(SHA_CTX *c); +int SHA_Update(SHA_CTX *c, const void *data, size_t len); +int SHA_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA(const unsigned char *d, size_t n, unsigned char *md); +void SHA_Transform(SHA_CTX *c, const unsigned char *data); +#endif +#ifndef OPENSSL_NO_SHA1 +int SHA1_Init(SHA_CTX *c); +int SHA1_Update(SHA_CTX *c, const void *data, size_t len); +int SHA1_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md); +void SHA1_Transform(SHA_CTX *c, const unsigned char *data); +#endif + +#define SHA256_CBLOCK (SHA_LBLOCK*4) /* SHA-256 treats input data as a + * contiguous array of 32 bit + * wide big-endian values. */ +#define SHA224_DIGEST_LENGTH 28 +#define SHA256_DIGEST_LENGTH 32 + +typedef struct SHA256state_st + { + SHA_LONG h[8]; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num,md_len; + } SHA256_CTX; + +#ifndef OPENSSL_NO_SHA256 +int SHA224_Init(SHA256_CTX *c); +int SHA224_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA224_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA224(const unsigned char *d, size_t n,unsigned char *md); +int SHA256_Init(SHA256_CTX *c); +int SHA256_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA256_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA256(const unsigned char *d, size_t n,unsigned char *md); +void SHA256_Transform(SHA256_CTX *c, const unsigned char *data); +#endif + +#define SHA384_DIGEST_LENGTH 48 +#define SHA512_DIGEST_LENGTH 64 + +#ifndef OPENSSL_NO_SHA512 +/* + * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64 + * being exactly 64-bit wide. See Implementation Notes in sha512.c + * for further details. + */ +#define SHA512_CBLOCK (SHA_LBLOCK*8) /* SHA-512 treats input data as a + * contiguous array of 64 bit + * wide big-endian values. */ +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +#define SHA_LONG64 unsigned __int64 +#define U64(C) C##UI64 +#elif defined(__arch64__) +#define SHA_LONG64 unsigned long +#define U64(C) C##UL +#else +#define SHA_LONG64 unsigned long long +#define U64(C) C##ULL +#endif + +typedef struct SHA512state_st + { + SHA_LONG64 h[8]; + SHA_LONG64 Nl,Nh; + union { + SHA_LONG64 d[SHA_LBLOCK]; + unsigned char p[SHA512_CBLOCK]; + } u; + unsigned int num,md_len; + } SHA512_CTX; +#endif + +#ifndef OPENSSL_NO_SHA512 +int SHA384_Init(SHA512_CTX *c); +int SHA384_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA384_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA384(const unsigned char *d, size_t n,unsigned char *md); +int SHA512_Init(SHA512_CTX *c); +int SHA512_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA512_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA512(const unsigned char *d, size_t n,unsigned char *md); +void SHA512_Transform(SHA512_CTX *c, const unsigned char *data); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.c new file mode 100644 index 0000000..d57040a --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.c @@ -0,0 +1,155 @@ + +/* + * 2010 (C) Marcus Clyne + */ + +#include + +#include + + +#if (NDK_HTTP_PRE_CONFIG) +static ngx_int_t ndk_http_preconfiguration (ngx_conf_t *cf); +#endif +#if (NDK_HTTP_POST_CONFIG) +static ngx_int_t ndk_http_postconfiguration (ngx_conf_t *cf); +#endif +#if (NDK_HTTP_CREATE_MAIN_CONF) +static void * ndk_http_create_main_conf (ngx_conf_t *cf); +#endif +#if (NDK_HTTP_INIT_MAIN_CONF) +static char * ndk_http_init_main_conf (ngx_conf_t *cf, void *conf); +#endif +#if (NDK_HTTP_CREATE_SRV_CONF) +static void * ndk_http_create_srv_conf (ngx_conf_t *cf); +#endif +#if (NDK_HTTP_MERGE_SRV_CONF) +static char * ndk_http_merge_srv_conf (ngx_conf_t *cf, void *parent, void *child); +#endif +#if (NDK_HTTP_CREATE_LOC_CONF) +static void * ndk_http_create_loc_conf (ngx_conf_t *cf); +#endif +#if (NDK_HTTP_MERGE_LOC_CONF) +static char * ndk_http_merge_loc_conf (ngx_conf_t *cf, void *parent, void *child); +#endif + + +#if (NDK_HTTP_INIT_MASTER) +static ngx_int_t ndk_http_init_master (ngx_log_t *log); +#endif +#if (NDK_HTTP_INIT_MODULE) +static ngx_int_t ndk_http_init_module (ngx_cycle_t *cycle); +#endif +#if (NDK_HTTP_INIT_PROCESS) +static ngx_int_t ndk_http_init_process (ngx_cycle_t *cycle); +#endif +#if (NDK_HTTP_EXIT_PROCESS) +static void ndk_http_exit_process (ngx_cycle_t *cycle); +#endif +#if (NDK_HTTP_EXIT_MASTER) +static void ndk_http_exit_master (ngx_cycle_t *cycle); +#endif + + +ngx_http_module_t ndk_http_module_ctx = { + +#if (NDK_HTTP_PRE_CONFIG) + ndk_http_preconfiguration, +#else + NULL, +#endif +#if (NDK_HTTP_POST_CONFIG) + ndk_http_postconfiguration, +#else + NULL, +#endif + +#if (NDK_HTTP_CREATE_MAIN_CONF) + ndk_http_create_main_conf, +#else + NULL, +#endif +#if (NDK_HTTP_INIT_MAIN_CONF) + ndk_http_merge_main_conf, +#else + NULL, +#endif + +#if (NDK_HTTP_CREATE_SVR_CONF) + ndk_http_create_srv_conf, +#else + NULL, +#endif +#if (NDK_HTTP_MERGE_SVR_CONF) + ndk_http_merge_srv_conf, +#else + NULL, +#endif + +#if (NDK_HTTP_CREATE_LOC_CONF) + ndk_http_create_loc_conf, +#else + NULL, +#endif +#if (NDK_HTTP_MERGE_LOC_CONF) + ndk_http_merge_loc_conf, +#else + NULL, +#endif + +}; + +ngx_module_t ndk_http_module = { + + NGX_MODULE_V1, + &ndk_http_module_ctx, /* module context */ + ndk_http_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + +#if (NDK_HTTP_INIT_MASTER) + ndk_http_init_master, +#else + NULL, +#endif + +#if (NDK_HTTP_INIT_MODULE) + ndk_http_init_module, +#else + NULL, +#endif +#if (NDK_HTTP_INIT_PROCESS) + ndk_http_init_process, +#else + NULL, +#endif + + NULL, /* init thread */ + NULL, /* exit thread */ + +#if (NDK_HTTP_EXIT_PROCESS) + ndk_http_exit_process, +#else + NULL, +#endif +#if (NDK_HTTP_EXIT_MASTER) + ndk_http_exit_master, +#else + NULL, +#endif + NGX_MODULE_V1_PADDING +}; + + + +#if (NDK_HTTP_CREATE_MAIN_CONF) +static void * +ndk_http_create_main_conf (ngx_conf_t *cf) +{ + ndk_http_main_conf_t *mcf; + + ndk_pcallocp_rce (mcf, cf->pool); + + return mcf; +} +#endif + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.h new file mode 100644 index 0000000..e08dfac --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk.h @@ -0,0 +1,53 @@ + +/* + * 2010 (C) Marcus Clyne +*/ + + +#ifndef NDK_H +#define NDK_H + + +#include +#include +#include + + +#define ndk_version 3004 +#define NDK_VERSION "0.3.4" + + +#if (NGX_DEBUG) +#ifndef NDK_DEBUG +#define NDK_DEBUG 1 +#endif +#else +#ifndef NDK_DEBUG +#define NDK_DEBUG 0 +#endif +#endif + + +#include + + +#if (NDK_HTTP_CREATE_MAIN_CONF) + +#define ndk_http_conf_get_main_conf(cf) ngx_http_conf_get_module_main_conf (cf, ndk_http_module) +#define ndk_http_get_main_conf(r) ngx_http_get_module_main_conf (r, ndk_http_module) + +typedef struct { +#if (NDK_UPSTREAM_LIST) + ngx_array_t *upstreams; +#endif +} ndk_http_main_conf_t; + +#endif /* NDK_HTTP_CREATE_MAIN_CONF */ + +#include + + +extern ngx_module_t ndk_http_module; + + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.c new file mode 100644 index 0000000..c491f72 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.c @@ -0,0 +1,43 @@ + +ngx_int_t +ndk_copy_chain_to_str (ngx_pool_t *pool, ngx_chain_t *in, ngx_str_t *str) +{ + ngx_chain_t *cl; + size_t len; + u_char *p; + ngx_buf_t *b; + + len = 0; + for (cl = in; cl; cl = cl->next) + len += ngx_buf_size (cl->buf); + + ndk_palloc_re (p, pool, len + 1); + + str->data = p; + str->len = len; + + for (cl = in; cl; cl = cl->next) { + + b = cl->buf; + + if (ngx_buf_in_memory (b)) { + p = ngx_cpymem (p, b->pos, b->last - b->pos); + } + } + + *p = '\0'; + + return NGX_OK; +} + + +char * +ndk_copy_chain_to_charp (ngx_pool_t *pool, ngx_chain_t *in) +{ + ngx_str_t str; + + if (ndk_copy_chain_to_str (pool, in, &str) != NGX_OK) + return NULL; + + return (char *) str.data; +} \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.h new file mode 100644 index 0000000..e6334ad --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_buf.h @@ -0,0 +1,5 @@ + + +ngx_int_t ndk_copy_chain_to_str (ngx_pool_t *pool, ngx_chain_t *in, ngx_str_t *str); +char * ndk_copy_chain_to_charp (ngx_pool_t *pool, ngx_chain_t *in); + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.c new file mode 100644 index 0000000..8b32713 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.c @@ -0,0 +1,129 @@ + + +ndk_http_complex_path_value_t ndk_empty_http_complex_path_value = {{0,NULL},0}; + + +ngx_int_t +ndk_http_complex_path_value_compile (ngx_conf_t *cf, ngx_http_complex_value_t *cv, ngx_str_t *value, ngx_uint_t prefix) +{ + ngx_http_compile_complex_value_t ccv; + + ngx_memzero (&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = value; + ccv.complex_value = cv; + + switch (prefix) { + + case 1 : + ccv.root_prefix = 1; + break; + + case 2 : + ccv.conf_prefix = 1; + break; + } + + ndk_path_to_dir_safe (value, 1, 0); + + if (!value->len) + return NGX_OK; + + return ngx_http_compile_complex_value (&ccv); +} + + + +ngx_array_t * +ndk_http_complex_path_create_compile (ngx_conf_t *cf, ngx_str_t *path, ngx_uint_t prefix) +{ + ndk_http_complex_path_elt_t *cpe; + ngx_array_t *a; + ngx_int_t n; + u_char *m, *s, *e; + ngx_str_t value; + + n = ndk_strcntc (path, ':') + 1; + + a = ngx_array_create (cf->pool, n, sizeof (ndk_http_complex_path_elt_t)); + if (a == NULL) { + return NULL; + } + + s = path->data; + e = s + path->len; + + + while (s < e) { + + m = s; + + while (m < e && *m != ':') m++; + + if (m == s) { + s = m+1; + continue; + } + + cpe = ngx_array_push (a); + if (cpe == NULL) { + return NULL; + } + + if (*s == '#') { + s++; + cpe->dynamic = 1; + } else { + cpe->dynamic = 0; + } + + value.data = s; + value.len = m - s; + + if (ndk_http_complex_path_value_compile (cf, &cpe->val, &value, prefix) == NGX_ERROR) + return NULL; + + s = m+1; + } + + return a; +} + + + + +char * +ndk_conf_set_http_complex_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *path; + ngx_conf_post_t *post; + ndk_http_complex_path_t *cp; + + cp = (ndk_http_complex_path_t *) (p + cmd->offset); + + if (cp->a != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + path = cf->args->elts; + path++; + + cp->a = ndk_http_complex_path_create_compile (cf, path, cp->prefix); + if (cp->a == NULL) { + /* TODO : log */ + return NGX_CONF_ERROR; + } + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, cp->a); + } + + return NGX_CONF_OK; +} + + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.h new file mode 100644 index 0000000..eb93d1f --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_path.h @@ -0,0 +1,30 @@ + + +typedef struct { + ngx_array_t *a; + ngx_uint_t prefix; +} ndk_http_complex_path_t; + +typedef struct { + ngx_http_complex_value_t val; + ngx_flag_t dynamic; +} ndk_http_complex_path_elt_t; + +typedef struct { + ngx_str_t val; + ngx_flag_t dynamic; +} ndk_http_complex_path_value_t; + +typedef struct { + ndk_http_complex_path_value_t *elts; + ngx_uint_t nelts; +} ndk_http_complex_path_values_t; + + +extern ndk_http_complex_path_value_t ndk_empty_http_complex_path_value; + + +ngx_array_t * ndk_http_complex_path_create_compile (ngx_conf_t *cf, ngx_str_t *path, ngx_uint_t prefix); +ngx_int_t ndk_http_complex_path_value_compile (ngx_conf_t *cf, ngx_http_complex_value_t *cv, + ngx_str_t *value, ngx_uint_t prefix); +char * ndk_conf_set_http_complex_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.c new file mode 100644 index 0000000..97681ff --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.c @@ -0,0 +1,192 @@ + + + +ngx_int_t +ndk_http_complex_value_compile (ngx_conf_t *cf, ngx_http_complex_value_t *cv, ngx_str_t *value) +{ + ngx_http_compile_complex_value_t ccv; + + ngx_memzero (&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = value; + ccv.complex_value = cv; + + return ngx_http_compile_complex_value (&ccv); +} + + + + +ngx_array_t * +ndk_http_complex_value_array_create (ngx_conf_t *cf, char **s, ngx_int_t n) +{ + ngx_int_t i; + ngx_http_complex_value_t *cv; + ngx_array_t *a; + ngx_str_t value; + + a = ngx_array_create (cf->pool, n, sizeof (ngx_http_complex_value_t)); + if (a == NULL) + return NULL; + + + for (i=0; ielts; + + for (i=0; inelts; i++, cv++) { + + if (ndk_http_complex_value_compile (cf, cv, &cv->value)) + return NGX_ERROR; + } + + return NGX_OK; +} + + + +char * +ndk_conf_set_http_complex_value_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_http_complex_value_t *cv; + ngx_str_t *value; + ngx_conf_post_t *post; + + cv = (ngx_http_complex_value_t *) (p + cmd->offset); + + if (cv->value.data) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ndk_http_complex_value_compile (cf, cv, value + 1)) + return NGX_CONF_ERROR; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, cv); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_http_complex_value_array_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_http_complex_value_t *cv; + ngx_array_t **a; + ngx_conf_post_t *post; + ngx_uint_t i, alloc; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a == NULL || *a == NGX_CONF_UNSET_PTR) { + + alloc = cf->args->nelts > 4 ? cf->args->nelts : 4; + + *a = ngx_array_create (cf->pool, alloc, sizeof (ngx_http_complex_value_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + + for (i=1; iargs->nelts; i++) { + + cv = ngx_array_push (*a); + if (cv == NULL) { + return NGX_CONF_ERROR; + } + + if (ndk_http_complex_value_compile (cf, cv, &value[i]) == NGX_ERROR) + return NGX_CONF_ERROR; + } + + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, a); + } + + return NGX_CONF_OK; +} + + +char * +ndk_conf_set_http_complex_keyval_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ndk_http_complex_keyval_t *ckv; + ngx_array_t **a; + ngx_conf_post_t *post; + ngx_int_t alloc; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a == NULL || *a == NGX_CONF_UNSET_PTR) { + + alloc = cf->args->nelts > 4 ? cf->args->nelts : 4; + + *a = ngx_array_create (cf->pool, alloc, sizeof (ndk_http_complex_keyval_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + ckv = ngx_array_push (*a); + if (ckv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ckv->key = value[1]; + + if (ndk_http_complex_value_compile (cf, &ckv->value, &value[2]) == NGX_ERROR) + return NGX_CONF_ERROR; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, a); + } + + return NGX_CONF_OK; +} + +/* TODO : complex keyval1 */ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.h new file mode 100644 index 0000000..4178d62 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_complex_value.h @@ -0,0 +1,21 @@ + + +typedef struct { + ngx_str_t key; + ngx_http_complex_value_t value; +} ndk_http_complex_keyval_t; + + + +/* create/compile functions */ + +ngx_int_t ndk_http_complex_value_compile (ngx_conf_t *cf, ngx_http_complex_value_t *cv, ngx_str_t *value); +ngx_array_t * ndk_http_complex_value_array_create (ngx_conf_t *cf, char **s, ngx_int_t n); +ngx_int_t ndk_http_complex_value_array_compile (ngx_conf_t *cf, ngx_array_t *a); + + +/* conf set slot functions */ + +char * ndk_conf_set_http_complex_keyval_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_http_complex_value_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_http_complex_value_array_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.c new file mode 100644 index 0000000..980641c --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.c @@ -0,0 +1,396 @@ + + +/* NOTE : you will find other conf_set functions in the following files : + * + * complex_value.c + * encoding.c + * path.c + * + */ + + +char * +ndk_conf_set_true_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_flag_t *fp; + ngx_conf_post_t *post; + + fp = (ngx_flag_t*) (p + cmd->offset); + + if (*fp != NGX_CONF_UNSET) { + return "is duplicate"; + } + + *fp = 1; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, fp); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_false_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_flag_t *fp; + ngx_conf_post_t *post; + + fp = (ngx_flag_t*) (p + cmd->offset); + + if (*fp != NGX_CONF_UNSET) { + return "is duplicate"; + } + + *fp = 0; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, fp); + } + + return NGX_CONF_OK; +} + + + + +char * +ndk_conf_set_ptr_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + void **ptr; + + ptr = (void**) (p + cmd->offset); + + if (*ptr != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *ptr = cmd->post; + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_null_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + void **pp; + ngx_conf_post_t *post; + + pp = (void **) (p + cmd->offset); + + if (*pp != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *pp = NULL; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, pp); + } + + return NGX_CONF_OK; +} + + +char * +ndk_conf_set_num64_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + int64_t *np; + ngx_str_t *value; + ngx_conf_post_t *post; + + + np = (int64_t *) (p + cmd->offset); + + if (*np != NGX_CONF_UNSET) { + return "is duplicate"; + } + + value = cf->args->elts; + *np = ndk_atoi64 (value[1].data, value[1].len); + if (*np == NGX_ERROR) { + return "invalid number"; + } + + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, np); + } + + return NGX_CONF_OK; +} + + +char * +ndk_conf_set_str_array_multi_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value, *s; + ngx_array_t **a; + ngx_conf_post_t *post; + ngx_uint_t i; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a == NGX_CONF_UNSET_PTR) { + *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + s = NULL; + + for (i=cf->args->nelts-1; i; i--) { + + s = ngx_array_push(*a); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + *s = value[i]; + } + + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, s); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_keyval1_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_keyval_t *kv; + ngx_conf_post_t *post; + + kv = (ngx_keyval_t *) (p + cmd->offset); + + if (kv->key.data) + return "is duplicate"; + + value = cf->args->elts; + + kv->key = value[1]; + kv->value = value[2]; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, kv); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_num_flag_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_int_t *np; + ngx_str_t *value; + ngx_conf_post_t *post; + + np = (ngx_int_t *) (p + cmd->offset); + + if (*np != NGX_CONF_UNSET) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcasecmp (value[1].data, (u_char *) "on") == 0) { + *np = NDK_CONF_SET_TRUE; + + } else if (ngx_strcasecmp (value[1].data, (u_char *) "off") == 0) { + *np = NDK_CONF_SET_FALSE; + + } else { + *np = ngx_atoi (value[1].data, value[1].len); + if (*np == NGX_ERROR) { + return "invalid number and not 'on'/'off'"; + } + } + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, np); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_sec_flag_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + time_t *tp; + ngx_str_t *value; + ngx_conf_post_t *post; + + tp = (time_t *) (p + cmd->offset); + + if (*tp != NGX_CONF_UNSET) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcasecmp (value[1].data, (u_char *) "on") == 0) { + *tp = NDK_CONF_SET_TRUE; + + } else if (ngx_strcasecmp (value[1].data, (u_char *) "off") == 0) { + *tp = NDK_CONF_SET_FALSE; + + } else { + *tp = ngx_parse_time (&value[1], 1); + if (*tp == NGX_ERROR) { + return "has an invalid time and not 'on'/'off'"; + } + } + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, tp); + } + + return NGX_CONF_OK; +} + + + +ngx_http_conf_ctx_t * +ndk_conf_create_http_location (ngx_conf_t *cf) +{ + ngx_http_conf_ctx_t *ctx, *pctx; + void *mconf; + ngx_http_core_loc_conf_t *clcf, *pclcf; + ngx_uint_t i; + ngx_http_module_t *module; + + ndk_pcallocp_rce (ctx, cf->pool); + + pctx = cf->ctx; + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ndk_pcalloc_rce (ctx->loc_conf, cf->pool, sizeof(void *) * ngx_http_max_module); + + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + continue; + } + + module = ngx_modules[i]->ctx; + + if (module->create_loc_conf) { + + mconf = module->create_loc_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; + } + } + + pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; + + clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; + clcf->loc_conf = ctx->loc_conf; + clcf->name = pclcf->name; + clcf->noname = 1; + + if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return ctx; +} + + +ngx_http_conf_ctx_t * +ngx_conf_create_http_named_location (ngx_conf_t *cf, ngx_str_t *name) +{ + ngx_http_conf_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + + ctx = ndk_conf_create_http_location (cf); + if (ctx == NGX_CONF_ERROR) + return NGX_CONF_ERROR; + + clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; + + /* in case the developer forgets to add '@' at the beginning of the named location */ + + if (name->data[0] != '@' && ndk_catstrf (cf->pool, name, "sS", "@", name) == NULL) + return NGX_CONF_ERROR; + + clcf->name = *name; /* TODO : copy? */ + clcf->noname = 0; + clcf->named = 1; + + return ctx; +} + + +ngx_int_t +ndk_replace_command (ngx_command_t *new_cmd, ngx_uint_t module_type) +{ + ngx_uint_t i; + ngx_command_t *cmd; + + for (i = 0; ngx_modules[i]; i++) { + + if (ngx_modules[i]->type != module_type) + continue; + + cmd = ngx_modules[i]->commands; + if (cmd == NULL) { + continue; + } + + for ( /* void */ ; cmd->name.len; cmd++) { + + if (ndk_cmpstr (&new_cmd->name, &cmd->name) == 0) { + + ndk_memcpyp (cmd, new_cmd); + return NGX_OK; + } + } + } + + return NGX_DECLINED; +} diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.h new file mode 100644 index 0000000..6956b17 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_conf_file.h @@ -0,0 +1,44 @@ + + +/* conf set functions */ + +char * ndk_conf_set_true_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_false_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_full_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_ptr_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_null_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_str_array_multi_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_keyval1_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_num_flag (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_num64_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_sec_flag_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +ngx_http_conf_ctx_t * ndk_conf_create_http_location (ngx_conf_t *cf); +ngx_http_conf_ctx_t * ngx_conf_create_http_named_location (ngx_conf_t *cf, ngx_str_t *name); + +ngx_int_t ndk_replace_command (ngx_command_t *new_cmd, ngx_uint_t module_type); + + +/* values for conf_set_xxx_flag */ + +#define NDK_CONF_SET_TRUE -2 +#define NDK_CONF_SET_FALSE -3 + + +/* wrappers for utility macros */ + +#define ndk_conf_set_bitmask_slot ngx_conf_set_bitmask_slot +#define ndk_conf_set_bufs_slot ngx_conf_set_bufs_slot +#define ndk_conf_set_enum_slot ngx_conf_set_enum_slot +#define ndk_conf_set_flag_slot ngx_conf_set_flag_slot +#define ndk_conf_set_keyval_slot ngx_conf_set_keyval_slot +#define ndk_conf_set_msec_slot ngx_conf_set_msec_slot +#define ndk_conf_set_num_slot ngx_conf_set_num_slot +#define ndk_conf_set_off_slot ngx_conf_set_off_slot +#define ndk_conf_set_sec_slot ngx_conf_set_sec_slot +#define ndk_conf_set_size_slot ngx_conf_set_size_slot +#define ndk_conf_set_str_slot ngx_conf_set_str_slot + + + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.c new file mode 100644 index 0000000..e0251cc --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.c @@ -0,0 +1,72 @@ + +#if (NGX_DEBUG) + +void +ndk_debug_helper (const char *func, const char *fmt, ...) +{ + size_t len, flen, tlen; + char *s, *p, *e; + + /* check to see if the format is empty */ + + flen = strlen (fmt); + + /* build func name */ + + len = strlen (func); + + if (flen == 0) + tlen = len + 1; + else + + char func_name [len + flen + 1]; + + s = func_name; + e = s + len; + + memcpy (s, func, len); + + /* remove initial ngx_ */ + + if (strncmp (s, "ngx_", 4) == 0) + s += 4; + + /* replace '_' with ' ' */ + + for (p=s; pmethod_name.len, r->method_name.data, + (int) r->uri.len, r->uri.data, + (int) r->args.len, r->args.data, + 0/*(int) r->main->count*/, r->main, + r, r->connection->data, r->parent); + + if (r->posted_requests) { + fprintf(stderr, " posted:"); + + for (pr = r->posted_requests; pr; pr = pr->next) { + fprintf (stderr, "%p,", pr); + } + } + + fprintf (stderr, "\n"); +} + + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.h new file mode 100644 index 0000000..883a6eb --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_debug.h @@ -0,0 +1,171 @@ +#ifndef NDK_DEBUG_H +#define NDK_DEBUG_H + + +/* TODO : use the Nginx printf function */ + + +#include +#include + +/* TODO +- andk_debug variety of debugging formats +- global include file for all debugging - can pass declaration to cflags for the option +*/ + + +#if (NDK_DEBUG) + + #if (NGX_HAVE_VARIADIC_MACROS) + + #define ndk_debug(...) ndk_debug_helper (__func__,__VA_ARGS__) + + #define ndk_debug_helper(func,...) \ + fprintf(stderr, "%-60s", func); \ + fprintf(stderr, (const char *)__VA_ARGS__); \ + fprintf(stderr,"\n"); + /*fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__)*/ + + #else + + /* NOTE : these includes might not be necessary since they're probably included with the core */ + + #include + #include + #include + + static void ndk_debug (const char * fmt, ...) { + } + + #endif + + #if NDK_DEBUG > 1 + + #define ndk_debug_request() ndk_debug_request_helper(r, __func__) + + static ngx_inline void + ndk_debug_request_helper (ngx_http_request_t *r, const char *func) + { + ngx_http_posted_request_t *pr; + + /* TODO : improve the format */ + + fprintf (stderr, "%s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", + func, + (int) r->method_name.len, r->method_name.data, + (int) r->uri.len, r->uri.data, + (int) r->args.len, r->args.data, + 0/*(int) r->main->count*/, r->main, + r, r->connection->data, r->parent); + + if (r->posted_requests) { + fprintf(stderr, " posted:"); + + for (pr = r->posted_requests; pr; pr = pr->next) { + fprintf (stderr, "%p,", pr); + } + } + + fprintf (stderr, "\n"); + } + + + #else + + #define ndk_debug_request() + + #endif + + + static ngx_inline void + ndk_debug_print_posted_requests (ngx_http_request_t *r) + { + ngx_http_posted_request_t *pr; + + ndk_request_log_debug_http (r, "ndk debug - http posted requests"); + + for (pr = r->main->posted_requests; pr; pr = pr->next) { + + if (!pr->request) + continue; + + ndk_request_log_debug_http (r, "ndk debug - http posted request:%V", &pr->request->uri); + } + } + + + #define ndk_debug_http_conf_location(cf) ndk_debug_http_conf_location_helper (cf, __func__) + + static ngx_inline void + ndk_debug_http_conf_location_helper (ngx_conf_t *cf, const char *func) + { + ngx_http_core_loc_conf_t *lcf; + + lcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_core_module); + + ndk_debug_helper (func, "[%s]", lcf->name.data); + } + + /* + static void + ndk_debug_log_chain (ngx_log_t *log, ngx_chain_t *cl) + { + + + } + */ + +#else + + #if (NGX_HAVE_VARIADIC_MACROS) + + #define ndk_debug(...) + #define ndk_debug_request() + + #else + + #include + + static void ndk_debug (const char * fmt, ...) { + } + + static void ndk_debug_request() { + } + + #endif + + #define ndk_debug_http_conf_location(cf) + +#endif + +#if (NDK_DEBUG) + + #define ndk_debug_check_read_event_handler(r) \ + \ + ndk_debug("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + + #define ndk_debug_check_write_event_handler(r) \ + \ + ndk_debug ("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + + #define ndk_debug_check_read_event_handler(r) + #define ndk_debug_check_write_event_handler(r) + +#endif + +#endif /* NDK_DEBUG_H */ + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.c new file mode 100644 index 0000000..4a07872 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.c @@ -0,0 +1,57 @@ + + + +char * +ndk_conf_set_encoding_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ndk_encoding_t *ep; + ngx_str_t *value; + size_t len; + iconv_t ic; + + ep = (ndk_encoding_t *) (p + cmd->offset); + if (ep->from && ep->to) + return "is duplicate"; + + value = cf->args->elts; + + + if (ep->from) { + + ep->to = (char *) value[1].data; + len = strlen (ep->from); + + } else if (ep->to) { + + ep->from = (char *) value[1].data; + len = strlen (ep->to); + + } else { + return "has no base encoding"; + } + + + if (len == value[1].len && !strncasecmp (ep->to, ep->from, len)) { + + ngx_log_error (NGX_LOG_WARN, cf->log, 0, + "\"%V\" '%V' encoding is ignored (no conversion)", &value[0], &value[1]); + + return NGX_CONF_OK; + } + + + ic = iconv_open (ep->to, ep->from); + if (ic == (iconv_t)-1) + return "has an invalid encoding"; + + + if (iconv_close (ic)) { + ngx_log_error (NGX_LOG_EMERG, cf->log, errno, "iconv_close()"); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.h new file mode 100644 index 0000000..b295b18 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_encoding.h @@ -0,0 +1,12 @@ + + +#include + +typedef struct { + char *from; + char *to; +} ndk_encoding_t; + + +char * ndk_conf_set_encoding_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.c new file mode 100644 index 0000000..dec3d41 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.c @@ -0,0 +1,82 @@ + +#include + + + +/* openssl hashes */ + +#define NDK_OPENSSL_HASH(type,ctxt_type,upper) \ + u_char md [ctxt_type ## _DIGEST_LENGTH]; \ + ctxt_type ##_CTX c; \ + \ + type ## _Init (&c); \ + type ## _Update (&c, data, len); \ + type ## _Final (md, &c); \ + \ + ndk_hex_dump (p, (u_char *) md, ctxt_type ## _DIGEST_LENGTH); \ + if (upper) { \ + ndk_strtoupper (p, (ctxt_type ## _DIGEST_LENGTH) *2); \ + } + + +#ifdef NDK_MD5 + +void +ndk_md5_hash (u_char *p, char *data, size_t len) +{ + NDK_OPENSSL_HASH (MD5, MD5, 0); +} + +void +ndk_md5_hash_upper (u_char *p, char *data, size_t len) +{ + NDK_OPENSSL_HASH (MD5, MD5, 1); +} + +#endif +#ifdef NDK_SHA1 + +void +ndk_sha1_hash (u_char *p, char *data, size_t len) +{ + NDK_OPENSSL_HASH (SHA1, SHA, 0); +} + +void +ndk_sha1_hash_upper (u_char *p, char *data, size_t len) +{ + NDK_OPENSSL_HASH (SHA1, SHA, 1); +} + +#endif + + + +/* non-openssl hashes */ + +#ifdef NDK_MURMUR2 + +#include "hash/murmurhash2.c" + +void +ndk_murmur2_hash (u_char *p, char *data, size_t len) +{ + uint32_t hash; + + hash = MurmurHash2 (data, len, 47); + + ndk_hex_dump (p, (u_char*) &hash, 4); +} + +void +ndk_murmur2_hash_upper (u_char *p, char *data, size_t len) +{ + uint32_t hash; + + hash = MurmurHash2 (data, len, 47); + + ndk_hex_dump (p, (u_char*) &hash, 4); + ndk_strtoupper (p, 8); +} + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.h new file mode 100644 index 0000000..a15e923 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_hash.h @@ -0,0 +1,45 @@ + +#ifndef NDK_HASH_H +#define NDK_HASH_H + +#ifdef NDK_HASH_ALL + +#ifndef NDK_MD5 +#define NDK_MD5 +#endif + +#ifndef NDK_MURMUR2 +#define NDK_MURMUR2 +#endif + +#ifndef NDK_SHA1 +#define NDK_SHA1 +#endif + +#endif + +#include +#include +typedef void (*ndk_hash_pt) (u_char *p, char *data, size_t len); + + +#ifdef NDK_MD5 +#include +void ndk_md5_hash (u_char *p, char *data, size_t len); +void ndk_md5_hash_upper (u_char *p, char *data, size_t len); +#endif + +#ifdef NDK_MURMUR2 +#define MURMURHASH2_DIGEST_LENGTH 4 +void ndk_murmur2_hash (u_char *p, char *data, size_t len); +void ndk_murmur2_hash_upper (u_char *p, char *data, size_t len); +#endif + +#ifdef NDK_SHA1 +#include +void ndk_sha1_hash (u_char *p, char *data, size_t len); +void ndk_sha1_hash_upper (u_char *p, char *data, size_t len); +#endif + +#endif /* NDK_HASH_H */ + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.c new file mode 100644 index 0000000..60728bb --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.c @@ -0,0 +1,138 @@ + +ngx_uint_t +ndk_http_count_phase_handlers (ngx_http_core_main_conf_t *cmcf) +{ + ngx_http_phase_handler_t *ph; + ngx_uint_t i; + + ph = cmcf->phase_engine.handlers; + + for (i=0; ph[i].checker; i++) /* void */; + + return i; +} + + +ngx_uint_t +ndk_http_parse_request_method (ngx_str_t *m) +{ + switch (m->len) { + + case 3: + +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) + { + u_char t[4]; + + ngx_memcpy (t, m->data, 3); + t[3] = ' '; + + if (ndk_str3_cmp (t, 'G', 'E', 'T', ' ')) { + return NGX_HTTP_GET; + } + + if (ndk_str3_cmp (t, 'P', 'U', 'T', ' ')) { + return NGX_HTTP_PUT; + } + } + +#else + + if (ndk_str3_cmp (m->data, 'G', 'E', 'T', ' ')) { + return NGX_HTTP_GET; + } + + if (ndk_str3_cmp (m->data, 'P', 'U', 'T', ' ')) { + return NGX_HTTP_PUT; + } + +#endif + break; + + case 4: + + if (m->data[1] == 'O') { + + if (ndk_str3Ocmp (m->data, 'P', 'O', 'S', 'T')) { + return NGX_HTTP_POST; + } + + if (ndk_str3Ocmp (m->data, 'C', 'O', 'P', 'Y')) { + return NGX_HTTP_COPY; + } + + if (ndk_str3Ocmp (m->data, 'M', 'O', 'V', 'E')) { + return NGX_HTTP_MOVE; + } + + if (ndk_str3Ocmp (m->data, 'L', 'O', 'C', 'K')) { + return NGX_HTTP_LOCK; + } + + } else { + + if (ndk_str4cmp (m->data, 'H', 'E', 'A', 'D')) { + return NGX_HTTP_HEAD; + } + } + + break; + + case 5: + + if (ndk_str5cmp (m->data, 'M', 'K', 'C', 'O', 'L')) { + return NGX_HTTP_MKCOL; + } + + if (ndk_str5cmp (m->data, 'P', 'A', 'T', 'C', 'H')) { + return NGX_HTTP_PATCH; + } + + if (ndk_str5cmp (m->data, 'T', 'R', 'A', 'C', 'E')) { + return NGX_HTTP_TRACE; + } + + break; + + case 6: + + if (ndk_str6cmp (m->data, 'D', 'E', 'L', 'E', 'T', 'E')) { + return NGX_HTTP_DELETE; + } + + if (ndk_str6cmp (m->data, 'U', 'N', 'L', 'O', 'C', 'K')) { + return NGX_HTTP_UNLOCK; + } + + break; + + case 7: + + if (ndk_str7_cmp (m->data, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' ')) + { + return NGX_HTTP_OPTIONS; + } + + break; + + case 8: + + if (ndk_str8cmp (m->data, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) + { + return NGX_HTTP_PROPFIND; + } + + break; + + case 9: + + if (ndk_str9cmp (m->data, 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) + { + return NGX_HTTP_PROPPATCH; + } + + break; + } + + return 0; +} \ No newline at end of file diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.h new file mode 100644 index 0000000..6a9d1c5 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http.h @@ -0,0 +1,3 @@ + +ngx_uint_t ndk_http_count_phase_handlers (ngx_http_core_main_conf_t *cmcf); +ngx_uint_t ndk_http_parse_request_method (ngx_str_t *m); diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http_headers.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http_headers.h new file mode 100644 index 0000000..e71c70e --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_http_headers.h @@ -0,0 +1,35 @@ + + +/* TODO : organize and add */ +/* TODO : check - should it be r->main? */ + +#define ndk_http_uri(r) (r)->uri +#define ndk_http_request_uri(r) (r)->unparsed_uri + +#define ndk_http_header_in(r,name) ((r)->headers_in.name ? &(r)->headers_in.name->value : NULL) +#define ndk_http_header_out(r,name) ((r)->headers_out.name ? &(r)->headers_out.name->value : NULL) + +#define ndk_http_host_header(r) ndk_http_header_in (r, host) +#define ndk_http_connection_header(r) ndk_http_header_in (r, connection) +#define ndk_http_if_modified_since_header(r) ndk_http_header_in (r, if_modified_since) +#define ndk_http_user_agent_header(r) ndk_http_header_in (r, user_agent) +#define ndk_http_referer_header(r) ndk_http_header_in (r, referer) +#define ndk_http_content_length_header(r) ndk_http_header_in (r, content_length) +#define ndk_http_content_type_header(r) ndk_http_header_in (r, content_type) +#define ndk_http_range_header(r) ndk_http_header_in (r, range) +#define ndk_http_if_range_header(r) ndk_http_header_in (r, if_range) +#define ndk_http_transfer_encoding_header(r) ndk_http_header_in (r, transfer_encoding) +#define ndk_http_expect_header(r) ndk_http_header_in (r, expect) +#define ndk_http_accept_encoding_header(r) ndk_http_header_in (r, accept_encoding) +#define ndk_http_via_header(r) ndk_http_header_in (r, via) +#define ndk_http_authorization_header(r) ndk_http_header_in (r, authorization) +#define ndk_http_keep_alive_header(r) ndk_http_header_in (r, keep_alive) +#define ndk_http_x_forwarded_for_header(r) ndk_http_header_in (r, x_forwarded_for) +#define ndk_http_x_real_ip_header(r) ndk_http_header_in (r, x_real_ip) +#define ndk_http_accept_header(r) ndk_http_header_in (r, accept) +#define ndk_http_accept_language_header(r) ndk_http_header_in (r, accept_language) +#define ndk_http_depth_header(r) ndk_http_header_in (r, depth) +#define ndk_http_destination_header(r) ndk_http_header_in (r, destination) +#define ndk_http_overwrite_header(r) ndk_http_header_in (r, overwrite) +#define ndk_http_date_header(r) ndk_http_header_in (r, date) + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.c new file mode 100644 index 0000000..36dca15 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.c @@ -0,0 +1,3 @@ + + +/* TODO : the required functions if the compiler does not have variadic macros */ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.h new file mode 100644 index 0000000..1dd9c22 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_log.h @@ -0,0 +1,165 @@ + +/* TODO : fix the conf_log macros */ + +#define NGX_LOG_DEBUG_SCRIPT NGX_LOG_DEBUG_HTTP /* TODO : add new section to log/conf directives */ + +#define ndk_conf_to_log(cf) ((cf)->log) + +#ifndef ndk_request_to_log +#define ndk_request_to_log(r) ((r)->connection->log) +#endif + + +/*********************************/ + +#if (NGX_HAVE_C99_VARIADIC_MACROS) + +#define ndk_log_stderr(log,...) ngx_log_error (NGX_LOG_STDERR, log, 0, __VA_ARGS__) +#define ndk_log_emerg(log,...) ngx_log_error (NGX_LOG_EMERG, log, 0, __VA_ARGS__) +#define ndk_log_alert(log,...) ngx_log_error (NGX_LOG_ALERT, log, 0, __VA_ARGS__) +#define ndk_log_crit(log,...) ngx_log_error (NGX_LOG_CRIT, log, 0, __VA_ARGS__) +#define ndk_log_err(log,...) ngx_log_error (NGX_LOG_ERR, log, 0, __VA_ARGS__) +#define ndk_log_warning(log,...) ngx_log_error (NGX_LOG_WARN, log, 0, __VA_ARGS__) +#define ndk_log_notice(log,...) ngx_log_error (NGX_LOG_NOTICE, log, 0, __VA_ARGS__) +#define ndk_log_info(log,...) ngx_log_error (NGX_LOG_INFO, log, 0, __VA_ARGS__) + +#define ndk_conf_log_stderr(cf,...) ngx_conf_log_error (NGX_LOG_STDERR, cf, 0, __VA_ARGS__) +#define ndk_conf_log_emerg(cf,...) ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, __VA_ARGS__) +#define ndk_conf_log_alert(cf,...) ngx_conf_log_error (NGX_LOG_ALERT, cf, 0, __VA_ARGS__) +#define ndk_conf_log_crit(cf,...) ngx_conf_log_error (NGX_LOG_CRIT, cf, 0, __VA_ARGS__) +#define ndk_conf_log_err(cf,...) ngx_conf_log_error (NGX_LOG_ERR, cf, 0, __VA_ARGS__) +#define ndk_conf_log_warning(cf,...) ngx_conf_log_error (NGX_LOG_WARN, cf, 0, __VA_ARGS__) +#define ndk_conf_log_notice(cf,...) ngx_conf_log_error (NGX_LOG_NOTICE, cf, 0, __VA_ARGS__) +#define ndk_conf_log_info(cf,...) ngx_conf_log_error (NGX_LOG_INFO, cf, 0, __VA_ARGS__) + +#define ndk_request_log_stderr(r,...) ndk_log_stderr (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_emerg(r,...) ndk_log_emerg (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_alert(r,...) ndk_log_alert (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_crit(r,...) ndk_log_crit (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_err(r,...) ndk_log_err (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_warning(r,...) ndk_log_warning (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_notice(r,...) ndk_log_notice (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_info(r,...) ndk_log_info (ndk_request_to_log(r), __VA_ARGS__) + + +#if (NGX_DEBUG) + +#define ndk_log_debug_core(log,...) ngx_log_debug (NGX_LOG_DEBUG_CORE, log, 0, __VA_ARGS__) +#define ndk_log_debug_alloc(log,...) ngx_log_debug (NGX_LOG_DEBUG_ALLOC, log, 0, __VA_ARGS__) +#define ndk_log_debug_mutex(log,...) ngx_log_debug (NGX_LOG_DEBUG_MUTEX, log, 0, __VA_ARGS__) +#define ndk_log_debug_event(log,...) ngx_log_debug (NGX_LOG_DEBUG_EVENT, log, 0, __VA_ARGS__) +#define ndk_log_debug_http(log,...) ngx_log_debug (NGX_LOG_DEBUG_HTTP, log, 0, __VA_ARGS__) +#define ndk_log_debug_mail(log,...) ngx_log_debug (NGX_LOG_DEBUG_MAIL, log, 0, __VA_ARGS__) +#define ndk_log_debug_mysql(log,...) ngx_log_debug (NGX_LOG_DEBUG_MYSQL, log, 0, __VA_ARGS__) + +#define ndk_conf_log_debug_core(r,...) ndk_log_debug_core (ndk_conf_to_log(r), __VA_ARGS__) +#define ndk_conf_log_debug_alloc(r,...) ndk_log_debug_alloc (ndk_conf_to_log(r), __VA_ARGS__) +#define ndk_conf_log_debug_mutex(r,...) ndk_log_debug_mutex (ndk_conf_to_log(r), __VA_ARGS__) +#define ndk_conf_log_debug_event(r,...) ndk_log_debug_event (ndk_conf_to_log(r), __VA_ARGS__) +#define ndk_conf_log_debug_http(r,...) ndk_log_debug_http (ndk_conf_to_log(r), __VA_ARGS__) +#define ndk_conf_log_debug_mail(r,...) ndk_log_debug_mail (ndk_conf_to_log(r), __VA_ARGS__) +#define ndk_conf_log_debug_mysql(r,...) ndk_log_debug_mysql (ndk_conf_to_log(r), __VA_ARGS__) + +#define ndk_request_log_debug_core(r,...) ndk_log_debug_core (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_debug_alloc(r,...) ndk_log_debug_alloc (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_debug_mutex(r,...) ndk_log_debug_mutex (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_debug_event(r,...) ndk_log_debug_event (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_debug_http(r,...) ndk_log_debug_http (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_debug_mail(r,...) ndk_log_debug_mail (ndk_request_to_log(r), __VA_ARGS__) +#define ndk_request_log_debug_mysql(r,...) ndk_log_debug_mysql (ndk_request_to_log(r), __VA_ARGS__) + +#else + +#define ndk_log_debug_core(log,...) +#define ndk_log_debug_alloc(log,...) +#define ndk_log_debug_mutex(log,...) +#define ndk_log_debug_event(log,...) +#define ndk_log_debug_http(log,...) +#define ndk_log_debug_mail(log,...) +#define ndk_log_debug_mysql(log,...) + +#define ndk_conf_log_debug_core(r,...) +#define ndk_conf_log_debug_alloc(r,...) +#define ndk_conf_log_debug_mutex(r,...) +#define ndk_conf_log_debug_event(r,...) +#define ndk_conf_log_debug_http(r,...) +#define ndk_conf_log_debug_mail(r,...) +#define ndk_conf_log_debug_mysql(r,...) + +#define ndk_request_log_debug_core(r,...) +#define ndk_request_log_debug_alloc(r,...) +#define ndk_request_log_debug_mutex(r,...) +#define ndk_request_log_debug_event(r,...) +#define ndk_request_log_debug_http(r,...) +#define ndk_request_log_debug_mail(r,...) +#define ndk_request_log_debug_mysql(r,...) + +#endif + + +/*********************************/ + +#elif (NGX_HAVE_GCC_VARIADIC_MACROS) + +#define ndk_log_stderr(log,args...) ngx_log_error (NGX_LOG_STDERR, log, 0, args) +#define ndk_log_emerg(log,args...) ngx_log_error (NGX_LOG_EMERG, log, 0, args) +#define ndk_log_alert(log,args...) ngx_log_error (NGX_LOG_ALERT, log, 0, args) +#define ndk_log_crit(log,args...) ngx_log_error (NGX_LOG_CRIT, log, 0, args) +#define ndk_log_err(log,args...) ngx_log_error (NGX_LOG_ERR, log, 0, args) +#define ndk_log_warning(log,args...) ngx_log_error (NGX_LOG_WARN, log, 0, args) +#define ndk_log_notice(log,args...) ngx_log_error (NGX_LOG_NOTICE, log, 0, args) +#define ndk_log_info(log,args...) ngx_log_error (NGX_LOG_INFO, log, 0, args) + +#define ndk_log_debug_core(log,args...) ngx_log_debug (NGX_LOG_DEBUG_CORE, log, 0, args) +#define ndk_log_debug_alloc(log,args...) ngx_log_debug (NGX_LOG_DEBUG_ALLOC, log, 0, args) +#define ndk_log_debug_mutex(log,args...) ngx_log_debug (NGX_LOG_DEBUG_MUTEX, log, 0, args) +#define ndk_log_debug_event(log,args...) ngx_log_debug (NGX_LOG_DEBUG_EVENT, log, 0, args) +#define ndk_log_debug_http(log,args...) ngx_log_debug (NGX_LOG_DEBUG_HTTP, log, 0, args) +#define ndk_log_debug_mail(log,args...) ngx_log_debug (NGX_LOG_DEBUG_MAIL, log, 0, args) +#define ndk_log_debug_mysql(log,args...) ngx_log_debug (NGX_LOG_DEBUG_MYSQL, log, 0, args) +#define ndk_log_debug_script(log,args...) ngx_log_debug (NGX_LOG_DEBUG_SCRIPT, log, 0, args) + +#define ndk_conf_log_stderr(cf,args...) ngx_conf_log_error (NGX_LOG_STDERR, cf, 0, args) +#define ndk_conf_log_emerg(cf,args...) ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, args) +#define ndk_conf_log_alert(cf,args...) ngx_conf_log_error (NGX_LOG_ALERT, cf, 0, args) +#define ndk_conf_log_crit(cf,args...) ngx_conf_log_error (NGX_LOG_CRIT, cf, 0, args) +#define ndk_conf_log_err(cf,args...) ngx_conf_log_error (NGX_LOG_ERR, cf, 0, args) +#define ndk_conf_log_warning(cf,args...) ngx_conf_log_error (NGX_LOG_WARN, cf, 0, args) +#define ndk_conf_log_notice(cf,args...) ngx_conf_log_error (NGX_LOG_NOTICE, cf, 0, args) +#define ndk_conf_log_info(cf,args...) ngx_conf_log_error (NGX_LOG_INFO, cf, 0, args) + +#define ndk_conf_log_debug_core(r,args...) ndk_log_debug_core (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_alloc(r,args...) ndk_log_debug_alloc (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_mutex(r,args...) ndk_log_debug_mutex (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_event(r,args...) ndk_log_debug_event (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_http(r,args...) ndk_log_debug_http (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_mail(r,args...) ndk_log_debug_mail (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_mysql(r,args...) ndk_log_debug_mysql (ndk_conf_to_log(r), args) +#define ndk_conf_log_debug_script(r,args...) ndk_log_debug_script (ndk_conf_to_log(r), args) + +#define ndk_request_log_stderr(r,args...) ndk_log_stderr (ndk_request_to_log(r), args) +#define ndk_request_log_emerg(r,args...) ndk_log_emerg (ndk_request_to_log(r), args) +#define ndk_request_log_alert(r,args...) ndk_log_alert (ndk_request_to_log(r), args) +#define ndk_request_log_crit(r,args...) ndk_log_crit (ndk_request_to_log(r), args) +#define ndk_request_log_err(r,args...) ndk_log_err (ndk_request_to_log(r), args) +#define ndk_request_log_warning(r,args...) ndk_log_warning (ndk_request_to_log(r), args) +#define ndk_request_log_notice(r,args...) ndk_log_notice (ndk_request_to_log(r), args) +#define ndk_request_log_info(r,args...) ndk_log_info (ndk_request_to_log(r), args) + +#define ndk_request_log_debug_core(r,args...) ndk_log_debug_core (ndk_request_to_log(r), args) +#define ndk_request_log_debug_alloc(r,args...) ndk_log_debug_alloc (ndk_request_to_log(r), args) +#define ndk_request_log_debug_mutex(r,args...) ndk_log_debug_mutex (ndk_request_to_log(r), args) +#define ndk_request_log_debug_event(r,args...) ndk_log_debug_event (ndk_request_to_log(r), args) +#define ndk_request_log_debug_http(r,args...) ndk_log_debug_http (ndk_request_to_log(r), args) +#define ndk_request_log_debug_mail(r,args...) ndk_log_debug_mail (ndk_request_to_log(r), args) +#define ndk_request_log_debug_mysql(r,args...) ndk_log_debug_mysql (ndk_request_to_log(r), args) +#define ndk_request_log_debug_script(r,args...) ndk_log_debug_script (ndk_request_to_log(r), args) + +/*********************************/ + +#else /* NO VARIADIC MACROS */ + +/* #warning does not work on Windows */ +#pragma message("Nginx Devel Kit logging without variadic macros not yet implemented") + +#endif /* VARIADIC MACROS */ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_parse.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_parse.h new file mode 100644 index 0000000..7c43e14 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_parse.h @@ -0,0 +1,67 @@ + + + +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) + +#define ndk_str3_cmp(m, c0, c1, c2, c3) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) + +#define ndk_str3Ocmp(m, c0, c1, c2, c3) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) + +#define ndk_str4cmp(m, c0, c1, c2, c3) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) + +#define ndk_str5cmp(m, c0, c1, c2, c3, c4) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ + && m[4] == c4 + +#define ndk_str6cmp(m, c0, c1, c2, c3, c4, c5) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ + && (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4) + +#define ndk_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ + && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) + +#define ndk_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ + && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) + +#define ndk_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ + *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ + && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \ + && m[8] == c8 + +#else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */ + +#define ndk_str3_cmp(m, c0, c1, c2, c3) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 + +#define ndk_str3Ocmp(m, c0, c1, c2, c3) \ + m[0] == c0 && m[2] == c2 && m[3] == c3 + +#define ndk_str4cmp(m, c0, c1, c2, c3) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 + +#define ndk_str5cmp(m, c0, c1, c2, c3, c4) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4 + +#define ndk_str6cmp(m, c0, c1, c2, c3, c4, c5) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 + +#define ndk_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 && m[6] == c6 + +#define ndk_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 + +#define ndk_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8 + +#endif + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.c new file mode 100644 index 0000000..0b7c266 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.c @@ -0,0 +1,583 @@ + + + +/* This function cleans a path to its most basic form, performing the following transformations : + * + * - ./ -> [empty] + * - // -> / + * - /base/parent/../ -> /base/ + * + * If possible, it leaves the original string in place and does not copy characters, otherwise + * characters are copied. +*/ + +void +ndk_clean_path (ngx_str_t *path, ngx_uint_t complex, size_t off) +{ + u_char *s, *p, *m, *e, c, *l; + ngx_uint_t root; + + if (path->len == 1) { + + if (path->data[0] == '.') { + path->len = 0; + } + + return; + } + + /* strip initial './' */ + + s = path->data; + e = s + path->len; + + if (off) { + p = s + off; + goto check_basic; + } + + if (*s == '/') + root = 1; + else + root = 0; + + while (s < e) { + + switch (*s) { + + case '/' : + + /* '//' => '/' */ + + s++; + continue; + + case '.' : + + if (s == e-1) { + + if (root) { + path->data[0] = '/'; + path->len = 1; + } else { + path->len = 0; + } + + return; + } + + /* './' => '' */ + + if (s[1] == '/') { + + s += 2; + + if (s == e) { + + path->len = 0; + return; + } + + continue; + } + } + + break; + } + + if (root && *s != '/') { + s--; + } + + p = s; + +check_basic : + + for ( ; p '/' */ + + m = p + 2; + goto copy; + + case '.' : + + if (e - p == 2) + break; + + switch (p[2]) { + + case '/' : + + /* './' => '' */ + + m = p + 2; + goto copy; + + case '.' : + + if (e - p == 3 || p[3] == '/') { + + if (p == s) { + + s += 3; + continue; + } + + if (p - s >= 2) { + + if (p[-1] == '.' && p[-2] == '.') { + + if (p - s == 2 || p[-3] == '/') { /* = '../../' */ + + p += 2; /* 3? */ + continue; + } + } + } + + m = p + 4; + + if (complex) { + + for (p--; p >= s; p--) { + + switch (*p) { + + case '/' : + goto copy; + + case '$' : + + p = m - 1; + + if (m == e) + goto end_basic; + + goto new_dir_first; + } + } + + } else { + + for (p--; p > s; p--) { + + /* '/path/folder/../' => '/path/' */ + + if (*p == '/') + break; + } + } + + goto copy; + } + } + } + } + } + +end_basic : + + path->data = s; + path->len = p - s; + + return; + +copy : + + p++; + + if (m < e) + goto new_dir; + + while (m < e) { + + c = *m; + *p = c; + p++; + + if (c == '/') { + + m++; + + new_dir : + + for ( ; m '' */ + + m += 2; + if (m == e) + break; + + goto new_dir; + + case '.' : + + if (e - m == 2 || m[2] == '/') { + + if (m - s >= 3) { /* NOTE : this is one higher than above because m has moved on 1 */ + + if (p[-2] == '.' && p[-3] == '.') { + + if (m - s == 3 || p[-4] == '/') { /* = '../../' */ + + p[0] = '.'; + p[1] = '.'; + p[2] = '/'; + p += 3; + m += 3; + goto new_dir; + } + } + } + + if (complex) { + + l = p; + + for (p -= 2; p >= s; p--) { + + switch (*p) { + + case '/' : + break; + + case '$' : + + l[0] = '.'; + l[1] = '.'; + l[2] = '/'; + p = l + 4; + break; + + default : + continue; + } + + break; + } + + m += 3; + if (m == e) + goto end; + + goto new_dir; + + } else { + + for (p -= 2; p > s; p--) { + + /* '/path/folder/../' => '/path/' */ + + if (*p == '/') + break; + } + + m += 3; + if (m == e) + goto end; + + goto new_dir; + } + } + } + } + + } else { + m++; + } + } + +end : + + path->data = s; + path->len = p - s; +} + + +/* This function converts a path to its directory version, and assumes that there is always space + * to allocatate an extra character on the end (which is only true if the provided strings always + * have NULL's at the end (hence the 'safe'). +*/ + +void +ndk_path_to_dir_safe (ngx_str_t *path, ngx_uint_t complex, size_t off) +{ + size_t len; + u_char *p, *m; + + ndk_clean_path (path, complex, off); + + len = path->len; + if (!len) + return; + + p = path->data; + m = p + len - 1; + + if (*m != '/') { + + p [len] = '/'; + path->len++; + } +} + + +/* Divides a path given by path/to/path1:path/to/path2 into separate strings and returns an + * array of these strings. +*/ + +ngx_array_t * +ndk_split_path_create (ngx_conf_t *cf, ngx_str_t *path) +{ + ngx_str_t *str; + int n; + u_char *m, *s, *e; + ngx_array_t *a; + + if (path == NULL) + return NULL; + + n = ndk_strcntc (path, ':'); + + a = ngx_array_create (cf->pool, n + 1, sizeof (ngx_str_t)); + if (a == NULL) { + return NULL; + } + + s = path->data; + e = s + path->len; + + while (s < e) { + + m = s; + + while (m < e && *m != ':') m++; + + if (m == s) { + s = m+1; + continue; + } + + str = ngx_array_push (a); + if (str == NULL) { + return NULL; + } + + str->data = s; + str->len = m - s; + + if (ngx_conf_full_name (cf->cycle, str, 0) == NGX_ERROR) + return NULL; + + s = m+1; + } + + return a; +} + + + +ngx_array_t * +ndk_split_path_create_raw (ngx_conf_t *cf, char *path) +{ + ngx_str_t *str; + int n; + char *m, *s; + ngx_array_t *a; + + if (path == NULL) + return NULL; + + n = ndk_strccnt (path, ':'); + + a = ngx_array_create (cf->pool, n + 1, sizeof (ngx_str_t)); + if (a == NULL) { + return NULL; + } + + s = path; + + + while (*s != '\0') { + + m = s; + + while (*m != '\0' && *m != ':') m++; + + if (m == s) { + s = m+1; + continue; + } + + str = ngx_array_push (a); + if (str == NULL) { + return NULL; + } + + str->data = (u_char *) s; + str->len = m - s; + + if (ngx_conf_full_name (cf->cycle, str, 0) == NGX_ERROR) + return NULL; + + if (*m == '\0') + break; + + s = m+1; + } + + return a; +} + + + +char * +ndk_conf_set_full_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *path, *value; + ngx_conf_post_t *post; + + path = (ngx_str_t *) (p + cmd->offset); + + if (path->data) { + return "is duplicate"; + } + + value = cf->args->elts; + + *path = value[1]; + + if (ngx_conf_full_name (cf->cycle, path, 0) == NGX_ERROR) + return NGX_CONF_ERROR; + + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, path); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_split_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + /* TODO : change to use the path func above */ + + char *p = conf; + + ngx_str_t *value, *str; + ngx_array_t **a; + ngx_conf_post_t *post; + int n; + u_char *m, *s, *e; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + value++; + + n = ndk_strcntc (value, ':') + 1; + + *a = ngx_array_create (cf->pool, n, sizeof (ngx_str_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + + s = value->data; + e = s + value->len; + + while (s < e) { + + m = s; + + while (m < e && *m != ':') m++; + + if (m == s) { + s = m+1; + continue; + } + + str = ngx_array_push (*a); + if (str == NULL) { + return NGX_CONF_ERROR; + } + + str->data = s; + str->len = m - s; + + if (ngx_conf_full_name (cf->cycle, str, 0) == NGX_ERROR) + return NGX_CONF_ERROR; + + s = m+1; + } + + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, a); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_full_path (ngx_conf_t *cf, void *data, ngx_str_t *path) +{ + if (ngx_conf_full_name (cf->cycle, path, 0) == NGX_ERROR) + return NGX_CONF_ERROR; + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_full_conf_path (ngx_conf_t *cf, void *data, ngx_str_t *path) +{ + if (ngx_conf_full_name (cf->cycle, path, 1) == NGX_ERROR) + return NGX_CONF_ERROR; + + return NGX_CONF_OK; +} + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.h new file mode 100644 index 0000000..22ba945 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_path.h @@ -0,0 +1,22 @@ + + +/* path conversion functions */ + +void ndk_clean_path (ngx_str_t *path, ngx_uint_t complex, size_t off); +void ndk_path_to_dir_safe (ngx_str_t *path, ngx_uint_t complex, size_t off); + +/* path create functions */ + +ngx_array_t * ndk_split_path_create (ngx_conf_t *cf, ngx_str_t *path); +ngx_array_t * ndk_split_path_create_raw (ngx_conf_t *cf, char *path); + +/* conf set functions */ + +char * ndk_conf_set_full_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_split_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +/* conf set post functions */ + +char * ndk_conf_set_full_path (ngx_conf_t *cf, void *data, ngx_str_t *path); +char * ndk_conf_set_full_conf_path (ngx_conf_t *cf, void *data, ngx_str_t *path); + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.c new file mode 100644 index 0000000..fbc789c --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.c @@ -0,0 +1,20 @@ + +ngx_int_t +ndk_init_signals (ngx_signal_t *sig, ngx_log_t *log) +{ + struct sigaction sa; + + for ( ; sig->signo != 0; sig++) { + ndk_zerov (sa); + sa.sa_handler = sig->handler; + sigemptyset (&sa.sa_mask); + + if (sigaction (sig->signo, &sa, NULL) == -1) { + ngx_log_error (NGX_LOG_EMERG, log, ngx_errno, + "sigaction(%s) failed", sig->signame); + return NGX_ERROR; + } + } + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.h new file mode 100644 index 0000000..7ac1d99 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_process.h @@ -0,0 +1,12 @@ + + +typedef struct { + int signo; + char *signame; + char *name; + void (*handler)(int signo); +} ngx_signal_t; + + +ngx_int_t ndk_init_signals (ngx_signal_t *sig, ngx_log_t *log); + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.c new file mode 100644 index 0000000..c1efd86 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.c @@ -0,0 +1,215 @@ + + +char * +ndk_conf_set_regex_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_conf_post_t *post; + ngx_regex_elt_t *re; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + re = (ngx_regex_elt_t *) (p + cmd->offset); + + if (re->name) { + return "is duplicate"; + } + + value = cf->args->elts; + value++; + + ndk_zerov (rc); + + rc.pool = cf->pool; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + rc.pattern = *value; + + if (ngx_regex_compile(&rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); + return NGX_CONF_ERROR; + } + + re->regex = rc.regex; + re->name = value->data; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, re); + } + + return NGX_CONF_OK; +} + + +char * +ndk_conf_set_regex_caseless_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_conf_post_t *post; + ngx_regex_elt_t *re; + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + re = (ngx_regex_elt_t *) (p + cmd->offset); + + if (re->name) { + return "is duplicate"; + } + + value = cf->args->elts; + value++; + + ndk_zerov (rc); + + rc.pool = cf->pool; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + rc.pattern = *value; + rc.options = NGX_REGEX_CASELESS; + + if (ngx_regex_compile(&rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); + return NGX_CONF_ERROR; + } + + re->regex = rc.regex; + re->name = value->data; + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, re); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_regex_array_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_conf_post_t *post; + ngx_array_t **a; + ngx_regex_elt_t *re; + ngx_regex_compile_t rc; + ngx_uint_t i, n = 0; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a != NGX_CONF_UNSET_PTR) { + + n = cf->args->nelts > 4 ? cf->args->nelts : 4; + + *a = ngx_array_create (cf->pool, n, sizeof (ngx_regex_elt_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + ndk_zerov (rc); + + rc.pool = cf->pool; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + value = cf->args->elts; + value++; + + for (i=0; iregex = rc.regex; + re->name = value->data; + } + + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, a); + } + + return NGX_CONF_OK; +} + + + +char * +ndk_conf_set_regex_array_caseless_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_conf_post_t *post; + ngx_array_t **a; + ngx_regex_elt_t *re; + ngx_regex_compile_t rc; + ngx_uint_t i, n = 0; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a != NGX_CONF_UNSET_PTR) { + + n = cf->args->nelts > 4 ? cf->args->nelts : 4; + + *a = ngx_array_create (cf->pool, n, sizeof (ngx_regex_elt_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + ndk_zerov (rc); + + rc.pool = cf->pool; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + value = cf->args->elts; + value++; + + for (i=0; iregex = rc.regex; + re->name = value->data; + } + + + if (cmd->post) { + post = cmd->post; + return post->post_handler (cf, post, a); + } + + return NGX_CONF_OK; +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.h new file mode 100644 index 0000000..4319b04 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_regex.h @@ -0,0 +1,7 @@ + + +char * ndk_conf_set_regex_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_regex_caseless_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_regex_array_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_conf_set_regex_array_caseless_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.c new file mode 100644 index 0000000..77ce9f8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.c @@ -0,0 +1,103 @@ + + +/* these have been taken from the rewrite module and http_script file + * because those functions are defined as being static - a patch will + * be provided later to un-define them as being static + */ + + +uintptr_t ndk_http_script_exit_code = (uintptr_t) NULL; + + +char * +ndk_http_rewrite_value (ngx_conf_t *cf, ndk_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) +{ + ngx_int_t n; + ngx_http_script_compile_t sc; + ngx_http_script_value_code_t *val; + ngx_http_script_complex_value_code_t *complex; + + n = ngx_http_script_variables_count(value); + + if (n == 0) { + val = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_value_code_t)); + if (val == NULL) { + return NGX_CONF_ERROR; + } + + n = ngx_atoi(value->data, value->len); + + if (n == NGX_ERROR) { + n = 0; + } + + val->code = ngx_http_script_value_code; + val->value = (uintptr_t) n; + val->text_len = (uintptr_t) value->len; + val->text_data = (uintptr_t) value->data; + + return NGX_CONF_OK; + } + + complex = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_complex_value_code_t)); + if (complex == NULL) { + return NGX_CONF_ERROR; + } + + complex->code = ngx_http_script_complex_value_code; + complex->lengths = NULL; + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = value; + sc.lengths = &complex->lengths; + sc.values = &lcf->codes; + sc.variables = n; + sc.complete_lengths = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +ngx_int_t +ndk_http_rewrite_var (ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_http_variable_t *var; + ngx_http_core_main_conf_t *cmcf; + ndk_http_rewrite_loc_conf_t *rlcf; + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module); + + if (rlcf->uninitialized_variable_warn == 0) { + *v = ngx_http_variable_null_value; + return NGX_OK; + } + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + var = cmcf->variables.elts; + + /* + * the ngx_http_rewrite_module sets variables directly in r->variables, + * and they should be handled by ngx_http_get_indexed_variable(), + * so the handler is called only if the variable is not initialized + */ + + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "using uninitialized \"%V\" variable", &var[data].name); + + *v = ngx_http_variable_null_value; + + return NGX_OK; +} + + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.h new file mode 100644 index 0000000..2479aa2 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_rewrite.h @@ -0,0 +1,26 @@ + + +/* TODO : should remove this when not needed */ + + + +/* used for plugging into the rewrite module (taken from the rewrite module) */ + +typedef struct { + ngx_array_t *codes; /* uintptr_t */ + ngx_uint_t stack_size; + ngx_flag_t log; + ngx_flag_t uninitialized_variable_warn; +} ndk_http_rewrite_loc_conf_t; + + +extern ngx_module_t ngx_http_rewrite_module; +extern uintptr_t ndk_http_script_exit_code; + +char * ndk_http_rewrite_value (ngx_conf_t *cf, ndk_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value); +ngx_int_t ndk_http_rewrite_var (ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +#define ndk_http_script_exit (u_char *) &ndk_http_script_exit_code + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.c new file mode 100644 index 0000000..388f873 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.c @@ -0,0 +1,602 @@ +#include + + +typedef struct { + ngx_http_script_code_pt code; + void *func; +} ndk_set_var_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + void *func; + size_t size; +} ndk_set_var_size_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + void *func; + void *data; +} ndk_set_var_data_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + void *func; + size_t size; + void *data; +} ndk_set_var_size_data_code_t; + + +typedef struct { + ngx_int_t index; + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_conf_t *cf; + ndk_http_rewrite_loc_conf_t *rlcf; +} ndk_set_var_info_t; + + +static void ndk_set_var_code (ngx_http_script_engine_t *e); +static void ndk_set_var_hash_code (ngx_http_script_engine_t *e); +static void ndk_set_var_value_code (ngx_http_script_engine_t *e); + + +static ngx_inline void +ndk_set_var_code_finalize(ngx_http_script_engine_t *e, ngx_int_t rc, + ngx_http_variable_value_t *v, ngx_str_t *str) +{ + switch (rc) { + + case NGX_OK: + + v->data = str->data; + v->len = str->len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script value (post filter): \"%v\"", v); + break; + + case NGX_DECLINED: + + v->valid = 0; + v->not_found = 1; + v->no_cacheable = 1; + break; + + case NGX_ERROR: + + e->ip = ndk_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + break; + } +} + + + +static void +ndk_set_var_code(ngx_http_script_engine_t *e) +{ + ngx_int_t rc; + ngx_str_t str; + ngx_http_variable_value_t *v; + ndk_set_var_code_t *sv; + ndk_set_var_pt func; + + sv = (ndk_set_var_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_code_t); + + v = e->sp++; + + func = (ndk_set_var_pt) sv->func; + + rc = func(e->request, &str); + + ndk_set_var_code_finalize(e, rc, v, &str); +} + + +static void +ndk_set_var_data_code(ngx_http_script_engine_t *e) +{ + ngx_int_t rc; + ngx_str_t str; + ngx_http_variable_value_t *v; + ndk_set_var_data_code_t *svd; + ndk_set_var_data_pt func; + + svd = (ndk_set_var_data_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_data_code_t); + + v = e->sp++; + + func = (ndk_set_var_data_pt) svd->func; + + rc = func(e->request, &str, svd->data); + + ndk_set_var_code_finalize(e, rc, v, &str); +} + + +static void +ndk_set_var_value_code(ngx_http_script_engine_t *e) +{ + ngx_int_t rc; + ngx_str_t str; + ngx_http_variable_value_t *v; + ndk_set_var_code_t *sv; + ndk_set_var_value_pt func; + + sv = (ndk_set_var_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_code_t); + + v = e->sp - 1; + + func = (ndk_set_var_value_pt) sv->func; + + rc = func(e->request, &str, v); + + ndk_set_var_code_finalize(e, rc, v, &str); +} + + +static void +ndk_set_var_value_data_code(ngx_http_script_engine_t *e) +{ + ngx_int_t rc; + ngx_str_t str; + ngx_http_variable_value_t *v; + ndk_set_var_data_code_t *svd; + ndk_set_var_value_data_pt func; + + svd = (ndk_set_var_data_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_data_code_t); + + v = e->sp - 1; + + func = (ndk_set_var_value_data_pt) svd->func; + + rc = func(e->request, &str, v, svd->data); + + ndk_set_var_code_finalize(e, rc, v, &str); +} + + +static void +ndk_set_var_multi_value_code(ngx_http_script_engine_t *e) +{ + ngx_int_t rc; + ngx_str_t str; + ngx_http_variable_value_t *v; + ndk_set_var_size_code_t *svs; + ndk_set_var_value_pt func; + + svs = (ndk_set_var_size_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_size_code_t); + + v = e->sp - svs->size; + e->sp = v + 1; + + func = (ndk_set_var_value_pt) svs->func; + + rc = func(e->request, &str, v); + + ndk_set_var_code_finalize(e, rc, v, &str); +} + + +static void +ndk_set_var_multi_value_data_code(ngx_http_script_engine_t *e) +{ + ngx_int_t rc; + ngx_str_t str; + ngx_http_variable_value_t *v; + ndk_set_var_size_data_code_t *svsd; + ndk_set_var_value_data_pt func; + + svsd = (ndk_set_var_size_data_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_size_data_code_t); + + v = e->sp - svsd->size; + e->sp = v + 1; + + func = (ndk_set_var_value_data_pt) svsd->func; + + rc = func(e->request, &str, v, svsd->data); + + ndk_set_var_code_finalize(e, rc, v, &str); +} + + +static void +ndk_set_var_hash_code(ngx_http_script_engine_t *e) +{ + u_char *p; + ngx_http_variable_value_t *v; + ndk_set_var_size_code_t *svs; + ndk_set_var_hash_pt func; + + svs = (ndk_set_var_size_code_t *) e->ip; + + e->ip += sizeof(ndk_set_var_size_code_t); + + p = ngx_palloc(e->request->pool, svs->size); + if (p == NULL) { + e->ip = ndk_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + v = e->sp - 1; + + func = (ndk_set_var_hash_pt) svs->func; + + func(p, (char *) v->data, v->len); + + v->data = (u_char *) p; + v->len = svs->size; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script hashed value: \"%v\"", v); +} + + + +static char * +ndk_set_var_name(ndk_set_var_info_t *info, ngx_str_t *varname) +{ + ngx_int_t index; + ngx_http_variable_t *v; + ngx_conf_t *cf; + ndk_http_rewrite_loc_conf_t *rlcf; + ngx_str_t name; + + name = *varname; + + cf = info->cf; + rlcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_rewrite_module); + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + index = ngx_http_get_variable_index(cf, &name); + if (index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (v->get_handler == NULL + && ngx_strncasecmp(name.data, (u_char *) "arg_", 4) != 0 + && ngx_strncasecmp(name.data, (u_char *) "cookie_", 7) != 0 + && ngx_strncasecmp(name.data, (u_char *) "http_", 5) != 0 + && ngx_strncasecmp(name.data, (u_char *) "sent_http_", 10) != 0 + && ngx_strncasecmp(name.data, (u_char *) "upstream_http_", 14) != 0) + { + v->get_handler = ndk_http_rewrite_var; + v->data = index; + } + + info->v = v; + info->index = index; + info->rlcf = rlcf; + + return NGX_CONF_OK; +} + + + +static void +ndk_set_variable_value_space(ndk_http_rewrite_loc_conf_t *rlcf, ngx_uint_t count) +{ + /* if the number of variable values that will be used is greater than 10, + * make sure there is enough space allocated on the rewrite value stack + */ + + if (count <= 10) + return; + + if (rlcf->stack_size == NGX_CONF_UNSET_UINT) { + rlcf->stack_size = count; + return; + } + + if (rlcf->stack_size < count) + rlcf->stack_size = count; +} + + + +static char * +ndk_set_var_filter(ngx_conf_t *cf, ndk_http_rewrite_loc_conf_t *rlcf, + ndk_set_var_t *filter) +{ + ndk_set_var_code_t *sv; + ndk_set_var_size_code_t *svs; + ndk_set_var_data_code_t *svd; + ndk_set_var_size_data_code_t *svsd; + + if (filter == NULL) { + return "no filter set"; + } + + switch (filter->type) { + case NDK_SET_VAR_BASIC: + + sv = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_code_t)); + if (sv == NULL) { + return NGX_CONF_ERROR; + } + + sv->code = ndk_set_var_code; + sv->func = filter->func; + break; + + case NDK_SET_VAR_DATA: + + svd = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_data_code_t)); + if (svd == NULL) { + return NGX_CONF_ERROR; + } + + svd->code = ndk_set_var_data_code; + svd->func = filter->func; + svd->data = filter->data; + break; + + case NDK_SET_VAR_VALUE: + + sv = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_code_t)); + if (sv == NULL) { + return NGX_CONF_ERROR; + } + + sv->code = ndk_set_var_value_code; + sv->func = filter->func; + break; + + case NDK_SET_VAR_VALUE_DATA: + + svd = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_data_code_t)); + if (svd == NULL) { + return NGX_CONF_ERROR; + } + + svd->code = ndk_set_var_value_data_code; + svd->func = filter->func; + svd->data = filter->data; + break; + + case NDK_SET_VAR_MULTI_VALUE: + + svs = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_size_code_t)); + if (svs == NULL) { + return NGX_CONF_ERROR; + } + + svs->code = ndk_set_var_multi_value_code; + svs->func = filter->func; + svs->size = filter->size; + + ndk_set_variable_value_space(rlcf, svs->size); + break; + + case NDK_SET_VAR_MULTI_VALUE_DATA: + + svsd = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_size_data_code_t)); + if (svsd == NULL) { + return NGX_CONF_ERROR; + } + + svsd->code = ndk_set_var_multi_value_data_code; + svsd->func = filter->func; + svsd->size = filter->size; + svsd->data = filter->data; + + ndk_set_variable_value_space(rlcf, svsd->size); + break; + + + case NDK_SET_VAR_HASH: + + svs = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ndk_set_var_size_code_t)); + if (svs == NULL) { + return NGX_CONF_ERROR; + } + + svs->code = ndk_set_var_hash_code; + svs->func = filter->func; + svs->size = filter->size; + break; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid filter type \"%ul\"", filter->type); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ndk_set_var_filter_value(ndk_set_var_info_t *info, ndk_set_var_t *filter) +{ + ngx_conf_t *cf; + ngx_http_variable_t *v; + ndk_http_rewrite_loc_conf_t *rlcf; + ngx_http_script_var_code_t *vcode; + ngx_http_script_var_handler_code_t *vhcode; + + v = info->v; + cf = info->cf; + rlcf = info->rlcf; + + if (ndk_set_var_filter(cf, rlcf, filter) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + if (v->set_handler) { + vhcode = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ngx_http_script_var_handler_code_t)); + if (vhcode == NULL) { + return NGX_CONF_ERROR; + } + + vhcode->code = ngx_http_script_var_set_handler_code; + vhcode->handler = v->set_handler; + vhcode->data = v->data; + + return NGX_CONF_OK; + } + + vcode = ngx_http_script_start_code(cf->pool, &rlcf->codes, + sizeof(ngx_http_script_var_code_t)); + if (vcode == NULL) { + return NGX_CONF_ERROR; + } + + vcode->code = ngx_http_script_set_var_code; + vcode->index = (uintptr_t) info->index; + + return NGX_CONF_OK; +} + + +char * +ndk_set_var_core(ngx_conf_t *cf, ngx_str_t *name, ndk_set_var_t *filter) +{ + char *p; + ndk_set_var_info_t info; + + info.cf = cf; + + p = ndk_set_var_name(&info, name); + if (p != NGX_CONF_OK) { + return p; + } + + return ndk_set_var_filter_value(&info, filter); +} + + +char * +ndk_set_var_value_core(ngx_conf_t *cf, ngx_str_t *name, ngx_str_t *value, ndk_set_var_t *filter) +{ + char *p; + ndk_set_var_info_t info; + + info.cf = cf; + + p = ndk_set_var_name(&info, name); + if (p != NGX_CONF_OK) { + return p; + } + + p = ndk_http_rewrite_value(cf, info.rlcf, value); + if (p != NGX_CONF_OK) { + return p; + } + + return ndk_set_var_filter_value(&info, filter); +} + + +char * +ndk_set_var_multi_value_core(ngx_conf_t *cf, ngx_str_t *name, + ngx_str_t *value, ndk_set_var_t *filter) +{ + char *p; + ndk_set_var_info_t info; + ngx_int_t i; + + info.cf = cf; + + p = ndk_set_var_name(&info, name); + if (p != NGX_CONF_OK) { + return p; + } + + for (i = filter->size; i; i--, value++) { + + p = ndk_http_rewrite_value(cf, info.rlcf, value); + if (p != NGX_CONF_OK) { + return p; + } + } + + return ndk_set_var_filter_value(&info, filter); +} + + +char * +ndk_set_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ndk_set_var_t *filter; + + value = cf->args->elts; + value++; + + filter = (ndk_set_var_t *) cmd->post; + + return ndk_set_var_core(cf, value, filter); +} + + +char * +ndk_set_var_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ndk_set_var_t *filter; + + value = cf->args->elts; + value++; + + filter = (ndk_set_var_t *) cmd->post; + + return ndk_set_var_value_core(cf, value, + cf->args->nelts == 1 + 1 ? value : value + 1, filter); +} + + +char * +ndk_set_var_multi_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ndk_set_var_t *filter; + + value = cf->args->elts; + value++; + + filter = (ndk_set_var_t *) cmd->post; + + return ndk_set_var_multi_value_core(cf, value, value + 1, filter); +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.h new file mode 100644 index 0000000..5dcba97 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_set_var.h @@ -0,0 +1,44 @@ +/* + * 2010 (C) Marcus Clyne + */ + +#ifndef _NDK_SET_VAR_H_INCLUDED_ +#define _NDK_SET_VAR_H_INCLUDED_ + + +typedef ngx_int_t (*ndk_set_var_pt) (ngx_http_request_t *r, ngx_str_t *val); +typedef ngx_int_t (*ndk_set_var_data_pt) (ngx_http_request_t *r, ngx_str_t *val, void *data); +typedef ngx_int_t (*ndk_set_var_value_pt) (ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *v); +typedef ngx_int_t (*ndk_set_var_value_data_pt) (ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *v, void *data); +typedef void (*ndk_set_var_hash_pt) (u_char *p, char *data, size_t len); + + +typedef struct { + ngx_uint_t type; + void *func; + size_t size; + void *data; +} ndk_set_var_t; + + +enum { + NDK_SET_VAR_BASIC = 0, + NDK_SET_VAR_DATA, + NDK_SET_VAR_VALUE, + NDK_SET_VAR_VALUE_DATA, + NDK_SET_VAR_MULTI_VALUE, + NDK_SET_VAR_MULTI_VALUE_DATA, + NDK_SET_VAR_HASH +}; + + +char * ndk_set_var (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_set_var_value (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char * ndk_set_var_multi_value (ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +char * ndk_set_var_core (ngx_conf_t *cf, ngx_str_t *name, ndk_set_var_t *filter); +char * ndk_set_var_value_core (ngx_conf_t *cf, ngx_str_t *name, ngx_str_t *value, ndk_set_var_t *filter); +char * ndk_set_var_multi_value_core (ngx_conf_t *cf, ngx_str_t *name, ngx_str_t *value, ndk_set_var_t *filter); + +#endif /* _NDK_SET_VAR_H_INCLUDED_ */ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.c new file mode 100644 index 0000000..7c2a965 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.c @@ -0,0 +1,434 @@ + + +int64_t +ndk_atoi64 (u_char *line, size_t n) +{ + int64_t value; + + if (n == 0ll) { + return NGX_ERROR; + } + + for (value = 0ll; n--; line++) { + if (*line < '0' || *line > '9') { + return NGX_ERROR; + } + + value = value * 10ll + (*line - '0'); + } + + if (value < 0ll) { + return NGX_ERROR; + } + + return value; +} + + +ngx_int_t +ndk_strcntc (ngx_str_t *s, char c) +{ + ngx_int_t n; + size_t i; + u_char *p; + + i = s->len; + p = s->data; + + for (n=0; i; i--, p++) { + + if (*p == (u_char) c) + n++; + } + + return n; +} + + +ngx_int_t +ndk_strccnt (char *s, char c) +{ + ngx_int_t n; + + n = 0; + + while (*s != '\0') { + + if (*s == 'c') + n++; + + s++; + } + + return n; +} + + + +ngx_array_t * +ndk_str_array_create (ngx_pool_t *pool, char **s, ngx_int_t n) +{ + ngx_int_t i; + ngx_str_t *str; + ngx_array_t *a; + + a = ngx_array_create (pool, n, sizeof (ngx_str_t)); + if (a == NULL) + return NULL; + + + for (i=0; idata = (u_char *) *s; + str->len = strlen (*s); + } + + return a; +} + + + +u_char * +ndk_vcatstrf (ngx_pool_t *pool, ngx_str_t *dest, const char *fmt, va_list args) +{ + size_t len, l, el; + int argc; + u_char *p, *m, *e, c, c1, *cp; + + argc = strlen (fmt); + + ngx_str_t *s; + ndk_estr_t *sp, *sp2, ss [argc]; + u_char cs [argc]; + + sp = sp2 = ss; + cp = cs; + + len = 0; + + /* TODO : maybe have 'e' at the beginning? */ + + /* parse format to get strings */ + + while (*fmt) { + + switch (*fmt) { + + case 'S' : + + s = va_arg (args, ngx_str_t *); + + sp->data = s->data; + sp->len = s->len; + sp->escaped = 0; + + len += sp->len; + break; + + case 's' : + + sp->data = va_arg (args, u_char *); + sp->len = (size_t) ngx_strlen (sp->data); + sp->escaped = 0; + + len += sp->len; + break; + + case 'l' : + + sp->data = va_arg (args, u_char *); + sp->len = (size_t) va_arg (args, int); + sp->escaped = 0; + + len += sp->len; + break; + + case 'L' : + + sp->data = va_arg (args, u_char *); + sp->len = va_arg (args, size_t); + sp->escaped = 0; + + len += sp->len; + break; + + case 'e' : + + p = va_arg (args, u_char *); + + sp->data = p; + + l = 0; + el = 0; + c = *p; + + while (c != '\0') { + + if (c == '\\') { + l += 2; + p += 2; + } else { + l++; + p++; + } + + el++; + c = *p; + } + + sp->len = l; + sp->escaped = 1; + + len += el; + break; + + case 'E' : + + s = va_arg (args, ngx_str_t *); + + sp->data = s->data; + sp->len = s->len; + + p = sp->data; + + el = 0; + e = p + sp->len; + + while (p < e) { + + c = *p; + + if (c == '\\') { + p += 2; + } else { + p++; + } + + el++; + } + + sp->escaped = 1; + + len += el; + break; + + case 'n' : + + sp->data = va_arg (args, u_char *); + sp->len = (size_t) va_arg (args, int); + + p = sp->data; + + el = 0; + e = p + sp->len; + + while (p < e) { + + c = *p; + + if (c == '\\') { + p += 2; + } else { + p++; + } + + el++; + } + + sp->escaped = 1; + + len += el; + break; + + case 'c' : + + *cp = (u_char) va_arg (args, int); + + sp->data = cp; + sp->len = (size_t) 1; + + len++; + cp++; + + break; + + default : + + ndk_log_alert (pool->log, 0, "catstrf () : format [%s] incorrect", fmt); + + return NULL; + + } + + sp++; + fmt++; + } + + + + /* create space for string (assumes no NULL's in strings) */ + + ndk_palloc_rn (p, pool, len + 1); + + dest->data = p; + dest->len = len; + + /* copy other strings */ + + if (len) { + + while (sp2 < sp) { + + if (sp2->escaped) { + + m = sp2->data; + e = m + sp2->len; + + while (m < e) { + + c = *m; + + if (c == '\\') { + + if (m == e - 1) { + *p = '\\'; + p++; + break; + } + + c1 = m[1]; + + switch (c1) { + + case 'n' : + *p = '\n'; + break; + + case 't' : + *p = '\t'; + break; + + case '0' : + *p = '\0'; + break; + + case '\\' : + *p = '\\'; + break; + + case 's' : + *p = ' '; + break; + + case 'b' : + *p = '\b'; + break; + + case 'r' : + *p = '\r'; + break; + + default : + + *p = c1; + break; + } + + m += 2; + + } else { + + *p = c; + m++; + } + + p++; + } + + } else { + + p = ngx_cpymem (p, sp2->data, sp2->len); + } + + sp2++; + } + } + + *p = '\0'; + + return dest->data; +} + + +u_char * +ndk_catstrf (ngx_pool_t *pool, ngx_str_t *dest, const char *fmt, ...) +{ + u_char *p; + va_list args; + + va_start (args, fmt); + p = ndk_vcatstrf (pool, dest, fmt, args); + va_end (args); + + return p; +} + + +ngx_int_t +ndk_cmpstr (ngx_str_t *s1, ngx_str_t *s2) +{ + ngx_int_t rv; + size_t len1, len2; + + len1 = s1->len; + len2 = s2->len; + + if (len1 == len2) { + return ngx_strncmp (s1->data, s2->data, len1); + } + + if (len1 > len2) { + + rv = ngx_strncmp (s1->data, s2->data, len2); + if (rv == 0) + return 1; + + return rv; + } + + rv = ngx_strncmp (s1->data, s2->data, len1); + if (rv == 0) + return -1; + + return rv; +} + + +u_char * +ndk_dupstr (ngx_pool_t *pool, ngx_str_t *dest, ngx_str_t *src) +{ + u_char *d; + size_t n; + + n = src->len; + + ndk_palloc_rn (d, pool, n + 1); + ndk_strncpy (d, src->data, n); + + dest->data = d; + dest->len = n; + + return d; +} + +/* +ngx_keyval_t * +ndk_url_args_to_keyval_list (ngx_pool_t *pool, ngx_str_t *str) +{ + ngx_keyval_t *kv; + ngx_st + +} +*/ diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.h new file mode 100644 index 0000000..ecd21c4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_string.h @@ -0,0 +1,37 @@ + + +#if 1 +/* TODO : set ndk_hex_dump for older versions of Nginx */ +#define ndk_hex_dump ngx_hex_dump +#endif + +typedef struct { + size_t len; + u_char *data; + ngx_flag_t escaped; +} ndk_estr_t; + +int64_t ndk_atoi64 (u_char *line, size_t n); + +ngx_int_t ndk_strcntc (ngx_str_t *s, char c); +ngx_int_t ndk_strccnt (char *s, char c); +ngx_array_t * ndk_str_array_create (ngx_pool_t *pool, char **s, ngx_int_t n); +u_char * ndk_catstrf (ngx_pool_t *pool, ngx_str_t *dest, const char *fmt, ...); +ngx_int_t ndk_cmpstr (ngx_str_t *s1, ngx_str_t *s2); +u_char * ndk_dupstr (ngx_pool_t *pool, ngx_str_t *dest, ngx_str_t *src); + +static ngx_inline void +ndk_strtoupper (u_char *p, size_t len) +{ + u_char *e = p + len; + for ( ; pdata = (u_char*) s; (ns)->len = sizeof (s) - 1;} + +#define ndk_zero(p,sz) memset (p,'\0',sz) +#define ndk_zerop(p) ndk_zero (p,sizeof(*p)) +#define ndk_zeropn(p,n) ndk_zero (p,sizeof(*p)*(n)) +#define ndk_zerov(v) ndk_zero (&v,sizeof(v)) + +#define ngx_null_enum { ngx_null_string, 0 } + +#define ndk_memcpyp(d,s) ngx_memcpy(d,s,sizeof(*s)) + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.c new file mode 100644 index 0000000..3a83a25 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.c @@ -0,0 +1,205 @@ + + +/* TODO : generalize this into a generic list module, with weight */ + + +typedef struct { + ngx_uint_t weight; + ngx_str_t s; + ngx_conf_t *cf; +} ndk_upstream_list_parse_t; + + + +static ngx_int_t +ndk_upstream_list_parse_weight (ndk_upstream_list_parse_t *ulp) +{ + size_t i; + ngx_str_t *s; + + s = &ulp->s; + + for (i=0; ilen; i++) { + + if (s->data[i] < '0' || s->data[i] > '9') + break; + } + + if (!i) { + ulp->weight = 1; + return NGX_OK; + } + + if (i == s->len) { + ngx_conf_log_error (NGX_LOG_EMERG, ulp->cf, 0, + "upstream list just consists of number \"%V\"", s); + + return NGX_ERROR; + } + + if (s->data[i] != ':') { + ngx_conf_log_error (NGX_LOG_EMERG, ulp->cf, 0, + "upstream list not correct format \"%V\"", s); + + return NGX_ERROR; + } + + + ulp->weight = ngx_atoi (s->data, i); + + s->data += (i + 1); + s->len -= (i + 1); + + return NGX_OK; +} + + + +static char * +ndk_upstream_list (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + /* TODO : change this for getting upstream pointer if available */ + + ngx_uint_t buckets, count, i, j; + ngx_str_t *value, **bucket, *us; + ngx_array_t *ula; + ndk_upstream_list_t *ul, *ule; + ndk_upstream_list_parse_t ulp; + + ndk_http_main_conf_t *mcf; + + mcf = ngx_http_conf_get_module_main_conf (cf, ndk_http_module); + + ula = mcf->upstreams; + + /* create array of upstream lists it doesn't already exist */ + + if (ula == NULL) { + + ula = ngx_array_create (cf->pool, 4, sizeof (ndk_upstream_list_t)); + if (ula == NULL) + return NGX_CONF_ERROR; + + mcf->upstreams = ula; + } + + + /* check to see if the list already exists */ + + value = cf->args->elts; + value++; + + ul = ula->elts; + ule = ul + ula->nelts; + + for ( ; ulname.len == value->len && + ngx_strncasecmp (ul->name.data, value->data, value->len) == 0) { + + ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, + "duplicate upstream list name \"%V\"", value); + + return NGX_CONF_ERROR; + } + } + + + /* create a new list */ + + ul = ngx_array_push (ula); + if (ul == NULL) + return NGX_CONF_ERROR; + + ul->name = *value; + + + + /* copy all the upstream names */ + + count = cf->args->nelts - 2; + + us = ngx_palloc (cf->pool, count * sizeof (ngx_str_t)); + if (us == NULL) + return NGX_CONF_ERROR; + + ngx_memcpy (us, value + 1, count * sizeof (ngx_str_t)); + + + /* calculate the total number of buckets */ + + buckets = 0; + + ulp.cf = cf; + + for (i=0; ipool, buckets * sizeof (ngx_str_t *)); + if (bucket == NULL) + return NGX_CONF_ERROR; + + ul->elts = bucket; + ul->nelts = buckets; + + + /* set values for each bucket */ + + us -= count; + + for (i=0; idata = ulp.s.data; + us->len = ulp.s.len; + + /* TODO : check format of upstream */ + /* TODO : add automatic adding of http:// in upstreams? */ + + for (j=0; jupstreams; + + if (ua == NULL) { + return NULL; + } + + ul = ua->elts; + ule = ul + ua->nelts; + + for (; ul < ule; ul++) { + if (ul->name.len == len && ngx_strncasecmp(ul->name.data, data, len) == 0) + { + return ul; + } + } + + return NULL; +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.h new file mode 100644 index 0000000..3786456 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_upstream_list.h @@ -0,0 +1,27 @@ + +#if (NDK_UPSTREAM_LIST_CMDS) + +/* TODO : use the generated commands */ + +{ + ngx_string ("upstream_list"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_2MORE, + ndk_upstream_list, + 0, + 0, + NULL +}, + +#else + +typedef struct { + ngx_str_t **elts; + ngx_uint_t nelts; + ngx_str_t name; +} ndk_upstream_list_t; + + +ndk_upstream_list_t * +ndk_get_upstream_list (ndk_http_main_conf_t *mcf, u_char *data, size_t len); + +#endif diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.c b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.c new file mode 100644 index 0000000..19e90e8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.c @@ -0,0 +1,45 @@ + + +/* TODO : check that this is correct */ + +u_char * +ndk_map_uri_to_path_add_suffix (ngx_http_request_t *r, ngx_str_t *path, ngx_str_t *suffix, ngx_int_t dot) +{ + size_t root_size; + u_char *p; + + if (suffix->len) { + + if (dot) { + + p = ngx_http_map_uri_to_path (r, path, &root_size, suffix->len + 1); + + if (p == NULL) + return NULL; + + *p = '.'; + p++; + + } else { + + p = ngx_http_map_uri_to_path (r, path, &root_size, suffix->len); + + if (p == NULL) + return NULL; + } + + path->len--; + + p = ngx_cpymem (p, suffix->data, suffix->len); + *p = '\0'; + + return p; + } + + p = ngx_http_map_uri_to_path (r, path, &root_size, 0); + + path->len--; + + return p; +} + diff --git a/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.h b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.h new file mode 100644 index 0000000..dac3880 --- /dev/null +++ b/modules_deb/libnginx-mod-http-ndk-0.3.4/src/ndk_uri.h @@ -0,0 +1,6 @@ + + + +u_char * ndk_map_uri_to_path_add_suffix (ngx_http_request_t *r, ngx_str_t *path, ngx_str_t *suffix, ngx_int_t dot); + + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/.gitattributes b/modules_deb/libnginx-mod-http-set-misc-0.33/.gitattributes new file mode 100644 index 0000000..6fe6f35 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/.gitattributes @@ -0,0 +1 @@ +*.t linguist-language=Text diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/.gitignore b/modules_deb/libnginx-mod-http-set-misc-0.33/.gitignore new file mode 100644 index 0000000..7500112 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/.gitignore @@ -0,0 +1,72 @@ +reindex +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[789] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +all +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +genmobi.sh +*.mobi +misc/chunked +ctags +src/base32.h +src/uri.c +src/module.c +src/upstream.c +src/upstream.h +src/uri.c +src/sql.c +src/uri.h +src/sql.h +src/uri.h +src/value.c +src/base32.c +src/value.h +src/hash.h +src/hash.c +src/today.h +src/today.c +src/json.[ch] +all.sh +go +t/servroot/ +src/base64.c +src/base64.h +src/hex.c +src/hex.h +src/hmac.c +src/hmac.h +src/rotate.[ch] +analyze +buildroot/ +src/module.h +work/ +src/random.[ch] +build1[0-9] +nginx +analyze +src/rotate.[ch] +*.plist +Makefile +src/base64url.[ch] +src/expired.[ch] diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/.travis.yml b/modules_deb/libnginx-mod-http-set-misc-0.33/.travis.yml new file mode 100644 index 0000000..a841a11 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/.travis.yml @@ -0,0 +1,54 @@ +sudo: required +dist: trusty + +branches: + only: + - "master" + +os: linux + +language: c +compiler: gcc + +env: + global: + - LUAJIT_PREFIX=/opt/luajit21 + - LUAJIT_LIB=$LUAJIT_PREFIX/lib + - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH + - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 + - LUA_INCLUDE_DIR=$LUAJIT_INC + - LUA_CMODULE_DIR=/lib + - JOBS=3 + - NGX_BUILD_JOBS=$JOBS + - TEST_NGINX_SLEEP=0.006 + matrix: + - NGINX_VERSION=1.19.9 + +before_install: + - sudo apt-get install -qq -y axel cpanminus libtest-base-perl libtext-diff-perl liburi-perl libwww-perl libtest-longstring-perl liblist-moreutils-perl > build.log 2>&1 || (cat build.log && exit 1) + +install: + - git clone https://github.com/openresty/nginx-devel-utils.git + - git clone https://github.com/openresty/openresty.git ../openresty + - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module + - git clone https://github.com/openresty/test-nginx.git + - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git + - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module + - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + - git clone https://github.com/calio/iconv-nginx-module.git ../iconv-nginx-module + +script: + - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH + - ngx-releng > check.txt || true + - lines=`wc -l check.txt | awk '{print $1}'`; if [ $lines -gt 3 ]; then cat check.txt; exit 1; fi + - cd luajit2 + - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1) + - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) + - cd ../test-nginx && sudo cpanm . && cd .. + - export NGX_BUILD_CC=$CC + - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - nginx -V + - prove -r t diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/README.markdown b/modules_deb/libnginx-mod-http-set-misc-0.33/README.markdown new file mode 100644 index 0000000..f7f4010 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/README.markdown @@ -0,0 +1,1451 @@ + + +Name +==== + +**ngx_set_misc** - Various set_xxx directives added to nginx's rewrite module (md5/sha1, sql/json quoting, and many more) + +*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). + +Table of Contents +================= + +* [Name](#name) +* [Version](#version) +* [Synopsis](#synopsis) +* [Description](#description) +* [Directives](#directives) + * [set_if_empty](#set_if_empty) + * [set_quote_sql_str](#set_quote_sql_str) + * [set_quote_pgsql_str](#set_quote_pgsql_str) + * [set_quote_json_str](#set_quote_json_str) + * [set_unescape_uri](#set_unescape_uri) + * [set_escape_uri](#set_escape_uri) + * [set_hashed_upstream](#set_hashed_upstream) + * [set_encode_base32](#set_encode_base32) + * [set_base32_padding](#set_base32_padding) + * [set_misc_base32_padding](#set_misc_base32_padding) + * [set_base32_alphabet](#set_base32_alphabet) + * [set_decode_base32](#set_decode_base32) + * [set_encode_base64](#set_encode_base64) + * [set_decode_base64](#set_decode_base64) + * [set_encode_base64url](#set_encode_base64url) + * [set_decode_base64url](#set_decode_base64url) + * [set_encode_hex](#set_encode_hex) + * [set_decode_hex](#set_decode_hex) + * [set_sha1](#set_sha1) + * [set_md5](#set_md5) + * [set_hmac_sha1](#set_hmac_sha1) + * [set_hmac_sha256](#set_hmac_sha256) + * [set_random](#set_random) + * [set_secure_random_alphanum](#set_secure_random_alphanum) + * [set_secure_random_lcalpha](#set_secure_random_lcalpha) + * [set_rotate](#set_rotate) + * [set_local_today](#set_local_today) + * [set_formatted_gmt_time](#set_formatted_gmt_time) + * [set_formatted_local_time](#set_formatted_local_time) +* [Caveats](#caveats) +* [Installation](#installation) + * [Building as a dynamic module](#building-as-a-dynamic-module) +* [Compatibility](#compatibility) +* [Report Bugs](#report-bugs) +* [Source Repository](#source-repository) +* [Changes](#changes) +* [Test Suite](#test-suite) +* [Getting involved](#getting-involved) +* [Author](#author) +* [Copyright & License](#copyright--license) +* [See Also](#see-also) + +Version +======= + +This document describes ngx_set_misc [v0.32](https://github.com/openresty/set-misc-nginx-module/tags) released on 19 April 2018. + +Synopsis +======== + +```nginx + + location /foo { + set $a $arg_a; + set_if_empty $a 56; + + # GET /foo?a=32 will yield $a == 32 + # while GET /foo and GET /foo?a= will + # yeild $a == 56 here. + } + + location /bar { + set $foo "hello\n\n'\"\\"; + set_quote_sql_str $foo $foo; # for mysql + + # OR in-place editing: + # set_quote_sql_str $foo; + + # now $foo is: 'hello\n\n\'\"\\' + } + + location /bar { + set $foo "hello\n\n'\"\\"; + set_quote_pgsql_str $foo; # for PostgreSQL + + # now $foo is: E'hello\n\n\'\"\\' + } + + location /json { + set $foo "hello\n\n'\"\\"; + set_quote_json_str $foo $foo; + + # OR in-place editing: + # set_quote_json_str $foo; + + # now $foo is: "hello\n\n'\"\\" + } + + location /baz { + set $foo "hello%20world"; + set_unescape_uri $foo $foo; + + # OR in-place editing: + # set_unescape_uri $foo; + + # now $foo is: hello world + } + + upstream_list universe moon sun earth; + upstream moon { ... } + upstream sun { ... } + upstream earth { ... } + location /foo { + set_hashed_upstream $backend universe $arg_id; + drizzle_pass $backend; # used with ngx_drizzle + } + + location /base32 { + set $a 'abcde'; + set_encode_base32 $a; + set_decode_base32 $b $a; + + # now $a == 'c5h66p35' and + # $b == 'abcde' + } + + location /base64 { + set $a 'abcde'; + set_encode_base64 $a; + set_decode_base64 $b $a; + + # now $a == 'YWJjZGU=' and + # $b == 'abcde' + } + + location /hex { + set $a 'abcde'; + set_encode_hex $a; + set_decode_hex $b $a; + + # now $a == '6162636465' and + # $b == 'abcde' + } + + # GET /sha1 yields the output + # aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d + location /sha1 { + set_sha1 $a hello; + echo $a; + } + + # ditto + location /sha1 { + set $a hello; + set_sha1 $a; + echo $a; + } + + # GET /today yields the date of today in local time using format 'yyyy-mm-dd' + location /today { + set_local_today $today; + echo $today; + } + + # GET /signature yields the hmac-sha-1 signature + # given a secret and a string to sign + # this example yields the base64 encoded singature which is + # "HkADYytcoQQzqbjQX33k/ZBB/DQ=" + location /signature { + set $secret_key 'secret-key'; + set $string_to_sign "some-string-to-sign"; + set_hmac_sha1 $signature $secret_key $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } + + location = /rand { + set $from 3; + set $to 15; + set_random $rand $from $to; + + # or write directly + # set_random $rand 3 15; + + echo $rand; # will print a random integer in the range [3, 15] + } +``` + +Description +=========== + +This module extends the standard HttpRewriteModule's directive set to provide more functionalities like URI escaping and unescaping, JSON quoting, Hexadecimal/MD5/SHA1/Base32/Base64 digest encoding and decoding, random number generator, and more! + +Every directive provided by this module can be mixed freely with other [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s directives, like [if](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if) and [set](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#set). (Thanks to the [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit)!) + +[Back to TOC](#table-of-contents) + +Directives +========== + +[Back to TOC](#table-of-contents) + +set_if_empty +------------ +**syntax:** *set_if_empty $dst <src>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Assign the value of the argument `` if and only if variable `$dst` is empty (i.e., not found or has an empty string value). + +In the following example, + +```nginx + + set $a 32; + set_if_empty $a 56; +``` + +the variable `$dst` will take the value 32 at last. But in the sample + +```nginx + + set $a ''; + set $value "hello, world" + set_if_empty $a $value; +``` + +`$a` will take the value `"hello, world"` at last. + +[Back to TOC](#table-of-contents) + +set_quote_sql_str +----------------- +**syntax:** *set_quote_sql_str $dst <src>* + +**syntax:** *set_quote_sql_str $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will quote the value of the second argument `` by MySQL's string value quoting rule and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set $value "hello\n\r'\"\\"; + set_quote_sql_str $quoted $value; + + echo $quoted; + } +``` + +Then request `GET /test` will yield the following output + +```sql + + 'hello\n\r\'\"\\' +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "hello\n\r'\"\\"; + set_quote_sql_str $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive is usually used to prevent SQL injection. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_quote_pgsql_str +------------------- +**syntax:** *set_quote_pgsql_str $dst <src>* + +**syntax:** *set_quote_pgsql_str $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +Very much like [set_quote_sql_str](#set_quote_sql_str), but with PostgreSQL quoting rules for SQL string literals. + +[Back to TOC](#table-of-contents) + +set_quote_json_str +------------------ +**syntax:** *set_quote_json_str $dst <src>* + +**syntax:** *set_quote_json_str $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will quote the value of the second argument `` by JSON string value quoting rule and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set $value "hello\n\r'\"\\"; + set_quote_json_str $quoted $value; + + echo $quoted; + } +``` + +Then request `GET /test` will yield the following output + +```javascript + + "hello\n\r'\"\\" +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "hello\n\r'\"\\"; + set_quote_json_str $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_unescape_uri +---------------- +**syntax:** *set_unescape_uri $dst <src>* + +**syntax:** *set_unescape_uri $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will unescape the value of the second argument `` as a URI component and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set_unescape_uri $key $arg_key; + echo $key; + } +``` + +Then request `GET /test?key=hello+world%21` will yield the following output + +``` +hello world! +``` + +The nginx standard [$arg_PARAMETER](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_arg_) variable holds the raw (escaped) value of the URI parameter. So we need the `set_unescape_uri` directive to unescape it first. + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $key $arg_key; + set_unescape_uri $key; + + echo $key; + } +``` + +then request `GET /test?key=hello+world%21` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_escape_uri +-------------- +**syntax:** *set_escape_uri $dst <src>* + +**syntax:** *set_escape_uri $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +Very much like the [set_unescape_uri](#set_unescape_uri) directive, but does the conversion the other way around, i.e., URL component escaping. + +[Back to TOC](#table-of-contents) + +set_hashed_upstream +------------------- +**syntax:** *set_hashed_upstream $dst <upstream_list_name> <src>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Hashes the string argument `` into one of the upstream name included in the upstream list named ``. The hash function being used is simple modulo. + +Here's an example, + +```nginx + + upstream moon { ... } + upstream sun { ... } + upstream earth { ... } + + upstream_list universe moon sun earth; + + location /test { + set_unescape_uri $key $arg_key; + set $list_name universe; + set_hashed_upstream $backend $list_name $key; + + echo $backend; + } +``` + +Then `GET /test?key=blah` will output either "moon", "sun", or "earth", depending on the actual value of the `key` query argument. + +This directive is usually used to compute an nginx variable to be passed to [memc-nginx-module](http://github.com/openresty/memc-nginx-module)'s [memc_pass](http://github.com/openresty/memc-nginx-module#memc_pass) directive, [redis2-nginx-module](http://github.com/openresty/redis2-nginx-module)'s [[HttpRedis2Module#redis2_pass]] directive, and [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html)'s [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive, among others. + +[Back to TOC](#table-of-contents) + +set_encode_base32 +----------------- +**syntax:** *set_encode_base32 $dst <src>* + +**syntax:** *set_encode_base32 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will encode the value of the second argument `` to its base32(hex) digest and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set $raw "abcde"; + set_encode_base32 $digest $raw; + + echo $digest; + } +``` + +Then request `GET /test` will yield the following output + +``` +c5h66p35 +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +RFC forces the `[A-Z2-7]` RFC-3548 compliant encoding, but we are using the "base32hex" encoding (`[0-9a-v]`) by default. The [set_base32_alphabet](#set_base32_alphabet) directive (first introduced in `v0.28`) allows you to change the alphabet used for encoding/decoding so RFC-3548 compliant encoding is still possible by custom configurations. + +By default, the `=` character is used to pad the left-over bytes due to alignment. But the padding behavior can be completely disabled by setting [set_base32_padding](#set_base32_padding) `off`. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "abcde"; + set_encode_base32 $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_base32_padding +------------------ +**syntax:** *set_base32_padding on|off* + +**default:** *on* + +**context:** *http, server, server if, location, location if* + +**phase:** *no* + +This directive can control whether to pad left-over bytes with the "=" character when encoding a base32 digest by the +[set_encode_base32](#set_encode_base32) directive. + +This directive was first introduced in `v0.28`. If you use earlier versions of this module, then you should use [set_misc_base32_padding](#set_misc_base32_padding) instead. + +[Back to TOC](#table-of-contents) + +set_misc_base32_padding +----------------------- +**syntax:** *set_misc_base32_padding on|off* + +**default:** *on* + +**context:** *http, server, server if, location, location if* + +**phase:** *no* + +This directive has been deprecated since `v0.28`. Use [set_base32_padding](#set_base32_padding) instead if you are using `v0.28+`. + +[Back to TOC](#table-of-contents) + +set_base32_alphabet +------------------- +**syntax:** *set_base32_alphabet <alphabet>* + +**default:** *"0123456789abcdefghijklmnopqrstuv"* + +**context:** *http, server, server if, location, location if* + +**phase:** *no* + +This directive controls the alphabet used for encoding/decoding a base32 digest. It accepts a string containing the desired alphabet like "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" for standard alphabet. + +Extended (base32hex) alphabet is used by default. + +This directive was first introduced in `v0.28`. + +[Back to TOC](#table-of-contents) + +set_decode_base32 +----------------- +**syntax:** *set_decode_base32 $dst <src>* + +**syntax:** *set_decode_base32 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +Similar to the [set_encode_base32](#set_encode_base32) directive, but does exactly the opposite operation, .i.e, decoding a base32(hex) digest into its original form. + +[Back to TOC](#table-of-contents) + +set_encode_base64 +----------------- +**syntax:** *set_encode_base64 $dst <src>* + +**syntax:** *set_encode_base64 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will encode the value of the second argument `` to its base64 digest and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set $raw "abcde"; + set_encode_base64 $digest $raw; + + echo $digest; + } +``` + +Then request `GET /test` will yield the following output + +``` +YWJjZGU= +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "abcde"; + set_encode_base64 $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_encode_base64url +----------------- +**syntax:** *set_encode_base64url $dst <src>* + +**syntax:** *set_encode_base64url $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will encode the value of the second argument `` to its base64 url safe digest and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set $raw "abcde"; + set_encode_base64url $digest $raw; + + echo $digest; + } +``` + +Then request `GET /test` will yield the following output + +``` +YWJjZGU= +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "abcde"; + set_encode_base64url $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_decode_base64 +----------------- +**syntax:** *set_decode_base64 $dst <src>* + +**syntax:** *set_decode_base64 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +Similar to the [set_encode_base64](#set_encode_base64) directive, but does exactly the opposite operation, .i.e, decoding a base64 digest into its original form. + +[Back to TOC](#table-of-contents) + +set_decode_base64url +----------------- +**syntax:** *set_decode_base64url $dst <src>* + +**syntax:** *set_decode_base64url $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +Similar to the [set_encode_base64url](#set_encode_base64url) directive, but does exactly the the opposite operation, .i.e, decoding a base64 url safe digest into its original form. + +[Back to TOC](#table-of-contents) + +set_encode_hex +-------------- +**syntax:** *set_encode_hex $dst <src>* + +**syntax:** *set_encode_hex $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will encode the value of the second argument `` to its hexadecimal digest and assign the result into the first argument, variable `$dst`. For example, + +```nginx + + location /test { + set $raw "章亦春"; + set_encode_hex $digest $raw; + + echo $digest; + } +``` + +Then request `GET /test` will yield the following output + +``` +e7aba0e4baa6e698a5 +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "章亦春"; + set_encode_hex $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_decode_hex +-------------- +**syntax:** *set_decode_hex $dst <src>* + +**syntax:** *set_decode_hex $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +Similar to the [set_encode_hex](#set_encode_hex) directive, but does exactly the opposite operation, .i.e, decoding a hexadecimal digest into its original form. + +[Back to TOC](#table-of-contents) + +set_sha1 +-------- +**syntax:** *set_sha1 $dst <src>* + +**syntax:** *set_sha1 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will encode the value of the second argument `` to its [SHA-1](http://en.wikipedia.org/wiki/SHA-1) digest and assign the result into the first argument, variable `$dst`. The hexadecimal form of the `SHA-1` digest will be generated automatically, use [set_decode_hex](#set_decode_hex) to decode the result if you want the binary form of the `SHA-1` digest. + +For example, + +```nginx + + location /test { + set $raw "hello"; + set_sha1 $digest $raw; + + echo $digest; + } +``` + +Then request `GET /test` will yield the following output + +``` +aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "hello"; + set_sha1 $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_md5 +------- +**syntax:** *set_md5 $dst <src>* + +**syntax:** *set_md5 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +**category:** *ndk_set_var_value* + +When taking two arguments, this directive will encode the value of the second argument `` to its [MD5](http://en.wikipedia.org/wiki/MD5) digest and assign the result into the first argument, variable `$dst`. The hexadecimal form of the `MD5` digest will be generated automatically, use [set_decode_hex](#set_decode_hex) to decode the result if you want the binary form of the `MD5` digest. + +For example, + +```nginx + + location /test { + set $raw "hello"; + set_md5 $digest $raw; + + echo $digest; + } +``` + +Then request `GET /test` will yield the following output + + + 5d41402abc4b2a76b9719d911017c592 + + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +When taking a single argument, this directive will do in-place modification of the argument variable. For example, + +```nginx + + location /test { + set $value "hello"; + set_md5 $value; + + echo $value; + } +``` + +then request `GET /test` will give exactly the same output as the previous example. + +This directive can be invoked by [lua-nginx-module](http://github.com/openresty/lua-nginx-module)'s [ndk.set_var.DIRECTIVE](http://github.com/openresty/lua-nginx-module#ndkset_vardirective) interface and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module)'s [array_map_op](http://github.com/openresty/array-var-nginx-module#array_map_op) directive. + +[Back to TOC](#table-of-contents) + +set_hmac_sha1 +------------- +**syntax:** *set_hmac_sha1 $dst <secret_key> <src>* + +**syntax:** *set_hmac_sha1 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Computes the [HMAC-SHA1](http://en.wikipedia.org/wiki/HMAC) digest of the argument `` and assigns the result into the argument variable `$dst` with the secret key ``. + +The raw binary form of the `HMAC-SHA1` digest will be generated, use [set_encode_base64](#set_encode_base64), for example, to encode the result to a textual representation if desired. + +For example, + +```nginx + + location /test { + set $secret 'thisisverysecretstuff'; + set $string_to_sign 'some string we want to sign'; + set_hmac_sha1 $signature $secret $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } +``` + +Then request `GET /test` will yield the following output + +``` +R/pvxzHC4NLtj7S+kXFg/NePTmk= +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +This directive requires the OpenSSL library enabled in your Nginx build (usually by passing the `--with-http_ssl_module` option to the `./configure` script). + +[Back to TOC](#table-of-contents) + +set_hmac_sha256 +--------------- +**syntax:** *set_hmac_sha256 $dst <secret_key> <src>* + +**syntax:** *set_hmac_sha256 $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Computes the [HMAC-SHA256](http://en.wikipedia.org/wiki/HMAC) digest of the argument `` and assigns the result into the argument variable `$dst` with the secret key ``. + +The raw binary form of the `HMAC-SHA256` digest will be generated, use [set_encode_base64](#set_encode_base64), for example, to encode the result to a textual representation if desired. + +For example, + +```nginx + + location /test { + set $secret 'thisisverysecretstuff'; + set $string_to_sign 'some string we want to sign'; + set_hmac_sha256 $signature $secret $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } +``` + +Then request `GET /test` will yield the following output + +``` +4pU3GRQrKKIoeLb9CqYsavHE2l6Hx+KMmRmesU+Cfrs= +``` + +Please note that we're using [echo-nginx-module](http://github.com/openresty/echo-nginx-module)'s [echo directive](http://github.com/openresty/echo-nginx-module#echo) here to output values of nginx variables directly. + +This directive requires the OpenSSL library enabled in your Nginx build (usually by passing the `--with-http_ssl_module` option to the `./configure` script). + +[Back to TOC](#table-of-contents) + +set_random +---------- +**syntax:** *set_random $res <from> <to>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Generates a (pseudo) random number (in textual form) within the range `[<$from>, <$to>]` (inclusive). + +Only non-negative numbers are allowed for the `` and `` arguments. + +When `` is greater than ``, their values will be exchanged accordingly. + +For instance, + +```nginx + + location /test { + set $from 5; + set $to 7; + set_random $res $from $to; + + echo $res; + } +``` + +then request `GET /test` will output a number between 5 and 7 (i.e., among 5, 6, 7). + +For now, there's no way to configure a custom random generator seed. + +Behind the scene, it makes use of the standard C function `rand()`. + +This directive was first introduced in the `v0.22rc1` release. + +See also [set_secure_random_alphanum](#set_secure_random_alphanum) and [set_secure_random_lcalpha](#set_secure_random_lcalpha). + +[Back to TOC](#table-of-contents) + +set_secure_random_alphanum +-------------------------- +**syntax:** *set_secure_random_alphanum $res <length>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Generates a cryptographically-strong random string `` characters long with the alphabet `[a-zA-Z0-9]`. + +`` may be between 1 and 64, inclusive. + +For instance, + +```nginx + + location /test { + set_secure_random_alphanum $res 32; + + echo $res; + } +``` + +then request `GET /test` will output a string like `ivVVRP2DGaAqDmdf3Rv4ZDJ7k0gOfASz`. + +This functionality depends on the presence of the `/dev/urandom` device, available on most UNIX-like systems. + +See also [set_secure_random_lcalpha](#set_secure_random_lcalpha) and [set_random](#set_random). + +This directive was first introduced in the `v0.22rc8` release. + +[Back to TOC](#table-of-contents) + +set_secure_random_lcalpha +------------------------- +**syntax:** *set_secure_random_lcalpha $res <length>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Generates a cryptographically-strong random string `` characters long with the alphabet `[a-z]`. + +`` may be between 1 and 64, inclusive. + +For instance, + +```nginx + + location /test { + set_secure_random_lcalpha $res 32; + + echo $res; + } +``` + +then request `GET /test` will output a string like `kcuxcddktffsippuekhshdaclaquiusj`. + +This functionality depends on the presence of the `/dev/urandom` device, available on most UNIX-like systems. + +This directive was first introduced in the `v0.22rc8` release. + +See also [set_secure_random_alphanum](#set_secure_random_alphanum) and [set_random](#set_random). + +[Back to TOC](#table-of-contents) + +set_rotate +---------- +**syntax:** *set_rotate $value <from> <to>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Increments `$value` but keeps it in range from `` to ``. +If `$value` is greater than `` or less than `` is will be +set to `` value. + +The current value after running this directive will always be saved on a per-location basis. And the this saved value will be used for incrementation when the `$value` is not initialized or has a bad value. + +Only non-negative numbers are allowed for the `` and `` arguments. + +When `` is greater than ``, their values will be exchanged accordingly. + +For instance, + +```nginx + + location /rotate { + default_type text/plain; + set $counter $cookie_counter; + set_rotate $counter 1 5; + echo $counter; + add_header Set-Cookie counter=$counter; + } +``` + +then request `GET /rotate` will output next number between 1 and 5 (i.e., 1, 2, 3, 4, 5) on each +refresh of the page. This directive may be userful for banner rotation purposes. + +Another example is to use server-side value persistence to do simple round-robin: + +```nginx + + location /rotate { + default_type text/plain; + set_rotate $counter 0 3; + echo $counter; + } +``` + +And accessing `/rotate` will also output integer sequence 0, 1, 2, 3, 0, 1, 2, 3, and so on. + +This directive was first introduced in the `v0.22rc7` release. + +[Back to TOC](#table-of-contents) + +set_local_today +--------------- +**syntax:** *set_local_today $dst* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Set today's date ("yyyy-mm-dd") in localtime to the argument variable `$dst`. + +Here's an example, + +```nginx + + location /today { + set_local_today $today; + echo $today; + } +``` + +then request `GET /today` will output something like + +``` +2011-08-16 +``` + +and year, the actual date you get here will vary every day ;) + +Behind the scene, this directive utilizes the `ngx_time` API in the Nginx core, so usually no syscall is involved due to the time caching mechanism in the Nginx core. + +[Back to TOC](#table-of-contents) + +set_formatted_gmt_time +---------------------- +**syntax:** *set_formatted_gmt_time $res <time-format>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Set a formatted GMT time to variable `$res` (as the first argument) using the format string in the second argument. + +All the conversion specification notations in the standard C function `strftime` are supported, like `%Y` (for 4-digit years) and `%M` (for minutes in decimal). See for a complete list of conversion specification symbols. + +Below is an example: + +```nginx + + location = /t { + set_formatted_gmt_time $timestr "%a %b %e %H:%M:%S %Y GMT"; + echo $timestr; + } +``` + +Accessing `/t` yields the output + +``` +Fri Dec 13 15:34:37 2013 GMT +``` + +This directive was first added in the `0.23` release. + +See also [set_formatted_local_time](#set_formatted_local_time). + +[Back to TOC](#table-of-contents) + +set_formatted_local_time +------------------------ +**syntax:** *set_formatted_local_time $res <time-format>* + +**default:** *no* + +**context:** *location, location if* + +**phase:** *rewrite* + +Set a formatted local time to variable `$res` (as the first argument) using the format string in the second argument. + +All the conversion specification notations in the standard C function `strftime` are supported, like `%Y` (for 4-digit years) and `%M` (for minutes in decimal). See for a complete list of conversion specification symbols. + +Below is an example: + +```nginx + + location = /t { + set_formatted_local_time $timestr "%a %b %e %H:%M:%S %Y %Z"; + echo $timestr; + } +``` + +Accessing `/t` yields the output + +``` +Fri Dec 13 15:42:15 2013 PST +``` + +This directive was first added in the `0.23` release. + +See also [set_formatted_gmt_time](#set_formatted_gmt_time). + +[Back to TOC](#table-of-contents) + +Caveats +======= + +Do not use [$arg_PARAMETER](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_arg_), [$cookie_COOKIE](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_cookie_), [$http_HEADER](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_) or other special variables defined in the Nginx core module as the target variable in this module's directives. For instance, + +```nginx + + set_if_empty $arg_user 'foo'; # DO NOT USE THIS! +``` + +may lead to segmentation faults. + +[Back to TOC](#table-of-contents) + +Installation +============ + +This module is included and enabled by default in the [OpenResty bundle](http://openresty.org). If you want to install this module manually with your own Nginx source tarball, then follow the steps below: + +Grab the nginx source code from [nginx.org](http://nginx.org/), for example, +the version 1.13.6 (see [nginx compatibility](#compatibility)), and then build the source with this module: + +```bash + + wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' + tar -xzvf nginx-1.13.6.tar.gz + cd nginx-1.13.6/ + + # Here we assume you would install you nginx under /opt/nginx/. + ./configure --prefix=/opt/nginx \ + --with-http_ssl_module \ + --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/set-misc-nginx-module + + make -j2 + make install +``` + +Download the latest version of the release tarball of this module from [set-misc-nginx-module file list](http://github.com/openresty/set-misc-nginx-module/tags), and the latest tarball for [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) from its [file list](https://github.com/simplresty/ngx_devel_kit/tags). + +[Back to TOC](#table-of-contents) + +Building as a dynamic module +---------------------------- + +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too +load_module /path/to/modules/ngx_http_set_misc_module.so; +``` + +Also, this module is included and enabled by default in the [OpenResty bundle](http://openresty.org/). + +[Back to TOC](#table-of-contents) + +Compatibility +============= + +The following versions of Nginx should work with this module: + +* **1.13.x** (last tested: 1.13.6) +* **1.12.x** +* **1.11.x** (last tested: 1.11.2) +* **1.10.x** +* **1.9.x** (last tested: 1.9.15) +* **1.8.x** +* **1.7.x** (last tested: 1.7.10) +* **1.6.x** +* **1.5.x** (last tested: 1.5.8) +* **1.4.x** (last tested: 1.4.4) +* **1.2.x** (last tested: 1.2.9) +* **1.1.x** (last tested: 1.1.5) +* **1.0.x** (last tested: 1.0.15) +* **0.9.x** (last tested: 0.9.4) +* **0.8.x** (last tested: 0.8.54) +* **0.7.x >= 0.7.46** (last tested: 0.7.68) + +If you find that any particular version of Nginx above 0.7.46 does not work with this module, please consider [reporting a bug](#report-bugs). + +[Back to TOC](#table-of-contents) + +Report Bugs +=========== + +Although a lot of effort has been put into testing and code tuning, there must be some serious bugs lurking somewhere in this module. So whenever you are bitten by any quirks, please don't hesitate to + +1. send a bug report or even patches to the [openresty-en mailing list](https://groups.google.com/group/openresty-en), +1. or create a ticket on the [issue tracking interface](http://github.com/openresty/set-misc-nginx-module/issues) provided by GitHub. + +[Back to TOC](#table-of-contents) + +Source Repository +================= + +Available on github at [openresty/set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module). + +[Back to TOC](#table-of-contents) + +Changes +======= + +The change logs for every release of this module can be obtained from the OpenResty bundle's change logs: + + + +[Back to TOC](#table-of-contents) + +Test Suite +========== + +This module comes with a Perl-driven test suite. The [test cases](http://github.com/openresty/set-misc-nginx-module/tree/master/t/) are +[declarative](http://github.com/openresty/set-misc-nginx-module/blob/master/t/escape-uri.t) too. Thanks to the [Test::Nginx](http://search.cpan.org/perldoc?Test::Nginx) module in the Perl world. + +To run it on your side: + +```bash + + $ PATH=/path/to/your/nginx-with-set-misc-module:$PATH prove -r t +``` + +You need to terminate any Nginx processes before running the test suite if you have changed the Nginx server binary. + +Because a single nginx server (by default, `localhost:1984`) is used across all the test scripts (`.t` files), it's meaningless to run the test suite in parallel by specifying `-jN` when invoking the `prove` utility. + +[Back to TOC](#table-of-contents) + +Getting involved +================ + +You'll be very welcomed to submit patches to the [author](#author) or just ask for a commit bit to the [source repository](#source-repository) on GitHub. + +[Back to TOC](#table-of-contents) + +Author +====== + +Yichun Zhang (agentzh) *<agentzh@gmail.com>*, OpenResty Inc. + +This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. + +[Back to TOC](#table-of-contents) + +Copyright & License +=================== + +Copyright (C) 2009-2018, Yichun Zhang (章亦春) , OpenResty Inc. + +This module is licensed under the terms of the BSD license. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) +* [The OpenResty bundle](http://openresty.org) + +[Back to TOC](#table-of-contents) + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/config b/modules_deb/libnginx-mod-http-set-misc-0.33/config new file mode 100755 index 0000000..7bb00af --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/config @@ -0,0 +1,79 @@ +ngx_addon_name=ngx_http_set_misc_module + +if test -n "$ngx_module_link"; then + if test -n "$NDK_SRCS"; then + echo "found ngx_devel_kit for ngx_set_misc; looks good." + else + echo "error: ngx_devel_kit is required to build ngx_set_misc; please put it before ngx_set_misc." 1>&2 + exit 1 + fi +else + if echo $HTTP_MODULES | grep " ndk_http_module" > /dev/null; then + echo "found ngx_devel_kit for ngx_set_misc; looks good." + else + echo "error: ngx_devel_kit is required to build ngx_set_misc; please put it before ngx_set_misc." 1>&2 + exit 1 + fi +fi + +SET_MISC_SRCS=" \ + $ngx_addon_dir/src/ngx_http_set_base32.c \ + $ngx_addon_dir/src/ngx_http_set_default_value.c \ + $ngx_addon_dir/src/ngx_http_set_hashed_upstream.c \ + $ngx_addon_dir/src/ngx_http_set_quote_sql.c \ + $ngx_addon_dir/src/ngx_http_set_quote_json.c \ + $ngx_addon_dir/src/ngx_http_set_unescape_uri.c \ + $ngx_addon_dir/src/ngx_http_set_misc_module.c \ + $ngx_addon_dir/src/ngx_http_set_escape_uri.c \ + $ngx_addon_dir/src/ngx_http_set_hash.c \ + $ngx_addon_dir/src/ngx_http_set_local_today.c \ + $ngx_addon_dir/src/ngx_http_set_hex.c \ + $ngx_addon_dir/src/ngx_http_set_base64.c \ + $ngx_addon_dir/src/ngx_http_set_base64url.c \ + $ngx_addon_dir/src/ngx_http_set_random.c \ + $ngx_addon_dir/src/ngx_http_set_secure_random.c \ + $ngx_addon_dir/src/ngx_http_set_rotate.c + " + +SET_MISC_DEPS=" \ + $ngx_addon_dir/src/ddebug.h \ + $ngx_addon_dir/src/ngx_http_set_default_value.h \ + $ngx_addon_dir/src/ngx_http_set_hashed_upstream.h \ + $ngx_addon_dir/src/ngx_http_set_quote_sql.h \ + $ngx_addon_dir/src/ngx_http_set_quote_json.h \ + $ngx_addon_dir/src/ngx_http_set_unescape_uri.h \ + $ngx_addon_dir/src/ngx_http_set_escape_uri.h \ + $ngx_addon_dir/src/ngx_http_set_hash.h \ + $ngx_addon_dir/src/ngx_http_set_local_today.h \ + $ngx_addon_dir/src/ngx_http_set_hex.h \ + $ngx_addon_dir/src/ngx_http_set_base64url.h \ + $ngx_addon_dir/src/ngx_http_set_base64.h \ + $ngx_addon_dir/src/ngx_http_set_random.h \ + $ngx_addon_dir/src/ngx_http_set_rotate.h \ + $ngx_addon_dir/src/ngx_http_set_secure_random.h \ + $ngx_addon_dir/src/ngx_http_set_misc_module.h \ + " + +if [ $USE_OPENSSL = YES -o $MAIL_SSL = YES ]; then + SET_MISC_DEPS="$SET_MISC_DEPS $ngx_addon_dir/src/ngx_http_set_hmac.h" + SET_MISC_SRCS="$SET_MISC_SRCS $ngx_addon_dir/src/ngx_http_set_hmac.c" +fi + +CFLAGS="$CFLAGS -DNDK_SET_VAR -DNDK_UPSTREAM_LIST" +USE_SHA1=YES +USE_MD5=YES + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=$ngx_addon_name + ngx_module_incs= + ngx_module_deps="$SET_MISC_DEPS" + ngx_module_srcs="$SET_MISC_SRCS" + ngx_module_libs= + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $SET_MISC_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $SET_MISC_DEPS" +fi diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/changelog b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/changelog new file mode 100644 index 0000000..bb494f4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/changelog @@ -0,0 +1,53 @@ +libnginx-mod-http-set-misc (0.33-6) unstable; urgency=medium + + * Team upload. + * d/control: bump Standards-Version: 4.7.2, no changes + * d/watch: use more generic template + * d/copyright: bump debian/* copyright year + + -- Jan Mojžíš Sat, 12 Apr 2025 09:05:50 +0200 + +libnginx-mod-http-set-misc (0.33-5) unstable; urgency=medium + + * Team upload. + * Better usage of dh-sequence-nginx. + * d/control: remove Build-Depends nginx-abi-1.24.0-1 + * d/rules: remove override_dh_auto_test, override_dh_auto_test + * d/control: remove Depends libnginx-mod-http-ndk + * d/copyright-scan-patterns.yml add + + -- Jan Mojžíš Sun, 08 Oct 2023 17:10:26 +0200 + +libnginx-mod-http-set-misc (0.33-4) unstable; urgency=medium + + * Team upload. + * NEW ABI: rebuild with nginx-abi-1.24.0-1 + + -- Jan Mojžíš Wed, 28 Jun 2023 00:01:59 +0200 + +libnginx-mod-http-set-misc (0.33-3) unstable; urgency=medium + + * Team upload. + * d/t/set_if_empty renamed to d/t/setifempty, fixes lintian + warning illegal-runtime-test-name + * d/t/generic rework. The test now checks module after + installation/reload/restart. + * d/control: bump Standards-Version: 4.6.2, no changes + * d/copyright: reformat text to be compatible with 'cme update dpkg-copyright' + * d/fix.scanned.copyright: added, fixes upstream author name parsing + * NEW ABI: rebuild with nginx-abi-1.22.1-7 + + -- Jan Mojžíš Mon, 13 Feb 2023 12:56:37 +0100 + +libnginx-mod-http-set-misc (0.33-2) unstable; urgency=medium + + * Team upload. + * d/control: fixed dependency libnginx-mod-http-ndk-dev (>= 1:0.3.2-2) + + -- Jan Mojžíš Fri, 09 Dec 2022 14:08:01 +0100 + +libnginx-mod-http-set-misc (0.33-1) unstable; urgency=medium + + * Initial release. (Closes: #1025291) + + -- Jérémy Lal Fri, 02 Dec 2022 00:32:56 +0100 diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/control b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/control new file mode 100644 index 0000000..9223829 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/control @@ -0,0 +1,27 @@ +Source: libnginx-mod-http-set-misc +Section: httpd +Priority: optional +Maintainer: Debian Nginx Maintainers +Uploaders: Jérémy Lal , +Build-Depends: debhelper-compat (= 13), + dh-sequence-nginx, + libnginx-mod-http-ndk-dev (>= 1:0.3.2-2), +Standards-Version: 4.7.2 +Homepage: https://github.com/openresty/set-misc-nginx-module +Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-set-misc.git +Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-set-misc +Rules-Requires-Root: no + +Package: libnginx-mod-http-set-misc +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Recommends: nginx, +Description: Extended rewrite directives module for Nginx + This module provides more directives that can be used in + the Nginx rewrite phase, like the 'set' directive. + - URI escaping and unescaping + - JSON quoting + - digests encoding and decoding + - random number generator diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright new file mode 100644 index 0000000..f77abc0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright @@ -0,0 +1,49 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: memc-nginx-module +Upstream-Contact: Yichun "agentzh" Zhang (章亦春) +Source: https://github.com/openresty/set-misc-nginx-module + +Files: * +Copyright: 2009-2018, Yichun Zhang (章亦春) , OpenResty Inc. +License: BSD-2-clause + +Files: config +Copyright: 2009-2018, Yichun Zhang (章亦春) , OpenResty Inc. +License: BSD-2-clause + +Files: debian/* +Copyright: 2022, Jérémy Lal , + 2022-2025, Jan Mojzis +License: BSD-2-clause + +Files: src/* +Copyright: 2009-2018, Yichun Zhang (章亦春) , OpenResty Inc. +License: BSD-2-clause + +Files: t/* +Copyright: 2009-2018, Yichun Zhang (章亦春) , OpenResty Inc. +License: BSD-2-clause + +Files: util/* +Copyright: 2009-2018, Yichun Zhang (章亦春) , OpenResty Inc. +License: BSD-2-clause + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright-scan-patterns.yml b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright-scan-patterns.yml new file mode 100644 index 0000000..e195ac6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/copyright-scan-patterns.yml @@ -0,0 +1,4 @@ +--- +ignore: + pattern: + - debian/output diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/fix.scanned.copyright b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/fix.scanned.copyright new file mode 100644 index 0000000..b25e244 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/fix.scanned.copyright @@ -0,0 +1,2 @@ +# fixes upstream author name parsing +! copyright Files:~/.*/ Copyright=~"s/(Zhang)\s\(.*x\{6625\}\)/$1\ (章亦春)/" diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/gbp.conf b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/gbp.conf new file mode 100644 index 0000000..38c12c1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/gbp.conf @@ -0,0 +1,9 @@ +[DEFAULT] +debian-branch = main +upstream-branch = upstream +upstream-tag = upstream/%(version)s +pristine-tar = True +sign-tags = True + +[import-orig] +merge-mode = replace diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/rules b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/rules new file mode 100755 index 0000000..d8309f6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/source/format b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/control b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/control new file mode 100644 index 0000000..9ecf806 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/control @@ -0,0 +1,13 @@ +Tests: generic +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, + +Tests: setifempty +Restrictions: allow-stderr isolation-container needs-root +Depends: curl, + nginx, + nginx-core, + @, diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/generic b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/generic new file mode 100644 index 0000000..a14fc80 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/generic @@ -0,0 +1,73 @@ +#!/bin/sh +# version 20221215 + +# generic test that only verifies that nginx is running with the given +# libnginx-... module +# - after installation +# - after nginx reload +# - after nginx restart + +EX=0 +CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null" + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +echo -n "curl after installation: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx reload ... " +if invoke-rc.d nginx reload; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + + +echo -n "curl after reload: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +echo -n "nginx restart ... " +if invoke-rc.d nginx restart; then + echo "OK" +else + EX=1 + echo "FAILED" +fi +sleep 5 + +echo -n "curl after restart: http status=" +if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then + echo "OK" +else + EX=1 + echo "FAILED" +fi + +if [ ${EX} -ne 0 ]; then + echo "=== journalctl ===" + journalctl -n all -xu nginx.service || : + + echo "=== error.log ===" + if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then + head -n 50 /var/log/nginx/error.log + echo '...' + tail -n 50 /var/log/nginx/error.log + else + cat /var/log/nginx/error.log + fi +fi + +exit ${EX} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/setifempty b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/setifempty new file mode 100644 index 0000000..6aee6f3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/tests/setifempty @@ -0,0 +1,36 @@ +#!/bin/sh +set -e + +cat < "/etc/nginx/sites-enabled/default" +server { + listen 80 default_server; + + location /setifempty { + set_if_empty \$var aaa; + set_if_empty \$var bbb; + if (\$var = aaa ) { + return 200; + } + return 500; + } +} +EOF + +exp="response_code: 200" + +nginx -t +invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; } + +out=`curl --fail -w "response_code: %{http_code}\n" http://127.0.0.1/setifempty` + +if [ x"${out}" != x"${exp}" ]; then + echo "output:" + echo "=====================" + echo "${out}" + echo "=====================" + echo "expected output:" + echo "=====================" + echo "${exp}" + echo "=====================" + exit 1 +fi diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/upstream/metadata b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/upstream/metadata new file mode 100644 index 0000000..fe767d2 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/openresty/set-misc-nginx-module/issues +Bug-Submit: https://github.com/openresty/set-misc-nginx-module/issues/new +Repository-Browse: https://github.com/openresty/set-misc-nginx-module diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/debian/watch b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/watch new file mode 100644 index 0000000..b6d7cc0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/debian/watch @@ -0,0 +1,6 @@ +version=4 +opts="\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\ +" \ +https://github.com/openresty/set-misc-nginx-module/tags \ +(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ddebug.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ddebug.h new file mode 100644 index 0000000..aaa6fef --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ddebug.h @@ -0,0 +1,74 @@ +#ifndef DDEBUG_H +#define DDEBUG_H + +#include +#include + +#if defined(DDEBUG) && (DDEBUG) + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) fprintf(stderr, "set_misc *** "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) + +# else + +#include +#include + +#include + +static ngx_inline void +dd(const char *fmt, ...) { +} + +# endif + +#else + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) + +# else + +#include + +static ngx_inline void +dd(const char *fmt, ...) { +} + +# endif + +#endif + +#if defined(DDEBUG) && (DDEBUG) + +#define dd_check_read_event_handler(r) \ + dd("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#define dd_check_write_event_handler(r) \ + dd("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + +#define dd_check_read_event_handler(r) +#define dd_check_write_event_handler(r) + +#endif + +#endif /* DDEBUG_H */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.c new file mode 100644 index 0000000..c56c7ba --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.c @@ -0,0 +1,263 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include + +#include "ngx_http_set_base32.h" +#include "ngx_http_set_misc_module.h" + + +#define base32_encoded_length(len) ((((len)+4)/5)*8) +#define base32_decoded_length(len) ((((len)+7)/8)*5) + + +static void encode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, + ngx_flag_t padding, ngx_str_t *alphabet); +static int decode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, + u_char *basis32); + + +ngx_int_t +ngx_http_set_misc_encode_base32(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + size_t len; + u_char *p; + u_char *src, *dst; + + ngx_http_set_misc_loc_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_set_misc_module); + + len = base32_encoded_length(v->len); + + dd("estimated dst len: %d", (int) len); + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + src = v->data; dst = p; + + encode_base32(v->len, src, &len, dst, conf->base32_padding, + &conf->base32_alphabet); + + res->data = p; + res->len = len; + + dd("res (len %d): %.*s", (int) res->len, (int) res->len, res->data); + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_misc_decode_base32(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + size_t len; + u_char *p; + u_char *src, *dst; + int ret; + + ngx_http_set_misc_loc_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_set_misc_module); + + len = base32_decoded_length(v->len); + + dd("estimated dst len: %d", (int) len); + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + src = v->data; dst = p; + + ret = decode_base32(v->len, src, &len, dst, conf->basis32); + + if (ret == 0 /* OK */) { + res->data = p; + res->len = len; + + return NGX_OK; + } + + /* failed to decode */ + + res->data = NULL; + res->len = 0; + + return NGX_OK; +} + + +/* See the implementation in src/core/ngx_string.c's + * ngx_(encode|decode)_base64() for details. */ + +static void +encode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, + ngx_flag_t padding, ngx_str_t *alphabet) +{ + unsigned char *basis32 = alphabet->data; + + size_t len; + u_char *s; + u_char *d; + + len = slen; + s = src; + d = dst; + + while (len > 4) { + *d++ = basis32[s[0] >> 3]; + *d++ = basis32[((s[0] & 0x07) << 2) | (s[1] >> 6)]; + *d++ = basis32[(s[1] >> 1) & 0x1f]; + *d++ = basis32[((s[1] & 1) << 4) | (s[2] >> 4)]; + *d++ = basis32[((s[2] & 0x0f) << 1) | (s[3] >> 7)]; + *d++ = basis32[(s[3] >> 2) & 0x1f]; + *d++ = basis32[((s[3] & 0x03) << 3) | (s[4] >> 5)]; + *d++ = basis32[s[4] & 0x1f]; + + s += 5; + len -= 5; + } + + if (len) { + *d++ = basis32[s[0] >> 3]; + + if (len == 1) { + /* 1 byte left */ + *d++ = basis32[(s[0] & 0x07) << 2]; + + /* pad six '='s to the end */ + if (padding) { + *d++ = '='; + *d++ = '='; + *d++ = '='; + *d++ = '='; + *d++ = '='; + } + + } else { + *d++ = basis32[((s[0] & 0x07) << 2) | (s[1] >> 6)]; + *d++ = basis32[(s[1] >> 1) & 0x1f]; + + if (len == 2) { + /* 2 bytes left */ + *d++ = basis32[(s[1] & 1) << 4]; + + /* pad four '='s to the end */ + if (padding) { + *d++ = '='; + *d++ = '='; + *d++ = '='; + } + + } else { + *d++ = basis32[((s[1] & 1) << 4) | (s[2] >> 4)]; + + if (len == 3) { + /* 3 bytes left */ + *d++ = basis32[(s[2] & 0x0f) << 1]; + + if (padding) { + /* pad three '='s to the end */ + *d++ = '='; + *d++ = '='; + } + + } else { + /* 4 bytes left */ + *d++ = basis32[((s[2] & 0x0f) << 1) | (s[3] >> 7)]; + *d++ = basis32[(s[3] >> 2) & 0x1f]; + *d++ = basis32[(s[3] & 0x03) << 3]; + + /* pad one '=' to the end */ + } + } + } + + if (padding) { + *d++ = '='; + } + } + + *dlen = (size_t) (d - dst); +} + + +static int +decode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, + u_char *basis32) +{ + size_t len, mod; + u_char *s = src; + u_char *d = dst; + + for (len = 0; len < slen; len++) { + if (s[len] == '=') { + break; + } + + if (basis32[s[len]] == 77) { + return -1; + } + } + + mod = len % 8; + + if (mod == 1 || mod == 3 || mod == 6) { + /* bad Base32 digest length */ + return -1; + } + + while (len > 7) { + *d++ = (basis32[s[0]] << 3) | ((basis32[s[1]] >> 2) & 0x07); + + *d++ = ((basis32[s[1]] & 0x03) << 6) | (basis32[s[2]] << 1) | + ((basis32[s[3]] >> 4) & 1); + + *d++ = ((basis32[s[3]] & 0x0f) << 4) | ((basis32[s[4]] >> 1) & 0x0f); + + *d++ = ((basis32[s[4]] & 1) << 7) | ((basis32[s[5]] & 0x1f) << 2) | + ((basis32[s[6]] >> 3) & 0x03); + *d++ = ((basis32[s[6]] & 0x07) << 5) | (basis32[s[7]] & 0x1f); + + s += 8; + len -= 8; + } + + if (len) { + /* 2 bytes left */ + *d++ = (basis32[s[0]] << 3) | ((basis32[s[1]] >> 2) & 0x07); + + if (len > 2) { + /* 4 bytes left */ + *d++ = ((basis32[s[1]] & 0x03) << 6) | ((basis32[s[2]] & 0x1f) << 1) + | ((basis32[s[3]] >> 4) & 1); + + if (len > 4) { + /* 5 bytes left */ + *d++ = ((basis32[s[3]] & 0x0f) << 4) | + ((basis32[s[4]] >> 1) & 0x0f); + + if (len > 5) { + /* 7 bytes left */ + *d++ = ((basis32[s[4]] & 1) << 7) | + ((basis32[s[5]] & 0x1f) << 2) | + ((basis32[s[6]] >> 3) & 0x03); + } + } + } + } + + *dlen = (size_t) (d - dst); + + return 0; +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.h new file mode 100644 index 0000000..68ca277 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base32.h @@ -0,0 +1,18 @@ +#ifndef NGX_HTTP_SET_BASE32 +#define NGX_HTTP_SET_BASE32 + + +#include +#include +#include + + +ngx_int_t ngx_http_set_misc_encode_base32(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_decode_base32(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +#endif /* NGX_HTTP_SET_BASE32 */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.c new file mode 100644 index 0000000..8666ad8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.c @@ -0,0 +1,48 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_base64.h" + + +ngx_int_t +ngx_http_set_misc_set_decode_base64(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_str_t src; + + src.len = v->len; + src.data = v->data; + + res->len = ngx_base64_decoded_length(v->len); + ndk_palloc_re(res->data, r->pool, res->len); + + if (ngx_decode_base64(res, &src) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_decode_base64: invalid value"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_misc_set_encode_base64(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_str_t src; + + src.len = v->len; + src.data = v->data; + + res->len = ngx_base64_encoded_length(v->len); + ndk_palloc_re(res->data, r->pool, res->len); + + ngx_encode_base64(res, &src); + + return NGX_OK; +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.h new file mode 100644 index 0000000..6594c77 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64.h @@ -0,0 +1,10 @@ +#include +#include +#include + +ngx_int_t ngx_http_set_misc_set_encode_base64(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_set_decode_base64(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.c new file mode 100644 index 0000000..f1426ad --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.c @@ -0,0 +1,50 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_base64url.h" + + +ngx_int_t +ngx_http_set_misc_set_decode_base64url(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + + ngx_str_t src; + + src.len = v->len; + src.data = v->data; + + res->len = ngx_base64_decoded_length(v->len); + ndk_palloc_re(res->data, r->pool, res->len); + + if (ngx_decode_base64url(res, &src) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_decode_base64url: invalid value"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_misc_set_encode_base64url(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + + ngx_str_t src; + + src.len = v->len; + src.data = v->data; + + res->len = ngx_base64_encoded_length(v->len); + ndk_palloc_re(res->data, r->pool, res->len); + + ngx_encode_base64url(res, &src); + + return NGX_OK; +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.h new file mode 100644 index 0000000..6ccf63b --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_base64url.h @@ -0,0 +1,10 @@ +#include +#include +#include + +ngx_int_t ngx_http_set_misc_set_encode_base64url(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_set_decode_base64url(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.c new file mode 100644 index 0000000..f4c80a1 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.c @@ -0,0 +1,48 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_default_value.h" + + +ngx_int_t +ngx_http_set_misc_set_if_empty(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_http_variable_value_t *cur_v, *default_v; + + cur_v = &v[0]; + default_v = &v[1]; + + if (cur_v->not_found || cur_v->len == 0) { + res->data = default_v->data; + res->len = default_v->len; + + return NGX_OK; + } + + res->data = cur_v->data; + res->len = cur_v->len; + + return NGX_OK; +} + + +char * +ngx_http_set_if_empty(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ndk_set_var_t filter; + + value = cf->args->elts; + + filter.type = NDK_SET_VAR_MULTI_VALUE; + filter.func = (void *) ngx_http_set_misc_set_if_empty; + filter.size = 2; + filter.data = NULL; + + return ndk_set_var_multi_value_core(cf, &value[1], &value[1], &filter); +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.h new file mode 100644 index 0000000..5bf5168 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_default_value.h @@ -0,0 +1,15 @@ +#include +#include +#include + +#ifndef NGX_HTTP_SET_DEFAULT_VALUE +#define NGX_HTTP_SET_DEFAULT_VALUE + + +char *ngx_http_set_if_empty(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +ngx_int_t ngx_http_set_misc_set_if_empty(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +#endif /* NGX_HTTP_SET_DEFAULT_VALUE */ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.c new file mode 100644 index 0000000..a09f8da --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.c @@ -0,0 +1,210 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_escape_uri.h" +#include "ngx_string.h" + + +static uintptr_t ngx_escape_uri_patched(u_char *dst, u_char *src, size_t size, + ngx_uint_t type); + + +ngx_int_t +ngx_http_set_misc_escape_uri(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + size_t len; + uintptr_t escape; + u_char *src, *dst; + + if (v->len == 0) { + res->len = 0; + res->data = NULL; + return NGX_OK; + } + + src = v->data; + + dd("before escape:%.*s", v->len, v->data); + escape = 2 * ngx_escape_uri_patched(NULL, src, v->len, NGX_ESCAPE_URI); + /* len = v->len + 2 * ngx_escape_uri(NULL, src, v->len, NGX_ESCAPE_URI); */ + len = escape + v->len; + dd("escaped string len:%zu", len); + + dst = ngx_palloc(r->pool, len); + + if (dst == NULL) { + return NGX_ERROR; + } + + if (escape == 0) { + ngx_memcpy(dst, src, len); + dd("escape == 0"); + + } else { + ngx_escape_uri_patched(dst, src, v->len, NGX_ESCAPE_URI); + } + + res->data = dst; + res->len = len; + + dd("after eacape:%.*s", (int) res->len, res->data); + + return NGX_OK; +} + + +static uintptr_t +ngx_escape_uri_patched(u_char *dst, u_char *src, size_t size, ngx_uint_t type) +{ + ngx_uint_t n; + uint32_t *escape; + static u_char hex[] = "0123456789ABCDEF"; + + /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ + + static uint32_t uri[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xfc00886d, /* 1111 1100 0000 0000 1000 1000 0110 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x78000000, /* 0111 1000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xa8000000, /* 1010 1000 0000 0000 0000 0000 0000 0000 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */ + + static uint32_t args[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x80000829, /* 1000 0000 0000 0000 0000 1000 0010 1001 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */ + + static uint32_t html[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* " ", """, "%", "'", %00-%1F, %7F-%FF */ + + static uint32_t refresh[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* " ", "%", %00-%1F */ + + static uint32_t memcached[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + }; + + /* mail_auth is the same as memcached */ + + static uint32_t *map[] = + { uri, args, html, refresh, memcached, memcached }; + + + escape = map[type]; + + if (dst == NULL) { + + /* find the number of the characters to be escaped */ + + n = 0; + + while (size) { + if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + n++; + } + + src++; + size--; + } + + return (uintptr_t) n; + } + + while (size) { + if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + *dst++ = '%'; + *dst++ = hex[*src >> 4]; + *dst++ = hex[*src & 0xf]; + src++; + + } else { + *dst++ = *src++; + } + + size--; + } + + return (uintptr_t) dst; +} + + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.h new file mode 100644 index 0000000..b8564bd --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_escape_uri.h @@ -0,0 +1,10 @@ +#ifndef NGX_HTTP_SET_ESCAPE_URI +#define NGX_HTTP_SET_ESCAPE_URI + + +ngx_int_t +ngx_http_set_misc_escape_uri(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v); + + +#endif /* NGX_HTTP_SET_ESCAPE_URI */ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.c new file mode 100644 index 0000000..59ad606 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.c @@ -0,0 +1,83 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_set_hash.h" + +#if NGX_HAVE_SHA1 +#include "ngx_sha1.h" + +#ifndef SHA_DIGEST_LENGTH +#define SHA_DIGEST_LENGTH 20 +#endif + +#endif + +#include "ngx_md5.h" + + +#ifndef MD5_DIGEST_LENGTH +#define MD5_DIGEST_LENGTH 16 +#endif + +enum { +#if NGX_HAVE_SHA1 + SHA_HEX_LENGTH = SHA_DIGEST_LENGTH * 2, +#endif + MD5_HEX_LENGTH = MD5_DIGEST_LENGTH * 2 +}; + + +#if NGX_HAVE_SHA1 +ngx_int_t +ngx_http_set_misc_set_sha1(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + u_char *p; + ngx_sha1_t sha; + u_char sha_buf[SHA_DIGEST_LENGTH]; + + p = ngx_palloc(r->pool, SHA_HEX_LENGTH); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_sha1_init(&sha); + ngx_sha1_update(&sha, v->data, v->len); + ngx_sha1_final(sha_buf, &sha); + + ngx_hex_dump(p, sha_buf, sizeof(sha_buf)); + + res->data = p; + res->len = SHA_HEX_LENGTH; + + return NGX_OK; +} +#endif + + +ngx_int_t +ngx_http_set_misc_set_md5(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + u_char *p; + ngx_md5_t md5; + u_char md5_buf[MD5_DIGEST_LENGTH]; + + p = ngx_palloc(r->pool, MD5_HEX_LENGTH); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_md5_init(&md5); + ngx_md5_update(&md5, v->data, v->len); + ngx_md5_final(md5_buf, &md5); + + ngx_hex_dump(p, md5_buf, sizeof(md5_buf)); + + res->data = p; + res->len = MD5_HEX_LENGTH; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.h new file mode 100644 index 0000000..db3a558 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hash.h @@ -0,0 +1,15 @@ +#ifndef NGX_HTTP_SET_HASH_H +#define NGX_HTTP_SET_HASH_H + + +#include "ngx_http_set_misc_module.h" + + +ngx_int_t ngx_http_set_misc_set_sha1(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +ngx_int_t ngx_http_set_misc_set_md5(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +#endif /* NGX_HTTP_SET_HASH_H */ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.c new file mode 100644 index 0000000..391dd35 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.c @@ -0,0 +1,141 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include "ngx_http_set_hashed_upstream.h" + + +ngx_uint_t +ngx_http_set_misc_apply_distribution(ngx_log_t *log, ngx_uint_t hash, + ndk_upstream_list_t *ul, ngx_http_set_misc_distribution_t type) +{ + switch (type) { + case ngx_http_set_misc_distribution_modula: + return (uint32_t) hash % (uint32_t) ul->nelts; + + default: + ngx_log_error(NGX_LOG_ERR, log, 0, "apply_distribution: " + "unknown distribution: %d", type); + + return 0; + } + + /* impossible to reach here */ +} + + +ngx_int_t +ngx_http_set_misc_set_hashed_upstream(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v, void *data) +{ + ngx_str_t **u; + ndk_upstream_list_t *ul = data; + ngx_str_t ulname; + ngx_uint_t hash, index; + ngx_http_variable_value_t *key; + + if (ul == NULL) { + ulname.data = v->data; + ulname.len = v->len; + + dd("ulname: %.*s", (int) ulname.len, ulname.data); + + ul = ndk_get_upstream_list(ndk_http_get_main_conf(r), + ulname.data, ulname.len); + + if (ul == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_hashed_upstream: upstream list \"%V\" " + "not defined yet", &ulname); + return NGX_ERROR; + } + + key = v + 1; + + } else { + key = v; + } + + if (ul->nelts == 0) { + res->data = NULL; + res->len = 0; + + return NGX_OK; + } + + u = ul->elts; + + dd("upstream list: %d upstreams found", (int) ul->nelts); + + if (ul->nelts == 1) { + dd("only one upstream found in the list"); + + res->data = u[0]->data; + res->len = u[0]->len; + + return NGX_OK; + } + + dd("key: \"%.*s\"", key->len, key->data); + + hash = ngx_hash_key_lc(key->data, key->len); + + index = ngx_http_set_misc_apply_distribution(r->connection->log, hash, ul, + ngx_http_set_misc_distribution_modula); + + res->data = u[index]->data; + res->len = u[index]->len; + + return NGX_OK; +} + + +char * +ngx_http_set_hashed_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ndk_set_var_t filter; + ngx_uint_t n; + ngx_str_t *var; + ngx_str_t *ulname; + ndk_upstream_list_t *ul; + ngx_str_t *v; + + value = cf->args->elts; + + var = &value[1]; + ulname = &value[2]; + + n = ngx_http_script_variables_count(ulname); + + filter.func = (void *) ngx_http_set_misc_set_hashed_upstream; + + if (n) { + /* upstream list name contains variables */ + v = &value[2]; + filter.size = 2; + filter.data = NULL; + filter.type = NDK_SET_VAR_MULTI_VALUE_DATA; + + return ndk_set_var_multi_value_core(cf, var, v, &filter); + } + + ul = ndk_get_upstream_list(ndk_http_conf_get_main_conf(cf), + ulname->data, ulname->len); + if (ul == NULL) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "set_hashed_upstream: upstream list \"%V\" " + "not defined yet", ulname); + return NGX_CONF_ERROR; + } + + v = &value[3]; + + filter.size = 1; + filter.data = ul; + filter.type = NDK_SET_VAR_VALUE_DATA; + + return ndk_set_var_value_core(cf, var, v, &filter); +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.h new file mode 100644 index 0000000..8b7caa7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hashed_upstream.h @@ -0,0 +1,27 @@ +#ifndef NGX_HTTP_SET_HASHED_UPSTREAM +#define NGX_HTTP_SET_HASHED_UPSTREAM + + +#include +#include +#include +#include + + +typedef enum { + ngx_http_set_misc_distribution_modula, + ngx_http_set_misc_distribution_random /* XXX not used */ +} ngx_http_set_misc_distribution_t; + + +ngx_uint_t ngx_http_set_misc_apply_distribution(ngx_log_t *log, ngx_uint_t hash, + ndk_upstream_list_t *ul, ngx_http_set_misc_distribution_t type); + +char *ngx_http_set_hashed_upstream(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +ngx_int_t ngx_http_set_misc_set_hashed_upstream(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v, void *data); + + +#endif /* NGX_HTTP_SET_HASHED_UPSTREAM */ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.c new file mode 100644 index 0000000..6900650 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.c @@ -0,0 +1,62 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_hex.h" + + +ngx_int_t +ngx_http_set_misc_set_decode_hex(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + u_char *p; + ngx_int_t n; + ngx_uint_t i; + size_t len; + + if (v->len % 2 != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_decode_hex: invalid value"); + return NGX_ERROR; + } + + p = v->data; + len = v->len >> 1; + + res->data = ngx_palloc(r->pool, len); + if (res->data == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < len; i++) { + n = ngx_hextoi(p, 2); + if (n == NGX_ERROR || n > 255) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_decode_hex: invalid value"); + return NGX_ERROR; + } + + p += 2; + res->data[i] = (u_char) n; + } + + res->len = len; + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_misc_set_encode_hex(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + res->len = v->len << 1; + res->data = ngx_palloc(r->pool, res->len); + if (res->data == NULL) { + return NGX_ERROR; + } + + ngx_hex_dump(res->data, v->data, v->len); + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.h new file mode 100644 index 0000000..e8b77e0 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hex.h @@ -0,0 +1,9 @@ +#include +#include +#include + +ngx_int_t ngx_http_set_misc_set_decode_hex(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_set_encode_hex(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.c new file mode 100644 index 0000000..139c0c7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.c @@ -0,0 +1,62 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include + +#include "ngx_http_set_hmac.h" +#include +#include + + +/* this function's implementation is partly borrowed from + * https://github.com/anomalizer/ngx_aws_auth */ +static ngx_int_t +ngx_http_set_misc_set_hmac(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v, const EVP_MD *evp_md) +{ + ngx_http_variable_value_t *secret, *string_to_sign; + unsigned int md_len = 0; + unsigned char md[EVP_MAX_MD_SIZE]; + + secret = v; + string_to_sign = v + 1; + + dd("secret=%.*s, string_to_sign=%.*s", (int) secret->len, secret->data, + (int) string_to_sign->len, string_to_sign->data); + + HMAC(evp_md, secret->data, secret->len, string_to_sign->data, + string_to_sign->len, md, &md_len); + + /* defensive test if there is something wrong with openssl */ + if (md_len == 0 || md_len > EVP_MAX_MD_SIZE) { + res->len = 0; + return NGX_ERROR; + } + + res->len = md_len; + ndk_palloc_re(res->data, r->pool, md_len); + + ngx_memcpy(res->data, + &md, + md_len); + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_misc_set_hmac_sha1(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + return ngx_http_set_misc_set_hmac(r, res, v, EVP_sha1()); +} + + +ngx_int_t +ngx_http_set_misc_set_hmac_sha256(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + return ngx_http_set_misc_set_hmac(r, res, v, EVP_sha256()); +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.h new file mode 100644 index 0000000..fe02ea4 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_hmac.h @@ -0,0 +1,9 @@ +#include +#include +#include + +ngx_int_t ngx_http_set_misc_set_hmac_sha1(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_set_hmac_sha256(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.c new file mode 100644 index 0000000..fa1c703 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.c @@ -0,0 +1,110 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include + + +#ifndef NGX_HTTP_SET_MISC_FMT_DATE_LEN +#define NGX_HTTP_SET_MISC_FMT_DATE_LEN 256 +#endif + + +ngx_int_t +ngx_http_set_local_today(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + time_t now; + ngx_tm_t tm; + u_char *p; + + /*t = ngx_timeofday();*/ + + now = ngx_time(); + + ngx_gmtime(now + ngx_cached_time->gmtoff * 60, &tm); + + dd("tm.ngx_tm_hour:%d", tm.ngx_tm_hour); + + p = ngx_palloc(r->pool, sizeof("yyyy-mm-dd") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(p, "%04d-%02d-%02d", tm.ngx_tm_year, tm.ngx_tm_mon, + tm.ngx_tm_mday); + + res->data = p; + res->len = sizeof("yyyy-mm-dd") - 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_formatted_gmt_time(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + time_t now; + u_char *p; + struct tm tm; + + if (v->not_found || v->len == 0) { + res->data = NULL; + res->len = 0; + return NGX_OK; + } + + now = ngx_time(); + ngx_libc_gmtime(now, &tm); + + p = ngx_palloc(r->pool, NGX_HTTP_SET_MISC_FMT_DATE_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + res->len = strftime((char *) p, NGX_HTTP_SET_MISC_FMT_DATE_LEN, + (char *) v->data, &tm); + if (res->len == 0) { + return NGX_ERROR; + } + + res->data = p; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_formatted_local_time(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + time_t now; + u_char *p; + struct tm tm; + + if (v->not_found || v->len == 0) { + res->data = NULL; + res->len = 0; + return NGX_OK; + } + + now = ngx_time(); + ngx_libc_localtime(now, &tm); + + p = ngx_palloc(r->pool, NGX_HTTP_SET_MISC_FMT_DATE_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + res->len = strftime((char *) p, NGX_HTTP_SET_MISC_FMT_DATE_LEN, + (char *) v->data, &tm); + if (res->len == 0) { + return NGX_ERROR; + } + + res->data = p; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.h new file mode 100644 index 0000000..993431e --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_local_today.h @@ -0,0 +1,13 @@ +#include +#include +#include + + +ngx_int_t ngx_http_set_local_today(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_formatted_gmt_time(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_formatted_local_time(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.c new file mode 100644 index 0000000..3b12b0e --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.c @@ -0,0 +1,586 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_set_misc_module.h" +#include +#include "ngx_http_set_base32.h" +#include "ngx_http_set_default_value.h" +#include "ngx_http_set_hashed_upstream.h" +#include "ngx_http_set_unescape_uri.h" +#include "ngx_http_set_quote_sql.h" +#include "ngx_http_set_quote_json.h" +#include "ngx_http_set_escape_uri.h" +#include "ngx_http_set_local_today.h" +#include "ngx_http_set_hash.h" +#include "ngx_http_set_hex.h" +#include "ngx_http_set_base64.h" +#include "ngx_http_set_base64url.h" +#if NGX_OPENSSL +#include "ngx_http_set_hmac.h" +#endif +#include "ngx_http_set_random.h" +#include "ngx_http_set_secure_random.h" +#include "ngx_http_set_rotate.h" + + +#define NGX_UNESCAPE_URI_COMPONENT 0 +#define BASE32_ALPHABET_LEN 32 + + +static void *ngx_http_set_misc_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_set_misc_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_set_misc_base32_alphabet(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +static ngx_conf_deprecated_t ngx_conf_deprecated_set_misc_base32_padding = { + ngx_conf_deprecated, "set_misc_base32_padding", "set_base32_padding" +}; + + +static ndk_set_var_t ngx_http_set_misc_set_encode_base64_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_encode_base64, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_decode_base64_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_decode_base64, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_encode_base64url_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_encode_base64url, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_decode_base64url_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_decode_base64url, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_decode_hex_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_decode_hex, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_encode_hex_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_encode_hex, + 1, + NULL +}; + + +#if NGX_OPENSSL +static ndk_set_var_t ngx_http_set_misc_set_hmac_sha1_filter = { + NDK_SET_VAR_MULTI_VALUE, + (void *) ngx_http_set_misc_set_hmac_sha1, + 2, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_hmac_sha256_filter = { + NDK_SET_VAR_MULTI_VALUE, + (void *) ngx_http_set_misc_set_hmac_sha256, + 2, + NULL +}; +#endif + + +#ifndef NGX_HTTP_SET_HASH +static ndk_set_var_t ngx_http_set_misc_set_md5_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_md5, + 1, + NULL +}; + + +#if NGX_HAVE_SHA1 +static ndk_set_var_t ngx_http_set_misc_set_sha1_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_sha1, + 1, + NULL +}; +#endif +#endif + + +static ndk_set_var_t ngx_http_set_misc_unescape_uri_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_unescape_uri, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_escape_uri_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_escape_uri, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_decode_base32_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_decode_base32, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_quote_sql_str_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_quote_sql_str, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_quote_pgsql_str_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_quote_pgsql_str, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_quote_json_str_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_quote_json_str, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_encode_base32_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_encode_base32, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_local_today_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_local_today, + 0, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_formatted_gmt_time_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_formatted_gmt_time, + 2, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_formatted_local_time_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_formatted_local_time, + 2, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_random_filter = { + NDK_SET_VAR_MULTI_VALUE, + (void *) ngx_http_set_misc_set_random, + 2, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_secure_random_alphanum_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_secure_random_alphanum, + 1, + NULL +}; + + +static ndk_set_var_t ngx_http_set_misc_set_secure_random_lcalpha_filter = { + NDK_SET_VAR_VALUE, + (void *) ngx_http_set_misc_set_secure_random_lcalpha, + 1, + NULL +}; + + +static ngx_command_t ngx_http_set_misc_commands[] = { + { ngx_string ("set_encode_base64"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_encode_base64_filter + }, + { ngx_string ("set_decode_base64"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_decode_base64_filter + }, + { ngx_string ("set_encode_base64url"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_encode_base64url_filter + }, + { ngx_string ("set_decode_base64url"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_decode_base64url_filter + }, + { ngx_string ("set_decode_hex"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_decode_hex_filter + }, + { ngx_string ("set_encode_hex"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_encode_hex_filter + }, +#if NGX_OPENSSL + { ngx_string ("set_hmac_sha1"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3, + ndk_set_var_multi_value, + 0, + 0, + &ngx_http_set_misc_set_hmac_sha1_filter + }, + { ngx_string ("set_hmac_sha256"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3, + ndk_set_var_multi_value, + 0, + 0, + &ngx_http_set_misc_set_hmac_sha256_filter + }, +#endif +#ifndef NGX_HTTP_SET_HASH + { ngx_string ("set_md5"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_md5_filter + }, +#if NGX_HAVE_SHA1 + { + ngx_string ("set_sha1"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_sha1_filter + }, +#endif +#endif + { + ngx_string ("set_unescape_uri"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_unescape_uri_filter + }, + { + ngx_string ("set_escape_uri"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_escape_uri_filter + }, + { + ngx_string ("set_quote_sql_str"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_quote_sql_str_filter + }, + { + ngx_string ("set_quote_pgsql_str"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_quote_pgsql_str_filter + }, + { + ngx_string ("set_quote_json_str"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_quote_json_str_filter + }, + { + ngx_string ("set_if_empty"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE2, + ngx_http_set_if_empty, + 0, + 0, + NULL + }, + { + ngx_string("set_hashed_upstream"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3, + ngx_http_set_hashed_upstream, + 0, + 0, + NULL + }, + { + /* this is now deprecated; use set_base32_padding instead */ + ngx_string("set_misc_base32_padding"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_set_misc_loc_conf_t, base32_padding), + &ngx_conf_deprecated_set_misc_base32_padding, + }, + { + ngx_string("set_base32_padding"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_set_misc_loc_conf_t, base32_padding), + NULL + }, + { + ngx_string("set_base32_alphabet"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_http_set_misc_base32_alphabet, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_set_misc_loc_conf_t, base32_alphabet), + NULL + }, + { + ngx_string("set_encode_base32"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_encode_base32_filter + }, + { + ngx_string("set_decode_base32"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_decode_base32_filter + }, + { + ngx_string("set_local_today"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_local_today_filter + }, + { + ngx_string("set_formatted_gmt_time"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE2, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_formatted_gmt_time_filter + }, + { + ngx_string("set_formatted_local_time"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE2, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_formatted_local_time_filter + }, + { ngx_string ("set_random"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3, + ndk_set_var_multi_value, + 0, + 0, + &ngx_http_set_misc_set_random_filter + }, + { ngx_string ("set_secure_random_alphanum"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_secure_random_alphanum_filter + }, + { ngx_string ("set_secure_random_lcalpha"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, + ndk_set_var_value, + 0, + 0, + &ngx_http_set_misc_set_secure_random_lcalpha_filter + }, + { ngx_string ("set_rotate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3, + ngx_http_set_rotate, + 0, + 0, + NULL + }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_set_misc_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_set_misc_create_loc_conf, /* create location configuration */ + ngx_http_set_misc_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_set_misc_module = { + NGX_MODULE_V1, + &ngx_http_set_misc_module_ctx, /* module context */ + ngx_http_set_misc_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 +}; + + +void * +ngx_http_set_misc_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_set_misc_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_set_misc_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->base32_padding = NGX_CONF_UNSET; + conf->base32_alphabet.data = NULL; + conf->base32_alphabet.len = 0; + conf->current = NGX_CONF_UNSET; + + return conf; +} + + +char * +ngx_http_set_misc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_uint_t i; + + ngx_http_set_misc_loc_conf_t *prev = parent; + ngx_http_set_misc_loc_conf_t *conf = child; + + ngx_conf_merge_value(conf->base32_padding, prev->base32_padding, 1); + + ngx_conf_merge_str_value(conf->base32_alphabet, prev->base32_alphabet, + "0123456789abcdefghijklmnopqrstuv"); + + ngx_conf_merge_value(conf->current, prev->current, NGX_CONF_UNSET); + + for (i = 0; i < BASE32_ALPHABET_LEN; i++) { + conf->basis32[conf->base32_alphabet.data[i]] = (u_char) i; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_set_misc_base32_alphabet(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_str_t *value; + + value = cf->args->elts; + + if (value[1].len != BASE32_ALPHABET_LEN) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"set_base32_alphabet\" directive takes an " + "alphabet of %uz bytes but %d expected", + value[1].len, BASE32_ALPHABET_LEN); + return NGX_CONF_ERROR; + } + + return ngx_conf_set_str_slot(cf, cmd, conf); +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.h new file mode 100644 index 0000000..49b3c9e --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_misc_module.h @@ -0,0 +1,30 @@ +#ifndef NGX_HTTP_SET_MISC_MODULE_H +#define NGX_HTTP_SET_MISC_MODULE_H + + +#include +#include +#include +#include + + +#ifndef NGX_HAVE_SHA1 +# if (nginx_version >= 1011002) +# define NGX_HAVE_SHA1 1 +# endif +#endif + + +typedef struct { + ngx_flag_t base32_padding; + ngx_str_t base32_alphabet; + u_char basis32[256]; + ngx_int_t current; /* for set_rotate */ +} ngx_http_set_misc_loc_conf_t; + + +extern ngx_module_t ngx_http_set_misc_module; + + +#endif /* NGX_HTTP_SET_MISC_MODULE_H */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.c new file mode 100644 index 0000000..4bed13c --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.c @@ -0,0 +1,165 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_quote_json.h" + +ngx_int_t +ngx_http_set_misc_quote_json_str(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + size_t len; + u_char *p; + size_t escape; + + if (v->not_found || v->len == 0) { + res->data = (u_char *) "null"; + res->len = sizeof("null") - 1; + return NGX_OK; + } + + escape = ngx_http_set_misc_escape_json_str(NULL, v->data, v->len); + + len = sizeof("''") - 1 + + v->len + + escape; + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + res->data = p; + res->len = len; + + *p++ = '\"'; + + if (escape == 0) { + p = ngx_copy(p, v->data, v->len); + + } else { + p = (u_char *) ngx_http_set_misc_escape_json_str(p, v->data, v->len); + } + + *p++ = '\"'; + + if (p != res->data + res->len) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_quote_sql_str: buffer error"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +uintptr_t +ngx_http_set_misc_escape_json_str(u_char *dst, u_char *src, size_t size) +{ + ngx_uint_t n; + + static u_char hex[] = "0123456789abcdef"; + + if (dst == NULL) { + /* find the number of characters to be escaped */ + + n = 0; + + while (size) { + /* UTF-8 char has high bit of 1 */ + if ((*src & 0x80) == 0) { + switch (*src) { + case '\r': + case '\n': + case '\\': + case '"': + case '\f': + case '\b': + case '\t': + n++; + break; + default: + if (*src < 32) { + n += sizeof("\\u00xx") - 2; + } + + break; + } + } + + src++; + size--; + } + + return (uintptr_t) n; + } + + while (size) { + if ((*src & 0x80) == 0) { + switch (*src) { + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + break; + + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + break; + + case '\\': + *dst++ = '\\'; + *dst++ = '\\'; + break; + + case '"': + *dst++ = '\\'; + *dst++ = '"'; + break; + + case '\f': + *dst++ = '\\'; + *dst++ = 'f'; + break; + + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + break; + + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + break; + + default: + if (*src < 32) { /* control chars */ + *dst++ = '\\'; + *dst++ = 'u'; + *dst++ = '0'; + *dst++ = '0'; + *dst++ = hex[*src >> 4]; + *dst++ = hex[*src & 0x0f]; + + } else { + *dst++ = *src; + } + + break; + } /* switch */ + + src++; + + } else { + *dst++ = *src++; + } + + size--; + } + + return (uintptr_t) dst; +} + + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.h new file mode 100644 index 0000000..1bf55e2 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_json.h @@ -0,0 +1,16 @@ +#ifndef NGX_HTTP_SET_QUOTE_JSON_H +#define NGX_HTTP_SET_QUOTE_JSON_H + + +#include +#include +#include + + +ngx_int_t ngx_http_set_misc_quote_json_str(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); +uintptr_t ngx_http_set_misc_escape_json_str(u_char *dst, u_char *src, + size_t size); + + +#endif /* NGX_HTTP_SET_QUOTE_JSON_H */ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.c new file mode 100644 index 0000000..8d78348 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.c @@ -0,0 +1,382 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_quote_sql.h" + + +static ngx_int_t ngx_http_pg_utf_escape(ngx_http_request_t *r, ngx_str_t *res); +static ngx_int_t ngx_http_pg_utf_islegal(const unsigned char *s, ngx_int_t len); +static ngx_int_t ngx_http_pg_utf_mblen(const unsigned char *s); + + +ngx_int_t +ngx_http_set_misc_quote_pgsql_str(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + u_char *pstr; + ngx_int_t length; + + if (v->not_found || v->len ==0) { + res->data = (u_char *) "''"; + res->len = sizeof("''") - 1; + return NGX_OK; + } + + ngx_http_set_misc_quote_sql_str(r, res, v); + length = res->len; + + pstr = ngx_palloc(r->pool, length + 1); + if (pstr == NULL) { + return NGX_ERROR; + } + + *pstr = 'E'; + memcpy(pstr + 1, res->data, length); + res->data = pstr; + res->len = length + 1; + + if (ngx_http_pg_utf_islegal(res->data, res->len)) { + return NGX_OK; + } + + if (ngx_http_pg_utf_escape(r, res) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_pg_utf_mblen(const unsigned char *s) +{ + int len; + + if ((*s & 0x80) == 0) + len = 1; + else if ((*s & 0xe0) == 0xc0) + len = 2; + else if ((*s & 0xf0) == 0xe0) + len = 3; + else if ((*s & 0xf8) == 0xf0) + len = 4; +#ifdef NOT_USED + else if ((*s & 0xfc) == 0xf8) + len = 5; + else if ((*s & 0xfe) == 0xfc) + len = 6; +#endif + else + len = 1; + return len; +} + + +static ngx_int_t +ngx_http_pg_utf_islegal(const unsigned char *s, ngx_int_t len) +{ + ngx_int_t mblen; + ngx_int_t slen; + u_char a; + + slen = len; + + while (slen > 0) { + mblen = ngx_http_pg_utf_mblen(s); + if (slen < mblen) { + return 0; + } + + switch (mblen) { + + case 4: + a = *(s + 3); + if (a < 0x80 || a > 0xBF) { + return 0; + } + + break; + + case 3: + a = *(s + 2); + if (a < 0x80 || a > 0xBF) { + return 0; + } + + break; + + case 2: + a = *(s + 1); + + switch (*s) { + + case 0xE0: + if (a < 0xA0 || a > 0xBF) { + return 0; + } + + break; + + case 0xED: + if (a < 0x80 || a > 0x9F) { + return 0; + } + + break; + + case 0xF0: + if (a < 0x90 || a > 0xBF) { + return 0; + } + + break; + + case 0xF4: + if (a < 0x80 || a > 0x8F) { + return 0; + } + + break; + + default: + if (a < 0x80 || a > 0xBF) { + return 0; + } + + break; + } + + break; + + case 1: + a = *s; + if (a >= 0x80 && a < 0xC2) { + return 0; + } + + if (a > 0xF4) { + return 0; + } + + break; + + default: + return 0; + } + + s += mblen; + slen -= mblen; + } + + return 1; +} + + +static ngx_int_t +ngx_http_pg_utf_escape(ngx_http_request_t *r, ngx_str_t *res) +{ + ngx_str_t *result; + ngx_int_t l, count; + u_char *d, *p, *p1; + + l = res->len; + d = res->data; + result = res; + count = 0; + + while (l-- > 0) { + if (*d & 0x80) { + count += 4; + } + + d++; + count++; + } + + d = res->data; + l = res->len; + + p = ngx_palloc(r->pool, count); + if (p == NULL) { + return NGX_ERROR; + } + + p1 = p; + while (l-- > 0) { + if ((*d & 0x80)) { + *p++ = '\\'; + *p++ = '\\'; + *p++ = (*d >> 6) + '0'; + *p++ = ((*d >> 3) & 07) + '0'; + *p++ = (*d & 07) + '0'; + + } else { + *p++ = *d; + } + + d++; + } + + result->len = count; + result->data = p1; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_set_misc_quote_sql_str(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + size_t len; + u_char *p; + size_t escape; + + if (v->not_found || v->len == 0) { + res->data = (u_char *) "''"; + res->len = sizeof("''") - 1; + return NGX_OK; + } + + escape = ngx_http_set_misc_escape_sql_str(NULL, v->data, v->len); + + len = sizeof("''") - 1 + v->len + escape; + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + res->data = p; + res->len = len; + + *p++ = '\''; + + if (escape == 0) { + p = ngx_copy(p, v->data, v->len); + + } else { + p = (u_char *) ngx_http_set_misc_escape_sql_str(p, v->data, v->len); + } + + *p++ = '\''; + + if (p != res->data + res->len) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_quote_sql_str: buffer error"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +uintptr_t +ngx_http_set_misc_escape_sql_str(u_char *dst, u_char *src, size_t size) +{ + ngx_uint_t n; + + if (dst == NULL) { + /* find the number of chars to be escaped */ + n = 0; + while (size) { + /* the highest bit of all the UTF-8 chars + * is always 1 */ + if ((*src & 0x80) == 0) { + switch (*src) { + case '\0': + case '\b': + case '\n': + case '\r': + case '\t': + case '\\': + case '\'': + case '"': + case '$': + case 26: /* \Z */ + n++; + break; + default: + break; + } + } + + src++; + size--; + } + + return (uintptr_t) n; + } + + while (size) { + if ((*src & 0x80) == 0) { + switch (*src) { + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + break; + + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + break; + + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + break; + + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + break; + + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + break; + + case '\\': + *dst++ = '\\'; + *dst++ = '\\'; + break; + + case '\'': + *dst++ = '\\'; + *dst++ = '\''; + break; + + case '"': + *dst++ = '\\'; + *dst++ = '"'; + break; + + case '$': + *dst++ = '\\'; + *dst++ = '$'; + break; + + case 26: + *dst++ = '\\'; + *dst++ = 'Z'; + break; + + default: + *dst++ = *src; + break; + } + + } else { + *dst++ = *src; + } + + src++; + size--; + } /* while (size) */ + + return (uintptr_t) dst; +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.h new file mode 100644 index 0000000..c631dd7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_quote_sql.h @@ -0,0 +1,21 @@ +#ifndef NGX_SET_QUOTE_SQL_H +#define NGX_SET_QUOTE_SQL_H + + +#include +#include +#include + + +uintptr_t ngx_http_set_misc_escape_sql_str(u_char *dst, u_char *src, + size_t size); + +ngx_int_t ngx_http_set_misc_quote_sql_str(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_quote_pgsql_str(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +#endif /* NGX_SET_QUOTE_SQL_H */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.c new file mode 100644 index 0000000..c223633 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.c @@ -0,0 +1,57 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include +#include "ngx_http_set_random.h" +#include + + +ngx_int_t +ngx_http_set_misc_set_random(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_http_variable_value_t *rand_from, *rand_to; + ngx_int_t int_from, int_to, tmp, random; + + rand_from = v; + rand_to = v + 1; + + int_from = ngx_atoi(rand_from->data, rand_from->len); + if (int_from == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_random: bad \"from\" argument: %v", rand_from); + return NGX_ERROR; + } + + int_to = ngx_atoi(rand_to->data, rand_to->len); + if (int_to == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_random: bad \"to\" argument: %v", rand_to); + return NGX_ERROR; + } + + if (int_from > int_to) { + tmp = int_from; + int_from = int_to; + int_to = tmp; + } + + random = rand() % (int_to - int_from + 1) + int_from; + + res->data = ngx_palloc(r->pool, NGX_INT_T_LEN); + if (res->data == NULL) { + return NGX_ERROR; + } + + res->len = ngx_sprintf(res->data, "%i", random) - res->data; + + /* Set all required params */ + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.h new file mode 100644 index 0000000..88cffdc --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_random.h @@ -0,0 +1,12 @@ +#ifndef NGX_SET_RANDOM_H +#define NGX_SET_RANDOM_H + +#include +#include +#include + +ngx_int_t ngx_http_set_misc_set_random(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +#endif /* NGX_SET_RANDOM_H */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.c new file mode 100644 index 0000000..b83dee7 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.c @@ -0,0 +1,113 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_rotate.h" +#include "ngx_http_set_misc_module.h" +#include + + +ngx_int_t +ngx_http_set_misc_set_rotate(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_http_variable_value_t *rotate_from, *rotate_to, *rotate_num; + ngx_int_t int_from, int_to, tmp, int_current; + + ngx_http_set_misc_loc_conf_t *conf; + + rotate_num = &v[0]; + rotate_from = &v[1]; + rotate_to = &v[2]; + + int_from = ngx_atoi(rotate_from->data, rotate_from->len); + if (int_from == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_rotate: bad \"from\" argument value: \"%v\"", + rotate_from); + return NGX_ERROR; + } + + int_to = ngx_atoi(rotate_to->data, rotate_to->len); + if (int_to == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_rotate: bad \"to\" argument value: \"%v\"", + rotate_to); + return NGX_ERROR; + } + + if (int_from > int_to) { + tmp = int_from; + int_from = int_to; + int_to = tmp; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_set_misc_module); + + dd("current value not found: %d", (int) rotate_num->not_found); + + if (rotate_num->len == 0) { + if (conf->current != NGX_CONF_UNSET) { + int_current = conf->current; + + } else { + int_current = int_from - 1; + } + + } else { + + int_current = ngx_atoi(rotate_num->data, rotate_num->len); + if (int_current == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_rotate: bad current value: \"%v\"", rotate_num); + + if (conf->current != NGX_CONF_UNSET) { + int_current = conf->current; + + } else { + int_current = int_from - 1; + } + } + } + + int_current++; + + if (int_current > int_to || int_current < int_from) { + int_current = int_from; + } + + conf->current = int_current; + + res->data = ngx_palloc(r->pool, NGX_INT_T_LEN); + if (res->data == NULL) { + return NGX_ERROR; + } + + res->len = ngx_sprintf(res->data, "%i", int_current) - res->data; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +char * +ngx_http_set_rotate(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ndk_set_var_t filter; + + value = cf->args->elts; + + filter.type = NDK_SET_VAR_MULTI_VALUE; + filter.func = (void *) ngx_http_set_misc_set_rotate; + filter.size = 3; + filter.data = NULL; + + return ndk_set_var_multi_value_core(cf, &value[1], &value[1], &filter); +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.h new file mode 100644 index 0000000..429204c --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_rotate.h @@ -0,0 +1,18 @@ +#ifndef NGX_HTTP_SET_MISC_ROTATE_H +#define NGX_HTTP_SET_MISC_ROTATE_H + + +#include +#include +#include + + +char *ngx_http_set_rotate(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +ngx_int_t ngx_http_set_misc_set_rotate(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +#endif /* NGX_HTTP_SET_MISC_ROTATE_H */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.c new file mode 100644 index 0000000..a07efe8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.c @@ -0,0 +1,104 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include +#include "ngx_http_set_secure_random.h" +#include + + +enum { + MAX_RANDOM_STRING = 64, + ALPHANUM = 1, + LCALPHA = 2 +}; + + +static ngx_int_t +ngx_http_set_misc_set_secure_random_common(int alphabet_type, + ngx_http_request_t *r, ngx_str_t *res, ngx_http_variable_value_t *v); + + +ngx_int_t +ngx_http_set_misc_set_secure_random_alphanum(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v) +{ + return ngx_http_set_misc_set_secure_random_common(ALPHANUM, r, res, v); +} + + +ngx_int_t +ngx_http_set_misc_set_secure_random_lcalpha(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v) +{ + return ngx_http_set_misc_set_secure_random_common(LCALPHA, r, res, v); +} + + +static ngx_int_t +ngx_http_set_misc_set_secure_random_common(int alphabet_type, + ngx_http_request_t *r, ngx_str_t *res, ngx_http_variable_value_t *v) +{ + static u_char alphabet[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + u_char entropy[MAX_RANDOM_STRING]; + u_char output[MAX_RANDOM_STRING]; + ngx_int_t length, i; + ngx_fd_t fd; + ssize_t n; + + length = ngx_atoi(v->data, v->len); + + if (length == NGX_ERROR || length < 1 || length > MAX_RANDOM_STRING) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_random: bad \"length\" argument: %v", v); + return NGX_ERROR; + } + + fd = ngx_open_file((u_char *) "/dev/urandom", NGX_FILE_RDONLY, + NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_secure_random: could not open /dev/urandom"); + return NGX_ERROR; + } + + n = ngx_read_fd(fd, entropy, length); + if (n != length) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_secure_random: could not read all %i byte(s) from " + "/dev/urandom", length); + ngx_close_file(fd); + return NGX_ERROR; + } + + ngx_close_file(fd); + + for (i = 0; i < length; i++) { + if (alphabet_type == LCALPHA) { + output[i] = entropy[i] % 26 + 'a'; + + } else { + output[i] = alphabet[ entropy[i] % (sizeof alphabet - 1) ]; + } + } + + res->data = ngx_palloc(r->pool, length); + if (res->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(res->data, output, length); + + res->len = length; + + /* set all required params */ + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.h new file mode 100644 index 0000000..d65129e --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_secure_random.h @@ -0,0 +1,15 @@ +#ifndef NGX_SET_SECURE_RANDOM_H +#define NGX_SET_SECURE_RANDOM_H + +#include +#include +#include + +ngx_int_t ngx_http_set_misc_set_secure_random_alphanum(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +ngx_int_t ngx_http_set_misc_set_secure_random_lcalpha(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + +#endif /* NGX_SET_SECURE_RANDOM_H */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.c b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.c new file mode 100644 index 0000000..3ae1d0a --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.c @@ -0,0 +1,184 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_set_unescape_uri.h" + +#define NGX_UNESCAPE_URI_COMPONENT 0 + + +static void ngx_unescape_uri_patched(u_char **dst, u_char **src, size_t size, + ngx_uint_t type); + + +ngx_int_t +ngx_http_set_misc_unescape_uri(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + size_t len; + u_char *p; + u_char *src, *dst; + + /* the unescaped string can only be smaller */ + len = v->len; + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + src = v->data; dst = p; + + ngx_unescape_uri_patched(&dst, &src, v->len, NGX_UNESCAPE_URI_COMPONENT); + + if (src != v->data + v->len) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_unescape_uri: input data not consumed completely"); + return NGX_ERROR; + } + + res->data = p; + res->len = dst - p; + + return NGX_OK; +} + + +/* XXX we also decode '+' to ' ' */ +static void +ngx_unescape_uri_patched(u_char **dst, u_char **src, size_t size, + ngx_uint_t type) +{ + u_char *d, *s, ch, c, decoded; + enum { + sw_usual = 0, + sw_quoted, + sw_quoted_second + } state; + + d = *dst; + s = *src; + + state = 0; + decoded = 0; + + while (size--) { + + ch = *s++; + + switch (state) { + case sw_usual: + if (ch == '?' + && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT))) + { + *d++ = ch; + goto done; + } + + if (ch == '%') { + state = sw_quoted; + break; + } + + if (ch == '+') { + *d++ = ' '; + break; + } + + *d++ = ch; + break; + + case sw_quoted: + + if (ch >= '0' && ch <= '9') { + decoded = (u_char) (ch - '0'); + state = sw_quoted_second; + break; + } + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + decoded = (u_char) (c - 'a' + 10); + state = sw_quoted_second; + break; + } + + /* the invalid quoted character */ + + state = sw_usual; + + *d++ = ch; + + break; + + case sw_quoted_second: + + state = sw_usual; + + if (ch >= '0' && ch <= '9') { + ch = (u_char) ((decoded << 4) + ch - '0'); + + if (type & NGX_UNESCAPE_REDIRECT) { + if (ch > '%' && ch < 0x7f) { + *d++ = ch; + break; + } + + *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1); + + break; + } + + *d++ = ch; + + break; + } + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + ch = (u_char) ((decoded << 4) + c - 'a' + 10); + + if (type & NGX_UNESCAPE_URI) { + if (ch == '?') { + *d++ = ch; + goto done; + } + + *d++ = ch; + break; + } + + if (type & NGX_UNESCAPE_REDIRECT) { + if (ch == '?') { + *d++ = ch; + goto done; + } + + if (ch > '%' && ch < 0x7f) { + *d++ = ch; + break; + } + + *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1); + break; + } + + *d++ = ch; + + break; + } + + /* the invalid quoted character */ + + break; + } + } + +done: + + *dst = d; + *src = s; +} + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.h b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.h new file mode 100644 index 0000000..59e9a93 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/src/ngx_http_set_unescape_uri.h @@ -0,0 +1,16 @@ + +#ifndef NGX_HTTP_SET_UNESCAPE_URI +#define NGX_HTTP_SET_UNESCAPE_URI + + +#include +#include +#include + + +ngx_int_t ngx_http_set_misc_unescape_uri(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +#endif /* NGX_HTTP_SET_UNESCAPE_URI */ + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/base32.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base32.t new file mode 100644 index 0000000..2efa731 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base32.t @@ -0,0 +1,556 @@ +# vi:filetype= + +use Test::Nginx::Socket; + +repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: base32 (5 bytes) +--- config + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +c5h66p35 +abcde + + + +=== TEST 2: base32 (1 byte) +--- config + location /bar { + set $a '!'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +44====== +! + + + +=== TEST 3: base32 (1 byte) - not in-place editing +--- config + location /bar { + set $a '!'; + set_encode_base32 $a $a; + set_decode_base32 $b $a; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +44====== +! + + + +=== TEST 4: base32 (hello world) +--- config + location /bar { + set $a '"hello, world!\nhiya"'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m6888ad1knio92 +"hello, world! +hiya" + + + +=== TEST 5: base32 (0 bytes left) +--- config + set_base32_padding on; + location /bar { + set $a '"hello, world!"'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892 + + + +=== TEST 6: base32 (6 bytes padded) +--- config + set_base32_padding on; + location /bar { + set $a '"hello, world!"a'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c4====== + + + +=== TEST 7: base32 (4 bytes left) +--- config + set_base32_padding on; + location /bar { + set $a '"hello, world!"ab'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c5h0==== + + + +=== TEST 8: base32 (3 bytes left) +--- config + set_base32_padding on; + location /bar { + set $a '"hello, world!"abc'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c5h66=== + + + +=== TEST 9: base32 (1 bytes left) +--- config + set_base32_padding on; + location /bar { + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c5h66p0= + + + +=== TEST 10: base32 standard alphabet (5 bytes) +--- config + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +MFRGGZDF +abcde + + + +=== TEST 11: base32 standard alphabet (1 byte) +--- config + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '!'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +EE====== +! + + + +=== TEST 12: base32 standard alphabet (1 byte) - not in-place editing +--- config + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '!'; + set_encode_base32 $a $a; + set_decode_base32 $b $a; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +EE====== +! + + + +=== TEST 13: base32 standard alphabet (hello world) +--- config + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!\nhiya"'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIIKNBUXSYJC +"hello, world! +hiya" + + + +=== TEST 14: base32 standard alphabet (0 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJC + + + +=== TEST 15: base32 standard alphabet (6 bytes padded) +--- config + set_base32_padding on; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"a'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCME====== + + + +=== TEST 16: base32 standard alphabet (4 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"ab'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCMFRA==== + + + +=== TEST 17: base32 standard alphabet (3 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"abc'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCMFRGG=== + + + +=== TEST 18: base32 standard alphabet (1 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCMFRGGZA= + + + +=== TEST 19: base32 custom alphabet (5 bytes) +--- config + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +qjvkk3hj +abcde + + + +=== TEST 20: base32 custom alphabet (1 byte) +--- config + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '!'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +ii====== +! + + + +=== TEST 21: base32 custom alphabet (1 byte) - not in-place editing +--- config + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '!'; + set_encode_base32 $a $a; + set_decode_base32 $b $a; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +ii====== +! + + + +=== TEST 22: base32 custom alphabet (hello world) +--- config + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '"hello, world!\nhiya"'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmmorfy1w2ng +"hello, world! +hiya" + + + +=== TEST 23: base32 custom alphabet (0 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '"hello, world!"'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmng + + + +=== TEST 24: base32 custom alphabet (6 bytes padded) +--- config + set_base32_padding on; + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '"hello, world!"a'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqi====== + + + +=== TEST 25: base32 custom alphabet (4 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '"hello, world!"ab'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqjve==== + + + +=== TEST 26: base32 custom alphabet (3 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '"hello, world!"abc'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqjvkk=== + + + +=== TEST 27: base32 custom alphabet (1 bytes left) +--- config + set_base32_padding on; + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + location /bar { + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqjvkk3e= + + + +=== TEST 28: use set_base32_alphabet in location +--- config + set_base32_padding on; + location /bar { + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789"; + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqjvkk3e= + + + +=== TEST 29: one byte less in set_base32_alphabet +--- config + set_base32_padding on; + location /bar { + set_base32_alphabet "efghijklmnopqrstuvwxyz012345678"; + set $a '"hello, world!"abcd?\/.;'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqjvkk3e= +--- must_die +--- error_log eval +qr/\[emerg\] .*? "set_base32_alphabet" directive takes an alphabet of 31 bytes but 32 expected/ + + + +=== TEST 30: one byte more in set_base32_alphabet +--- config + set_base32_padding on; + location /bar { + set_base32_alphabet "efghijklmnopqrstuvwxyz0123456789A"; + set $a '"hello, world!"abcd?\/.;'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +inyko5hqr60ge75tsn0kmmngqjvkk3e= +--- must_die +--- error_log eval +qr/\[emerg\] .*? "set_base32_alphabet" directive takes an alphabet of 33 bytes but 32 expected/ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/base32_no_padding.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base32_no_padding.t new file mode 100644 index 0000000..9330cbf --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base32_no_padding.t @@ -0,0 +1,531 @@ +# vi:filetype= + +use Test::Nginx::Socket; + +repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: base32 (5 bytes) +--- config + set_base32_padding off; + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +c5h66p35 +abcde + + + +=== TEST 2: base32 (1 byte) +--- config + set_base32_padding off; + location /bar { + set $a '!'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +44 +! + + + +=== TEST 3: base32 (1 byte) - not in-place editing +--- config + location /bar { + set_base32_padding off; + set $a '!'; + set_encode_base32 $a $a; + set_decode_base32 $b $a; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +44 +! + + + +=== TEST 4: base32 (hello world) +--- config + set_base32_padding off; + location /bar { + set $a '"hello, world!\nhiya"'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m6888ad1knio92 +"hello, world! +hiya" + + + +=== TEST 5: base32 (0 bytes left) +--- config + set_base32_padding off; + location /bar { + set $a '"hello, world!"'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892 + + + +=== TEST 6: base32 (6 bytes padded) +--- config + set_base32_padding off; + location /bar { + set $a '"hello, world!"a'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c4 + + + +=== TEST 7: base32 (4 bytes left) +--- config + set_base32_padding off; + location /bar { + set $a '"hello, world!"ab'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c5h0 + + + +=== TEST 8: base32 (3 bytes left) +--- config + set_base32_padding off; + location /bar { + set $a '"hello, world!"abc'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c5h66 + + + +=== TEST 9: base32 (1 bytes left) +--- config + set_base32_padding off; + location /bar { + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +49k6ar3cdsm20trfe9m68892c5h66p0 + + + +=== TEST 10: base32 standard alphabet (5 bytes) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +MFRGGZDF +abcde + + + +=== TEST 11: base32 standard alphabet (1 byte) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '!'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +EE +! + + + +=== TEST 12: base32 standard alphabet (1 byte) - not in-place editing +--- config + location /bar { + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + set $a '!'; + set_encode_base32 $a $a; + set_decode_base32 $b $a; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +EE +! + + + +=== TEST 13: base32 standard alphabet (hello world) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!\nhiya"'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIIKNBUXSYJC +"hello, world! +hiya" + + + +=== TEST 14: base32 standard alphabet (0 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJC + + + +=== TEST 15: base32 standard alphabet (6 bytes padded) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"a'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCME + + + +=== TEST 16: base32 standard alphabet (4 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"ab'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCMFRA + + + +=== TEST 17: base32 standard alphabet (3 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"abc'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCMFRGG + + + +=== TEST 18: base32 standard alphabet (1 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + location /bar { + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +EJUGK3DMN4WCA53POJWGIIJCMFRGGZA + + + +=== TEST 19: base32 custom alphabet (5 bytes) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +ohtii2fh +abcde + + + +=== TEST 20: base32 custom alphabet (1 byte) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '!'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +gg +! + + + +=== TEST 21: base32 custom alphabet (1 byte) - not in-place editing +--- config + location /bar { + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + set $a '!'; + set_encode_base32 $a $a; + set_decode_base32 $b $a; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +gg +! + + + +=== TEST 22: base32 custom alphabet (hello world) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '"hello, world!\nhiya"'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +glwim4fop5yec64rqlyikkkmpdwzu1le +"hello, world! +hiya" + + + +=== TEST 23: base32 custom alphabet (0 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '"hello, world!"'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +glwim4fop5yec64rqlyikkle + + + +=== TEST 24: base32 custom alphabet (6 bytes padded) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '"hello, world!"a'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +glwim4fop5yec64rqlyikkleog + + + +=== TEST 25: base32 custom alphabet (4 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '"hello, world!"ab'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +glwim4fop5yec64rqlyikkleohtc + + + +=== TEST 26: base32 custom alphabet (3 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '"hello, world!"abc'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +glwim4fop5yec64rqlyikkleohtii + + + +=== TEST 27: base32 custom alphabet (1 bytes left) +--- config + set_base32_padding off; + set_base32_alphabet "cdefghijklmnopqrstuvwxyz12345678"; + location /bar { + set $a '"hello, world!"abcd'; + set_encode_base32 $a; + + echo $a; + } +--- request + GET /bar +--- response_body +glwim4fop5yec64rqlyikkleohtii2c + + + +=== TEST 28: deprecated set_misc_base32_padding +--- config + set_misc_base32_padding off; + location /bar { + set $a 'abcde'; + set_encode_base32 $a; + set $b $a; + set_decode_base32 $b; + + echo $a; + echo $b; + } +--- request + GET /bar +--- response_body +c5h66p35 +abcde diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/base64.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base64.t new file mode 100644 index 0000000..5dd5af8 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base64.t @@ -0,0 +1,40 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: base64 encode +--- config + location /bar { + set_encode_base64 $out "abcde"; + echo $out; + } +--- request + GET /bar +--- response_body +YWJjZGU= + + + +=== TEST 2: base64 decode +--- config + location /bar { + set_decode_base64 $out "YWJjZGU="; + echo $out; + } +--- request + GET /bar +--- response_body +abcde diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/base64url.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base64url.t new file mode 100644 index 0000000..fc71d59 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/base64url.t @@ -0,0 +1,40 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: base64url encode +--- config + location /bar { + set_encode_base64url $out "?b> repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: set if empty +--- config + location /foo { + set $a 32; + set_if_empty $a 56; + echo $a; + + set_if_empty $b 72; + echo $b; + } +--- request +GET /foo +--- response_body +32 +72 + + + +=== TEST 2: set if empty +--- config + location /foo { + set $bar $arg_bar; + set_if_empty $bar 15; + echo $bar; + + set $bah $arg_bah; + set_if_empty $bah 25; + echo $bah; + } +--- request +GET /foo?bar=71 +--- response_body +71 +25 + + + +=== TEST 3: set if empty +--- config + location /foo { + set $bar $arg_bar; + set_if_empty $bar 15; + echo $bar; + + set $bah $arg_bah; + set_if_empty $bah 25; + echo $bah; + } +--- request +GET /foo?bar= +--- response_body +15 +25 + + + +=== TEST 4: set if empty (using arg_xxx directly) +buggy? +--- config + location /foo { + set_if_empty $arg_bar 15; + echo $arg_bar; + + set_if_empty $arg_bah 25; + echo $arg_bah; + } +--- request +GET /foo?bar=71 +--- response_body +71 +25 diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/escape-uri.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/escape-uri.t new file mode 100644 index 0000000..7cbd067 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/escape-uri.t @@ -0,0 +1,139 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: set escape uri +--- config + location /foo { + set $foo "hello world"; + set_escape_uri $foo $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +hello%20world + + + +=== TEST 2: set escape uri(in-place) +--- config + location /foo { + set $foo "hello world"; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +hello%20world + + + +=== TEST 3: blank string +--- config + location /foo { + set $foo ""; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body eval +"\n" + + + +=== TEST 4: blank string(in place) +--- config + location /foo { + set $foo ""; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body eval +"\n" + + + +=== TEST 5: eacape chinese character +--- config + location /foo { + set $foo "你好"; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +%E4%BD%A0%E5%A5%BD + + + +=== TEST 6: escape long string +--- config + location /foo { + set $foo "法规及饿哦物权法家哦低价非结果哦我二期界 附件饿哦武器 积分饿哦为契机佛i 该软件哦气氛 份额叫我起 国无二君哦气氛为界非ieowq结果哦而完全附件 份额叫我iqfjeowiqgjeriowqfjpdjfosadijfoiasdjf 附件饿哦武器界 份额叫我起界份额叫我起哦ifjefejwioq附件饿哦武器界非风格及去哦根据份额叫我起哦界份额为契机哦乳房阿基完全哦igqtewqo个人就去哦ieorjwrewqoi日哦额外起今天诶哦我亲热为特务前日哦我而哥特完全哦iijrtewmkdf 服务鄂潜江哦irewq"; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +%E6%B3%95%E8%A7%84%E5%8F%8A%E9%A5%BF%E5%93%A6%E7%89%A9%E6%9D%83%E6%B3%95%E5%AE%B6%E5%93%A6%E4%BD%8E%E4%BB%B7%E9%9D%9E%E7%BB%93%E6%9E%9C%E5%93%A6%E6%88%91%E4%BA%8C%E6%9C%9F%E7%95%8C%20%20%E9%99%84%E4%BB%B6%E9%A5%BF%E5%93%A6%E6%AD%A6%E5%99%A8%20%20%E7%A7%AF%E5%88%86%E9%A5%BF%E5%93%A6%E4%B8%BA%E5%A5%91%E6%9C%BA%E4%BD%9Bi%20%E8%AF%A5%E8%BD%AF%E4%BB%B6%E5%93%A6%E6%B0%94%E6%B0%9B%20%20%E4%BB%BD%E9%A2%9D%E5%8F%AB%E6%88%91%E8%B5%B7%20%E5%9B%BD%E6%97%A0%E4%BA%8C%E5%90%9B%E5%93%A6%E6%B0%94%E6%B0%9B%E4%B8%BA%E7%95%8C%E9%9D%9Eieowq%E7%BB%93%E6%9E%9C%E5%93%A6%E8%80%8C%E5%AE%8C%E5%85%A8%E9%99%84%E4%BB%B6%20%20%E4%BB%BD%E9%A2%9D%E5%8F%AB%E6%88%91iqfjeowiqgjeriowqfjpdjfosadijfoiasdjf%20%E9%99%84%E4%BB%B6%E9%A5%BF%E5%93%A6%E6%AD%A6%E5%99%A8%E7%95%8C%20%E4%BB%BD%E9%A2%9D%E5%8F%AB%E6%88%91%E8%B5%B7%E7%95%8C%E4%BB%BD%E9%A2%9D%E5%8F%AB%E6%88%91%E8%B5%B7%E5%93%A6ifjefejwioq%E9%99%84%E4%BB%B6%E9%A5%BF%E5%93%A6%E6%AD%A6%E5%99%A8%E7%95%8C%E9%9D%9E%E9%A3%8E%E6%A0%BC%E5%8F%8A%E5%8E%BB%E5%93%A6%E6%A0%B9%E6%8D%AE%E4%BB%BD%E9%A2%9D%E5%8F%AB%E6%88%91%E8%B5%B7%E5%93%A6%E7%95%8C%E4%BB%BD%E9%A2%9D%E4%B8%BA%E5%A5%91%E6%9C%BA%E5%93%A6%E4%B9%B3%E6%88%BF%E9%98%BF%E5%9F%BA%E5%AE%8C%E5%85%A8%E5%93%A6igqtewqo%E4%B8%AA%E4%BA%BA%E5%B0%B1%E5%8E%BB%E5%93%A6ieorjwrewqoi%E6%97%A5%E5%93%A6%E9%A2%9D%E5%A4%96%E8%B5%B7%E4%BB%8A%E5%A4%A9%E8%AF%B6%E5%93%A6%E6%88%91%E4%BA%B2%E7%83%AD%E4%B8%BA%E7%89%B9%E5%8A%A1%E5%89%8D%E6%97%A5%E5%93%A6%E6%88%91%E8%80%8C%E5%93%A5%E7%89%B9%E5%AE%8C%E5%85%A8%E5%93%A6iijrtewmkdf%20%E6%9C%8D%E5%8A%A1%E9%84%82%E6%BD%9C%E6%B1%9F%E5%93%A6irewq + + + +=== TEST 7: no need to escape +--- config + location /foo { + set $foo 'welcometotheworldofnginx'; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +welcometotheworldofnginx + + + +=== TEST 8: fixed ngx_escape_uri issues: + and / should also be escaped +--- config + location /foo { + set $foo '+/='; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +%2B%2F%3D + + + +=== TEST 9: fixed ngx_escape_uri issues: / {} : & [] and more +--- config + location /foo { + set $foo '"a/b={}:<>;&[]\\^'; + set_escape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +%22a%2Fb%3D%7B%7D%3A%3C%3E%3B%26%5B%5D%5C%5E diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/formatted-time.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/formatted-time.t new file mode 100644 index 0000000..9b0fc73 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/formatted-time.t @@ -0,0 +1,84 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; +use POSIX qw(strftime); + +my $fmt="%a %b %e %H:%M:%S %Y"; + +our $str_local = (strftime $fmt, localtime time()).'|'.(strftime $fmt, localtime time()+1).'|'.(strftime $fmt, localtime time()+2); + +our $str_gmt = (strftime $fmt, gmtime time()).'|'.(strftime $fmt, gmtime time()+1).'|'.(strftime $fmt, gmtime time()+2); + +repeat_each(2); + +plan tests => repeat_each() * 2 * blocks(); + +log_level('warn'); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: local time format +--- config + location /foo { + set_formatted_local_time $today "%a %b %e %H:%M:%S %Y"; + echo $today; + } +--- request +GET /foo +--- response_body_like eval: $main::str_local + + + +=== TEST 2: GMT time format +--- config + location /bar { + set_formatted_gmt_time $today "%a %b %e %H:%M:%S %Y"; + echo $today; + } +--- request +GET /bar +--- response_body_like eval: $main::str_gmt + + + +=== TEST 3: set_formatted_gmt_time (empty formatter) +--- config + location /bar { + set_formatted_gmt_time $today ""; + echo "[$today]"; + } +--- request +GET /bar +--- response_body +[] + + + +=== TEST 4: set_formatted_local_time (empty formatter) +--- config + location /bar { + set_formatted_local_time $today ""; + echo "[$today]"; + } +--- request +GET /bar +--- response_body +[] + + + +=== TEST 5: set_formatted_local_time (constant formatter) +--- config + location /bar { + set_formatted_local_time $today "hello world"; + echo "[$today]"; + } +--- request +GET /bar +--- response_body +[hello world] diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/hash.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hash.t new file mode 100644 index 0000000..a9c884b --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hash.t @@ -0,0 +1,94 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: sha1 hello (copy) +--- config + location /sha1 { + set_sha1 $a hello; + echo $a; + } +--- request +GET /sha1 +--- response_body +aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d + + + +=== TEST 2: sha1 hello (in-place) +--- config + location /sha1 { + set $a hello; + set_sha1 $a; + echo $a; + } +--- request +GET /sha1 +--- response_body +aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d + + + +=== TEST 3: sha1 (empty) +--- config + location /sha1 { + set_sha1 $a ""; + echo $a; + } +--- request +GET /sha1 +--- response_body +da39a3ee5e6b4b0d3255bfef95601890afd80709 + + + +=== TEST 4: md5 hello (copy) +--- config + location /md5 { + set_md5 $a hello; + echo $a; + } +--- request +GET /md5 +--- response_body +5d41402abc4b2a76b9719d911017c592 + + + +=== TEST 5: md5 hello (in-place) +--- config + location /md5 { + set $a hello; + set_md5 $a; + echo $a; + } +--- request +GET /md5 +--- response_body +5d41402abc4b2a76b9719d911017c592 + + + +=== TEST 6: md5 (empty) +--- config + location /md5 { + set_md5 $a ""; + echo $a; + } +--- request +GET /md5 +--- response_body +d41d8cd98f00b204e9800998ecf8427e diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/hashed-upstream.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hashed-upstream.t new file mode 100644 index 0000000..fdebd15 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hashed-upstream.t @@ -0,0 +1,70 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +#master_on(); +#log_level("warn"); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: set hashed upstream +buggy? +--- config + upstream_list universe moon sun earth; + location /foo { + set_hashed_upstream $backend universe $arg_id; + echo $backend; + } + location /main { + echo_location_async /foo; + echo_location_async /foo?id=hello; + echo_location_async /foo?id=world; + echo_location_async /foo?id=larry; + echo_location_async /foo?id=audreyt; + } +--- request +GET /main +--- response_body +moon +sun +moon +earth +earth + + + +=== TEST 2: set hashed upstream (use var for upstream_list name) +buggy? +--- config + upstream_list universe moon sun earth; + location /foo { + set $list_name universe; + set_hashed_upstream $backend $list_name $arg_id; + echo $backend; + } + location /main { + echo_location_async /foo; + echo_location_async /foo?id=hello; + echo_location_async /foo?id=world; + echo_location_async /foo?id=larry; + echo_location_async /foo?id=audreyt; + } +--- request +GET /main +--- response_body +moon +sun +moon +earth +earth diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/hex.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hex.t new file mode 100644 index 0000000..ae28105 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hex.t @@ -0,0 +1,57 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: hex encode +--- config + location /bar { + set_encode_hex $out "abcde"; + echo $out; + } +--- request + GET /bar +--- response_body +6162636465 + + + +=== TEST 2: hex decode +--- config + location /bar { + set_decode_hex $out "6162636465"; + echo $out; + } +--- request + GET /bar +--- response_body +abcde + + + +=== TEST 3: hex encode (chinese) +--- config + location /bar { + set $raw "章亦春"; + set_encode_hex $digest $raw; + set_decode_hex $hex $digest; + echo $digest; + echo $hex; + } +--- request + GET /bar +--- response_body +e7aba0e4baa6e698a5 +章亦春 diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/hmac.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hmac.t new file mode 100644 index 0000000..5353eca --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/hmac.t @@ -0,0 +1,78 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: hmac_sha1 +--- config + location /bar { + set $secret 'thisisverysecretstuff'; + set $string_to_sign 'some string we want to sign'; + set_hmac_sha1 $signature $secret $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } +--- request + GET /bar +--- response_body +R/pvxzHC4NLtj7S+kXFg/NePTmk= + + + +=== TEST 2: hmac_sha1 empty vars +--- config + location /bar { + set $secret ''; + set $string_to_sign ''; + set_hmac_sha1 $signature $secret $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } +--- request + GET /bar +--- response_body ++9sdGxiqbAgyS31ktx+3Y3BpDh0= + + + +=== TEST 3: hmac_sha256 +--- config + location /bar { + set $secret 'thisisverysecretstuff'; + set $string_to_sign 'some string we want to sign'; + set_hmac_sha256 $signature $secret $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } +--- request + GET /bar +--- response_body +4pU3GRQrKKIoeLb9CqYsavHE2l6Hx+KMmRmesU+Cfrs= + + + +=== TEST 4: hmac_sha256 empty vars +--- config + location /bar { + set $secret ''; + set $string_to_sign ''; + set_hmac_sha256 $signature $secret $string_to_sign; + set_encode_base64 $signature $signature; + echo $signature; + } +--- request + GET /bar +--- response_body +thNnmggU2ex3L5XXeMNfxf8Wl8STcVZTxscSFEKSxa0= diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/local-today.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/local-today.t new file mode 100644 index 0000000..7de0968 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/local-today.t @@ -0,0 +1,29 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +my ($sec, $min, $hour, $mday, $mon, $year) = localtime; + +our $str = sprintf("%04d-%02d-%02d\n", $year + 1900, $mon + 1, $mday); +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +#no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /foo { + set_local_today $today; + echo $today; + } +--- request +GET /foo +--- response_body eval: $main::str diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-json.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-json.t new file mode 100644 index 0000000..8e15def --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-json.t @@ -0,0 +1,69 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: set quote json value +--- config + location /foo { + set $foo "hello\n\r'\"\\"; + set_quote_json_str $foo $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +"hello\n\r'\"\\" + + + +=== TEST 2: set quote json value (in place) +--- config + location /foo { + set $foo "hello\n\r'\"\\"; + set_quote_json_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +"hello\n\r'\"\\" + + + +=== TEST 3: set quote empty json value +--- config + location /foo { + set $foo ""; + set_quote_json_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +null + + + +=== TEST 4: set quote null json value +--- config + location /foo { + set_quote_json_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +null diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-sql.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-sql.t new file mode 100644 index 0000000..bd81a87 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/quote-sql.t @@ -0,0 +1,195 @@ +# vi:filetype= + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: set quote sql value +--- config + location /foo { + set $foo "hello\n\r'\"\\"; + set_quote_sql_str $foo $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +'hello\n\r\'\"\\' + + + +=== TEST 2: set quote sql value (in place) +--- config + location /foo { + set $foo "hello\n\r'\"\\"; + set_quote_sql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +'hello\n\r\'\"\\' + + + +=== TEST 3: set quote empty sql value +--- config + location /foo { + set $foo ""; + set_quote_sql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +'' + + + +=== TEST 4: set quote null sql value +--- config + location /foo { + set_quote_sql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +'' + + + +=== TEST 5: set quote null pgsql value +--- config + location /foo { + set_quote_pgsql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +'' + + + +=== TEST 6: set quote pgsql value +--- config + location /foo { + set $foo "hello\n\r'\"\\"; + set_quote_pgsql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +E'hello\n\r\'\"\\' + + + +=== TEST 7: set quote pgsql valid utf8 value +--- config + location /foo { + set $foo "你好"; + set_quote_pgsql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +E'你好' + + + +=== TEST 8: set quote pgsql invalid utf8 value +--- config + location /foo { + set $foo "你好"; + set_iconv $foo $foo from=utf-8 to=gbk; + set_quote_pgsql_str $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +E'\\304\\343\\272\\303' + + + +=== TEST 9: \0 for mysql +--- config + location /foo { + set_unescape_uri $foo $arg_a; + set_quote_sql_str $foo $foo; + echo $foo; + } +--- request +GET /foo?a=a%00b%00 +--- response_body +'a\0b\0' + + + +=== TEST 10: \b for mysql +--- config + location /foo { + set_unescape_uri $foo $arg_a; + set_quote_sql_str $foo $foo; + echo $foo; + } +--- request +GET /foo?a=a%08b%08 +--- response_body +'a\bb\b' + + + +=== TEST 11: \t for mysql +--- config + location /foo { + set_unescape_uri $foo $arg_a; + set_quote_sql_str $foo $foo; + echo $foo; + } +--- request +GET /foo?a=a%09b%09 +--- response_body +'a\tb\t' + + + +=== TEST 12: \Z for mysql +--- config + location /foo { + set_unescape_uri $foo $arg_a; + set_quote_sql_str $foo $foo; + echo $foo; + } +--- request +GET /foo?a=a%1ab%1a +--- response_body +'a\Zb\Z' + + + +=== TEST 13: set quote sql value +--- config + location /foo { + set_unescape_uri $foo $arg_a; + set_quote_sql_str $foo $foo; + echo $foo; + } +--- request +GET /foo?a=$$ +--- response_body +'\$\$' diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/rand.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/rand.t new file mode 100644 index 0000000..7f042bb --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/rand.t @@ -0,0 +1,168 @@ +# vi:filetype=perl + +use Test::Nginx::Socket; + +repeat_each(100); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /rand { + set $from 5; + set $to 7; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: [5-7] + + + +=== TEST 2: sanity (two digits) +--- config + location /rand { + set $from 35; + set $to 37; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 3[5-7] + + + +=== TEST 3: sanity (two digits, from > to) +--- config + location /rand { + set $from 37; + set $to 35; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 3[5-7] + + + +=== TEST 4: sanity (two digits, from == to) +--- config + location /rand { + set $from 117; + set $to 117; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body +117 + + + +=== TEST 5: negative number not allowed in from arg +--- config + location /rand { + set $from -2; + set $to 4; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 6: negative number not allowed in to arg +--- config + location /rand { + set $from 2; + set $to -4; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 7: empty string not allowed in from arg +--- config + location /rand { + set $from ''; + set $to 4; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 8: empty string not allowed in to arg +--- config + location /rand { + set $from 2; + set $to ''; + set_random $res $from $to; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 9: wrong number of arguments +--- config + location /rand { + set $from 2; + set_random $res $from; + + echo $res; + } +--- request + GET /rand +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- SKIP + + + +=== TEST 10: zero is fine +--- config + location /rand { + set_random $res 0 0; + + echo $res; + } +--- request + GET /rand +--- response_body +0 diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/rotate.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/rotate.t new file mode 100644 index 0000000..2982a71 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/rotate.t @@ -0,0 +1,270 @@ +# vi:filetype= + +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * (3 * blocks()); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /bar { + set $a 1; + set_rotate $a 1 3; + + set $b 2; + set_rotate $b 1 3; + + set $c 3; + set_rotate $c 1 3; + + set $d 0; + set_rotate $d 1 3; + + set $e 1; + set_rotate $e 3 5; + + echo "a = $a"; + echo "b = $b"; + echo "c = $c"; + echo "d = $d"; + echo "e = $e"; + } +--- request + GET /bar +--- response_body +a = 2 +b = 3 +c = 1 +d = 1 +e = 3 +--- no_error_log +[error] + + + +=== TEST 2: bad current value +--- config + location /bar { + set $a abc; + set_rotate $a 1 3; + + echo "a = $a"; + } +--- request + GET /bar +--- response_body_like: ^a = [12]$ +--- error_log +set_rotate: bad current value: "abc" + + + +=== TEST 3: bad "from" value +--- config + location /bar { + set $a 2; + set_rotate $a abc 3; + + echo "a = $a"; + } +--- request + GET /bar +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +set_rotate: bad "from" argument value: "abc" + + + +=== TEST 4: bad "to" argument value +--- config + location /bar { + set $a 2; + set_rotate $a 1 abc; + + echo "a = $a"; + } +--- request + GET /bar +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +set_rotate: bad "to" argument value: "abc" + + + +=== TEST 5: when no current value is given +--- config + location /incr { + set_rotate $a 1 3; + + echo "a = $a"; + } + + location /t { + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + } +--- request + GET /t +--- response_body +a = 1 +a = 2 +a = 3 +a = 1 +a = 2 +a = 3 +--- no_error_log +[error] + + + +=== TEST 6: when no current value is given (starting from 0) +--- config + location /incr { + set_rotate $a 0 2; + + echo "a = $a"; + } + + location /t { + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + } +--- request + GET /t +--- response_body +a = 0 +a = 1 +a = 2 +a = 0 +a = 1 +a = 2 +--- no_error_log +[error] + + + +=== TEST 7: when a non-integer string value is given +--- config + location /incr { + set $a "hello"; + set_rotate $a 0 2; + + echo "a = $a"; + } + + location /t { + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + } +--- request + GET /t +--- response_body +a = 0 +a = 1 +a = 2 +a = 0 +a = 1 +a = 2 +--- error_log +set_rotate: bad current value: "hello" + + + +=== TEST 8: when an empty string value is given +--- config + location /incr { + set $a ""; + set_rotate $a 0 2; + + echo "a = $a"; + } + + location /t { + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + echo_location /incr; + } +--- request + GET /t +--- response_body +a = 0 +a = 1 +a = 2 +a = 0 +a = 1 +a = 2 +--- no_error_log +[error] + + + +=== TEST 9: value persistence is per-location +--- config + location /incr { + set_rotate $a 0 2; + + echo "a = $a"; + } + + location /incr2 { + set_rotate $a 0 2; + + echo "a = $a"; + } + + location /t { + echo_location /incr; + echo_location /incr2; + echo_location /incr; + echo_location /incr2; + echo_location /incr; + echo_location /incr2; + echo_location /incr; + echo_location /incr2; + echo_location /incr; + echo_location /incr2; + echo_location /incr; + echo_location /incr2; + } +--- request + GET /t +--- response_body +a = 0 +a = 0 +a = 1 +a = 1 +a = 2 +a = 2 +a = 0 +a = 0 +a = 1 +a = 1 +a = 2 +a = 2 +--- no_error_log +[error] diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/secure-random.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/secure-random.t new file mode 100644 index 0000000..1f0b4a3 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/secure-random.t @@ -0,0 +1,107 @@ +# vi:filetype= + +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: a 32-character alphanum +--- config + location /alphanum { + set_secure_random_alphanum $res 32; + + echo $res; + } +--- request + GET /alphanum +--- response_body_like: ^[a-zA-Z0-9]{32}$ + + + +=== TEST 2: a 16-character alphanum +--- config + location /alphanum { + set_secure_random_alphanum $res 16; + + echo $res; + } +--- request + GET /alphanum +--- response_body_like: ^[a-zA-Z0-9]{16}$ + + + +=== TEST 3: a 1-character alphanum +--- config + location /alphanum { + set_secure_random_alphanum $res 1; + + echo $res; + } +--- request + GET /alphanum +--- response_body_like: ^[a-zA-Z0-9]{1}$ + + + +=== TEST 4: length less than <= 0 should fail +--- config + location /alphanum { + set_secure_random_alphanum $res 0; + + echo $res; + } +--- request + GET /alphanum +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 5: length less than <= 0 should fail +--- config + location /alphanum { + set_secure_random_alphanum $res -4; + + echo $res; + } +--- request + GET /alphanum +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 6: non-numeric length should fail +--- config + location /alphanum { + set_secure_random_alphanum $res bob; + + echo $res; + } +--- request + GET /alphanum +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + + + +=== TEST 7: a 16-character lcalpha +--- config + location /lcalpha { + set_secure_random_lcalpha $res 16; + + echo $res; + } +--- request + GET /lcalpha +--- response_body_like: ^[a-z]{16}$ diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/t/unescape-uri.t b/modules_deb/libnginx-mod-http-set-misc-0.33/t/unescape-uri.t new file mode 100644 index 0000000..ad52b59 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/t/unescape-uri.t @@ -0,0 +1,58 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(3); + +plan tests => repeat_each() * 2 * blocks(); + +no_long_string(); + +run_tests(); + +#no_diff(); + +__DATA__ + +=== TEST 1: set unescape uri +buggy? +--- config + location /foo { + set $foo "hello%20world"; + set_unescape_uri $foo $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +hello world + + + +=== TEST 2: set unescape uri (in-place) +buggy? +--- config + location /foo { + set $foo "hello%20world"; + set_unescape_uri $foo; + echo $foo; + } +--- request +GET /foo +--- response_body +hello world + + + +=== TEST 3: unescape '+' to ' ' +--- config + location /bar { + set $a 'a+b'; + set_unescape_uri $a; + echo $a; + } +--- request + GET /bar +--- response_body +a b diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/util/build.sh b/modules_deb/libnginx-mod-http-set-misc-0.33/util/build.sh new file mode 100755 index 0000000..dc2bcb6 --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/util/build.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# this file is mostly meant to be used by the author himself. + +root=`pwd` +home=~ +version=$1 +force=$2 + + #--with-cc="gcc46" \ + #--with-ld-opt="-rdynamic" \ + #--with-mail \ + #--with-mail_ssl_module \ + +ngx-build $force $version \ + --with-cc-opt="-I$PCRE_INC -I$OPENSSL_INC" \ + --with-ld-opt="-L$PCRE_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE_LIB:$OPENSSL_LIB" \ + --with-http_ssl_module \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --without-mail_smtp_module \ + --without-http_upstream_ip_hash_module \ + --without-http_empty_gif_module \ + --without-http_memcached_module \ + --without-http_referer_module \ + --without-http_autoindex_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + --add-module=$root/../echo-nginx-module \ + --add-module=$root/../ndk-nginx-module \ + --add-module=$root/../iconv-nginx-module \ + --add-module=$root $opts \ + --with-debug \ + || exit 1 + diff --git a/modules_deb/libnginx-mod-http-set-misc-0.33/valgrind.suppress b/modules_deb/libnginx-mod-http-set-misc-0.33/valgrind.suppress new file mode 100644 index 0000000..470978e --- /dev/null +++ b/modules_deb/libnginx-mod-http-set-misc-0.33/valgrind.suppress @@ -0,0 +1,105 @@ +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_http_init_request +} +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_event_accept +} +{ + + Memcheck:Addr4 + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main +} +{ + + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_calloc + fun:ngx_event_process_init +} +{ + + exp-sgcheck:SorG + fun:ngx_http_variables_init_vars + fun:ngx_http_block +} +{ + + exp-sgcheck:SorG + fun:ngx_conf_parse +} +{ + + exp-sgcheck:SorG + fun:ngx_vslprintf + fun:ngx_log_error_core +} +{ + + exp-sgcheck:SorG + fun:ngx_conf_parse + fun:ngx_http_core_location +} +{ + nginx-core-process-init + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_event_process_init +} +{ + nginx-core-crc32-init + Memcheck:Leak + fun:malloc + fun:ngx_alloc + fun:ngx_crc32_table_init + fun:main +} +{ + libc-2.12.so + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl +} +{ + + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle +} diff --git a/modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitattributes b/modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitattributes new file mode 100644 index 0000000..6fe6f35 --- /dev/null +++ b/modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitattributes @@ -0,0 +1 @@ +*.t linguist-language=Text diff --git a/modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitignore b/modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitignore new file mode 100644 index 0000000..5e0cb97 --- /dev/null +++ b/modules_deb/libnginx-mod-http-srcache-filter-0.33/.gitignore @@ -0,0 +1,79 @@ +*.mobi +genmobi.sh +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[78] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +src/handler.h +src/util.c +src/module.h +src/module.c +src/drizzle.c +src/processor.h +src/handler.c +src/util.h +src/drizzle.h +src/processor.c +src/output.c +src/output.h +libdrizzle +ctags +src/stream.h +nginx +keepalive +reindex +src/keepalive.c +src/keepalive.h +src/checker.h +src/checker.c +src/quoting.h +src/quoting.c +src/module.h +src/module.c +src/util.h +src/util.c +src/processor.h +src/processor.c +src/rds.h +src/utils.h +src/handler.c +src/handler.h +src/var.[ch] +util/bench +*.html +trace.out* +try.sh +build9 +src/fetch.[ch] +src/store.[ch] +t/servroot/ +headers.[ch] +buildroot/ +build1[0-9] +go +all +analyze +addr2line +*.plist +Makefile diff --git a/modules_deb/libnginx-mod-http-srcache-filter-0.33/.travis.yml b/modules_deb/libnginx-mod-http-srcache-filter-0.33/.travis.yml new file mode 100644 index 0000000..600cf7d --- /dev/null +++ b/modules_deb/libnginx-mod-http-srcache-filter-0.33/.travis.yml @@ -0,0 +1,87 @@ +sudo: required +dist: bionic + +os: linux + +language: c + +cache: + directories: + - download-cache + +compiler: + - gcc + +env: + global: + - LUAJIT_PREFIX=/opt/luajit21 + - LUAJIT_LIB=$LUAJIT_PREFIX/lib + - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH + - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 + - LUA_INCLUDE_DIR=$LUAJIT_INC + - LUA_CMODULE_DIR=/lib + - JOBS=3 + - NGX_BUILD_JOBS=$JOBS + matrix: + - NGINX_VERSION=1.17.8 + - NGINX_VERSION=1.19.9 + - NGINX_VERSION=1.23.0 + +services: + - memcache + - redis-server + - postgresql + - mysql + +before_install: + - sudo apt-get install -qq -y axel cpanminus libtest-base-perl libtext-diff-perl liburi-perl libwww-perl libtest-longstring-perl liblist-moreutils-perl > build.log 2>&1 || (cat build.log && exit 1) + +install: + - echo $HOME + - if [ ! -d download-cache ]; then mkdir download-cache; fi + - if [ ! -f download-cache/ngx_http_redis-0.3.7.tar.gz ]; then wget -O download-cache/ngx_http_redis-0.3.7.tar.gz http://people.freebsd.org/~osa/ngx_http_redis-0.3.7.tar.gz; fi + - if [ ! -f download-cache/drizzle7-2011.07.21.tar.gz ]; then wget -O download-cache/drizzle7-2011.07.21.tar.gz http://openresty.org/download/drizzle7-2011.07.21.tar.gz; fi + - mkdir -p ~/work/nginx && cp download-cache/ngx_http_redis-0.3.7.tar.gz ~/work/nginx/ + - git clone https://github.com/openresty/nginx-devel-utils.git + - git clone https://github.com/openresty/openresty.git ../openresty + - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module + - git clone https://github.com/openresty/test-nginx.git + - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git + - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module + - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + - git clone https://github.com/openresty/nginx-eval-module.git ../eval-nginx-module + - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + - git clone https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module + - git clone https://github.com/openresty/xss-nginx-module.git ../xss-nginx-module + - git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module + - git clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module + - git clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module + - git clone https://github.com/openresty/drizzle-nginx-module.git ../drizzle-nginx-module + - git clone https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module + - git clone https://github.com/openresty/ngx_postgres.git ../postgres-nginx-module + - git clone https://github.com/openresty/openresty.git ../ngx_openresty + +before_script: + - mysql -uroot -e 'create database ngx_test; grant all on ngx_test.* to "ngx_test"@"%" identified by "ngx_test"; flush privileges;' + - psql -c "create database ngx_test;" -U postgres + - psql -c "create user ngx_test with password 'ngx_test';" -U postgres + - psql -c "grant all privileges on database ngx_test to ngx_test;" -U postgres + +script: + - tar xzf download-cache/drizzle7-2011.07.21.tar.gz && cd drizzle7-2011.07.21 + - ./configure --prefix=/usr --without-server > build.log 2>&1 || (cat build.log && exit 1) + - sudo PATH=$PATH make libdrizzle-1.0 install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1) + - cd .. + - cd luajit2 + - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1) + - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) + - cd .. + - cd test-nginx && sudo cpanm . && cd .. + - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH + - export NGX_BUILD_CC=$CC + - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - nginx -V + - ldd `which nginx`|grep luajit + - prove -I. -r t diff --git a/modules_deb/libnginx-mod-http-srcache-filter-0.33/Changes b/modules_deb/libnginx-mod-http-srcache-filter-0.33/Changes new file mode 100644 index 0000000..5f257fe --- /dev/null +++ b/modules_deb/libnginx-mod-http-srcache-filter-0.33/Changes @@ -0,0 +1,16 @@ +v0.12 - 11 July 2011 +* now we properly support fetch/store subrequests with internal redirection in them. main requests with internal redirection will still not be stored into the cache if there is a cache miss. thanks Liseen Wan for reporting it. +* fixed spots that trigger the unused-but-set-variable warning by gcc 4.6. +* added srcache_store_skip and srcache_fetch_skip directives to skip cache fetching or storing based on variables that are set and not empty nor 0. thanks Andre. Examples of using Lua to set $nocache to avoid storing URIs that contain /tmp: + set_by_lua $nocache ' + if string.match(ngx.var.request_uri, "/tmp") then + return "true" + else + return "" + end'; + + srcache_store_skip $nocache; +* added new directive srcache_store_max_size. thanks Andre. +* made our filter optimization work with nginx HUP by clearing the ngx_http_srcache_used flag at nginx pre-config callback. thanks Marcus Clyne. +* now we skip NULL chains in our output filters and also removed the SUBREQUEST_IN_MEMORY flag for our srcache_store subrequests because it will cause mysterious hanging issues when memcached returns CLIENT_ERROR for "get". + diff --git a/modules_deb/libnginx-mod-http-srcache-filter-0.33/README.markdown b/modules_deb/libnginx-mod-http-srcache-filter-0.33/README.markdown new file mode 100644 index 0000000..e880b9c --- /dev/null +++ b/modules_deb/libnginx-mod-http-srcache-filter-0.33/README.markdown @@ -0,0 +1,1258 @@ +Name +==== + +**ngx_srcache** - Transparent subrequest-based caching layout for arbitrary nginx locations + +*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Version](#version) +* [Synopsis](#synopsis) +* [Description](#description) + * [Subrequest caching](#subrequest-caching) + * [Distributed Memcached Caching](#distributed-memcached-caching) + * [Caching with Redis](#caching-with-redis) + * [Cache Key Preprocessing](#cache-key-preprocessing) +* [Directives](#directives) + * [srcache_fetch](#srcache_fetch) + * [srcache_fetch_skip](#srcache_fetch_skip) + * [srcache_store](#srcache_store) + * [srcache_store_max_size](#srcache_store_max_size) + * [srcache_store_skip](#srcache_store_skip) + * [srcache_store_statuses](#srcache_store_statuses) + * [srcache_store_ranges](#srcache_store_ranges) + * [srcache_header_buffer_size](#srcache_header_buffer_size) + * [srcache_store_hide_header](#srcache_store_hide_header) + * [srcache_store_pass_header](#srcache_store_pass_header) + * [srcache_methods](#srcache_methods) + * [srcache_ignore_content_encoding](#srcache_ignore_content_encoding) + * [srcache_request_cache_control](#srcache_request_cache_control) + * [srcache_response_cache_control](#srcache_response_cache_control) + * [srcache_store_no_store](#srcache_store_no_store) + * [srcache_store_no_cache](#srcache_store_no_cache) + * [srcache_store_private](#srcache_store_private) + * [srcache_default_expire](#srcache_default_expire) + * [srcache_max_expire](#srcache_max_expire) +* [Variables](#variables) + * [$srcache_expire](#srcache_expire) + * [$srcache_fetch_status](#srcache_fetch_status) + * [$srcache_store_status](#srcache_store_status) +* [Known Issues](#known-issues) +* [Caveats](#caveats) +* [Trouble Shooting](#trouble-shooting) +* [Installation](#installation) +* [Compatibility](#compatibility) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Source Repository](#source-repository) +* [Test Suite](#test-suite) +* [TODO](#todo) +* [Getting involved](#getting-involved) +* [Author](#author) +* [Copyright & License](#copyright--license) +* [See Also](#see-also) + +Status +====== + +This module is production ready. + +Version +======= + +This document describes srcache-nginx-module [v0.32](https://github.com/openresty/srcache-nginx-module/tags) released on 2 July 2020. + +Synopsis +======== + +```nginx + + upstream my_memcached { + server 10.62.136.7:11211; + keepalive 10; + } + + location = /memc { + internal; + + memc_connect_timeout 100ms; + memc_send_timeout 100ms; + memc_read_timeout 100ms; + memc_ignore_client_abort on; + + set $memc_key $query_string; + set $memc_exptime 300; + + memc_pass my_memcached; + } + + location /foo { + set $key $uri$args; + srcache_fetch GET /memc $key; + srcache_store PUT /memc $key; + srcache_store_statuses 200 301 302 307 308; + + # proxy_pass/fastcgi_pass/drizzle_pass/echo/etc... + # or even static files on the disk + } +``` + +```nginx + + location = /memc2 { + internal; + + memc_connect_timeout 100ms; + memc_send_timeout 100ms; + memc_read_timeout 100ms; + memc_ignore_client_abort on; + + set_unescape_uri $memc_key $arg_key; + set $memc_exptime $arg_exptime; + + memc_pass unix:/tmp/memcached.sock; + } + + location /bar { + set_escape_uri $key $uri$args; + srcache_fetch GET /memc2 key=$key; + srcache_store PUT /memc2 key=$key&exptime=$srcache_expire; + + # proxy_pass/fastcgi_pass/drizzle_pass/echo/etc... + # or even static files on the disk + } +``` + +```nginx + + map $request_method $skip_fetch { + default 0; + POST 1; + PUT 1; + } + + server { + listen 8080; + + location /api/ { + set $key "$uri?$args"; + + srcache_fetch GET /memc $key; + srcache_store PUT /memc $key; + + srcache_methods GET PUT POST; + srcache_fetch_skip $skip_fetch; + + # proxy_pass/drizzle_pass/content_by_lua/echo/... + } + } +``` + +[Back to TOC](#table-of-contents) + +Description +=========== + +This module provides a transparent caching layer for arbitrary nginx locations (like those use an upstream or even serve static disk files). The caching behavior is mostly compatible with [RFC 2616](http://www.ietf.org/rfc/rfc2616.txt). + +Usually, [memc-nginx-module](https://github.com/openresty/memc-nginx-module) is used together with this module to provide a concrete caching storage backend. But technically, any modules that provide a REST interface can be used as the fetching and storage subrequests used by this module. + +For main requests, the [srcache_fetch](#srcache_fetch) directive works at the end of the access phase, so the [standard access module](http://nginx.org/en/docs/http/ngx_http_access_module.html)'s [allow](http://nginx.org/en/docs/http/ngx_http_access_module.html#allow) and [deny](http://nginx.org/en/docs/http/ngx_http_access_module.html#deny) direcives run *before* ours, which is usually the desired behavior for security reasons. + +The workflow of this module looks like below: + +![srcache flowchart](http://agentzh.org/misc/image/srcache-flowchart.png "srcache flowchart") + +[Back to TOC](#table-of-contents) + +Subrequest caching +------------------ + +For *subrequests*, we explicitly **disallow** the use of this module because it's too difficult to get right. There used to be an implementation but it was buggy and I finally gave up fixing it and abandoned it. + +However, if you're using [lua-nginx-module](https://github.com/openresty/lua-nginx-module), it's easy to do subrequest caching in Lua all by yourself. That is, first issue a subrequest to an [memc-nginx-module](https://github.com/openresty/memc-nginx-module) location to do an explicit cache lookup, if cache hit, just use the cached data returned; otherwise, fall back to the true backend, and finally do a cache insertion to feed the data into the cache. + +Using this module for main request caching and Lua for subrequest caching is the approach that we're taking in our business. This hybrid solution works great in production. + +[Back to TOC](#table-of-contents) + +Distributed Memcached Caching +----------------------------- + +Here is a simple example demonstrating a distributed memcached caching mechanism built atop this module. Suppose we do have three different memcached nodes and we use simple modulo to hash our keys. + +```nginx + + http { + upstream moon { + server 10.62.136.54:11211; + server unix:/tmp/memcached.sock backup; + } + + upstream earth { + server 10.62.136.55:11211; + } + + upstream sun { + server 10.62.136.56:11211; + } + + upstream_list universe moon earth sun; + + server { + memc_connect_timeout 100ms; + memc_send_timeout 100ms; + memc_read_timeout 100ms; + + location = /memc { + internal; + + set $memc_key $query_string; + set_hashed_upstream $backend universe $memc_key; + set $memc_exptime 3600; # in seconds + memc_pass $backend; + } + + location / { + set $key $uri; + srcache_fetch GET /memc $key; + srcache_store PUT /memc $key; + + # proxy_pass/fastcgi_pass/content_by_lua/drizzle_pass/... + } + } + } +``` +Here's what is going on in the sample above: +1. We first define three upstreams, `moon`, `earth`, and `sun`. These are our three memcached servers. +1. And then we group them together as an upstream list entity named `universe` with the `upstream_list` directive provided by [set-misc-nginx-module](https://github.com/openresty/set-misc-nginx-module). +1. After that, we define an internal location named `/memc` for talking to the memcached cluster. +1. In this `/memc` location, we first set the `$memc_key` variable with the query string (`$args`), and then use the [set_hashed_upstream](https://github.com/openresty/set-misc-nginx-module#set_hashed_upstream) directive to hash our [$memc_key](https://github.com/openresty/memc-nginx-module#memc_key) over the upsteam list `universe`, so as to obtain a concrete upstream name to be assigned to the variable `$backend`. +1. We pass this `$backend` variable into the [memc_pass](https://github.com/openresty/memc-nginx-module#memc_pass) directive. The `$backend` variable can hold a value among `moon`, `earth`, and `sun`. +1. Also, we define the memcached caching expiration time to be 3600 seconds (i.e., an hour) by overriding the [$memc_exptime](https://github.com/openresty/memc-nginx-module#memc_exptime) variable. +1. In our main public location `/`, we configure the `$uri` variable as our cache key, and then configure [srcache_fetch](#srcache_fetch) for cache lookups and [srcache_store](#srcache_store) for cache updates. We're using two subrequests to our `/memc` location defined earlier in these two directives. + +One can use [lua-nginx-module](https://github.com/openresty/lua-nginx-module)'s [set_by_lua](https://github.com/openresty/lua-nginx-module#set_by_lua) or [rewrite_by_lua](https://github.com/openresty/lua-nginx-module#rewrite_by_lua) directives to inject custom Lua code to compute the `$backend` and/or `$key` variables in the sample above. + +One thing that should be taken care of is that memcached does have restriction on key lengths, i.e., 250 bytes, so for keys that may be very long, one could use the [set_md5](https://github.com/openresty/set-misc-nginx-module#set_md5) directive or its friends to pre-hash the key to a fixed-length digest before assigning it to `$memc_key` in the `/memc` location or the like. + +Further, one can utilize the [srcache_fetch_skip](#srcache_fetch_skip) and [srcache_store_skip](#srcache_store_skip) directives to control what to cache and what not on a per-request basis, and Lua can also be used here in a similar way. So the possibility is really unlimited. + +To maximize speed, we often enable TCP (or Unix Domain Socket) connection pool for our memcached upstreams provided by [HttpUpstreamKeepaliveModule](http://wiki.nginx.org/HttpUpstreamKeepaliveModule), for example, + +```nginx + + upstream moon { + server 10.62.136.54:11211; + server unix:/tmp/memcached.sock backup; + keepalive 10; + } +``` + +where we define a connection pool which holds up to 10 keep-alive connections (per nginx worker process) for our `moon` upstream (cluster). + +[Back to TOC](#table-of-contents) + +Caching with Redis +------------------ + +Redis is an alternative key-value store with many additional features. + +Here is a working example using the lua-resty-redis module: + +``` + location ~ '\.php$|^/update.php' { + # cache setup + set $key $request_uri; + try_files $uri =404; + + srcache_fetch_skip $skip_cache; + srcache_store_skip $skip_cache; + + srcache_response_cache_control off; + srcache_store_statuses 200 201 301 302 307 308 404 503; + + set_escape_uri $escaped_key $key; + + srcache_fetch GET /redis-fetch $key; + srcache_store PUT /redis-store key=$escaped_key; + + more_set_headers 'X-Cache-Fetch-Status $srcache_fetch_status'; + more_set_headers 'X-Cache-Store-Status $srcache_store_status'; + + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + # Security note: If you're running a version of PHP older than the + # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. + # See http://serverfault.com/q/627903/94922 for details. + include fastcgi_params; + # Block httproxy attacks. See https://httpoxy.org/. + fastcgi_param HTTP_PROXY ""; + fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + fastcgi_intercept_errors on; + + fastcgi_pass upstream-name; + } + + location /redis-fetch { + internal; + + resolver 8.8.8.8 valid=300s; + resolver_timeout 10s; + + content_by_lua_block { + local key = assert(ngx.var.request_uri, "no key found") + local redis = require "resty.redis" + local red, err = redis:new() + if not red then + ngx.log(ngx.ERR, "Failed to create redis variable, error -> ", err) + ngx.exit(500) + end + assert(red:connect("redis-master.default.svc.cluster.local", 6379)) + if not red then + ngx.log(ngx.ERR, "Failed to connect to redis, error -> ", err) + ngx.exit(500) + end + local res, err = red:auth("redispassword") + if not res then + ngx.say("failed to authenticate, ", err) + ngx.exit(500) + end + local data = assert(red:get(key)) + assert(red:set_keepalive(10000, 100)) + if res == ngx.null then + return ngx.exit(404) + end + ngx.print(data) + } + } + + location /redis-store { + internal; + + resolver 8.8.8.8 valid=300s; + resolver_timeout 10s; + + content_by_lua_block { + local value = assert(ngx.req.get_body_data(), "no value found") + local key = assert(ngx.var.request_uri, "no key found") + local redis = require "resty.redis" + local red, err = redis:new() + if not red then + ngx.log(ngx.ERR, "Failed to create redis variable, error -> ", err) + ngx.exit(500) + end + assert(red:connect("redis-master.default.svc.cluster.local", 6379)) + if not red then + ngx.log(ngx.ERR, "Failed to connect to redis, error -> ", err) + ngx.exit(500) + end + local res, err = red:auth("redispassword") + if not res then + ngx.say("failed to authenticate, ", err) + ngx.exit(500) + end + local data = assert(red:set(key, value)) + assert(red:set_keepalive(10000, 100)) + if res == ngx.null then + return ngx.exit(404) + end + } + } +``` + + +Here is a working example by using the HTTPRedis (fetch) and Redis2 (store) modules: + +```nginx + + location /api { + default_type text/css; + + set $key $uri; + set_escape_uri $escaped_key $key; + + srcache_fetch GET /redis $key; + srcache_store PUT /redis2 key=$escaped_key&exptime=120; + + # fastcgi_pass/proxy_pass/drizzle_pass/postgres_pass/echo/etc + } + + location = /redis { + internal; + + set_md5 $redis_key $args; + redis_pass 127.0.0.1:6379; + } + + location = /redis2 { + internal; + + set_unescape_uri $exptime $arg_exptime; + set_unescape_uri $key $arg_key; + set_md5 $key; + + redis2_query set $key $echo_request_body; + redis2_query expire $key $exptime; + redis2_pass 127.0.0.1:6379; + } +``` + +This example makes use of the [$echo_request_body](https://github.com/openresty/echo-nginx-module#echo_request_body) variable provided by [echo-nginx-module](https://github.com/openresty/echo-nginx-module). Note that you need the latest version of [echo-nginx-module](https://github.com/openresty/echo-nginx-module), `v0.38rc2` because earlier versions may not work reliably. + +Also, you need both [HttpRedisModule](http://wiki.nginx.org/HttpRedisModule) and [redis2-nginx-module](https://github.com/openresty/redis2-nginx-module). The former is used in the [srcache_fetch](#srcache_fetch) subrequest and the latter is used in the [srcache_store](#srcache_store) subrequest. + +The Nginx core also has a bug that could prevent [redis2-nginx-module](https://github.com/openresty/redis2-nginx-module)'s pipelining support from working properly in certain extreme conditions. And the following patch fixes this: + + http://mailman.nginx.org/pipermail/nginx-devel/2012-March/002040.html + +Note that, however, if you are using the [OpenResty](http://openresty.org/) 1.0.15.3 bundle or later, then you already have everything that you need here in the bundle. + +[Back to TOC](#table-of-contents) + +Cache Key Preprocessing +----------------------- + +It is often desired to preprocess the cache key to exclude random noises that may hurt the cache hit rate. For example, random session IDs in the URI arguments are usually desired to get removed. + +Consider the following URI querystring + + SID=BC3781C3-2E02-4A11-89CF-34E5CFE8B0EF&UID=44332&L=EN&M=1&H=1&UNC=0&SRC=LK&RT=62 + +we want to remove the `SID` and `UID` arguments from it. It is easy to achieve if you use [lua-nginx-module](https://github.com/openresty/lua-nginx-module) at the same time: + +```nginx + + location = /t { + rewrite_by_lua ' + local args = ngx.req.get_uri_args() + args.SID = nil + args.UID = nil + ngx.req.set_uri_args(args) + '; + + echo $args; + } +``` + +Here we use the [echo](https://github.com/openresty/echo-nginx-module#echo) directive from [echo-nginx-module](https://github.com/openresty/echo-nginx-module) to dump out +the final value of [$args](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_args) in the end. You can replace it with your +[srcache-nginx-module](https://github.com/openresty/srcache-nginx-module) configurations and upstream configurations instead for +your case. Let's test this /t interface with curl: + + $ curl 'localhost:8081/t?RT=62&SID=BC3781C3-2E02-4A11-89CF-34E5CFE8B0EF&UID=44332&L=EN&M=1&H=1&UNC=0&SRC=LK' + M=1&UNC=0&RT=62&H=1&L=EN&SRC=LK + +It is worth mentioning that, if you want to retain the order of the URI +arguments, then you can do string substitutions on the value of [$args](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_args) +directly, for example, + + location = /t { + rewrite_by_lua ' + local args = ngx.var.args + newargs, n, err = ngx.re.gsub(args, [[\b[SU]ID=[^&]*&?]], "", "jo") + if n and n > 0 then + ngx.var.args = newargs + end + '; + + echo $args; + } + +Now test it with the original curl command again, we get exactly what +we would expect: + + RT=62&L=EN&M=1&H=1&UNC=0&SRC=LK + +But for caching purposes, it's good to normalize the URI argument +order so that you can increase the cache hit rate. And the hash table +entry order used by LuaJIT or Lua can be used to normalize the order +as a nice side effect. + +[Back to TOC](#table-of-contents) + +Directives +========== + +[Back to TOC](#table-of-contents) + +srcache_fetch +------------- +**syntax:** *srcache_fetch <method> <uri> <args>?* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *post-access* + +This directive registers an access phase handler that will issue an Nginx subrequest to lookup the cache. + +When the subrequest returns status code other than `200`, than a cache miss is signaled and the control flow will continue to the later phases including the content phase configured by [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html), and others. If the subrequest returns `200 OK`, then a cache hit is signaled and this module will send the subrequest's response as the current main request's response to the client directly. + +This directive will always run at the end of the access phase, such that [ngx_http_access_module](http://nginx.org/en/docs/http/ngx_http_access_module.html)'s [allow](http://nginx.org/en/docs/http/ngx_http_access_module.html#allow) and [deny](http://nginx.org/en/docs/http/ngx_http_access_module.html#deny) will always run *before* this. + +You can use the [srcache_fetch_skip](#srcache_fetch_skip) directive to disable cache look-up selectively. + +[Back to TOC](#table-of-contents) + +srcache_fetch_skip +------------------ +**syntax:** *srcache_fetch_skip <flag>* + +**default:** *srcache_fetch_skip 0* + +**context:** *http, server, location, location if* + +**phase:** *post-access* + +The `` argument supports nginx variables. When this argument's value is not empty *and* not equal to `0`, then the fetching process will be unconditionally skipped. + +For example, to skip caching requests which have a cookie named `foo` with the value `bar`, we can write + +```nginx + + location / { + set $key ...; + set_by_lua $skip ' + if ngx.var.cookie_foo == "bar" then + return 1 + end + return 0 + '; + + srcache_fetch_skip $skip; + srcache_store_skip $skip; + + srcache_fetch GET /memc $key; + srcache_store GET /memc $key; + + # proxy_pass/fastcgi_pass/content_by_lua/... + } +``` +where [lua-nginx-module](https://github.com/openresty/lua-nginx-module) is used to calculate the value of the `$skip` variable at the (earlier) rewrite phase. Similarly, the `$key` variable can be computed by Lua using the [set_by_lua](https://github.com/openresty/lua-nginx-module#set_by_lua) or [rewrite_by_lua](https://github.com/openresty/lua-nginx-module#rewrite_by_lua) directive too. + +The standard [map](http://nginx.org/en/docs/http/ngx_http_map_module.html#map) directive can also be used to compute the value of the `$skip` variable used in the sample above: + +```nginx + + map $cookie_foo $skip { + default 0; + bar 1; + } +``` + +but your [map](http://nginx.org/en/docs/http/ngx_http_map_module.html#map) statement should be put into the `http` config block in your `nginx.conf` file though. + +[Back to TOC](#table-of-contents) + +srcache_store +------------- +**syntax:** *srcache_store <method> <uri> <args>?* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *output-filter* + +This directive registers an output filter handler that will issue an Nginx subrequest to save the response of the current main request into a cache backend. The status code of the subrequest will be ignored. + +You can use the [srcache_store_skip](#srcache_store_skip) and [srcache_store_max_size](#srcache_store_max_size) directives to disable caching for certain requests in case of a cache miss. + +Since the `v0.12rc7` release, both the response status line, response headers, and response bodies will be put into the cache. By default, the following special response headers will not be cached: + +* Connection +* Keep-Alive +* Proxy-Authenticate +* Proxy-Authorization +* TE +* Trailers +* Transfer-Encoding +* Upgrade +* Set-Cookie + +You can use the [srcache_store_pass_header](#srcache_store_pass_header) and/or [srcache_store_hide_header](#srcache_store_hide_header) directives to control what headers to cache and what not. + +The original response's data chunks get emitted as soon as +they arrive. `srcache_store` just copies and collects the data in an output filter without postponing them from being sent downstream. + +But please note that even though all the response data will be sent immediately, the current Nginx request lifetime will not finish until the srcache_store subrequest completes. That means a delay in closing the TCP connection on the server side (when HTTP keepalive is disabled, but proper HTTP clients should close the connection actively on the client side, which adds no extra delay or other issues at all) or serving the next request sent on the same TCP connection (when HTTP keepalive is in action). + +[Back to TOC](#table-of-contents) + +srcache_store_max_size +---------------------- +**syntax:** *srcache_store_max_size <size>* + +**default:** *srcache_store_max_size 0* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +When the response body length is exceeding this size, this module will not try to store the response body into the cache using the subrequest template that is specified in [srcache_store](#srcache_store). + +This is particular useful when using a cache storage backend that does have a hard upper limit on the input data. For example, the Memcached server has a default limit of `1 MB` by item. + +When `0` is specified (the default value), there's no limit check at all. + +[Back to TOC](#table-of-contents) + +srcache_store_skip +------------------ +**syntax:** *srcache_store_skip <flag>* + +**default:** *srcache_store_skip 0* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +The `` argument supports Nginx variables. When this argument's value is not empty *and* not equal to `0`, then the storing process will be unconditionally skipped. + +Starting from the `v0.25` release, the `` expression (possibly containing Nginx variables) can be evaluated up to twice: the first time is right after the response header is being sent and when the `` expression is not evaluated to true values it will be evaluated again right after the end of the response body data stream is seen. Before `v0.25`, only the first time evaluation is performed. + +Here's an example using Lua to set $nocache to avoid storing URIs that contain the string "/tmp": + +```nginx + + set_by_lua $nocache ' + if string.match(ngx.var.uri, "/tmp") then + return 1 + end + return 0'; + + srcache_store_skip $nocache; +``` + +[Back to TOC](#table-of-contents) + +srcache_store_statuses +---------------------- +**syntax:** *srcache_store_statuses <status1> <status2> ..* + +**default:** *srcache_store_statuses 200 301 302 307 308* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +This directive controls what responses to store to the cache according to their status code. + +By default, only `200`, `301`, `302`, `307` and `308` responses will be stored to cache and any other responses will skip [srcache_store](#srcache_store). + +You can specify arbitrary positive numbers for the response status code that you'd like to cache, even including error code like `404` and `503`. For example: + +```nginx + + srcache_store_statuses 200 201 301 302 307 308 404 503; +``` + +At least one argument should be given to this directive. + +This directive was first introduced in the `v0.13rc2` release. + +[Back to TOC](#table-of-contents) + +srcache_store_ranges +-------------------- +**syntax:** *srcache_store_ranges on|off* + +**default:** *srcache_store_ranges off* + +**context:** *http, server, location, location if* + +**phase:** *output-body-filter* + +When this directive is turned on (default to `off`), [srcache_store](#srcache_store) will also store 206 Partial Content responses generated by the standard `ngx_http_range_filter_module`. If you turn this directive on, you MUST add `$http_range` to your cache keys. For example, + +```nginx + + location / { + set $key "$uri$args$http_range"; + srcache_fetch GET /memc $key; + srcache_store PUT /memc $key; + } +``` + +This directive was first introduced in the `v0.27` release. + +[Back to TOC](#table-of-contents) + +srcache_header_buffer_size +-------------------------- +**syntax:** *srcache_header_buffer_size <size>* + +**default:** *srcache_header_buffer_size 4k/8k* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +This directive controles the header buffer when serializing response headers for [srcache_store](#srcache_store). The default size is the page size, usually `4k` or `8k` depending on specific platforms. + +Note that the buffer is not used to hold all the response headers, but just each individual header. So the buffer is merely needed to be big enough to hold the longest response header. + +This directive was first introduced in the `v0.12rc7` release. + +[Back to TOC](#table-of-contents) + +srcache_store_hide_header +------------------------- +**syntax:** *srcache_store_hide_header <header>* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +By default, this module caches all the response headers except the following ones: + +* Connection +* Keep-Alive +* Proxy-Authenticate +* Proxy-Authorization +* TE +* Trailers +* Transfer-Encoding +* Upgrade +* Set-Cookie + +You can hide even more response headers from [srcache_store](#srcache_store) by listing their names (case-insensitive) by means of this directive. For examples, + +```nginx + + srcache_store_hide_header X-Foo; + srcache_store_hide_header Last-Modified; +``` + +Multiple occurrences of this directive are allowed in a single location. + +This directive was first introduced in the `v0.12rc7` release. + +See also [srcache_store_pass_header](#srcache_store_pass_header). + +[Back to TOC](#table-of-contents) + +srcache_store_pass_header +------------------------- +**syntax:** *srcache_store_pass_header <header>* + +**default:** *no* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +By default, this module caches all the response headers except the following ones: + +* Connection +* Keep-Alive +* Proxy-Authenticate +* Proxy-Authorization +* TE +* Trailers +* Transfer-Encoding +* Upgrade +* Set-Cookie + +You can force [srcache_store](#srcache_store) to store one or more of these response headers from [srcache_store](#srcache_store) by listing their names (case-insensitive) by means of this directive. For examples, + +```nginx + + srcache_store_pass_header Set-Cookie; + srcache_store_pass_header Proxy-Autenticate; +``` + +Multiple occurrences of this directive are allowed in a single location. + +This directive was first introduced in the `v0.12rc7` release. + +See also [srcache_store_hide_header](#srcache_store_hide_header). + +[Back to TOC](#table-of-contents) + +srcache_methods +--------------- +**syntax:** *srcache_methods <method>...* + +**default:** *srcache_methods GET HEAD* + +**context:** *http, server, location* + +**phase:** *post-access, output-header-filter* + +This directive specifies HTTP request methods that are considered by either [srcache_fetch](#srcache_fetch) or [srcache_store](#srcache_store). HTTP request methods not listed will be skipped completely from the cache. + +The following HTTP methods are allowed: `GET`, `HEAD`, `POST`, `PUT`, and `DELETE`. The `GET` and `HEAD` methods are always implicitly included in the list regardless of their presence in this directive. + +Note that since the `v0.17` release `HEAD` requests are always skipped by [srcache_store](#srcache_store) because their responses never carry a response body. + +This directive was first introduced in the `v0.12rc7` release. + +[Back to TOC](#table-of-contents) + +srcache_ignore_content_encoding +------------------------------- +**syntax:** *srcache_ignore_content_encoding on|off* + +**default:** *srcache_ignore_content_encoding off* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +When this directive is turned `off` (which is the default), non-empty `Content-Encoding` response header will cause [srcache_store](#srcache_store) skip storing the whole response into the cache and issue a warning into nginx's `error.log` file like this: + + + [warn] 12500#0: *1 srcache_store skipped due to response header "Content-Encoding: gzip" + (maybe you forgot to disable compression on the backend?) + + +Turning on this directive will ignore the `Content-Encoding` response header and store the response as usual (and also without warning). + +It's recommended to always disable gzip/deflate compression on your backend server by specifying the following line in your `nginx.conf` file: + +```nginx + + proxy_set_header Accept-Encoding ""; +``` + +This directive was first introduced in the `v0.12rc7` release. + +[Back to TOC](#table-of-contents) + +srcache_request_cache_control +----------------------------- +**syntax:** *srcache_request_cache_control on|off* + +**default:** *srcache_request_cache_control off* + +**context:** *http, server, location* + +**phase:** *post-access, output-header-filter* + +When this directive is turned `on`, the request headers `Cache-Control` and `Pragma` will be honored by this module in the following ways: + +1. [srcache_fetch](#srcache_fetch), i.e., the cache lookup operation, will be skipped when request headers `Cache-Control: no-cache` and/or `Pragma: no-cache` are present. +1. [srcache_store](#srcache_store), i.e., the cache store operation, will be skipped when the request header `Cache-Control: no-store` is specified. + +Turning off this directive will disable this functionality and is considered safer for busy sites mainly relying on cache for speed. + +This directive was first introduced in the `v0.12rc7` release. + +See also [srcache_response_cache_control](#srcache_response_cache_control). + +[Back to TOC](#table-of-contents) + +srcache_response_cache_control +------------------------------ +**syntax:** *srcache_response_cache_control on|off* + +**default:** *srcache_response_cache_control on* + +**context:** *http, server, location* + +**phase:** *output-header-filter* + +When this directive is turned `on`, the response headers `Cache-Control` and `Expires` will be honored by this module in the following ways: + +* `Cache-Control: private` skips [srcache_store](#srcache_store), +* `Cache-Control: no-store` skips [srcache_store](#srcache_store), +* `Cache-Control: no-cache` skips [srcache_store](#srcache_store), +* `Cache-Control: max-age=0` skips [srcache_store](#srcache_store), +* and `Expires: ` skips [srcache_store](#srcache_store). + +This directive takes priority over the [srcache_store_no_store](#srcache_store_no_store), [srcache_store_no_cache](#srcache_store_no_cache), and [srcache_store_private](#srcache_store_private) directives. + +This directive was first introduced in the `v0.12rc7` release. + +See also [srcache_request_cache_control](#srcache_request_cache_control). + +[Back to TOC](#table-of-contents) + +srcache_store_no_store +---------------------- +**syntax:** *srcache_store_no_store on|off* + +**default:** *srcache_store_no_store off* + +**context:** *http, server, location* + +**phase:** *output-header-filter* + +Turning this directive on will force responses with the header `Cache-Control: no-store` to be stored into the cache when [srcache_response_cache_control](#srcache_response_cache_control) is turned `on` *and* other conditions are met. Default to `off`. + +This directive was first introduced in the `v0.12rc7` release. + +[Back to TOC](#table-of-contents) + +srcache_store_no_cache +---------------------- +**syntax:** *srcache_store_no_cache on|off* + +**default:** *srcache_store_no_cache off* + +**context:** *http, server, location* + +**phase:** *output-header-filter* + +Turning this directive on will force responses with the header `Cache-Control: no-cache` to be stored into the cache when [srcache_response_cache_control](#srcache_response_cache_control) is turned `on` *and* other conditions are met. Default to `off`. + +This directive was first introduced in the `v0.12rc7` release. + +[Back to TOC](#table-of-contents) + +srcache_store_private +--------------------- +**syntax:** *srcache_store_private on|off* + +**default:** *srcache_store_private off* + +**context:** *http, server, location* + +**phase:** *output-header-filter* + +Turning this directive on will force responses with the header `Cache-Control: private` to be stored into the cache when [srcache_response_cache_control](#srcache_response_cache_control) is turned `on` *and* other conditions are met. Default to `off`. + +This directive was first introduced in the `v0.12rc7` release. + +[Back to TOC](#table-of-contents) + +srcache_default_expire +---------------------- +**syntax:** *srcache_default_expire <time>* + +**default:** *srcache_default_expire 60s* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +This directive controls the default expiration time period that is allowed for the [$srcache_expire](#srcache_expire) variable value when neither `Cache-Control: max-age=N` nor `Expires` are specified in the response headers. + +The `